diff --git a/src/Mod/AddonManager/AddonManagerTest/gui/gui_mocks.py b/src/Mod/AddonManager/AddonManagerTest/gui/gui_mocks.py index f6f7ec7018..f810fd28b3 100644 --- a/src/Mod/AddonManager/AddonManagerTest/gui/gui_mocks.py +++ b/src/Mod/AddonManager/AddonManagerTest/gui/gui_mocks.py @@ -23,26 +23,21 @@ from PySide import QtCore, QtWidgets -class DialogWatcher(QtCore.QObject): - """Examine the running GUI and look for a modal dialog with a given title, containing a button - with a given label. Click that button, which is expected to close the dialog. Generally run on - a one-shot QTimer to allow the dialog time to open up. If the specified dialog is found, but - it does not contain the expected button, button_found will be false, and the dialog will be - closed with a reject() slot.""" +class DialogInteractor(QtCore.QObject): + """Takes the title of the dialog, a button string, and a callable. The callable is passed + the widget we found and can do whatever it wants to it. Whatever it does should eventually + close the dialog, however.""" - def __init__(self, dialog_to_watch_for, button=QtWidgets.QDialogButtonBox.NoButton): + def __init__(self, dialog_to_watch_for, interaction): super().__init__() # Status variables for tests to check: self.dialog_found = False self.has_run = False self.button_found = False + self.interaction = interaction self.dialog_to_watch_for = dialog_to_watch_for - if button != QtWidgets.QDialogButtonBox.NoButton: - self.button = button - else: - self.button = QtWidgets.QDialogButtonBox.Cancel self.execution_counter = 0 self.timer = QtCore.QTimer() @@ -51,17 +46,12 @@ class DialogWatcher(QtCore.QObject): def run(self): widget = QtWidgets.QApplication.activeModalWidget() - if widget: - # Is this the widget we are looking for? - if ( - hasattr(widget, "windowTitle") - and callable(widget.windowTitle) - and widget.windowTitle() == self.dialog_to_watch_for - ): - # Found the dialog we are looking for: now try to "click" the appropriate button - self.click_button(widget) - self.dialog_found = True - self.timer.stop() + if widget and self._dialog_matches(widget): + # Found the dialog we are looking for: now try to run the interaction + if self.interaction is not None and callable(self.interaction): + self.interaction(widget) + self.dialog_found = True + self.timer.stop() if self.execution_counter > 25 and not self.dialog_found: # OK, it wasn't the active modal widget... was it some other window, and never became @@ -69,11 +59,12 @@ class DialogWatcher(QtCore.QObject): windows = QtWidgets.QApplication.topLevelWidgets() for widget in windows: if ( - hasattr(widget, "windowTitle") - and callable(widget.windowTitle) - and widget.windowTitle() == self.dialog_to_watch_for + hasattr(widget, "windowTitle") + and callable(widget.windowTitle) + and widget.windowTitle() == self.dialog_to_watch_for ): - self.click_button(widget) + if self.interaction is not None and callable(self.interaction): + self.interaction(widget) self.timer.stop() print("Found a window with the expected title, but it was not the active modal dialog.") @@ -83,6 +74,32 @@ class DialogWatcher(QtCore.QObject): print("Stopped timer after 100 iterations") self.timer.stop() + def _dialog_matches(self, widget) -> bool: + # Is this the widget we are looking for? Only applies on Linux and Windows: macOS + # doesn't set the title of a modal dialog: + os = QtCore.QSysInfo.productType() # Qt5 gives "osx", Qt6 gives "macos" + if os in ["osx", "macos"] or ( + hasattr(widget, "windowTitle") + and callable(widget.windowTitle) + and widget.windowTitle() == self.dialog_to_watch_for + ): + return True + return False + + +class DialogWatcher(DialogInteractor): + """Examine the running GUI and look for a modal dialog with a given title, containing a button + with a role. Click that button, which is expected to close the dialog. Generally run on + a one-shot QTimer to allow the dialog time to open up. If the specified dialog is found, but + it does not contain the expected button, button_found will be false, and the dialog will be + closed with a reject() slot.""" + def __init__(self, dialog_to_watch_for, button=QtWidgets.QDialogButtonBox.NoButton): + super().__init__(dialog_to_watch_for, self.click_button) + if button != QtWidgets.QDialogButtonBox.NoButton: + self.button = button + else: + self.button = QtWidgets.QDialogButtonBox.Cancel + def click_button(self, widget): button_boxes = widget.findChildren(QtWidgets.QDialogButtonBox) if len(button_boxes) == 1: # There should be one, and only one @@ -96,30 +113,6 @@ class DialogWatcher(QtCore.QObject): widget.reject() -class DialogInteractor(DialogWatcher): - def __init__(self, dialog_to_watch_for, interaction): - """Takes the title of the dialog, a button string, and a callable. The callable is passed - the widget we found and can do whatever it wants to it. Whatever it does should eventually - close the dialog, however.""" - super().__init__(dialog_to_watch_for, None) - self.interaction = interaction - - def run(self): - widget = QtWidgets.QApplication.activeModalWidget() - if widget: - # Is this the widget we are looking for? - if ( - hasattr(widget, "windowTitle") - and callable(widget.windowTitle) - and widget.windowTitle() == self.dialog_to_watch_for - ): - self.dialog_found = True - if self.dialog_found: - self.has_run = True - if self.interaction is not None and callable(self.interaction): - self.interaction(widget) - - class FakeWorker: def __init__(self): self.called = False