|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2006 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the Breakpoint model. |
|
8 """ |
|
9 |
|
10 import copy |
|
11 |
|
12 from PyQt5.QtCore import pyqtSignal, Qt, QAbstractItemModel, QModelIndex |
|
13 |
|
14 |
|
15 class BreakPointModel(QAbstractItemModel): |
|
16 """ |
|
17 Class implementing a custom model for breakpoints. |
|
18 |
|
19 @signal dataAboutToBeChanged(QModelIndex, QModelIndex) emitted to indicate |
|
20 a change of the data |
|
21 """ |
|
22 dataAboutToBeChanged = pyqtSignal(QModelIndex, QModelIndex) |
|
23 |
|
24 def __init__(self, project, parent=None): |
|
25 """ |
|
26 Constructor |
|
27 |
|
28 @param project reference to the project object |
|
29 @type Project |
|
30 @param parent reference to the parent widget |
|
31 @type QObject |
|
32 """ |
|
33 super().__init__(parent) |
|
34 |
|
35 self.__project = project |
|
36 |
|
37 self.breakpoints = [] |
|
38 self.header = [ |
|
39 self.tr("Filename"), |
|
40 self.tr("Line"), |
|
41 self.tr('Condition'), |
|
42 self.tr('Temporary'), |
|
43 self.tr('Enabled'), |
|
44 self.tr('Ignore Count'), |
|
45 ] |
|
46 self.alignments = [Qt.Alignment(Qt.AlignmentFlag.AlignLeft), |
|
47 Qt.Alignment(Qt.AlignmentFlag.AlignRight), |
|
48 Qt.Alignment(Qt.AlignmentFlag.AlignLeft), |
|
49 Qt.Alignment(Qt.AlignmentFlag.AlignHCenter), |
|
50 Qt.Alignment(Qt.AlignmentFlag.AlignHCenter), |
|
51 Qt.Alignment(Qt.AlignmentFlag.AlignRight), |
|
52 Qt.Alignment(Qt.AlignmentFlag.AlignHCenter), |
|
53 ] |
|
54 |
|
55 def columnCount(self, parent=None): |
|
56 """ |
|
57 Public method to get the current column count. |
|
58 |
|
59 @param parent reference to parent index (Unused) |
|
60 @type QModelIndex |
|
61 @return column count |
|
62 @rtype int |
|
63 """ |
|
64 return len(self.header) |
|
65 |
|
66 def rowCount(self, parent=None): |
|
67 """ |
|
68 Public method to get the current row count. |
|
69 |
|
70 @param parent reference to parent index |
|
71 @type QModelIndex |
|
72 @return row count |
|
73 @rtype int |
|
74 """ |
|
75 # we do not have a tree, parent should always be invalid |
|
76 if parent is None or not parent.isValid(): |
|
77 return len(self.breakpoints) |
|
78 else: |
|
79 return 0 |
|
80 |
|
81 def data(self, index, role=Qt.ItemDataRole.DisplayRole): |
|
82 """ |
|
83 Public method to get the requested data. |
|
84 |
|
85 @param index index of the requested data |
|
86 @type QModelIndex |
|
87 @param role role of the requested data |
|
88 @type Qt.ItemDataRole |
|
89 @return the requested data |
|
90 @rtype any |
|
91 """ |
|
92 if not index.isValid(): |
|
93 return None |
|
94 |
|
95 if role == Qt.ItemDataRole.DisplayRole: |
|
96 if index.column() == 0: |
|
97 filename = self.breakpoints[index.row()][0] |
|
98 if self.__project.isOpen(): |
|
99 return self.__project.getRelativePath(filename) |
|
100 else: |
|
101 return filename |
|
102 elif index.column() in (1, 2, 5): |
|
103 return self.breakpoints[index.row()][index.column()] |
|
104 |
|
105 if ( |
|
106 role == Qt.ItemDataRole.CheckStateRole and |
|
107 index.column() in (3, 4) |
|
108 ): |
|
109 return self.breakpoints[index.row()][index.column()] |
|
110 |
|
111 if ( |
|
112 role == Qt.ItemDataRole.ToolTipRole and |
|
113 index.column() in (0, 2) |
|
114 ): |
|
115 return self.breakpoints[index.row()][index.column()] |
|
116 |
|
117 if ( |
|
118 role == Qt.ItemDataRole.TextAlignmentRole and |
|
119 index.column() < len(self.alignments) |
|
120 ): |
|
121 return self.alignments[index.column()] |
|
122 |
|
123 return None |
|
124 |
|
125 def setData(self, index, value, role=Qt.ItemDataRole.EditRole): |
|
126 """ |
|
127 Public method to change data in the model. |
|
128 |
|
129 @param index index of the changed data |
|
130 @type QModelIndex |
|
131 @param value value of the changed data |
|
132 @type any |
|
133 @param role role of the changed data |
|
134 @type Qt.ItemDataRole |
|
135 @return flag indicating success |
|
136 @rtype bool |
|
137 """ |
|
138 if (not index.isValid() or |
|
139 index.column() >= len(self.header) or |
|
140 index.row() >= len(self.breakpoints)): |
|
141 return False |
|
142 |
|
143 self.dataAboutToBeChanged.emit(index, index) |
|
144 self.breakpoints[index.row()][index.column()] = value |
|
145 self.dataChanged.emit(index, index) |
|
146 return True |
|
147 |
|
148 def flags(self, index): |
|
149 """ |
|
150 Public method to get item flags. |
|
151 |
|
152 @param index index of the requested flags |
|
153 @type QModelIndex |
|
154 @return item flags for the given index |
|
155 @rtype Qt.ItemFlags |
|
156 """ |
|
157 if not index.isValid(): |
|
158 return Qt.ItemFlag.ItemIsEnabled |
|
159 |
|
160 return Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable |
|
161 |
|
162 def headerData(self, section, orientation, |
|
163 role=Qt.ItemDataRole.DisplayRole): |
|
164 """ |
|
165 Public method to get header data. |
|
166 |
|
167 @param section section number of the requested header data |
|
168 @type int |
|
169 @param orientation orientation of the header |
|
170 @type Qt.Orientation |
|
171 @param role role of the requested data |
|
172 @type Qt.ItemDataRole |
|
173 @return header data |
|
174 @rtype str |
|
175 """ |
|
176 if ( |
|
177 orientation == Qt.Orientation.Horizontal and |
|
178 role == Qt.ItemDataRole.DisplayRole |
|
179 ): |
|
180 if section >= len(self.header): |
|
181 return "" |
|
182 else: |
|
183 return self.header[section] |
|
184 |
|
185 return None |
|
186 |
|
187 def index(self, row, column, parent=None): |
|
188 """ |
|
189 Public method to create an index. |
|
190 |
|
191 @param row row number for the index |
|
192 @type int |
|
193 @param column column number for the index |
|
194 @type int |
|
195 @param parent index of the parent item |
|
196 @type QModelIndex |
|
197 @return requested index |
|
198 @rtype QModelIndex |
|
199 """ |
|
200 if ((parent and parent.isValid()) or |
|
201 row < 0 or row >= len(self.breakpoints) or |
|
202 column < 0 or column >= len(self.header)): |
|
203 return QModelIndex() |
|
204 |
|
205 return self.createIndex(row, column, self.breakpoints[row]) |
|
206 |
|
207 def parent(self, index): |
|
208 """ |
|
209 Public method to get the parent index. |
|
210 |
|
211 @param index index of item to get parent |
|
212 @type QModelIndex |
|
213 @return index of parent |
|
214 @rtype QModelIndex |
|
215 """ |
|
216 return QModelIndex() |
|
217 |
|
218 def hasChildren(self, parent=None): |
|
219 """ |
|
220 Public method to check for the presence of child items. |
|
221 |
|
222 @param parent index of parent item |
|
223 @type QModelIndex |
|
224 @return flag indicating the presence of child items |
|
225 @rtype bool |
|
226 """ |
|
227 if parent is None or not parent.isValid(): |
|
228 return len(self.breakpoints) > 0 |
|
229 else: |
|
230 return False |
|
231 |
|
232 ########################################################################### |
|
233 |
|
234 def addBreakPoint(self, fn, line, properties): |
|
235 """ |
|
236 Public method to add a new breakpoint to the list. |
|
237 |
|
238 @param fn filename of the breakpoint |
|
239 @type str |
|
240 @param line line number of the breakpoint |
|
241 @type int |
|
242 @param properties properties of the breakpoint |
|
243 (tuple of condition, temporary flag, enabled flag, ignore count) |
|
244 @type tuple of (str, bool, bool, int) |
|
245 """ |
|
246 bp = [fn, line] + list(properties) |
|
247 cnt = len(self.breakpoints) |
|
248 self.beginInsertRows(QModelIndex(), cnt, cnt) |
|
249 self.breakpoints.append(bp) |
|
250 self.endInsertRows() |
|
251 |
|
252 def addBreakPoints(self, breakpoints): |
|
253 """ |
|
254 Public method to add multiple breakpoints to the list. |
|
255 |
|
256 @param breakpoints list of breakpoints with file name, line number, |
|
257 condition, temporary flag, enabled flag and ignore count each |
|
258 @type list of (str, int, str, bool, bool, int) |
|
259 """ |
|
260 cnt = len(self.breakpoints) |
|
261 self.beginInsertRows(QModelIndex(), cnt, cnt + len(breakpoints) - 1) |
|
262 self.breakpoints += breakpoints |
|
263 self.endInsertRows() |
|
264 |
|
265 def setBreakPointByIndex(self, index, fn, line, properties): |
|
266 """ |
|
267 Public method to set the values of a breakpoint given by index. |
|
268 |
|
269 @param index index of the breakpoint |
|
270 @type QModelIndex |
|
271 @param fn filename of the breakpoint |
|
272 @type str |
|
273 @param line line number of the breakpoint |
|
274 @type int |
|
275 @param properties properties of the breakpoint |
|
276 (tuple of condition, temporary flag, enabled flag, ignore count) |
|
277 @type tuple of (str, bool, bool, int) |
|
278 """ |
|
279 if index.isValid(): |
|
280 row = index.row() |
|
281 index1 = self.createIndex(row, 0, self.breakpoints[row]) |
|
282 index2 = self.createIndex( |
|
283 row, len(self.breakpoints[row]), self.breakpoints[row]) |
|
284 self.dataAboutToBeChanged.emit(index1, index2) |
|
285 self.breakpoints[row] = [fn, line] + list(properties) |
|
286 self.dataChanged.emit(index1, index2) |
|
287 |
|
288 def setBreakPointEnabledByIndex(self, index, enabled): |
|
289 """ |
|
290 Public method to set the enabled state of a breakpoint given by index. |
|
291 |
|
292 @param index index of the breakpoint |
|
293 @type QModelIndex |
|
294 @param enabled flag giving the enabled state |
|
295 @type bool |
|
296 """ |
|
297 if index.isValid(): |
|
298 row = index.row() |
|
299 col = 4 |
|
300 index1 = self.createIndex(row, col, self.breakpoints[row]) |
|
301 self.dataAboutToBeChanged.emit(index1, index1) |
|
302 self.breakpoints[row][col] = enabled |
|
303 self.dataChanged.emit(index1, index1) |
|
304 |
|
305 def deleteBreakPointByIndex(self, index): |
|
306 """ |
|
307 Public method to set the values of a breakpoint given by index. |
|
308 |
|
309 @param index index of the breakpoint |
|
310 @type QModelIndex |
|
311 """ |
|
312 if index.isValid(): |
|
313 row = index.row() |
|
314 self.beginRemoveRows(QModelIndex(), row, row) |
|
315 del self.breakpoints[row] |
|
316 self.endRemoveRows() |
|
317 |
|
318 def deleteBreakPoints(self, idxList): |
|
319 """ |
|
320 Public method to delete a list of breakpoints given by their indexes. |
|
321 |
|
322 @param idxList list of breakpoint indexes |
|
323 @type list of QModelIndex |
|
324 """ |
|
325 rows = [] |
|
326 for index in idxList: |
|
327 if index.isValid(): |
|
328 rows.append(index.row()) |
|
329 rows.sort(reverse=True) |
|
330 for row in rows: |
|
331 if row < len(self.breakpoints): |
|
332 self.beginRemoveRows(QModelIndex(), row, row) |
|
333 del self.breakpoints[row] |
|
334 self.endRemoveRows() |
|
335 |
|
336 def deleteAll(self): |
|
337 """ |
|
338 Public method to delete all breakpoints. |
|
339 """ |
|
340 if self.breakpoints: |
|
341 self.beginRemoveRows(QModelIndex(), 0, len(self.breakpoints) - 1) |
|
342 self.breakpoints = [] |
|
343 self.endRemoveRows() |
|
344 |
|
345 def getBreakPointByIndex(self, index): |
|
346 """ |
|
347 Public method to get the values of a breakpoint given by index. |
|
348 |
|
349 @param index index of the breakpoint |
|
350 @type QModelIndex |
|
351 @return breakpoint (list of six values (filename, line number, |
|
352 condition, temporary flag, enabled flag, ignore count)) |
|
353 @rtype list of (str, int, str, bool, bool, int) |
|
354 """ |
|
355 if index.isValid(): |
|
356 return self.breakpoints[index.row()][:] # return a copy |
|
357 else: |
|
358 return [] |
|
359 |
|
360 def getAllBreakpoints(self): |
|
361 """ |
|
362 Public method to get a copy of the breakpoints. |
|
363 |
|
364 @return list of breakpoints |
|
365 @rtype list of list of [str, int, str, bool, bool, int] |
|
366 """ |
|
367 return copy.deepcopy(self.breakpoints) |
|
368 |
|
369 def getBreakPointIndex(self, fn, lineno): |
|
370 """ |
|
371 Public method to get the index of a breakpoint given by filename and |
|
372 line number. |
|
373 |
|
374 @param fn filename of the breakpoint |
|
375 @type str |
|
376 @param lineno line number of the breakpoint |
|
377 @type int |
|
378 @return index |
|
379 @rtype QModelIndex |
|
380 """ |
|
381 for row in range(len(self.breakpoints)): |
|
382 bp = self.breakpoints[row] |
|
383 if bp[0] == fn and bp[1] == lineno: |
|
384 return self.createIndex(row, 0, self.breakpoints[row]) |
|
385 |
|
386 return QModelIndex() |
|
387 |
|
388 def isBreakPointTemporaryByIndex(self, index): |
|
389 """ |
|
390 Public method to test, if a breakpoint given by its index is temporary. |
|
391 |
|
392 @param index index of the breakpoint to test |
|
393 @type QModelIndex |
|
394 @return flag indicating a temporary breakpoint |
|
395 @rtype bool |
|
396 """ |
|
397 if index.isValid(): |
|
398 return self.breakpoints[index.row()][3] |
|
399 else: |
|
400 return False |