14 pass |
14 pass |
15 |
15 |
16 from PyQt5.QtCore import Qt, QRegExp, qVersion, QCoreApplication |
16 from PyQt5.QtCore import Qt, QRegExp, qVersion, QCoreApplication |
17 from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem, QAbstractItemView, \ |
17 from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem, QAbstractItemView, \ |
18 QMenu |
18 QMenu |
19 from PyQt5.QtGui import QTextDocument # __IGNORE_WARNING__ |
|
20 |
19 |
21 from E5Gui.E5Application import e5App |
20 from E5Gui.E5Application import e5App |
22 |
21 |
23 from DebugClients.Python3.DebugConfig import ConfigVarTypeStrings |
|
24 |
|
25 from .Config import ConfigVarTypeDispStrings |
22 from .Config import ConfigVarTypeDispStrings |
26 |
23 |
27 import Preferences |
24 import Preferences |
28 import Utilities |
25 import Utilities |
29 |
26 |
30 |
27 |
31 class VariableItem(QTreeWidgetItem): |
28 class VariableItem(QTreeWidgetItem): |
32 """ |
29 """ |
33 Class implementing the data structure for variable items. |
30 Class implementing the data structure for variable items. |
34 """ |
31 """ |
|
32 Indicators = ("()", "[]", "{:}", "{}") # __IGNORE_WARNING_M613__ |
|
33 Type2Indicators = { |
|
34 # Python types |
|
35 'list': '[]', |
|
36 'tuple': '()', |
|
37 'dict': '{:}', # __IGNORE_WARNING_M613__ |
|
38 'set': '{}', # __IGNORE_WARNING_M613__ |
|
39 'frozenset': '{}', # __IGNORE_WARNING_M613__ |
|
40 } |
|
41 |
35 def __init__(self, parent, dvar, dvalue, dtype): |
42 def __init__(self, parent, dvar, dvalue, dtype): |
36 """ |
43 """ |
37 Constructor |
44 Constructor |
38 |
45 |
39 @param parent reference to the parent item |
46 @param parent reference to the parent item |
40 @param dvar variable name (string) |
47 @param dvar variable name (string) |
41 @param dvalue value string (string) |
48 @param dvalue value string (string) |
42 @param dtype type string (string) |
49 @param dtype type string (string) |
43 """ |
50 """ |
|
51 dvar, self.__varID = VariableItem.extractId(dvar) |
|
52 |
44 self.__value = dvalue |
53 self.__value = dvalue |
45 if len(dvalue) > 2048: # 1024 * 2 |
54 if len(dvalue) > 2048: # 1024 * 2 |
46 dvalue = QCoreApplication.translate( |
55 dvalue = QCoreApplication.translate( |
47 "VariableItem", "<double click to show value>") |
56 "VariableItem", "<double click to show value>") |
48 self.__tooltip = dvalue |
57 self.__tooltip = dvalue |
75 Public method to return the value of the item. |
84 Public method to return the value of the item. |
76 |
85 |
77 @return value of the item (string) |
86 @return value of the item (string) |
78 """ |
87 """ |
79 return self.__value |
88 return self.__value |
80 |
89 |
|
90 def getId(self): |
|
91 """ |
|
92 Public method to get the ID string. |
|
93 |
|
94 @return ID string |
|
95 @rtype str |
|
96 """ |
|
97 return self.__varID |
|
98 |
|
99 @classmethod |
|
100 def extractId(cls, var): |
|
101 """ |
|
102 Class method to extract the ID string from a variable text. |
|
103 |
|
104 @param var variable text |
|
105 @type str |
|
106 @return tuple containing the variable text without ID and the ID string |
|
107 @rtype tuple of two str |
|
108 """ |
|
109 if " (ID:" in var: |
|
110 dvar, varID = var.rsplit(None, 1) |
|
111 if varID.endswith(VariableItem.Indicators): |
|
112 varID, indicators = VariableItem.extractIndicators(varID) |
|
113 dvar += indicators |
|
114 else: |
|
115 dvar = var |
|
116 varID = None |
|
117 |
|
118 return dvar, varID |
|
119 |
|
120 @classmethod |
|
121 def extractIndicators(cls, var): |
|
122 """ |
|
123 Class method to extract the indicator string from a variable text. |
|
124 |
|
125 @param var variable text |
|
126 @type str |
|
127 @return tuple containing the variable text without indicators and the |
|
128 indicator string |
|
129 @rtype tuple of two str |
|
130 """ |
|
131 for indicator in VariableItem.Indicators: |
|
132 if var.endswith(indicator): |
|
133 return var[:-len(indicator)], indicator |
|
134 |
|
135 return var, "" |
|
136 |
|
137 def _buildKey(self): |
|
138 """ |
|
139 Protected method to build the access key for the variable. |
|
140 |
|
141 @return access key |
|
142 @type str |
|
143 """ |
|
144 indicators = "" |
|
145 txt = self.text(0) |
|
146 if txt.endswith(VariableItem.Indicators): |
|
147 txt, indicators = VariableItem.extractIndicators(txt) |
|
148 if self.__varID: |
|
149 txt = "{0} {1}{2}".format(txt, self.__varID, indicators) |
|
150 else: |
|
151 txt = "{0}{1}".format(txt, indicators) |
|
152 return txt |
|
153 |
81 def data(self, column, role): |
154 def data(self, column, role): |
82 """ |
155 """ |
83 Public method to return the data for the requested role. |
156 Public method to return the data for the requested role. |
84 |
157 |
85 This implementation changes the original behavior in a way, that the |
158 This implementation changes the original behavior in a way, that the |
154 Public method to expand the item. |
227 Public method to expand the item. |
155 """ |
228 """ |
156 self.deleteChildren() |
229 self.deleteChildren() |
157 self.populated = True |
230 self.populated = True |
158 |
231 |
159 pathlist = [self.text(0)] |
232 pathlist = [self._buildKey()] |
160 par = self.parent() |
233 par = self.parent() |
161 |
234 |
162 # step 1: get a pathlist up to the requested variable |
235 # step 1: get a pathlist up to the requested variable |
163 while par is not None: |
236 while par is not None: |
164 pathlist.insert(0, par.text(0)) |
237 pathlist.insert(0, par._buildKey()) |
165 par = par.parent() |
238 par = par.parent() |
166 |
239 |
167 # step 2: request the variable from the debugger |
240 # step 2: request the variable from the debugger |
168 filter = e5App().getObject("DebugUI").variablesFilter(self.globalScope) |
241 filter = e5App().getObject("DebugUI").variablesFilter(self.globalScope) |
169 e5App().getObject("DebugServer").remoteClientVariable( |
242 e5App().getObject("DebugServer").remoteClientVariable( |
219 Array elements have numbers as names, but the key must be |
292 Array elements have numbers as names, but the key must be |
220 right justified and zero filled to 6 decimal places. Then |
293 right justified and zero filled to 6 decimal places. Then |
221 element 2 will have a key of '000002' and appear before |
294 element 2 will have a key of '000002' and appear before |
222 element 10 with a key of '000010' |
295 element 10 with a key of '000010' |
223 """ |
296 """ |
224 col0Str = self.text(0)[:-2] # strip off [], () or {} |
297 # strip off [], () or {} |
225 indicator = self.text(0)[-2:] |
298 col0Str, indicators = VariableItem.extractIndicators(self.text(0)) |
226 self.setText(0, "{0:6d}{1}".format(int(col0Str), indicator)) |
299 self.setText(0, "{0:6d}{1}".format(int(col0Str), indicators)) |
227 |
300 |
228 |
301 |
229 class VariablesViewer(QTreeWidget): |
302 class VariablesViewer(QTreeWidget): |
230 """ |
303 """ |
231 Class implementing the variables viewer widget. |
304 Class implementing the variables viewer widget. |
251 """ |
324 """ |
252 super(VariablesViewer, self).__init__(parent) |
325 super(VariablesViewer, self).__init__(parent) |
253 |
326 |
254 self.__debugViewer = viewer |
327 self.__debugViewer = viewer |
255 self.__globalScope = globalScope |
328 self.__globalScope = globalScope |
256 |
|
257 self.indicators = { |
|
258 # Python types |
|
259 'list': '[]', |
|
260 'tuple': '()', |
|
261 'dict': '{}', # __IGNORE_WARNING__ |
|
262 |
|
263 } |
|
264 |
329 |
265 self.rx_class = QRegExp('<.*(instance|object) at 0x.*>') |
330 self.rx_class = QRegExp('<.*(instance|object) at 0x.*>') |
266 self.rx_class2 = QRegExp('class .*') |
331 self.rx_class2 = QRegExp('class .*') |
267 self.rx_class3 = QRegExp('<class .* at 0x.*>') |
332 self.rx_class3 = QRegExp('<class .* at 0x.*>') |
268 self.dvar_rx_class1 = QRegExp( |
333 self.dvar_rx_class1 = QRegExp( |
368 if node is None: |
433 if node is None: |
369 count = self.topLevelItemCount() |
434 count = self.topLevelItemCount() |
370 else: |
435 else: |
371 count = node.childCount() |
436 count = node.childCount() |
372 |
437 |
|
438 if column == 0: |
|
439 searchStr = VariableItem.extractId(slist[0])[0] |
|
440 else: |
|
441 searchStr = slist[0] |
|
442 |
373 for index in range(count): |
443 for index in range(count): |
374 if node is None: |
444 if node is None: |
375 itm = self.topLevelItem(index) |
445 itm = self.topLevelItem(index) |
376 else: |
446 else: |
377 itm = node.child(index) |
447 itm = node.child(index) |
378 if itm.text(column) == slist[0]: |
448 if itm.text(column) == searchStr: |
379 if len(slist) > 1: |
449 if len(slist) > 1: |
380 itm = self.__findItem(slist[1:], column, itm) |
450 itm = self.__findItem(slist[1:], column, itm) |
381 return itm |
451 return itm |
382 |
452 |
383 return None |
453 return None |
540 @return The item that was added to the listview (QTreeWidgetItem). |
610 @return The item that was added to the listview (QTreeWidgetItem). |
541 """ |
611 """ |
542 if parent is None: |
612 if parent is None: |
543 parent = self |
613 parent = self |
544 try: |
614 try: |
545 dvar = '{0}{1}'.format(var, self.indicators[vtype]) |
615 dvar = '{0}{1}'.format(var, VariableItem.Type2Indicators[vtype]) |
546 except KeyError: |
616 except KeyError: |
547 dvar = var |
617 dvar = var |
548 dvtype = self.__getDispType(vtype) |
618 dvtype = self.__getDispType(vtype) |
549 |
619 |
550 if vtype in ['list', 'Array', 'tuple', 'dict', 'Hash']: |
620 if vtype in ['list', 'tuple', 'dict', 'set', 'frozenset']: |
551 itm = self.__generateItem(parent, dvar, |
621 itm = self.__generateItem(parent, dvar, |
552 self.tr("{0} items").format(value), |
622 self.tr("{0} items").format(value), |
553 dvtype, True) |
623 dvtype, True) |
554 elif vtype in ['unicode', 'str']: |
624 elif vtype in ['unicode', 'str']: |
555 if self.rx_nonprintable.indexIn(value) != -1: |
625 if self.rx_nonprintable.indexIn(value) != -1: |
573 @param vtype the type, the display string should be looked up for |
643 @param vtype the type, the display string should be looked up for |
574 (string) |
644 (string) |
575 @return displaystring (string) |
645 @return displaystring (string) |
576 """ |
646 """ |
577 try: |
647 try: |
578 i = ConfigVarTypeStrings.index(vtype) |
648 dvtype = self.tr(ConfigVarTypeDispStrings[vtype]) |
579 dvtype = self.tr(ConfigVarTypeDispStrings[i]) |
649 except KeyError: |
580 except ValueError: |
|
581 if vtype == 'classobj': |
650 if vtype == 'classobj': |
582 dvtype = self.tr(ConfigVarTypeDispStrings[ |
651 dvtype = self.tr(ConfigVarTypeDispStrings['instance']) |
583 ConfigVarTypeStrings.index('instance')]) |
|
584 else: |
652 else: |
585 dvtype = vtype |
653 dvtype = vtype |
586 return dvtype |
654 return dvtype |
587 |
655 |
588 def __refreshView(self): |
656 def __refreshView(self): |
626 |
694 |
627 if not val: |
695 if not val: |
628 return # do not display anything, if the variable has no value |
696 return # do not display anything, if the variable has no value |
629 |
697 |
630 vtype = itm.text(2) |
698 vtype = itm.text(2) |
631 name = itm.text(0) |
699 name = VariableItem.extractIndicators(itm.text(0).strip())[0] |
632 if name[-2:] in ['[]', '{}', '()']: # __IGNORE_WARNING__ |
|
633 name = name[:-2] |
|
634 |
700 |
635 par = itm.parent() |
701 par = itm.parent() |
636 nlist = [name] |
702 nlist = [name] |
637 # build up the fully qualified name |
703 # build up the fully qualified name |
638 while par is not None: |
704 while par is not None: |
639 pname = par.text(0) |
705 pname, indicators = VariableItem.extractIndicators( |
640 if pname[-2:] in ['[]', '{}', '()']: # __IGNORE_WARNING__ |
706 par.text(0).strip()) |
|
707 if indicators: |
641 if nlist[0].endswith("."): |
708 if nlist[0].endswith("."): |
642 nlist[0] = '[{0}].'.format(nlist[0][:-1]) |
709 nlist[0] = '[{0}].'.format(nlist[0][:-1]) |
643 else: |
710 else: |
644 nlist[0] = '[{0}]'.format(nlist[0]) |
711 nlist[0] = '[{0}]'.format(nlist[0]) |
645 nlist.insert(0, pname[:-2]) |
712 nlist.insert(0, pname) |
646 else: |
713 else: |
647 nlist.insert(0, '{0}.'.format(pname)) |
714 nlist.insert(0, '{0}.'.format(pname)) |
648 par = par.parent() |
715 par = par.parent() |
649 |
716 |
650 name = ''.join(nlist) |
717 name = ''.join(nlist) |