|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2002 - 2019 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the variables viewer widget. |
|
8 """ |
|
9 |
|
10 from __future__ import unicode_literals |
|
11 try: |
|
12 str = unicode |
|
13 except NameError: |
|
14 pass |
|
15 |
|
16 from PyQt5.QtCore import Qt, QRegExp, QCoreApplication |
|
17 from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem, QAbstractItemView, \ |
|
18 QMenu |
|
19 |
|
20 from E5Gui.E5Application import e5App |
|
21 |
|
22 from .Config import ConfigVarTypeDispStrings |
|
23 |
|
24 import Preferences |
|
25 import Utilities |
|
26 from Globals import qVersionTuple |
|
27 |
|
28 |
|
29 class VariableItem(QTreeWidgetItem): |
|
30 """ |
|
31 Class implementing the data structure for variable items. |
|
32 """ |
|
33 Indicators = ("()", "[]", "{:}", "{}") # __IGNORE_WARNING_M613__ |
|
34 Type2Indicators = { |
|
35 # Python types |
|
36 'list': '[]', |
|
37 'tuple': '()', |
|
38 'dict': '{:}', # __IGNORE_WARNING_M613__ |
|
39 'set': '{}', # __IGNORE_WARNING_M613__ |
|
40 'frozenset': '{}', # __IGNORE_WARNING_M613__ |
|
41 } |
|
42 |
|
43 def __init__(self, parent, dvar, dvalue, dtype): |
|
44 """ |
|
45 Constructor |
|
46 |
|
47 @param parent reference to the parent item |
|
48 @param dvar variable name (string) |
|
49 @param dvalue value string (string) |
|
50 @param dtype type string (string) |
|
51 """ |
|
52 dvar, self.__varID = VariableItem.extractId(dvar) |
|
53 |
|
54 self.__value = dvalue |
|
55 if len(dvalue) > 2048: # 1024 * 2 |
|
56 dvalue = QCoreApplication.translate( |
|
57 "VariableItem", "<double click to show value>") |
|
58 self.__tooltip = dvalue |
|
59 elif dvalue == "@@TOO_BIG_TO_SHOW@@": |
|
60 dvalue = QCoreApplication.translate( |
|
61 "VariableItem", "<variable value is too big>") |
|
62 else: |
|
63 if Qt.mightBeRichText(dvalue): |
|
64 self.__tooltip = Utilities.html_encode(dvalue) |
|
65 else: |
|
66 self.__tooltip = dvalue |
|
67 lines = dvalue.splitlines() |
|
68 if len(lines) > 1: |
|
69 # only show the first non-empty line; |
|
70 # indicate skipped lines by <...> at the |
|
71 # beginning and/or end |
|
72 index = 0 |
|
73 while index < len(lines) - 1 and lines[index] == "": |
|
74 index += 1 |
|
75 dvalue = "" |
|
76 if index > 0: |
|
77 dvalue += "<...>" |
|
78 dvalue += lines[index] |
|
79 if index < len(lines) - 1: |
|
80 dvalue += "<...>" |
|
81 |
|
82 super(VariableItem, self).__init__(parent, [dvar, dvalue, dtype]) |
|
83 |
|
84 self.populated = True |
|
85 |
|
86 def getValue(self): |
|
87 """ |
|
88 Public method to return the value of the item. |
|
89 |
|
90 @return value of the item (string) |
|
91 """ |
|
92 return self.__value |
|
93 |
|
94 def getId(self): |
|
95 """ |
|
96 Public method to get the ID string. |
|
97 |
|
98 @return ID string |
|
99 @rtype str |
|
100 """ |
|
101 return self.__varID |
|
102 |
|
103 @classmethod |
|
104 def extractId(cls, var): |
|
105 """ |
|
106 Class method to extract the ID string from a variable text. |
|
107 |
|
108 @param var variable text |
|
109 @type str |
|
110 @return tuple containing the variable text without ID and the ID string |
|
111 @rtype tuple of two str |
|
112 """ |
|
113 if " (ID:" in var: |
|
114 dvar, varID = var.rsplit(None, 1) |
|
115 if varID.endswith(VariableItem.Indicators): |
|
116 varID, indicators = VariableItem.extractIndicators(varID) |
|
117 dvar += indicators |
|
118 else: |
|
119 dvar = var |
|
120 varID = None |
|
121 |
|
122 return dvar, varID |
|
123 |
|
124 @classmethod |
|
125 def extractIndicators(cls, var): |
|
126 """ |
|
127 Class method to extract the indicator string from a variable text. |
|
128 |
|
129 @param var variable text |
|
130 @type str |
|
131 @return tuple containing the variable text without indicators and the |
|
132 indicator string |
|
133 @rtype tuple of two str |
|
134 """ |
|
135 for indicator in VariableItem.Indicators: |
|
136 if var.endswith(indicator): |
|
137 return var[:-len(indicator)], indicator |
|
138 |
|
139 return var, "" |
|
140 |
|
141 def _buildKey(self): |
|
142 """ |
|
143 Protected method to build the access key for the variable. |
|
144 |
|
145 @return access key |
|
146 @rtype str |
|
147 """ |
|
148 indicators = "" |
|
149 txt = self.text(0) |
|
150 if txt.endswith(VariableItem.Indicators): |
|
151 txt, indicators = VariableItem.extractIndicators(txt) |
|
152 if self.__varID: |
|
153 txt = "{0} {1}{2}".format(txt, self.__varID, indicators) |
|
154 else: |
|
155 txt = "{0}{1}".format(txt, indicators) |
|
156 return txt |
|
157 |
|
158 def data(self, column, role): |
|
159 """ |
|
160 Public method to return the data for the requested role. |
|
161 |
|
162 This implementation changes the original behavior in a way, that the |
|
163 display data is returned as the tooltip for column 1. |
|
164 |
|
165 @param column column number (integer) |
|
166 @param role data role (Qt.ItemDataRole) |
|
167 @return requested data |
|
168 """ |
|
169 if column == 1 and role == Qt.ToolTipRole: |
|
170 return self.__tooltip |
|
171 return super(VariableItem, self).data(column, role) |
|
172 |
|
173 def attachDummy(self): |
|
174 """ |
|
175 Public method to attach a dummy sub item to allow for lazy population. |
|
176 """ |
|
177 QTreeWidgetItem(self, ["DUMMY"]) |
|
178 |
|
179 def deleteChildren(self): |
|
180 """ |
|
181 Public method to delete all children (cleaning the subtree). |
|
182 """ |
|
183 for itm in self.takeChildren(): |
|
184 del itm |
|
185 |
|
186 def expand(self): |
|
187 """ |
|
188 Public method to expand the item. |
|
189 |
|
190 Note: This is just a do nothing and should be overwritten. |
|
191 """ |
|
192 return |
|
193 |
|
194 def collapse(self): |
|
195 """ |
|
196 Public method to collapse the item. |
|
197 |
|
198 Note: This is just a do nothing and should be overwritten. |
|
199 """ |
|
200 return |
|
201 |
|
202 |
|
203 class SpecialVarItem(VariableItem): |
|
204 """ |
|
205 Class implementing a VariableItem that represents a special variable node. |
|
206 |
|
207 These special variable nodes are generated for classes, lists, |
|
208 tuples and dictionaries. |
|
209 """ |
|
210 def __init__(self, parent, dvar, dvalue, dtype, frmnr, globalScope): |
|
211 """ |
|
212 Constructor |
|
213 |
|
214 @param parent parent of this item |
|
215 @param dvar variable name (string) |
|
216 @param dvalue value string (string) |
|
217 @param dtype type string (string) |
|
218 @param frmnr frame number (0 is the current frame) (int) |
|
219 @param globalScope flag indicating global (True) or local (False) |
|
220 variables |
|
221 """ |
|
222 VariableItem.__init__(self, parent, dvar, dvalue, dtype) |
|
223 self.attachDummy() |
|
224 self.populated = False |
|
225 |
|
226 self.framenr = frmnr |
|
227 self.globalScope = globalScope |
|
228 |
|
229 def expand(self): |
|
230 """ |
|
231 Public method to expand the item. |
|
232 """ |
|
233 self.deleteChildren() |
|
234 self.populated = True |
|
235 |
|
236 pathlist = [self._buildKey()] |
|
237 par = self.parent() |
|
238 |
|
239 # step 1: get a pathlist up to the requested variable |
|
240 while par is not None: |
|
241 pathlist.insert(0, par._buildKey()) |
|
242 par = par.parent() |
|
243 |
|
244 # step 2: request the variable from the debugger |
|
245 variablesFilter = e5App().getObject("DebugUI").variablesFilter( |
|
246 self.globalScope) |
|
247 e5App().getObject("DebugServer").remoteClientVariable( |
|
248 self.globalScope, variablesFilter, pathlist, self.framenr) |
|
249 |
|
250 |
|
251 class ArrayElementVarItem(VariableItem): |
|
252 """ |
|
253 Class implementing a VariableItem that represents an array element. |
|
254 """ |
|
255 def __init__(self, parent, dvar, dvalue, dtype): |
|
256 """ |
|
257 Constructor |
|
258 |
|
259 @param parent parent of this item |
|
260 @param dvar variable name (string) |
|
261 @param dvalue value string (string) |
|
262 @param dtype type string (string) |
|
263 """ |
|
264 VariableItem.__init__(self, parent, dvar, dvalue, dtype) |
|
265 |
|
266 """ |
|
267 Array elements have numbers as names, but the key must be |
|
268 right justified and zero filled to 6 decimal places. Then |
|
269 element 2 will have a key of '000002' and appear before |
|
270 element 10 with a key of '000010' |
|
271 """ |
|
272 col0Str = self.text(0) |
|
273 self.setText(0, "{0:6d}".format(int(col0Str))) |
|
274 |
|
275 |
|
276 class SpecialArrayElementVarItem(SpecialVarItem): |
|
277 """ |
|
278 Class implementing a QTreeWidgetItem that represents a special array |
|
279 variable node. |
|
280 """ |
|
281 def __init__(self, parent, dvar, dvalue, dtype, frmnr, globalScope): |
|
282 """ |
|
283 Constructor |
|
284 |
|
285 @param parent parent of this item |
|
286 @param dvar variable name (string) |
|
287 @param dvalue value string (string) |
|
288 @param dtype type string (string) |
|
289 @param frmnr frame number (0 is the current frame) (int) |
|
290 @param globalScope flag indicating global (True) or local (False) |
|
291 variables |
|
292 """ |
|
293 SpecialVarItem.__init__(self, parent, dvar, dvalue, dtype, frmnr, |
|
294 globalScope) |
|
295 |
|
296 """ |
|
297 Array elements have numbers as names, but the key must be |
|
298 right justified and zero filled to 6 decimal places. Then |
|
299 element 2 will have a key of '000002' and appear before |
|
300 element 10 with a key of '000010' |
|
301 """ |
|
302 # strip off [], () or {} |
|
303 col0Str, indicators = VariableItem.extractIndicators(self.text(0)) |
|
304 self.setText(0, "{0:6d}{1}".format(int(col0Str), indicators)) |
|
305 |
|
306 |
|
307 class VariablesViewer(QTreeWidget): |
|
308 """ |
|
309 Class implementing the variables viewer widget. |
|
310 |
|
311 This widget is used to display the variables of the program being |
|
312 debugged in a tree. Compound types will be shown with |
|
313 their main entry first. Once the subtree has been expanded, the |
|
314 individual entries will be shown. Double clicking an entry will |
|
315 popup a dialog showing the variables parameters in a more readable |
|
316 form. This is especially useful for lengthy strings. |
|
317 |
|
318 This widget has two modes for displaying the global and the local |
|
319 variables. |
|
320 """ |
|
321 def __init__(self, viewer, globalScope, parent=None): |
|
322 """ |
|
323 Constructor |
|
324 |
|
325 @param viewer reference to the debug viewer object (DebugViewer) |
|
326 @param globalScope flag indicating global (True) or local (False) |
|
327 variables |
|
328 @param parent the parent (QWidget) |
|
329 """ |
|
330 super(VariablesViewer, self).__init__(parent) |
|
331 |
|
332 self.__debugViewer = viewer |
|
333 self.__globalScope = globalScope |
|
334 |
|
335 indicatorPattern = "|".join([QRegExp.escape(indicator) |
|
336 for indicator in VariableItem.Indicators]) |
|
337 self.rx_class = QRegExp('<.*(instance|object) at 0x.*>') |
|
338 self.rx_class2 = QRegExp('class .*') |
|
339 self.rx_class3 = QRegExp('<class .* at 0x.*>') |
|
340 self.dvar_rx_class1 = QRegExp( |
|
341 r'<.*(instance|object) at 0x.*>({0})'.format(indicatorPattern)) |
|
342 self.dvar_rx_class2 = QRegExp( |
|
343 r'<class .* at 0x.*>({0})'.format(indicatorPattern)) |
|
344 self.dvar_rx_array_element = QRegExp(r'^\d+$') |
|
345 self.dvar_rx_special_array_element = QRegExp( |
|
346 r'^\d+({0})$'.format(indicatorPattern)) |
|
347 self.rx_nonprintable = QRegExp(r"""(\\x\d\d)+""") |
|
348 |
|
349 self.framenr = 0 |
|
350 |
|
351 self.loc = Preferences.getSystem("StringEncoding") |
|
352 |
|
353 self.openItems = [] |
|
354 |
|
355 self.setRootIsDecorated(True) |
|
356 self.setAlternatingRowColors(True) |
|
357 self.setSelectionBehavior(QAbstractItemView.SelectRows) |
|
358 |
|
359 if self.__globalScope: |
|
360 self.setWindowTitle(self.tr("Global Variables")) |
|
361 self.setHeaderLabels([ |
|
362 self.tr("Globals"), |
|
363 self.tr("Value"), |
|
364 self.tr("Type")]) |
|
365 self.setWhatsThis(self.tr( |
|
366 """<b>The Global Variables Viewer Window</b>""" |
|
367 """<p>This window displays the global variables""" |
|
368 """ of the debugged program.</p>""" |
|
369 )) |
|
370 else: |
|
371 self.setWindowTitle(self.tr("Local Variables")) |
|
372 self.setHeaderLabels([ |
|
373 self.tr("Locals"), |
|
374 self.tr("Value"), |
|
375 self.tr("Type")]) |
|
376 self.setWhatsThis(self.tr( |
|
377 """<b>The Local Variables Viewer Window</b>""" |
|
378 """<p>This window displays the local variables""" |
|
379 """ of the debugged program.</p>""" |
|
380 )) |
|
381 |
|
382 header = self.header() |
|
383 header.setSortIndicator(0, Qt.AscendingOrder) |
|
384 header.setSortIndicatorShown(True) |
|
385 if qVersionTuple() >= (5, 0, 0): |
|
386 header.setSectionsClickable(True) |
|
387 else: |
|
388 header.setClickable(True) |
|
389 header.sectionClicked.connect(self.__sectionClicked) |
|
390 header.resizeSection(0, 120) # variable column |
|
391 header.resizeSection(1, 150) # value column |
|
392 |
|
393 self.__createPopupMenus() |
|
394 self.setContextMenuPolicy(Qt.CustomContextMenu) |
|
395 self.customContextMenuRequested.connect(self.__showContextMenu) |
|
396 |
|
397 self.itemExpanded.connect(self.__expandItemSignal) |
|
398 self.itemCollapsed.connect(self.collapseItem) |
|
399 |
|
400 self.resortEnabled = True |
|
401 |
|
402 def __createPopupMenus(self): |
|
403 """ |
|
404 Private method to generate the popup menus. |
|
405 """ |
|
406 self.menu = QMenu() |
|
407 self.menu.addAction(self.tr("Show Details..."), self.__showDetails) |
|
408 self.menu.addAction(self.tr("Refresh"), self.__refreshView) |
|
409 self.menu.addSeparator() |
|
410 self.menu.addAction(self.tr("Configure..."), self.__configure) |
|
411 |
|
412 self.backMenu = QMenu() |
|
413 self.backMenu.addAction(self.tr("Refresh"), self.__refreshView) |
|
414 self.backMenu.addSeparator() |
|
415 self.backMenu.addAction(self.tr("Configure..."), self.__configure) |
|
416 |
|
417 def __showContextMenu(self, coord): |
|
418 """ |
|
419 Private slot to show the context menu. |
|
420 |
|
421 @param coord the position of the mouse pointer (QPoint) |
|
422 """ |
|
423 gcoord = self.mapToGlobal(coord) |
|
424 if self.itemAt(coord) is not None: |
|
425 self.menu.popup(gcoord) |
|
426 else: |
|
427 self.backMenu.popup(gcoord) |
|
428 |
|
429 def __findItem(self, slist, column, node=None): |
|
430 """ |
|
431 Private method to search for an item. |
|
432 |
|
433 It is used to find a specific item in column, |
|
434 that is a child of node. If node is None, a child of the |
|
435 QTreeWidget is searched. |
|
436 |
|
437 @param slist searchlist (list of strings) |
|
438 @param column index of column to search in (int) |
|
439 @param node start point of the search |
|
440 @return the found item or None |
|
441 """ |
|
442 if node is None: |
|
443 count = self.topLevelItemCount() |
|
444 else: |
|
445 count = node.childCount() |
|
446 |
|
447 if column == 0: |
|
448 searchStr = VariableItem.extractId(slist[0])[0] |
|
449 else: |
|
450 searchStr = slist[0] |
|
451 |
|
452 for index in range(count): |
|
453 if node is None: |
|
454 itm = self.topLevelItem(index) |
|
455 else: |
|
456 itm = node.child(index) |
|
457 if itm.text(column) == searchStr: |
|
458 if len(slist) > 1: |
|
459 itm = self.__findItem(slist[1:], column, itm) |
|
460 return itm |
|
461 |
|
462 return None |
|
463 |
|
464 def showVariables(self, vlist, frmnr): |
|
465 """ |
|
466 Public method to show variables in a list. |
|
467 |
|
468 @param vlist the list of variables to be displayed. Each |
|
469 listentry is a tuple of three values. |
|
470 <ul> |
|
471 <li>the variable name (string)</li> |
|
472 <li>the variables type (string)</li> |
|
473 <li>the variables value (string)</li> |
|
474 </ul> |
|
475 @param frmnr frame number (0 is the current frame) (int) |
|
476 """ |
|
477 self.current = self.currentItem() |
|
478 if self.current: |
|
479 self.curpathlist = self.__buildTreePath(self.current) |
|
480 self.clear() |
|
481 self.__scrollToItem = None |
|
482 self.framenr = frmnr |
|
483 |
|
484 if len(vlist): |
|
485 self.resortEnabled = False |
|
486 for (var, vtype, value) in vlist: |
|
487 self.__addItem(None, vtype, var, value) |
|
488 |
|
489 # re-expand tree |
|
490 openItems = sorted(self.openItems[:]) |
|
491 self.openItems = [] |
|
492 for itemPath in openItems: |
|
493 itm = self.__findItem(itemPath, 0) |
|
494 if itm is not None: |
|
495 self.expandItem(itm) |
|
496 else: |
|
497 self.openItems.append(itemPath) |
|
498 |
|
499 if self.current: |
|
500 citm = self.__findItem(self.curpathlist, 0) |
|
501 if citm: |
|
502 self.setCurrentItem(citm) |
|
503 citm.setSelected(True) |
|
504 self.scrollToItem(citm, QAbstractItemView.PositionAtTop) |
|
505 self.current = None |
|
506 |
|
507 self.resortEnabled = True |
|
508 self.__resort() |
|
509 |
|
510 def showVariable(self, vlist): |
|
511 """ |
|
512 Public method to show variables in a list. |
|
513 |
|
514 @param vlist the list of subitems to be displayed. |
|
515 The first element gives the path of the |
|
516 parent variable. Each other listentry is |
|
517 a tuple of three values. |
|
518 <ul> |
|
519 <li>the variable name (string)</li> |
|
520 <li>the variables type (string)</li> |
|
521 <li>the variables value (string)</li> |
|
522 </ul> |
|
523 """ |
|
524 resortEnabled = self.resortEnabled |
|
525 self.resortEnabled = False |
|
526 if self.current is None: |
|
527 self.current = self.currentItem() |
|
528 if self.current: |
|
529 self.curpathlist = self.__buildTreePath(self.current) |
|
530 |
|
531 if vlist: |
|
532 itm = self.__findItem(vlist[0], 0) |
|
533 for var, vtype, value in vlist[1:]: |
|
534 self.__addItem(itm, vtype, var, value) |
|
535 |
|
536 # re-expand tree |
|
537 openItems = sorted(self.openItems[:]) |
|
538 self.openItems = [] |
|
539 for itemPath in openItems: |
|
540 itm = self.__findItem(itemPath, 0) |
|
541 if itm is not None and not itm.isExpanded(): |
|
542 if itm.populated: |
|
543 self.blockSignals(True) |
|
544 itm.setExpanded(True) |
|
545 self.blockSignals(False) |
|
546 else: |
|
547 self.expandItem(itm) |
|
548 self.openItems = openItems[:] |
|
549 |
|
550 if self.current: |
|
551 citm = self.__findItem(self.curpathlist, 0) |
|
552 if citm: |
|
553 self.setCurrentItem(citm) |
|
554 citm.setSelected(True) |
|
555 if self.__scrollToItem: |
|
556 self.scrollToItem(self.__scrollToItem, |
|
557 QAbstractItemView.PositionAtTop) |
|
558 else: |
|
559 self.scrollToItem(citm, QAbstractItemView.PositionAtTop) |
|
560 self.current = None |
|
561 elif self.__scrollToItem: |
|
562 self.scrollToItem(self.__scrollToItem, |
|
563 QAbstractItemView.PositionAtTop) |
|
564 |
|
565 self.resortEnabled = resortEnabled |
|
566 self.__resort() |
|
567 |
|
568 def __generateItem(self, parent, dvar, dvalue, dtype, isSpecial=False): |
|
569 """ |
|
570 Private method used to generate a VariableItem. |
|
571 |
|
572 @param parent parent of the item to be generated |
|
573 @param dvar variable name (string) |
|
574 @param dvalue value string (string) |
|
575 @param dtype type string (string) |
|
576 @param isSpecial flag indicating that a special node should be |
|
577 generated (boolean) |
|
578 @return The item that was generated (VariableItem). |
|
579 """ |
|
580 if isSpecial and \ |
|
581 (self.dvar_rx_class1.exactMatch(dvar) or |
|
582 self.dvar_rx_class2.exactMatch(dvar)): |
|
583 isSpecial = False |
|
584 |
|
585 if self.rx_class2.exactMatch(dtype): |
|
586 return SpecialVarItem( |
|
587 parent, dvar, dvalue, dtype[7:-1], self.framenr, |
|
588 self.__globalScope) |
|
589 elif dtype != "void *" and \ |
|
590 (self.rx_class.exactMatch(dvalue) or |
|
591 self.rx_class3.exactMatch(dvalue) or |
|
592 isSpecial): |
|
593 if self.dvar_rx_special_array_element.exactMatch(dvar): |
|
594 return SpecialArrayElementVarItem( |
|
595 parent, dvar, dvalue, dtype, self.framenr, |
|
596 self.__globalScope) |
|
597 else: |
|
598 return SpecialVarItem(parent, dvar, dvalue, dtype, |
|
599 self.framenr, self.__globalScope) |
|
600 elif dtype in ["numpy.ndarray", "django.MultiValueDict", |
|
601 "array.array"]: |
|
602 return SpecialVarItem( |
|
603 parent, dvar, self.tr("{0} items").format(dvalue), dtype, |
|
604 self.framenr, self.__globalScope) |
|
605 else: |
|
606 if self.dvar_rx_array_element.exactMatch(dvar): |
|
607 return ArrayElementVarItem(parent, dvar, dvalue, dtype) |
|
608 else: |
|
609 return VariableItem(parent, dvar, dvalue, dtype) |
|
610 |
|
611 def __addItem(self, parent, vtype, var, value): |
|
612 """ |
|
613 Private method used to add an item to the list. |
|
614 |
|
615 If the item is of a type with subelements (i.e. list, dictionary, |
|
616 tuple), these subelements are added by calling this method recursively. |
|
617 |
|
618 @param parent the parent of the item to be added |
|
619 (QTreeWidgetItem or None) |
|
620 @param vtype the type of the item to be added |
|
621 (string) |
|
622 @param var the variable name (string) |
|
623 @param value the value string (string) |
|
624 @return The item that was added to the listview (QTreeWidgetItem). |
|
625 """ |
|
626 if parent is None: |
|
627 parent = self |
|
628 try: |
|
629 dvar = '{0}{1}'.format(var, VariableItem.Type2Indicators[vtype]) |
|
630 except KeyError: |
|
631 dvar = var |
|
632 dvtype = self.__getDispType(vtype) |
|
633 |
|
634 if vtype in ['list', 'tuple', 'dict', 'set', 'frozenset']: |
|
635 itm = self.__generateItem(parent, dvar, |
|
636 self.tr("{0} items").format(value), |
|
637 dvtype, True) |
|
638 elif vtype in ['unicode', 'str']: |
|
639 if self.rx_nonprintable.indexIn(value) != -1: |
|
640 sval = value |
|
641 else: |
|
642 try: |
|
643 sval = eval(value) |
|
644 except Exception: |
|
645 sval = value |
|
646 itm = self.__generateItem(parent, dvar, str(sval), dvtype) |
|
647 |
|
648 else: |
|
649 itm = self.__generateItem(parent, dvar, value, dvtype) |
|
650 |
|
651 return itm |
|
652 |
|
653 def __getDispType(self, vtype): |
|
654 """ |
|
655 Private method used to get the display string for type vtype. |
|
656 |
|
657 @param vtype the type, the display string should be looked up for |
|
658 (string) |
|
659 @return displaystring (string) |
|
660 """ |
|
661 try: |
|
662 dvtype = self.tr(ConfigVarTypeDispStrings[vtype]) |
|
663 except KeyError: |
|
664 if vtype == 'classobj': |
|
665 dvtype = self.tr(ConfigVarTypeDispStrings['instance']) |
|
666 else: |
|
667 dvtype = vtype |
|
668 return dvtype |
|
669 |
|
670 def __refreshView(self): |
|
671 """ |
|
672 Private slot to refresh the view. |
|
673 """ |
|
674 if self.__globalScope: |
|
675 self.__debugViewer.setGlobalsFilter() |
|
676 else: |
|
677 self.__debugViewer.setLocalsFilter() |
|
678 |
|
679 def mouseDoubleClickEvent(self, mouseEvent): |
|
680 """ |
|
681 Protected method of QAbstractItemView. |
|
682 |
|
683 Reimplemented to disable expanding/collapsing of items when |
|
684 double-clicking. Instead the double-clicked entry is opened. |
|
685 |
|
686 @param mouseEvent the mouse event object (QMouseEvent) |
|
687 """ |
|
688 itm = self.itemAt(mouseEvent.pos()) |
|
689 self.__showVariableDetails(itm) |
|
690 |
|
691 def __showDetails(self): |
|
692 """ |
|
693 Private slot to show details about the selected variable. |
|
694 """ |
|
695 itm = self.currentItem() |
|
696 self.__showVariableDetails(itm) |
|
697 |
|
698 def __showVariableDetails(self, itm): |
|
699 """ |
|
700 Private method to show details about a variable. |
|
701 |
|
702 @param itm reference to the variable item |
|
703 """ |
|
704 if itm is None: |
|
705 return |
|
706 |
|
707 val = itm.getValue() |
|
708 |
|
709 if not val: |
|
710 return # do not display anything, if the variable has no value |
|
711 |
|
712 vtype = itm.text(2) |
|
713 name = VariableItem.extractIndicators(itm.text(0).strip())[0] |
|
714 |
|
715 par = itm.parent() |
|
716 if name.startswith("["): # numpy.ndarray, array.array |
|
717 nlist = [] |
|
718 else: |
|
719 nlist = [name] |
|
720 |
|
721 # build up the fully qualified name |
|
722 while par is not None: |
|
723 pname, indicators = VariableItem.extractIndicators( |
|
724 par.text(0).strip()) |
|
725 if indicators: |
|
726 if nlist[0].endswith("."): |
|
727 nlist[0] = '[{0}].'.format(nlist[0][:-1]) |
|
728 else: |
|
729 nlist[0] = '[{0}]'.format(nlist[0]) |
|
730 if not pname.startswith("["): # numpy.ndarray, array.array |
|
731 nlist.insert(0, pname) |
|
732 else: |
|
733 if par.text(2) == "django.MultiValueDict": |
|
734 nlist[0] = 'getlist({0})'.format(nlist[0]) |
|
735 elif par.text(2) == "numpy.ndarray": |
|
736 if nlist[0][0].isalpha(): |
|
737 if nlist[0] in ["min", "max", "mean"]: |
|
738 nlist[0] = ".{0}()".format(nlist[0]) |
|
739 else: |
|
740 nlist[0] = ".{0}".format(nlist[0]) |
|
741 nlist.insert(0, pname) |
|
742 else: |
|
743 nlist.insert(0, '{0}.'.format(pname)) |
|
744 par = par.parent() |
|
745 |
|
746 name = ''.join(nlist) |
|
747 # now show the dialog |
|
748 from .VariableDetailDialog import VariableDetailDialog |
|
749 dlg = VariableDetailDialog(name, vtype, val) |
|
750 dlg.exec_() |
|
751 |
|
752 def __buildTreePath(self, itm): |
|
753 """ |
|
754 Private method to build up a path from the top to an item. |
|
755 |
|
756 @param itm item to build the path for (QTreeWidgetItem) |
|
757 @return list of names denoting the path from the top (list of strings) |
|
758 """ |
|
759 name = itm.text(0) |
|
760 pathlist = [name] |
|
761 |
|
762 par = itm.parent() |
|
763 # build up a path from the top to the item |
|
764 while par is not None: |
|
765 pname = par.text(0) |
|
766 pathlist.insert(0, pname) |
|
767 par = par.parent() |
|
768 |
|
769 return pathlist[:] |
|
770 |
|
771 def __expandItemSignal(self, parentItem): |
|
772 """ |
|
773 Private slot to handle the expanded signal. |
|
774 |
|
775 @param parentItem reference to the item being expanded |
|
776 (QTreeWidgetItem) |
|
777 """ |
|
778 self.expandItem(parentItem) |
|
779 self.__scrollToItem = parentItem |
|
780 |
|
781 def expandItem(self, parentItem): |
|
782 """ |
|
783 Public slot to handle the expanded signal. |
|
784 |
|
785 @param parentItem reference to the item being expanded |
|
786 (QTreeWidgetItem) |
|
787 """ |
|
788 pathlist = self.__buildTreePath(parentItem) |
|
789 self.openItems.append(pathlist) |
|
790 if parentItem.populated: |
|
791 return |
|
792 |
|
793 try: |
|
794 parentItem.expand() |
|
795 except AttributeError: |
|
796 super(VariablesViewer, self).expandItem(parentItem) |
|
797 |
|
798 def collapseItem(self, parentItem): |
|
799 """ |
|
800 Public slot to handle the collapsed signal. |
|
801 |
|
802 @param parentItem reference to the item being collapsed |
|
803 (QTreeWidgetItem) |
|
804 """ |
|
805 pathlist = self.__buildTreePath(parentItem) |
|
806 self.openItems.remove(pathlist) |
|
807 |
|
808 try: |
|
809 parentItem.collapse() |
|
810 except AttributeError: |
|
811 super(VariablesViewer, self).collapseItem(parentItem) |
|
812 |
|
813 def __sectionClicked(self): |
|
814 """ |
|
815 Private method handling a click onto a header section. |
|
816 """ |
|
817 self.__resort() |
|
818 |
|
819 def __resort(self, parent=None): |
|
820 """ |
|
821 Private method to resort the tree. |
|
822 |
|
823 @param parent reference to a parent item |
|
824 @type QTreeWidgetItem |
|
825 """ |
|
826 if self.resortEnabled: |
|
827 if parent is not None: |
|
828 parent.sortChildren(self.sortColumn(), |
|
829 self.header().sortIndicatorOrder()) |
|
830 else: |
|
831 self.sortItems(self.sortColumn(), |
|
832 self.header().sortIndicatorOrder()) |
|
833 |
|
834 def handleResetUI(self): |
|
835 """ |
|
836 Public method to reset the VariablesViewer. |
|
837 """ |
|
838 self.clear() |
|
839 self.openItems = [] |
|
840 |
|
841 def __configure(self): |
|
842 """ |
|
843 Private method to open the configuration dialog. |
|
844 """ |
|
845 e5App().getObject("UserInterface")\ |
|
846 .showPreferences("debuggerGeneralPage") |