From 418ccc870f8e401e3f8bdc2c1ae4dec3d1cb9ce4 Mon Sep 17 00:00:00 2001 From: Chris Hennes Date: Sun, 4 Feb 2024 14:48:04 -0600 Subject: [PATCH] Addon Manager: Refactor global button bar --- src/Mod/AddonManager/AddonManager.py | 75 ++++++------- src/Mod/AddonManager/AddonManager.ui | 90 +--------------- src/Mod/AddonManager/Widgets/CMakeLists.txt | 1 + .../addonmanager_widget_global_buttons.py | 100 ++++++++++++++++++ 4 files changed, 141 insertions(+), 125 deletions(-) create mode 100644 src/Mod/AddonManager/Widgets/addonmanager_widget_global_buttons.py diff --git a/src/Mod/AddonManager/AddonManager.py b/src/Mod/AddonManager/AddonManager.py index 8d80b689fa..2c2dcabf63 100644 --- a/src/Mod/AddonManager/AddonManager.py +++ b/src/Mod/AddonManager/AddonManager.py @@ -53,6 +53,7 @@ import addonmanager_utilities as utils import AddonManager_rc # This is required by Qt, it's not unused from package_list import PackageList, PackageListItemModel from package_details import PackageDetails +from Widgets.addonmanager_widget_global_buttons import WidgetGlobalButtonBar from Addon import Addon from manage_python_dependencies import ( PythonPackageManager, @@ -130,6 +131,7 @@ class CommandAddonManager: self.update_all_worker = None self.developer_mode = None self.installer_gui = None + self.button_bar = None self.update_cache = False self.dialog = None @@ -185,21 +187,21 @@ class CommandAddonManager: w = pref.GetInt("WindowWidth", 800) h = pref.GetInt("WindowHeight", 600) self.dialog.resize(w, h) + self.button_bar = WidgetGlobalButtonBar(self.dialog) # If we are checking for updates automatically, hide the Check for updates button: autocheck = pref.GetBool("AutoCheck", False) if autocheck: - self.dialog.buttonCheckForUpdates.hide() + self.button_bar.check_for_updates.hide() else: - self.dialog.buttonUpdateAll.hide() + self.button_bar.update_all_addons.hide() # Set up the listing of packages using the model-view-controller architecture self.packageList = PackageList(self.dialog) self.item_model = PackageListItemModel() self.packageList.setModel(self.item_model) - self.dialog.contentPlaceholder.hide() - self.dialog.layout().replaceWidget(self.dialog.contentPlaceholder, self.packageList) - self.packageList.show() + self.dialog.layout().addWidget(self.packageList) + self.dialog.layout().addWidget(self.button_bar) # Package details start out hidden self.packageDetails = PackageDetails(self.dialog) @@ -209,35 +211,30 @@ class CommandAddonManager: # set nice icons to everything, by theme with fallback to FreeCAD icons self.dialog.setWindowIcon(QtGui.QIcon(":/icons/AddonManager.svg")) - self.dialog.buttonUpdateAll.setIcon(QtGui.QIcon(":/icons/button_valid.svg")) - self.dialog.buttonCheckForUpdates.setIcon(QtGui.QIcon(":/icons/view-refresh.svg")) - self.dialog.buttonClose.setIcon( - QtGui.QIcon.fromTheme("close", QtGui.QIcon(":/icons/process-stop.svg")) - ) pref = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Addons") dev_mode_active = pref.GetBool("developerMode", False) # enable/disable stuff - self.dialog.buttonUpdateAll.setEnabled(False) + self.button_bar.update_all_addons.setEnabled(False) self.hide_progress_widgets() - self.dialog.buttonUpdateCache.setEnabled(False) - self.dialog.buttonUpdateCache.setText(translate("AddonsInstaller", "Starting up...")) + self.button_bar.refresh_local_cache.setEnabled(False) + self.button_bar.refresh_local_cache.setText(translate("AddonsInstaller", "Starting up...")) if dev_mode_active: - self.dialog.buttonDevTools.show() + self.button_bar.developer_tools.show() else: - self.dialog.buttonDevTools.hide() + self.button_bar.developer_tools.hide() # connect slots self.dialog.rejected.connect(self.reject) - self.dialog.buttonUpdateAll.clicked.connect(self.update_all) - self.dialog.buttonClose.clicked.connect(self.dialog.reject) - self.dialog.buttonUpdateCache.clicked.connect(self.on_buttonUpdateCache_clicked) - self.dialog.buttonCheckForUpdates.clicked.connect( + self.button_bar.update_all_addons.clicked.connect(self.update_all) + self.button_bar.close.clicked.connect(self.dialog.reject) + self.button_bar.refresh_local_cache.clicked.connect(self.on_buttonUpdateCache_clicked) + self.button_bar.check_for_updates.clicked.connect( lambda: self.force_check_updates(standalone=True) ) - self.dialog.buttonUpdateDependencies.clicked.connect(self.show_python_updates_dialog) - self.dialog.buttonDevTools.clicked.connect(self.show_developer_tools) + self.button_bar.python_dependencies.clicked.connect(self.show_python_updates_dialog) + self.button_bar.developer_tools.clicked.connect(self.show_developer_tools) self.packageList.ui.progressBar.stop_clicked.connect(self.stop_update) self.packageList.itemSelected.connect(self.table_row_activated) self.packageList.setEnabled(False) @@ -415,8 +412,8 @@ class CommandAddonManager: else: self.hide_progress_widgets() self.update_cache = False - self.dialog.buttonUpdateCache.setEnabled(True) - self.dialog.buttonUpdateCache.setText( + self.button_bar.refresh_local_cache.setEnabled(True) + self.button_bar.refresh_local_cache.setText( translate("AddonsInstaller", "Refresh local cache") ) pref = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Addons") @@ -545,8 +542,10 @@ class CommandAddonManager: cache_path = FreeCAD.getUserCachePath() am_path = os.path.join(cache_path, "AddonManager") utils.rmdir(am_path) - self.dialog.buttonUpdateCache.setEnabled(False) - self.dialog.buttonUpdateCache.setText(translate("AddonsInstaller", "Updating cache...")) + self.button_bar.refresh_local_cache.setEnabled(False) + self.button_bar.refresh_local_cache.setText( + translate("AddonsInstaller", "Updating cache...") + ) self.startup() # Recaching implies checking for updates, regardless of the user's autocheck option @@ -608,10 +607,12 @@ class CommandAddonManager: self.do_next_startup_phase() return - self.dialog.buttonUpdateAll.setText(translate("AddonsInstaller", "Checking for updates...")) + self.button_bar.update_all_addons.setText( + translate("AddonsInstaller", "Checking for updates...") + ) self.packages_with_updates.clear() - self.dialog.buttonUpdateAll.show() - self.dialog.buttonCheckForUpdates.setDisabled(True) + self.button_bar.update_all_addons.show() + self.button_bar.check_for_updates.setDisabled(True) self.check_worker = CheckWorkbenchesForUpdatesWorker(self.item_model.repos) self.check_worker.finished.connect(self.do_next_startup_phase) self.check_worker.finished.connect(self.update_check_complete) @@ -636,21 +637,21 @@ class CommandAddonManager: if number_of_updates: s = translate("AddonsInstaller", "Apply {} update(s)", "", number_of_updates) - self.dialog.buttonUpdateAll.setText(s.format(number_of_updates)) - self.dialog.buttonUpdateAll.setEnabled(True) + self.button_bar.update_all_addons.setText(s.format(number_of_updates)) + self.button_bar.update_all_addons.setEnabled(True) elif hasattr(self, "check_worker") and self.check_worker.isRunning(): - self.dialog.buttonUpdateAll.setText( + self.button_bar.update_all_addons.setText( translate("AddonsInstaller", "Checking for updates...") ) else: - self.dialog.buttonUpdateAll.setText( + self.button_bar.update_all_addons.setText( translate("AddonsInstaller", "No updates available") ) - self.dialog.buttonUpdateAll.setEnabled(False) + self.button_bar.update_all_addons.setEnabled(False) def update_check_complete(self) -> None: self.enable_updates(len(self.packages_with_updates)) - self.dialog.buttonCheckForUpdates.setEnabled(True) + self.button_bar.check_for_updates.setEnabled(True) def check_python_updates(self) -> None: PythonPackageManager.migrate_old_am_installations() # Migrate 0.20 to 0.21 @@ -846,8 +847,10 @@ class CommandAddonManager: self.cleanup_workers() self.hide_progress_widgets() self.write_cache_stopfile() - self.dialog.buttonUpdateCache.setEnabled(True) - self.dialog.buttonUpdateCache.setText(translate("AddonsInstaller", "Refresh local cache")) + self.button_bar.refresh_local_cache.setEnabled(True) + self.button_bar.refresh_local_cache.setText( + translate("AddonsInstaller", "Refresh local cache") + ) def write_cache_stopfile(self) -> None: stopfile = utils.get_cache_file_name("CACHE_UPDATE_INTERRUPTED") diff --git a/src/Mod/AddonManager/AddonManager.ui b/src/Mod/AddonManager/AddonManager.ui index 8d394a589c..b2d31fcb15 100644 --- a/src/Mod/AddonManager/AddonManager.ui +++ b/src/Mod/AddonManager/AddonManager.ui @@ -13,95 +13,7 @@ Addon Manager - - - - - - 0 - 0 - - - - - - - - QLayout::SetDefaultConstraint - - - - - Refresh local cache - - - - - - - Download and apply all available updates - - - Update all Addons - - - - - - - Check for updates - - - - - - - true - - - View and update Python package dependencies - - - Python dependencies... - - - - - - - Developer tools... - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Close the Addon Manager - - - Close - - - true - - - - - - + diff --git a/src/Mod/AddonManager/Widgets/CMakeLists.txt b/src/Mod/AddonManager/Widgets/CMakeLists.txt index 99b4ee4617..e3fefa9405 100644 --- a/src/Mod/AddonManager/Widgets/CMakeLists.txt +++ b/src/Mod/AddonManager/Widgets/CMakeLists.txt @@ -1,6 +1,7 @@ SET(AddonManagerWidget_SRCS __init__.py addonmanager_widget_filter_selector.py + addonmanager_widget_global_buttons.py addonmanager_widget_progress_bar.py addonmanager_widget_search.py addonmanager_widget_view_control_bar.py diff --git a/src/Mod/AddonManager/Widgets/addonmanager_widget_global_buttons.py b/src/Mod/AddonManager/Widgets/addonmanager_widget_global_buttons.py new file mode 100644 index 0000000000..b175657b56 --- /dev/null +++ b/src/Mod/AddonManager/Widgets/addonmanager_widget_global_buttons.py @@ -0,0 +1,100 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# *************************************************************************** +# * * +# * Copyright (c) 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 QWidget-derived class for displaying a set of buttons that affect the Addon +Manager as a whole (rather than a specific Addon). Typically inserted at the bottom of the Addon +Manager main window. """ + +try: + import FreeCAD + + translate = FreeCAD.Qt.translate +except ImportError: + FreeCAD = None + + def translate(_: str, text: str): + return text + + +# 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 QtGui, QtWidgets + + +class WidgetGlobalButtonBar(QtWidgets.QWidget): + """A QWidget-derived class for displaying a set of buttons that affect the Addon Manager as a + whole (rather than a specific Addon).""" + + def __init__(self, parent: QtWidgets.QWidget = None): + super().__init__(parent) + self.horizontal_layout = None + self.refresh_local_cache = None + self.update_all_addons = None + self.check_for_updates = None + self.python_dependencies = None + self.developer_tools = None + self.close = None + self._update_ui() + self.retranslateUi(None) + self._set_icons() + + def _update_ui(self): + self.horizontal_layout = QtWidgets.QHBoxLayout() + self.refresh_local_cache = QtWidgets.QPushButton(self) + self.update_all_addons = QtWidgets.QPushButton(self) + self.check_for_updates = QtWidgets.QPushButton(self) + self.python_dependencies = QtWidgets.QPushButton(self) + self.developer_tools = QtWidgets.QPushButton(self) + self.close = QtWidgets.QPushButton(self) + self.horizontal_layout.addWidget(self.refresh_local_cache) + self.horizontal_layout.addWidget(self.update_all_addons) + self.horizontal_layout.addWidget(self.check_for_updates) + self.horizontal_layout.addWidget(self.python_dependencies) + self.horizontal_layout.addWidget(self.developer_tools) + self.horizontal_layout.addStretch() + self.horizontal_layout.addWidget(self.close) + self.setLayout(self.horizontal_layout) + + def _set_icons(self): + self.update_all_addons.setIcon(QtGui.QIcon(":/icons/button_valid.svg")) + self.check_for_updates.setIcon(QtGui.QIcon(":/icons/view-refresh.svg")) + self.close.setIcon(QtGui.QIcon.fromTheme("close", QtGui.QIcon(":/icons/process-stop.svg"))) + + def retranslateUi(self, _): + self.refresh_local_cache.setText(translate("AddonsInstaller", "Close")) + self.update_all_addons.setText(translate("AddonsInstaller", "Update all addons")) + self.check_for_updates.setText(translate("AddonsInstaller", "Check for updates")) + self.python_dependencies.setText(translate("AddonsInstaller", "Python dependencies...")) + self.developer_tools.setText(translate("AddonsInstaller", "Developer tools...")) + self.close.setText(translate("AddonsInstaller", "Close"))