From 74a8d3deec1d0b188b7a67638197efe2bbc9bbca Mon Sep 17 00:00:00 2001 From: Chris Hennes Date: Thu, 10 Nov 2022 15:09:15 -0600 Subject: [PATCH] Addon Manager: Refactor to extract connection check GUI --- src/Mod/AddonManager/AddonManager.py | 65 ++-------- src/Mod/AddonManager/CMakeLists.txt | 1 + .../addonmanager_connection_checker.py | 113 ++++++++++++++++++ 3 files changed, 123 insertions(+), 56 deletions(-) create mode 100644 src/Mod/AddonManager/addonmanager_connection_checker.py diff --git a/src/Mod/AddonManager/AddonManager.py b/src/Mod/AddonManager/AddonManager.py index 464b3904d5..b2d2c3c5bf 100644 --- a/src/Mod/AddonManager/AddonManager.py +++ b/src/Mod/AddonManager/AddonManager.py @@ -54,7 +54,6 @@ from addonmanager_workers_installation import ( UpdateMetadataCacheWorker, UpdateAllWorker, ) -from addonmanager_workers_utility import ConnectionChecker import addonmanager_utilities as utils import AddonManager_rc from package_list import PackageList, PackageListItemModel @@ -69,6 +68,7 @@ from manage_python_dependencies import ( ) from addonmanager_devmode import DeveloperMode from addonmanager_firstrun import FirstRunDialog +from addonmanager_connection_checker import ConnectionCheckerGUI import NetworkManager @@ -111,7 +111,6 @@ class CommandAddonManager: """The main Addon Manager class and FreeCAD command""" workers = [ - "connection_checker", "create_addon_list_worker", "check_worker", "show_worker", @@ -164,6 +163,10 @@ class CommandAddonManager: self.update_all_worker = None self.developer_mode = None + # Set up the connection checker + self.connection_checker = ConnectionCheckerGUI() + self.connection_checker.connection_available.connect(self.launch) + # Give other parts of the AM access to the current instance global INSTANCE INSTANCE = self @@ -184,61 +187,11 @@ class CommandAddonManager: NetworkManager.InitializeNetworkManager() firstRunDialog = FirstRunDialog() - readWarning = firstRunDialog.exec() + if not firstRunDialog.exec(): + return + + self.connection_checker.start() - pref = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Addons") - dev_mode_active = pref.GetBool("developerMode", False) - - if readWarning: - # Check the connection in a new thread, so FreeCAD stays responsive - self.connection_checker = ConnectionChecker() - self.connection_checker.success.connect(self.launch) - self.connection_checker.failure.connect(self.network_connection_failed) - self.connection_checker.start() - - # If it takes longer than a half second to check the connection, show a message: - self.connection_message_timer = QtCore.QTimer.singleShot( - 500, self.show_connection_check_message - ) - - def show_connection_check_message(self): - if not self.connection_checker.isFinished(): - self.connection_check_message = QtWidgets.QMessageBox( - QtWidgets.QMessageBox.Information, - translate("AddonsInstaller", "Checking connection"), - translate("AddonsInstaller", "Checking for connection to GitHub..."), - QtWidgets.QMessageBox.Cancel, - ) - self.connection_check_message.buttonClicked.connect( - self.cancel_network_check - ) - self.connection_check_message.show() - - def cancel_network_check(self, _): - if not self.connection_checker.isFinished(): - self.connection_checker.success.disconnect(self.launch) - self.connection_checker.failure.disconnect(self.network_connection_failed) - self.connection_checker.requestInterruption() - self.connection_checker.wait(500) - self.connection_check_message.close() - - def network_connection_failed(self, message: str) -> None: - # This must run on the main GUI thread - if hasattr(self, "connection_check_message") and self.connection_check_message: - self.connection_check_message.close() - if NetworkManager.HAVE_QTNETWORK: - QtWidgets.QMessageBox.critical( - None, translate("AddonsInstaller", "Connection failed"), message - ) - else: - QtWidgets.QMessageBox.critical( - None, - translate("AddonsInstaller", "Missing dependency"), - translate( - "AddonsInstaller", - "Could not import QtNetwork -- see Report View for details. Addon Manager unavailable.", - ), - ) def launch(self) -> None: """Shows the Addon Manager UI""" diff --git a/src/Mod/AddonManager/CMakeLists.txt b/src/Mod/AddonManager/CMakeLists.txt index 705a739c7b..5e8bf8c0e4 100644 --- a/src/Mod/AddonManager/CMakeLists.txt +++ b/src/Mod/AddonManager/CMakeLists.txt @@ -7,6 +7,7 @@ SET(AddonManager_SRCS Addon.py AddonManager.py AddonManager.ui + addonmanager_connection_checker.py addonmanager_devmode.py addonmanager_devmode_add_content.py addonmanager_devmode_license_selector.py diff --git a/src/Mod/AddonManager/addonmanager_connection_checker.py b/src/Mod/AddonManager/addonmanager_connection_checker.py new file mode 100644 index 0000000000..90b0e6cbad --- /dev/null +++ b/src/Mod/AddonManager/addonmanager_connection_checker.py @@ -0,0 +1,113 @@ +# *************************************************************************** +# * * +# * Copyright (c) 2022 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 * +# * . * +# * * +# *************************************************************************** + +""" System for checking the network connection status asynchronously. """ + +import FreeCAD + +from PySide import QtCore, QtWidgets + +import NetworkManager +from addonmanager_workers_utility import ConnectionChecker + +translate = FreeCAD.Qt.translate + + +class ConnectionCheckerGUI(QtCore.QObject): + """Determine whether there is an active network connection, showing a progress message if it + starts to take too long, and an error message if the network cannot be accessed.""" + + connection_available = QtCore.Signal() + check_complete = QtCore.Signal() + + def __init__(self): + super().__init__() + + # Check the connection in a new thread, so FreeCAD stays responsive + self.connection_checker = ConnectionChecker() + self.connection_checker.success.connect(self._check_succeeded) + self.connection_checker.failure.connect(self._network_connection_failed) + + self.connection_message_timer = None + self.connection_check_message = None + + def start(self): + """Start the connection check""" + self.connection_checker.start() + + # If it takes longer than a half second to check the connection, show a message: + self.connection_message_timer = QtCore.QTimer.singleShot( + 500, self._show_connection_check_message + ) + + def _show_connection_check_message(self): + """Display a message informing the user that the check is in process""" + if not self.connection_checker.isFinished(): + self.connection_check_message = QtWidgets.QMessageBox( + QtWidgets.QMessageBox.Information, + translate("AddonsInstaller", "Checking connection"), + translate("AddonsInstaller", "Checking for connection to GitHub..."), + QtWidgets.QMessageBox.Cancel, + ) + self.connection_check_message.buttonClicked.connect( + self.cancel_network_check + ) + self.connection_check_message.show() + + def cancel_network_check(self, _): + """Cancel the check""" + if not self.connection_checker.isFinished(): + self.connection_checker.success.disconnect(self.launch) + self.connection_checker.failure.disconnect(self.network_connection_failed) + self.connection_checker.requestInterruption() + self.connection_checker.wait(500) + self.connection_check_message.close() + self.check_complete.emit() + + def _network_connection_failed(self, message: str) -> None: + """Callback for failed connection check. Displays an error message, then emits the + check_complete signal (but not the connection available signal).""" + # This must run on the main GUI thread + if hasattr(self, "connection_check_message") and self.connection_check_message: + self.connection_check_message.close() + if NetworkManager.HAVE_QTNETWORK: + QtWidgets.QMessageBox.critical( + None, translate("AddonsInstaller", "Connection failed"), message + ) + else: + #pylint: disable=line-too-long + QtWidgets.QMessageBox.critical( + None, + translate("AddonsInstaller", "Missing dependency"), + translate( + "AddonsInstaller", + "Could not import QtNetwork -- see Report View for details. Addon Manager unavailable.", + ), + ) + + self.check_complete.emit() + + def _check_succeeded(self): + """Emit both the connection_available and the check_complete signals, in that order.""" + + self.connection_available.emit() + self.check_complete.emit()