testexecutor-ui 0.6.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- testexecutor/VERSION +1 -0
- testexecutor/__init__.py +6 -0
- testexecutor/control/TestListenerApi.py +56 -0
- testexecutor/control/TestSuiteListener.py +249 -0
- testexecutor/control/__init__.py +0 -0
- testexecutor/model/GenericListModel.py +63 -0
- testexecutor/model/InstructionsModel.py +351 -0
- testexecutor/model/KeyValueModel.py +177 -0
- testexecutor/model/MultiTestWindowModel.py +184 -0
- testexecutor/model/ResultModel.py +314 -0
- testexecutor/model/TestSuiteControlModel.py +139 -0
- testexecutor/model/TestSuiteGroup.py +105 -0
- testexecutor/model/TestSuiteModel.py +301 -0
- testexecutor/model/__init__.py +0 -0
- testexecutor/model/selector/FilterGroupModel.py +90 -0
- testexecutor/model/selector/FilterModel.py +251 -0
- testexecutor/model/selector/MultiSelectDetails.py +106 -0
- testexecutor/model/selector/MultiSelectListModel.py +48 -0
- testexecutor/model/selector/__init__.py +0 -0
- testexecutor/ui/IdentificationWidget.qml +40 -0
- testexecutor/ui/InputWidget.qml +74 -0
- testexecutor/ui/InstructionWidget.qml +185 -0
- testexecutor/ui/KeyValueItem.qml +194 -0
- testexecutor/ui/KeyValueItemConfig.qml +41 -0
- testexecutor/ui/KeyValueList.qml +49 -0
- testexecutor/ui/MultiTestWidget.qml +48 -0
- testexecutor/ui/MultiTestWindow.qml +88 -0
- testexecutor/ui/ResultItem.qml +199 -0
- testexecutor/ui/ResultItemConfig.qml +46 -0
- testexecutor/ui/ResultList.qml +58 -0
- testexecutor/ui/TestSuiteConfig.qml +95 -0
- testexecutor/ui/TestSuiteController.qml +54 -0
- testexecutor/ui/TestSuiteWidget.qml +350 -0
- testexecutor/ui/selector/FilterItem.qml +75 -0
- testexecutor/ui/selector/FilterItemConfig.qml +24 -0
- testexecutor/ui/selector/FilterMultiSelectorItem.qml +169 -0
- testexecutor/ui/selector/FilterMultiSelectorItemConfig.qml +22 -0
- testexecutor/ui/selector/FilterMultiSelectorList.qml +50 -0
- testexecutor/ui/selector/HeaderConfig.qml +24 -0
- testexecutor/ui/selector/SectionConfig.qml +24 -0
- testexecutor/ui/selector/SectionDelegate.qml +85 -0
- testexecutor/ui/selector/SelectorHeader.qml +43 -0
- testexecutor/ui/selector/SuiteList.qml +150 -0
- testexecutor/ui/selector/SuiteSelector.qml +71 -0
- testexecutor/ui/selector/SuiteSelectorConfig.qml +38 -0
- testexecutor/ui/selector/TestConfig.qml +22 -0
- testexecutor/ui/selector/TestDelegate.qml +75 -0
- testexecutor/ui/te-64x64.ico +0 -0
- testexecutor_ui-0.6.1.dist-info/LICENSE +204 -0
- testexecutor_ui-0.6.1.dist-info/METADATA +27 -0
- testexecutor_ui-0.6.1.dist-info/NOTICE +3 -0
- testexecutor_ui-0.6.1.dist-info/RECORD +54 -0
- testexecutor_ui-0.6.1.dist-info/WHEEL +5 -0
- testexecutor_ui-0.6.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Copyright 2020 Direkt, Australia
|
|
2
|
+
# Copyright 2021 Direkt Embedded Pty Ltd
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
"""
|
|
17
|
+
A class which inherits QAbstractListModel to provide a list of TestSuites for a multi test runner.
|
|
18
|
+
Usage
|
|
19
|
+
# Write your MyTestSuiteListener class which inherits TestSuiteListener and provide your business logic in the callbacks
|
|
20
|
+
# Setup the list of suites
|
|
21
|
+
mySuiteGroup = TestSuiteGroup()
|
|
22
|
+
for i in range(4):
|
|
23
|
+
mySuiteGroup.addData(MyTestSuiteListener())
|
|
24
|
+
|
|
25
|
+
# Setup the qml UI
|
|
26
|
+
qml_file = os.path.join(ui_path, 'MultiTestWidget.qml')
|
|
27
|
+
url = QUrl.fromLocalFile(qml_file)
|
|
28
|
+
view.setSource(url)
|
|
29
|
+
view.setResizeMode(QQuickView.SizeRootObjectToView)
|
|
30
|
+
if view.status() != QQuickView.Error:
|
|
31
|
+
# Set the UIs Property model_list to the set of 4 TestSuiteListeners (which inherit TestSuiteModel)
|
|
32
|
+
view.rootContext().setContextProperty("model_list", mySuiteGroup)
|
|
33
|
+
view.showMaximized()
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
from PySide6.QtCore import QAbstractListModel
|
|
37
|
+
from PySide6.QtCore import Qt
|
|
38
|
+
from PySide6.QtCore import QModelIndex
|
|
39
|
+
from PySide6.QtCore import Signal, Property
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class TestSuiteGroup(QAbstractListModel):
|
|
43
|
+
|
|
44
|
+
TestSuiteRole = Qt.UserRole
|
|
45
|
+
TestSuiteKey = b"testsuite"
|
|
46
|
+
|
|
47
|
+
_roles = {
|
|
48
|
+
TestSuiteRole: TestSuiteKey
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
def __init__(self, parent=None):
|
|
52
|
+
QAbstractListModel.__init__(self, parent)
|
|
53
|
+
self._datas = []
|
|
54
|
+
|
|
55
|
+
def addData(self, data):
|
|
56
|
+
index = QModelIndex()
|
|
57
|
+
self.beginInsertRows(index, self.rowCount(), self.rowCount())
|
|
58
|
+
self._datas.append(data)
|
|
59
|
+
self.endInsertRows()
|
|
60
|
+
|
|
61
|
+
def setData(self, index, value, role=None):
|
|
62
|
+
try:
|
|
63
|
+
data = self._datas[index.row()]
|
|
64
|
+
except IndexError:
|
|
65
|
+
return False
|
|
66
|
+
if role == self.TestSuiteRole:
|
|
67
|
+
self._datas[index.row()] = value
|
|
68
|
+
self.dataChanged.emit(index, index, {self.TestSuiteRole: self.TestSuiteKey})
|
|
69
|
+
return True
|
|
70
|
+
|
|
71
|
+
def rowCount(self, parent=QModelIndex()):
|
|
72
|
+
return len(self._datas)
|
|
73
|
+
|
|
74
|
+
def data(self, index, role=Qt.DisplayRole):
|
|
75
|
+
try:
|
|
76
|
+
data = self._datas[index.row()]
|
|
77
|
+
except IndexError:
|
|
78
|
+
return None
|
|
79
|
+
|
|
80
|
+
if role == self.TestSuiteRole:
|
|
81
|
+
return data
|
|
82
|
+
|
|
83
|
+
return None
|
|
84
|
+
|
|
85
|
+
def roleNames(self):
|
|
86
|
+
return self._roles
|
|
87
|
+
|
|
88
|
+
def _getactive_suites(self):
|
|
89
|
+
""" Getter for active_suites Property """
|
|
90
|
+
active = False
|
|
91
|
+
for item in self._datas:
|
|
92
|
+
active = item.active()
|
|
93
|
+
if active:
|
|
94
|
+
break
|
|
95
|
+
return active
|
|
96
|
+
|
|
97
|
+
active_suites_changed = Signal()
|
|
98
|
+
active_suites = Property(bool, _getactive_suites, None, notify=active_suites_changed)
|
|
99
|
+
|
|
100
|
+
def abortAll(self, hard=False):
|
|
101
|
+
for item in self._datas:
|
|
102
|
+
if hard:
|
|
103
|
+
item.close()
|
|
104
|
+
else:
|
|
105
|
+
item.suitestate = "stopping"
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
# Copyright 2020 Direkt, Australia
|
|
2
|
+
# Copyright 2021 Direkt Embedded Pty Ltd
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
# This Python file uses the following encoding: utf-8
|
|
17
|
+
import threading
|
|
18
|
+
import time
|
|
19
|
+
from PySide6.QtCore import QObject, Qt
|
|
20
|
+
from PySide6.QtCore import Signal, Property, Slot
|
|
21
|
+
from testexecutor.model.InstructionsModel import InstructionModel
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class SuiteColours(QObject):
|
|
25
|
+
"""
|
|
26
|
+
Dynamic colours that the user can set on the suite
|
|
27
|
+
If the colour is None/Undefined then the default colour as in
|
|
28
|
+
the configuration will be used.
|
|
29
|
+
"""
|
|
30
|
+
def __init__(self):
|
|
31
|
+
QObject.__init__(self)
|
|
32
|
+
self.lock = threading.RLock()
|
|
33
|
+
self._running_colour = None
|
|
34
|
+
self._interaction_colour = None
|
|
35
|
+
|
|
36
|
+
def clear(self):
|
|
37
|
+
self.running = None
|
|
38
|
+
self.interaction = None
|
|
39
|
+
|
|
40
|
+
def _set_running_colour(self, _running_colour):
|
|
41
|
+
""" Setter for running_colour Property """
|
|
42
|
+
with self.lock:
|
|
43
|
+
self._running_colour = _running_colour
|
|
44
|
+
self.running_colour_changed.emit()
|
|
45
|
+
|
|
46
|
+
def _get_running_colour(self):
|
|
47
|
+
""" Getter for running_colour Property """
|
|
48
|
+
with self.lock:
|
|
49
|
+
col = self._running_colour
|
|
50
|
+
return col
|
|
51
|
+
|
|
52
|
+
running_colour_changed = Signal()
|
|
53
|
+
running = Property(str, _get_running_colour, _set_running_colour, notify=running_colour_changed)
|
|
54
|
+
|
|
55
|
+
def _set_interaction_colour(self, _interaction_colour):
|
|
56
|
+
""" Setter for interaction_colour Property """
|
|
57
|
+
with self.lock:
|
|
58
|
+
self._interaction_colour = _interaction_colour
|
|
59
|
+
self.interaction_colour_changed.emit()
|
|
60
|
+
|
|
61
|
+
def _get_interaction_colour(self):
|
|
62
|
+
""" Getter for interaction_colour Property """
|
|
63
|
+
with self.lock:
|
|
64
|
+
col = self._interaction_colour
|
|
65
|
+
return col
|
|
66
|
+
|
|
67
|
+
interaction_colour_changed = Signal()
|
|
68
|
+
interaction = Property(str, _get_interaction_colour, _set_interaction_colour,
|
|
69
|
+
notify=interaction_colour_changed)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class TestSuiteModel(QObject):
|
|
73
|
+
# these state strings must match those in TestSuiteWidget.qml
|
|
74
|
+
STATE_RUNNING = "running"
|
|
75
|
+
STATE_STARTING = "starting"
|
|
76
|
+
STATE_STOPPING = "stopping"
|
|
77
|
+
STATE_STOPPED = "stopped"
|
|
78
|
+
STATE_END = "end"
|
|
79
|
+
STATE_IDLE = "idle"
|
|
80
|
+
STATE_READY = "ready"
|
|
81
|
+
STATE_RESTART = "restart"
|
|
82
|
+
ACTION_CLEAR = "Clear"
|
|
83
|
+
ACTION_STOP = "Stop"
|
|
84
|
+
|
|
85
|
+
def __init__(self, idlist=None, resultlist=None, setid_callback=None, setstate_callback=None, title=None):
|
|
86
|
+
QObject.__init__(self)
|
|
87
|
+
self.lock = threading.RLock()
|
|
88
|
+
self._setidentifiers(idlist)
|
|
89
|
+
self._setresults(resultlist)
|
|
90
|
+
self._setinstructions(InstructionModel())
|
|
91
|
+
self._newId = None # See newid Property below
|
|
92
|
+
self.setid_callback = setid_callback
|
|
93
|
+
self._state = None # see suitestate Property below
|
|
94
|
+
self.setstate_callback = setstate_callback
|
|
95
|
+
self._title = title
|
|
96
|
+
self._controller = None
|
|
97
|
+
self._suite_colours = SuiteColours()
|
|
98
|
+
self.on_input.connect(self.instructions.control.onExternalInput, Qt.QueuedConnection)
|
|
99
|
+
|
|
100
|
+
def clear(self):
|
|
101
|
+
self.identifiers.clearData()
|
|
102
|
+
self.instructions.clear()
|
|
103
|
+
self.results.clear()
|
|
104
|
+
time.sleep(0.1)
|
|
105
|
+
self.identifiers.clearData() # Intentionally duplicate until qml corrected to clear combobox selected item
|
|
106
|
+
self.suitestate = self.STATE_IDLE
|
|
107
|
+
self.suite_colours.clear()
|
|
108
|
+
|
|
109
|
+
def setstate(self, st):
|
|
110
|
+
""" Setter for suitestate Property """
|
|
111
|
+
newstate = None
|
|
112
|
+
changed = False
|
|
113
|
+
if self.setstate_callback:
|
|
114
|
+
newstate = self.setstate_callback(st)
|
|
115
|
+
else:
|
|
116
|
+
newstate = st
|
|
117
|
+
with self.lock:
|
|
118
|
+
if newstate and newstate != self._state:
|
|
119
|
+
changed = True
|
|
120
|
+
if changed:
|
|
121
|
+
self._state = newstate
|
|
122
|
+
if changed:
|
|
123
|
+
if newstate == self.STATE_READY:
|
|
124
|
+
self.results.clear()
|
|
125
|
+
elif newstate == self.STATE_STOPPING:
|
|
126
|
+
self.instructions.clear()
|
|
127
|
+
self.result_changed.emit()
|
|
128
|
+
self.stateChanged.emit()
|
|
129
|
+
|
|
130
|
+
def _getstate(self):
|
|
131
|
+
""" Getter for suitestate Property """
|
|
132
|
+
state = None
|
|
133
|
+
with self.lock:
|
|
134
|
+
state = self._state
|
|
135
|
+
return state
|
|
136
|
+
|
|
137
|
+
stateChanged = Signal()
|
|
138
|
+
suitestate = Property(str, _getstate, setstate, notify=stateChanged)
|
|
139
|
+
|
|
140
|
+
def _setid(self, id):
|
|
141
|
+
""" Setter for newid Property """
|
|
142
|
+
with self.lock:
|
|
143
|
+
self._newId = id
|
|
144
|
+
# call id call back only when not active as we do not want to change ids after started
|
|
145
|
+
if not self.active():
|
|
146
|
+
if self.setid_callback:
|
|
147
|
+
self.setid_callback(id)
|
|
148
|
+
else:
|
|
149
|
+
self.on_input.emit(id)
|
|
150
|
+
self.id_changed.emit()
|
|
151
|
+
|
|
152
|
+
def _getid(self):
|
|
153
|
+
""" Getter for newid Property """
|
|
154
|
+
id = None
|
|
155
|
+
with self.lock:
|
|
156
|
+
id = self._newId
|
|
157
|
+
return id
|
|
158
|
+
|
|
159
|
+
id_changed = Signal()
|
|
160
|
+
on_input = Signal(str)
|
|
161
|
+
newid = Property(str, _getid, _setid, notify=id_changed)
|
|
162
|
+
|
|
163
|
+
def _setidentifiers(self, identifiers):
|
|
164
|
+
""" Setter for identifiers QAbstractList Property """
|
|
165
|
+
with self.lock:
|
|
166
|
+
self._idlist = identifiers
|
|
167
|
+
self.identifiers_changed.emit()
|
|
168
|
+
|
|
169
|
+
def _getidentifiers(self):
|
|
170
|
+
""" Getter for identifiers QAbstractList Property """
|
|
171
|
+
with self.lock:
|
|
172
|
+
list = self._idlist
|
|
173
|
+
return list
|
|
174
|
+
|
|
175
|
+
identifiers_changed = Signal()
|
|
176
|
+
identifiers = Property(QObject, _getidentifiers, _setidentifiers, notify=identifiers_changed)
|
|
177
|
+
|
|
178
|
+
def _setresults(self, results):
|
|
179
|
+
""" Setter for results QAbstractList Property """
|
|
180
|
+
with self.lock:
|
|
181
|
+
self._resultlist = results
|
|
182
|
+
self.results_changed.emit()
|
|
183
|
+
|
|
184
|
+
def _getresults(self):
|
|
185
|
+
""" Getter for results QAbstractList Property """
|
|
186
|
+
with self.lock:
|
|
187
|
+
list = self._resultlist
|
|
188
|
+
return list
|
|
189
|
+
|
|
190
|
+
results_changed = Signal()
|
|
191
|
+
results = Property(QObject, _getresults, _setresults, notify=results_changed)
|
|
192
|
+
|
|
193
|
+
def _getsuite_colours(self):
|
|
194
|
+
""" Getter for suite_colours Property """
|
|
195
|
+
with self.lock:
|
|
196
|
+
col = self._suite_colours
|
|
197
|
+
return col
|
|
198
|
+
|
|
199
|
+
suite_colours_changed = Signal()
|
|
200
|
+
suite_colours = Property(QObject, _getsuite_colours, None, notify=suite_colours_changed)
|
|
201
|
+
|
|
202
|
+
def _setinstructions(self, instruction_info):
|
|
203
|
+
""" Setter for instructions Property """
|
|
204
|
+
with self.lock:
|
|
205
|
+
self._instructions = instruction_info
|
|
206
|
+
self.instructions_changed.emit()
|
|
207
|
+
|
|
208
|
+
def _getinstructions(self):
|
|
209
|
+
""" Getter for instructions Property """
|
|
210
|
+
with self.lock:
|
|
211
|
+
instr = self._instructions
|
|
212
|
+
return instr
|
|
213
|
+
|
|
214
|
+
instructions_changed = Signal()
|
|
215
|
+
instructions = Property(QObject, _getinstructions, _setinstructions, notify=instructions_changed)
|
|
216
|
+
|
|
217
|
+
def _getresult(self):
|
|
218
|
+
"""
|
|
219
|
+
Getter for result Property
|
|
220
|
+
Checks all test results and returns state
|
|
221
|
+
:return: Result.StatePass if every test passed
|
|
222
|
+
Result.StateFail if a single test failed within suite
|
|
223
|
+
Result.StateRunning if suite is still in progress
|
|
224
|
+
None if error occurred or no tests started
|
|
225
|
+
"""
|
|
226
|
+
suite_result = None
|
|
227
|
+
with self.lock:
|
|
228
|
+
if self.results:
|
|
229
|
+
suite_result = self.results.overallResult()
|
|
230
|
+
return suite_result
|
|
231
|
+
|
|
232
|
+
result_changed = Signal()
|
|
233
|
+
result = Property(str, _getresult, None, notify=result_changed)
|
|
234
|
+
|
|
235
|
+
def _settitle(self, title):
|
|
236
|
+
""" Setter for title Property """
|
|
237
|
+
changed = False
|
|
238
|
+
with self.lock:
|
|
239
|
+
if self._title != title:
|
|
240
|
+
self._title = title
|
|
241
|
+
changed = True
|
|
242
|
+
if changed:
|
|
243
|
+
self.title_changed.emit()
|
|
244
|
+
|
|
245
|
+
def _gettitle(self):
|
|
246
|
+
""" Getter for title Property """
|
|
247
|
+
title = ""
|
|
248
|
+
with self.lock:
|
|
249
|
+
title = self._title
|
|
250
|
+
return title
|
|
251
|
+
|
|
252
|
+
title_changed = Signal()
|
|
253
|
+
title = Property(str, _gettitle, _settitle, notify=title_changed)
|
|
254
|
+
|
|
255
|
+
def _setcontroller(self, controller):
|
|
256
|
+
""" Setter for controller Property """
|
|
257
|
+
changed = False
|
|
258
|
+
with self.lock:
|
|
259
|
+
if self._controller != controller:
|
|
260
|
+
self._controller = controller
|
|
261
|
+
changed = True
|
|
262
|
+
if changed:
|
|
263
|
+
self.controller_changed.emit()
|
|
264
|
+
|
|
265
|
+
def _getcontroller(self):
|
|
266
|
+
"""
|
|
267
|
+
Getter for controller Property
|
|
268
|
+
A suite can have an attached controller which can be used to define a test list and the like.
|
|
269
|
+
"""
|
|
270
|
+
controller = None
|
|
271
|
+
with self.lock:
|
|
272
|
+
controller = self._controller
|
|
273
|
+
return controller
|
|
274
|
+
|
|
275
|
+
controller_changed = Signal()
|
|
276
|
+
controller = Property(QObject, _getcontroller, _setcontroller, notify=controller_changed)
|
|
277
|
+
|
|
278
|
+
@Slot()
|
|
279
|
+
def active(self):
|
|
280
|
+
activeStates = [self.STATE_STOPPING, self.STATE_STARTING, self.STATE_RUNNING]
|
|
281
|
+
return self.suitestate in activeStates
|
|
282
|
+
|
|
283
|
+
@Slot(str)
|
|
284
|
+
def action(self, action):
|
|
285
|
+
"""
|
|
286
|
+
Two default actions are supported, Clear and Stop. The action string comes from the text on the control/action
|
|
287
|
+
button of the TestSuiteWidget.qml states, so ensure the configuration has strings which match exactly.
|
|
288
|
+
:param action:
|
|
289
|
+
:return:
|
|
290
|
+
"""
|
|
291
|
+
if action == self.ACTION_CLEAR:
|
|
292
|
+
self.clear()
|
|
293
|
+
elif action == self.ACTION_STOP:
|
|
294
|
+
self.suitestate = self.STATE_STOPPING
|
|
295
|
+
|
|
296
|
+
def close(self):
|
|
297
|
+
"""
|
|
298
|
+
API for Hard closing the suite, ensuring any processes or threads created are killed
|
|
299
|
+
:return:
|
|
300
|
+
"""
|
|
301
|
+
pass
|
|
File without changes
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Copyright 2020 Sipke Vriend, Australia
|
|
2
|
+
# Copyright 2021 Direkt Embedded Pty Ltd
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
"""
|
|
17
|
+
Model for a list of filters as FilterModel.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from PySide6.QtCore import QAbstractListModel
|
|
21
|
+
from PySide6.QtCore import Qt
|
|
22
|
+
from PySide6.QtCore import QModelIndex
|
|
23
|
+
from .FilterModel import FilterModel
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class FilterGroupModel(QAbstractListModel):
|
|
27
|
+
|
|
28
|
+
FilterRole = Qt.UserRole
|
|
29
|
+
FilterKey = b"filter"
|
|
30
|
+
|
|
31
|
+
_roles = {
|
|
32
|
+
FilterRole: FilterKey
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
def __init__(self, filters=None, parent=None, onSelectedChanged=None):
|
|
36
|
+
QAbstractListModel.__init__(self, parent)
|
|
37
|
+
self._datas = []
|
|
38
|
+
if type(filters) == dict:
|
|
39
|
+
for item in filters.items():
|
|
40
|
+
filter = FilterModel(item[0], item[1])
|
|
41
|
+
if onSelectedChanged:
|
|
42
|
+
filter.updated_selected.connect(onSelectedChanged, Qt.QueuedConnection)
|
|
43
|
+
self.addData(filter)
|
|
44
|
+
|
|
45
|
+
def addData(self, data):
|
|
46
|
+
index = QModelIndex()
|
|
47
|
+
self.beginInsertRows(index, self.rowCount(), self.rowCount())
|
|
48
|
+
self._datas.append(data)
|
|
49
|
+
self.endInsertRows()
|
|
50
|
+
|
|
51
|
+
def setData(self, index, value, role):
|
|
52
|
+
try:
|
|
53
|
+
data = self._datas[index.row()]
|
|
54
|
+
except IndexError:
|
|
55
|
+
return False
|
|
56
|
+
if role == self.FilterRole:
|
|
57
|
+
self._datas[index.row()] = value
|
|
58
|
+
self.dataChanged.emit(index, index, {self.FilterRole: self.FilterKey})
|
|
59
|
+
return True
|
|
60
|
+
|
|
61
|
+
def rowCount(self, parent=QModelIndex()):
|
|
62
|
+
return len(self._datas)
|
|
63
|
+
|
|
64
|
+
def data(self, index, role=Qt.DisplayRole):
|
|
65
|
+
try:
|
|
66
|
+
data = self._datas[index.row()]
|
|
67
|
+
except IndexError:
|
|
68
|
+
return None
|
|
69
|
+
|
|
70
|
+
if role == self.FilterRole:
|
|
71
|
+
return data
|
|
72
|
+
|
|
73
|
+
return None
|
|
74
|
+
|
|
75
|
+
def roleNames(self):
|
|
76
|
+
return self._roles
|
|
77
|
+
|
|
78
|
+
def updateData(self, name, content_list):
|
|
79
|
+
"""
|
|
80
|
+
Update an existing filter with new content. If filter with name does not exist, nothing will happen
|
|
81
|
+
:param name:
|
|
82
|
+
:param content_list:
|
|
83
|
+
:return:
|
|
84
|
+
"""
|
|
85
|
+
rowCount = self.rowCount()
|
|
86
|
+
for i in range(rowCount):
|
|
87
|
+
existingItem = self.index(i, 0).data(self.FilterRole)
|
|
88
|
+
if existingItem.name == name:
|
|
89
|
+
existingItem.proposed.setStringList(content_list)
|
|
90
|
+
self.dataChanged.emit(self.index(i, 0), self.index(i, 0), self._roles)
|