From 5f2df548112942e38b90221f9b0b04fa442461dd Mon Sep 17 00:00:00 2001 From: Chris Hennes Date: Sat, 3 Feb 2024 22:28:50 +0100 Subject: [PATCH] Addon Manager: Refactor overall top bar --- src/Mod/AddonManager/AddonManager.py | 4 +- src/Mod/AddonManager/Widgets/CMakeLists.txt | 2 +- .../Widgets/addonmanager_widget_top_bar.py | 159 ------------------ .../addonmanager_widget_view_control_bar.py | 74 ++++++++ .../AddonManager/addonmanager_utilities.py | 3 +- src/Mod/AddonManager/package_list.py | 42 ++--- 6 files changed, 91 insertions(+), 193 deletions(-) delete mode 100644 src/Mod/AddonManager/Widgets/addonmanager_widget_top_bar.py create mode 100644 src/Mod/AddonManager/Widgets/addonmanager_widget_view_control_bar.py diff --git a/src/Mod/AddonManager/AddonManager.py b/src/Mod/AddonManager/AddonManager.py index fad624cbdb..7a2680ce67 100644 --- a/src/Mod/AddonManager/AddonManager.py +++ b/src/Mod/AddonManager/AddonManager.py @@ -481,7 +481,7 @@ class CommandAddonManager: def activate_table_widgets(self) -> None: self.packageList.setEnabled(True) - self.packageList.ui.search_box.setFocus() + self.packageList.ui.view_bar.search.setFocus() self.do_next_startup_phase() def populate_macros(self) -> None: @@ -824,7 +824,7 @@ class CommandAddonManager: self.dialog.labelStatusInfo.hide() self.dialog.progressBar.hide() self.dialog.buttonPauseUpdate.hide() - self.packageList.ui.search_box.setFocus() + self.packageList.ui.view_bar.search.setFocus() def show_progress_widgets(self) -> None: if self.dialog.progressBar.isHidden(): diff --git a/src/Mod/AddonManager/Widgets/CMakeLists.txt b/src/Mod/AddonManager/Widgets/CMakeLists.txt index 2f1f6762a5..61d8d613b1 100644 --- a/src/Mod/AddonManager/Widgets/CMakeLists.txt +++ b/src/Mod/AddonManager/Widgets/CMakeLists.txt @@ -2,7 +2,7 @@ SET(AddonManagerWidget_SRCS __init__.py addonmanager_widget_filter_selector.py addonmanager_widget_search.py - addonmanager_widget_top_bar.py + addonmanager_widget_view_control_bar.py addonmanager_widget_view_selector.py ) diff --git a/src/Mod/AddonManager/Widgets/addonmanager_widget_top_bar.py b/src/Mod/AddonManager/Widgets/addonmanager_widget_top_bar.py deleted file mode 100644 index d1c6993d7e..0000000000 --- a/src/Mod/AddonManager/Widgets/addonmanager_widget_top_bar.py +++ /dev/null @@ -1,159 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1-or-later -# *************************************************************************** -# * * -# * Copyright (c) 2022-2024 FreeCAD Project Association * -# * * -# * This file is part of FreeCAD. * -# * * -# * FreeCAD is free software: you can redistribute it and/or modify it * -# * under the terms of the GNU Lesser General Public License as * -# * published by the Free Software Foundation, either version 2.1 of the * -# * License, or (at your option) any later version. * -# * * -# * FreeCAD is distributed in the hope that it will be useful, but * -# * WITHOUT ANY WARRANTY; without even the implied warranty of * -# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * -# * Lesser General Public License for more details. * -# * * -# * You should have received a copy of the GNU Lesser General Public * -# * License along with FreeCAD. If not, see * -# * . * -# * * -# *************************************************************************** - -""" Defines a class derived from QWidget for displaying the bar at the top of the addons list. """ - -from enum import IntEnum -from addonmanager_widget_view_selector import WidgetViewSelector - -# Get whatever version of PySide we can -try: - import PySide # Use the FreeCAD wrapper -except ImportError: - try: - import PySide6 # Outside FreeCAD, try Qt6 first - - PySide = PySide6 - except ImportError: - import PySide2 # Fall back to Qt5 (if this fails, Python will kill this module's import) - - PySide = PySide2 - -from PySide import QtCore, QtWidgets - -translate = FreeCAD.Qt.translate - - -class StatusFilter(IntEnum): - """Predefined filers""" - - ANY = 0 - INSTALLED = 1 - NOT_INSTALLED = 2 - UPDATE_AVAILABLE = 3 - - -# pylint: disable=too-few-public-methods - - -class WidgetTopBar(QtWidgets.QWidget): - """A widget to display the buttons at the top of the Addon manager, for changing the view, - filtering, and sorting.""" - - view_changed = QtCore.Signal(int) - filter_changed = QtCore.Signal(str) - search_changed = QtCore.Signal(str) - - def __init__(self, parent=None): - super().__init__(parent) - self.horizontal_layout = None - self.package_type_label = None - self.package_type_combobox = None - self._setup_ui() - self._setup_connections() - self.retranslateUi() - - def _setup_ui(self): - self.horizontal_layout = QtWidgets.QHBoxLayout() - - self.view_selector = WidgetViewSelector(self) - self.horizontal_layout.addWidget(self.view_selector) - - self.package_type_label = QtWidgets.QLabel(self) - self.horizontal_layout.addWidget(self.package_type_label) - - self.package_type_combobox = QtWidgets.QComboBox(self) - self.horizontal_layout.addWidget(self.package_type_combobox) - - self.status_combo_box = QtWidgets.QComboBox(self) - self.horizontal_layout.addWidget(self.status_combo_box) - - self.filter_line_edit = QtWidgets.QLineEdit(self) - self.horizontal_layout.addWidget(self.filter_line_edit) - - # Only shows when the user types in a filter - self.ui.filter_validity_label = QtWidgets.QLabel(self) - self.horizontal_layout.addWidget(self.filter_validity_label) - self.ui.filter_validity_label.hide() - - def _setup_connections(self): - self.ui.view_selector.view_changed.connect(self.view_changed.emit) - - # Set up the view the same as the last time: - pref = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Addons") - package_type = pref.GetInt("PackageTypeSelection", 1) - self.ui.comboPackageType.setCurrentIndex(package_type) - status = pref.GetInt("StatusSelection", 0) - self.ui.comboStatus.setCurrentIndex(status) - - def update_type_filter(self, type_filter: int) -> None: - """hide/show rows corresponding to the type filter - - type_filter is an integer: 0 for all, 1 for workbenches, 2 for macros, - and 3 for preference packs - - """ - - self.item_filter.setPackageFilter(type_filter) - pref = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Addons") - pref.SetInt("PackageTypeSelection", type_filter) - - def update_status_filter(self, status_filter: int) -> None: - """hide/show rows corresponding to the status filter - - status_filter is an integer: 0 for any, 1 for installed, 2 for not installed, - and 3 for update available - - """ - - self.item_filter.setStatusFilter(status_filter) - pref = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Addons") - pref.SetInt("StatusSelection", status_filter) - - def update_text_filter(self, text_filter: str) -> None: - """filter name and description by the regex specified by text_filter""" - - if text_filter: - if hasattr(self.item_filter, "setFilterRegularExpression"): # Added in Qt 5.12 - test_regex = QtCore.QRegularExpression(text_filter) - else: - test_regex = QtCore.QRegExp(text_filter) - if test_regex.isValid(): - self.ui.labelFilterValidity.setToolTip( - translate("AddonsInstaller", "Filter is valid") - ) - icon = QtGui.QIcon.fromTheme("ok", QtGui.QIcon(":/icons/edit_OK.svg")) - self.ui.labelFilterValidity.setPixmap(icon.pixmap(16, 16)) - else: - self.ui.labelFilterValidity.setToolTip( - translate("AddonsInstaller", "Filter regular expression is invalid") - ) - icon = QtGui.QIcon.fromTheme("cancel", QtGui.QIcon(":/icons/edit_Cancel.svg")) - self.ui.labelFilterValidity.setPixmap(icon.pixmap(16, 16)) - self.ui.labelFilterValidity.show() - else: - self.ui.labelFilterValidity.hide() - if hasattr(self.item_filter, "setFilterRegularExpression"): # Added in Qt 5.12 - self.item_filter.setFilterRegularExpression(text_filter) - else: - self.item_filter.setFilterRegExp(text_filter) diff --git a/src/Mod/AddonManager/Widgets/addonmanager_widget_view_control_bar.py b/src/Mod/AddonManager/Widgets/addonmanager_widget_view_control_bar.py new file mode 100644 index 0000000000..286ceac589 --- /dev/null +++ b/src/Mod/AddonManager/Widgets/addonmanager_widget_view_control_bar.py @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# *************************************************************************** +# * * +# * Copyright (c) 2022-2024 FreeCAD Project Association * +# * * +# * This file is part of FreeCAD. * +# * * +# * FreeCAD is free software: you can redistribute it and/or modify it * +# * under the terms of the GNU Lesser General Public License as * +# * published by the Free Software Foundation, either version 2.1 of the * +# * License, or (at your option) any later version. * +# * * +# * FreeCAD is distributed in the hope that it will be useful, but * +# * WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * +# * Lesser General Public License for more details. * +# * * +# * You should have received a copy of the GNU Lesser General Public * +# * License along with FreeCAD. If not, see * +# * . * +# * * +# *************************************************************************** + +""" Defines a class derived from QWidget for displaying the bar at the top of the addons list. """ + +# Get whatever version of PySide we can +try: + import PySide # Use the FreeCAD wrapper +except ImportError: + try: + import PySide6 # Outside FreeCAD, try Qt6 first + + PySide = PySide6 + except ImportError: + import PySide2 # Fall back to Qt5 (if this fails, Python will kill this module's import) + + PySide = PySide2 + +from PySide import QtCore, QtWidgets +from .addonmanager_widget_view_selector import WidgetViewSelector +from .addonmanager_widget_filter_selector import WidgetFilterSelector +from .addonmanager_widget_search import WidgetSearch + + +class WidgetViewControlBar(QtWidgets.QWidget): + """A bar containing a view selection widget, a filter widget, and a search widget""" + + view_changed = QtCore.Signal(int) + filter_changed = QtCore.Signal(object) + search_changed = QtCore.Signal(str) + + def __init__(self, parent: QtWidgets.QWidget = None): + super().__init__(parent) + self._setup_ui() + self._setup_connections() + self.retranslateUi(None) + + def _setup_ui(self): + self.horizontal_layout = QtWidgets.QHBoxLayout() + self.view_selector = WidgetViewSelector(self) + self.filter_selector = WidgetFilterSelector(self) + self.search = WidgetSearch(self) + self.horizontal_layout.addWidget(self.view_selector) + self.horizontal_layout.addWidget(self.filter_selector) + self.horizontal_layout.addWidget(self.search) + self.setLayout(self.horizontal_layout) + + def _setup_connections(self): + self.view_selector.view_changed.connect(self.view_changed.emit) + self.filter_selector.filter_changed.connect(self.filter_changed.emit) + self.search.search_changed.connect(self.search_changed.emit) + + def retranslateUi(self, _=None): + pass diff --git a/src/Mod/AddonManager/addonmanager_utilities.py b/src/Mod/AddonManager/addonmanager_utilities.py index ac91794424..41d6a81229 100644 --- a/src/Mod/AddonManager/addonmanager_utilities.py +++ b/src/Mod/AddonManager/addonmanager_utilities.py @@ -40,6 +40,7 @@ try: except ImportError: QtCore = None QtWidgets = None + QtGui = None import addonmanager_freecad_interface as fci @@ -95,7 +96,7 @@ def symlink(source, link_name): raise ctypes.WinError() -def rmdir(path: os.PathLike) -> bool: +def rmdir(path: str) -> bool: try: if os.path.islink(path): os.unlink(path) # Remove symlink diff --git a/src/Mod/AddonManager/package_list.py b/src/Mod/AddonManager/package_list.py index 6279990c9c..2d8c2b0565 100644 --- a/src/Mod/AddonManager/package_list.py +++ b/src/Mod/AddonManager/package_list.py @@ -37,9 +37,9 @@ from expanded_view import Ui_ExpandedView import addonmanager_utilities as utils from addonmanager_metadata import get_first_supported_freecad_version, Version -from Widgets.addonmanager_widget_view_selector import WidgetViewSelector, AddonManagerDisplayStyle -from Widgets.addonmanager_widget_search import WidgetSearch -from Widgets.addonmanager_widget_filter_selector import WidgetFilterSelector, StatusFilter, Filter +from Widgets.addonmanager_widget_view_control_bar import WidgetViewControlBar +from Widgets.addonmanager_widget_view_selector import AddonManagerDisplayStyle +from Widgets.addonmanager_widget_filter_selector import StatusFilter, Filter, ContentFilter translate = FreeCAD.Qt.translate @@ -64,16 +64,16 @@ class PackageList(QtWidgets.QWidget): self.ui.listPackages.setItemDelegate(self.item_delegate) self.ui.listPackages.clicked.connect(self.on_listPackages_clicked) - self.ui.filter_selector.filter_changed.connect(self.update_status_filter) - self.ui.search_box.search_changed.connect(self.item_filter.setFilterRegularExpression) - self.ui.view_selector.view_changed.connect(self.set_view_style) + self.ui.view_bar.view_changed.connect(self.set_view_style) + self.ui.view_bar.filter_changed.connect(self.update_status_filter) + self.ui.view_bar.search_changed.connect(self.item_filter.setFilterRegularExpression) # Set up the view the same as the last time: pref = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Addons") package_type = pref.GetInt("PackageTypeSelection", 1) status = pref.GetInt("StatusSelection", 0) - self.ui.filter_selector.set_contents_filter(package_type) - self.ui.filter_selector.set_status_filter(status) + self.ui.view_bar.filter_selector.set_contents_filter(package_type) + self.ui.view_bar.filter_selector.set_status_filter(status) # Pre-init of other members: self.item_model = None @@ -87,7 +87,7 @@ class PackageList(QtWidgets.QWidget): pref = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Addons") style = pref.GetInt("ViewStyle", AddonManagerDisplayStyle.EXPANDED) self.set_view_style(style) - self.ui.view_selector.set_current_view(style) + self.ui.view_bar.view_selector.set_current_view(style) self.item_filter.setHidePy2(pref.GetBool("HidePy2", True)) self.item_filter.setHideObsolete(pref.GetBool("HideObsolete", True)) @@ -599,22 +599,9 @@ class Ui_PackageList: self.horizontalLayout_6 = QtWidgets.QHBoxLayout() self.horizontalLayout_6.setObjectName("horizontalLayout_6") - self.view_selector = WidgetViewSelector(form) - self.horizontalLayout_6.addWidget(self.view_selector) - - self.labelPackagesContaining = QtWidgets.QLabel(form) - self.labelPackagesContaining.setObjectName("labelPackagesContaining") - - self.horizontalLayout_6.addWidget(self.labelPackagesContaining) - - self.filter_selector = WidgetFilterSelector(form) - self.filter_selector.setObjectName("filter_selector") - self.horizontalLayout_6.addWidget(self.filter_selector) - - self.search_box = WidgetSearch(form) - self.search_box.setObjectName("search_box") - - self.horizontalLayout_6.addWidget(self.search_box) + self.view_bar = WidgetViewControlBar(form) + self.view_bar.setObjectName("ViewControlBar") + self.horizontalLayout_6.addWidget(self.view_bar) self.verticalLayout.addLayout(self.horizontalLayout_6) @@ -630,9 +617,4 @@ class Ui_PackageList: self.verticalLayout.addWidget(self.listPackages) - self.retranslateUi(form) - QtCore.QMetaObject.connectSlotsByName(form) - - def retranslateUi(self, _): - pass