7 Module implementing the variables viewer view based on QTreeView. |
7 Module implementing the variables viewer view based on QTreeView. |
8 """ |
8 """ |
9 |
9 |
10 import ast |
10 import ast |
11 import re |
11 import re |
|
12 import contextlib |
12 |
13 |
13 from PyQt5.QtCore import ( |
14 from PyQt5.QtCore import ( |
14 Qt, QAbstractItemModel, QModelIndex, QCoreApplication, |
15 Qt, QAbstractItemModel, QModelIndex, QCoreApplication, |
15 QSortFilterProxyModel, pyqtSignal |
16 QSortFilterProxyModel, pyqtSignal |
16 ) |
17 ) |
143 """ |
144 """ |
144 # Python class? |
145 # Python class? |
145 if dtype.startswith('class '): |
146 if dtype.startswith('class '): |
146 dtype = dtype[7:-1] |
147 dtype = dtype[7:-1] |
147 # Qt related stuff? |
148 # Qt related stuff? |
148 elif (dtype.startswith(ConfigQtNames) and |
149 elif ( |
149 dtype.endswith(ConfigKnownQtTypes)): |
150 (dtype.startswith(ConfigQtNames) and |
150 self.hasChildren = True |
151 dtype.endswith(ConfigKnownQtTypes)) or |
151 |
152 dtype in ('instance', 'class') |
152 elif dtype in ('instance', 'class'): |
153 ): |
153 self.hasChildren = True |
154 self.hasChildren = True |
154 |
155 |
155 # Special Qt types should not be expanded infinite |
156 # Special Qt types should not be expanded infinite |
156 elif ".{0}".format(dtype) in ConfigKnownQtTypes: |
157 elif ".{0}".format(dtype) in ConfigKnownQtTypes: |
157 self.type = dtype # It's a Qt type, so skipping translation is ok |
158 self.type = dtype # It's a Qt type, so skipping translation is ok |
199 elif dtype == "Shiboken.EnumType": |
200 elif dtype == "Shiboken.EnumType": |
200 self.hasChildren = True |
201 self.hasChildren = True |
201 |
202 |
202 elif dtype == 'str': |
203 elif dtype == 'str': |
203 if VariableItem.rx_nonprintable.search(dvalue) is None: |
204 if VariableItem.rx_nonprintable.search(dvalue) is None: |
204 try: |
205 with contextlib.suppress(Exception): |
205 dvalue = ast.literal_eval(dvalue) |
206 dvalue = ast.literal_eval(dvalue) |
206 except Exception: # secok |
|
207 pass |
|
208 dvalue = str(dvalue) |
207 dvalue = str(dvalue) |
209 |
208 |
210 self.value = dvalue |
209 self.value = dvalue |
211 |
210 |
212 if len(dvalue) > 2048: # 2 kB |
211 if len(dvalue) > 2048: # 2 kB |
261 @type VariablesViewer |
260 @type VariablesViewer |
262 @param globalScope flag indicating global (True) or local (False) |
261 @param globalScope flag indicating global (True) or local (False) |
263 variables |
262 variables |
264 @type bool |
263 @type bool |
265 """ |
264 """ |
266 super(VariablesModel, self).__init__() |
265 super().__init__() |
267 self.treeView = treeView |
266 self.treeView = treeView |
268 self.proxyModel = treeView.proxyModel |
267 self.proxyModel = treeView.proxyModel |
269 |
268 |
270 self.framenr = -1 |
269 self.framenr = -1 |
271 self.openItems = [] |
270 self.openItems = [] |
272 self.closedItems = [] |
271 self.closedItems = [] |
273 |
272 |
274 if globalScope: |
273 visibility = self.tr("Globals") if globalScope else self.tr("Locals") |
275 visibility = self.tr("Globals") |
|
276 else: |
|
277 visibility = self.tr("Locals") |
|
278 |
|
279 self.rootNode = VariableItem(None, visibility, self.tr("Type"), |
274 self.rootNode = VariableItem(None, visibility, self.tr("Type"), |
280 self.tr("Value")) |
275 self.tr("Value")) |
281 |
276 |
282 self.__globalScope = globalScope |
277 self.__globalScope = globalScope |
283 |
278 |
480 @param parentIdx item to reset marker |
475 @param parentIdx item to reset marker |
481 @type QModelIndex |
476 @type QModelIndex |
482 @param pathlist full path to the variable |
477 @param pathlist full path to the variable |
483 @type list of str |
478 @type list of str |
484 """ |
479 """ |
485 if parentIdx.isValid(): |
480 parent = (parentIdx.internalPointer() if parentIdx.isValid() |
486 parent = parentIdx.internalPointer() |
481 else self.rootNode) |
487 else: |
|
488 parent = self.rootNode |
|
489 |
482 |
490 parent.newItems.clear() |
483 parent.newItems.clear() |
491 parent.changedItems.clear() |
484 parent.changedItems.clear() |
492 |
485 |
493 pll = len(pathlist) |
486 pll = len(pathlist) |
495 posPaths |= {x for x in self.closedItems if len(x) > pll} |
488 posPaths |= {x for x in self.closedItems if len(x) > pll} |
496 posPaths = {x[pll] for x in posPaths if x[:pll] == pathlist} |
489 posPaths = {x[pll] for x in posPaths if x[:pll] == pathlist} |
497 |
490 |
498 if posPaths: |
491 if posPaths: |
499 for child in parent.children: |
492 for child in parent.children: |
500 if child.hasChildren and child.nameWithId in posPaths: |
493 if ( |
501 if child.currentCount >= 0: |
494 child.hasChildren and |
502 # Discard loaded elements and refresh if still expanded |
495 child.nameWithId in posPaths and |
503 child.currentCount = -1 |
496 child.currentCount >= 0 |
504 child.populated = False |
497 ): |
505 row = parent.children.index(child) |
498 # Discard loaded elements and refresh if still expanded |
506 newParentIdx = self.index(row, 0, parentIdx) |
499 child.currentCount = -1 |
507 self.resetModifiedMarker( |
500 child.populated = False |
508 newParentIdx, pathlist + (child.nameWithId,)) |
501 row = parent.children.index(child) |
|
502 newParentIdx = self.index(row, 0, parentIdx) |
|
503 self.resetModifiedMarker( |
|
504 newParentIdx, pathlist + (child.nameWithId,)) |
509 |
505 |
510 self.closedItems = [] |
506 self.closedItems = [] |
511 |
507 |
512 # Little quirk: Refresh all visible items to clear the changed marker |
508 # Little quirk: Refresh all visible items to clear the changed marker |
513 if parentIdx == QModelIndex(): |
509 if parentIdx == QModelIndex(): |
535 @param parent the model parent |
531 @param parent the model parent |
536 @type QModelIndex |
532 @type QModelIndex |
537 @return number of rows |
533 @return number of rows |
538 @rtype int |
534 @rtype int |
539 """ |
535 """ |
540 if parent.isValid(): |
536 node = parent.internalPointer() if parent.isValid() else self.rootNode |
541 node = parent.internalPointer() |
|
542 else: |
|
543 node = self.rootNode |
|
544 |
537 |
545 return len(node.children) |
538 return len(node.children) |
546 |
539 |
547 def flags(self, index): |
540 def flags(self, index): |
548 """ |
541 """ |
586 @rtype QModelIndex |
579 @rtype QModelIndex |
587 """ |
580 """ |
588 if not self.hasIndex(row, column, parent): |
581 if not self.hasIndex(row, column, parent): |
589 return QModelIndex() |
582 return QModelIndex() |
590 |
583 |
591 if not parent.isValid(): |
584 node = parent.internalPointer() if parent.isValid() else self.rootNode |
592 node = self.rootNode |
|
593 else: |
|
594 node = parent.internalPointer() |
|
595 |
585 |
596 return self.createIndex(row, column, node.children[row]) |
586 return self.createIndex(row, column, node.children[row]) |
597 |
587 |
598 def parent(self, child): |
588 def parent(self, child): |
599 """ |
589 """ |
643 if column == 0: |
633 if column == 0: |
644 # Sort first column with values from third column |
634 # Sort first column with values from third column |
645 if role == SORT_ROLE: |
635 if role == SORT_ROLE: |
646 return node.sort |
636 return node.sort |
647 return node.name + node.indicator |
637 return node.name + node.indicator |
648 elif column == 1: |
|
649 return node.valueShort |
|
650 elif column == 2: |
|
651 return node.type |
|
652 elif column == 3: |
|
653 return node.sort |
|
654 else: |
638 else: |
655 return None |
639 return { |
|
640 1: node.valueShort, |
|
641 2: node.type, |
|
642 3: node.sort |
|
643 }.get(column) |
656 except AttributeError: |
644 except AttributeError: |
657 return ['None', '', '', ''][column] |
645 return ['None', '', '', ''][column] |
658 |
646 |
659 elif role == Qt.ItemDataRole.BackgroundRole: |
647 elif role == Qt.ItemDataRole.BackgroundRole: |
660 if node in node.parent.changedItems: |
648 if node in node.parent.changedItems: |
721 role != Qt.ItemDataRole.DisplayRole or |
709 role != Qt.ItemDataRole.DisplayRole or |
722 orientation != Qt.Orientation.Horizontal |
710 orientation != Qt.Orientation.Horizontal |
723 ): |
711 ): |
724 return None |
712 return None |
725 |
713 |
726 if section == 0: |
714 return { |
727 return self.rootNode.name |
715 0: self.rootNode.name, |
728 elif section == 1: |
716 1: self.rootNode.value, |
729 return self.rootNode.value |
717 2: self.rootNode.type, |
730 elif section == 2: |
718 3: self.rootNode.sort |
731 return self.rootNode.type |
719 }.get(section) |
732 elif section == 3: |
|
733 return self.rootNode.sort |
|
734 |
|
735 return None |
|
736 |
720 |
737 def __findPendingItem(self, parent=None, pathlist=()): |
721 def __findPendingItem(self, parent=None, pathlist=()): |
738 """ |
722 """ |
739 Private method to find the next item to request data from debugger. |
723 Private method to find the next item to request data from debugger. |
740 |
724 |
863 Constructor |
847 Constructor |
864 |
848 |
865 @param parent the parent model index |
849 @param parent the parent model index |
866 @type QModelIndex |
850 @type QModelIndex |
867 """ |
851 """ |
868 super(VariablesProxyModel, self).__init__(parent) |
852 super().__init__(parent) |
869 self.setSortRole(SORT_ROLE) |
853 self.setSortRole(SORT_ROLE) |
870 |
854 |
871 def hasChildren(self, parent): |
855 def hasChildren(self, parent): |
872 """ |
856 """ |
873 Public method to get a flag if parent has children. |
857 Public method to get a flag if parent has children. |
1044 |
1028 |
1045 @param value current value of the vertical scrollbar |
1029 @param value current value of the vertical scrollbar |
1046 @type int |
1030 @type int |
1047 """ |
1031 """ |
1048 self.varModel.getMore() |
1032 self.varModel.getMore() |
1049 super(VariablesViewer, self).verticalScrollbarValueChanged(value) |
1033 super().verticalScrollbarValueChanged(value) |
1050 |
1034 |
1051 def resizeEvent(self, event): |
1035 def resizeEvent(self, event): |
1052 """ |
1036 """ |
1053 Protected slot informing about the widget size change. |
1037 Protected slot informing about the widget size change. |
1054 |
1038 |
1055 @param event information |
1039 @param event information |
1056 @type QResizeEvent |
1040 @type QResizeEvent |
1057 """ |
1041 """ |
1058 self.varModel.getMore() |
1042 self.varModel.getMore() |
1059 super(VariablesViewer, self).resizeEvent(event) |
1043 super().resizeEvent(event) |
1060 |
1044 |
1061 def __itemDoubleClicked(self, index): |
1045 def __itemDoubleClicked(self, index): |
1062 """ |
1046 """ |
1063 Private method called if an item was double clicked. |
1047 Private method called if an item was double clicked. |
1064 |
1048 |