/
gui_mocks.py
141 lines (120 loc) · 5.98 KB
/
gui_mocks.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# ***************************************************************************
# * *
# * 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 *
# * <https://www.gnu.org/licenses/>. *
# * *
# ***************************************************************************
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."""
def __init__(self, dialog_to_watch_for, button=QtWidgets.QDialogButtonBox.NoButton):
super().__init__()
# Status variables for tests to check:
self.dialog_found = False
self.has_run = False
self.button_found = False
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()
self.timer.timeout.connect(self.run)
self.timer.start(10)
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 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
# active? That's an error, but we should get it closed anyway.
windows = QtWidgets.QApplication.topLevelWidgets()
for widget in windows:
if (
hasattr(widget, "windowTitle")
and callable(widget.windowTitle)
and widget.windowTitle() == self.dialog_to_watch_for
):
self.click_button(widget)
self.timer.stop()
print("Found a window with the expected title, but it was not the active modal dialog.")
self.has_run = True
self.execution_counter += 1
if self.execution_counter > 100:
print("Stopped timer after 100 iterations")
self.timer.stop()
def click_button(self, widget):
button_boxes = widget.findChildren(QtWidgets.QDialogButtonBox)
if len(button_boxes) == 1: # There should be one, and only one
button_to_click = button_boxes[0].button(self.button)
if button_to_click:
self.button_found = True
button_to_click.click()
else:
widget.reject()
else:
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
self.should_continue = True
def work(self):
while self.should_continue:
QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents, 100)
def stop(self):
self.should_continue = False
class MockThread:
def wait(self):
pass
def isRunning(self):
return False