eric6/Debugger/VariablesViewer.py

changeset 6942
2602857055c5
parent 6645
ad476851d7e0
child 6953
b06cb5bbc880
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/eric6/Debugger/VariablesViewer.py	Sun Apr 14 15:09:21 2019 +0200
@@ -0,0 +1,846 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2002 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the variables viewer widget.
+"""
+
+from __future__ import unicode_literals
+try:
+    str = unicode
+except NameError:
+    pass
+
+from PyQt5.QtCore import Qt, QRegExp, QCoreApplication
+from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem, QAbstractItemView, \
+    QMenu
+
+from E5Gui.E5Application import e5App
+
+from .Config import ConfigVarTypeDispStrings
+
+import Preferences
+import Utilities
+from Globals import qVersionTuple
+
+
+class VariableItem(QTreeWidgetItem):
+    """
+    Class implementing the data structure for variable items.
+    """
+    Indicators = ("()", "[]", "{:}", "{}")      # __IGNORE_WARNING_M613__
+    Type2Indicators = {
+        # Python types
+        'list': '[]',
+        'tuple': '()',
+        'dict': '{:}',                          # __IGNORE_WARNING_M613__
+        'set': '{}',                            # __IGNORE_WARNING_M613__
+        'frozenset': '{}',                      # __IGNORE_WARNING_M613__
+    }
+    
+    def __init__(self, parent, dvar, dvalue, dtype):
+        """
+        Constructor
+        
+        @param parent reference to the parent item
+        @param dvar variable name (string)
+        @param dvalue value string (string)
+        @param dtype type string (string)
+        """
+        dvar, self.__varID = VariableItem.extractId(dvar)
+        
+        self.__value = dvalue
+        if len(dvalue) > 2048:     # 1024 * 2
+            dvalue = QCoreApplication.translate(
+                "VariableItem", "<double click to show value>")
+            self.__tooltip = dvalue
+        elif dvalue == "@@TOO_BIG_TO_SHOW@@":
+            dvalue = QCoreApplication.translate(
+                "VariableItem", "<variable value is too big>")
+        else:
+            if Qt.mightBeRichText(dvalue):
+                self.__tooltip = Utilities.html_encode(dvalue)
+            else:
+                self.__tooltip = dvalue
+            lines = dvalue.splitlines()
+            if len(lines) > 1:
+                # only show the first non-empty line;
+                # indicate skipped lines by <...> at the
+                # beginning and/or end
+                index = 0
+                while index < len(lines) - 1 and lines[index] == "":
+                    index += 1
+                dvalue = ""
+                if index > 0:
+                    dvalue += "<...>"
+                dvalue += lines[index]
+                if index < len(lines) - 1:
+                    dvalue += "<...>"
+        
+        super(VariableItem, self).__init__(parent, [dvar, dvalue, dtype])
+        
+        self.populated = True
+        
+    def getValue(self):
+        """
+        Public method to return the value of the item.
+        
+        @return value of the item (string)
+        """
+        return self.__value
+    
+    def getId(self):
+        """
+        Public method to get the ID string.
+        
+        @return ID string
+        @rtype str
+        """
+        return self.__varID
+    
+    @classmethod
+    def extractId(cls, var):
+        """
+        Class method to extract the ID string from a variable text.
+        
+        @param var variable text
+        @type str
+        @return tuple containing the variable text without ID and the ID string
+        @rtype tuple of two str
+        """
+        if " (ID:" in var:
+            dvar, varID = var.rsplit(None, 1)
+            if varID.endswith(VariableItem.Indicators):
+                varID, indicators = VariableItem.extractIndicators(varID)
+                dvar += indicators
+        else:
+            dvar = var
+            varID = None
+        
+        return dvar, varID
+    
+    @classmethod
+    def extractIndicators(cls, var):
+        """
+        Class method to extract the indicator string from a variable text.
+        
+        @param var variable text
+        @type str
+        @return tuple containing the variable text without indicators and the
+            indicator string
+        @rtype tuple of two str
+        """
+        for indicator in VariableItem.Indicators:
+            if var.endswith(indicator):
+                return var[:-len(indicator)], indicator
+        
+        return var, ""
+    
+    def _buildKey(self):
+        """
+        Protected method to build the access key for the variable.
+        
+        @return access key
+        @rtype str
+        """
+        indicators = ""
+        txt = self.text(0)
+        if txt.endswith(VariableItem.Indicators):
+            txt, indicators = VariableItem.extractIndicators(txt)
+        if self.__varID:
+            txt = "{0} {1}{2}".format(txt, self.__varID, indicators)
+        else:
+            txt = "{0}{1}".format(txt, indicators)
+        return txt
+    
+    def data(self, column, role):
+        """
+        Public method to return the data for the requested role.
+        
+        This implementation changes the original behavior in a way, that the
+        display data is returned as the tooltip for column 1.
+        
+        @param column column number (integer)
+        @param role data role (Qt.ItemDataRole)
+        @return requested data
+        """
+        if column == 1 and role == Qt.ToolTipRole:
+            return self.__tooltip
+        return super(VariableItem, self).data(column, role)
+        
+    def attachDummy(self):
+        """
+        Public method to attach a dummy sub item to allow for lazy population.
+        """
+        QTreeWidgetItem(self, ["DUMMY"])
+        
+    def deleteChildren(self):
+        """
+        Public method to delete all children (cleaning the subtree).
+        """
+        for itm in self.takeChildren():
+            del itm
+        
+    def expand(self):
+        """
+        Public method to expand the item.
+        
+        Note: This is just a do nothing and should be overwritten.
+        """
+        return
+        
+    def collapse(self):
+        """
+        Public method to collapse the item.
+        
+        Note: This is just a do nothing and should be overwritten.
+        """
+        return
+
+
+class SpecialVarItem(VariableItem):
+    """
+    Class implementing a VariableItem that represents a special variable node.
+    
+    These special variable nodes are generated for classes, lists,
+    tuples and dictionaries.
+    """
+    def __init__(self, parent, dvar, dvalue, dtype, frmnr, globalScope):
+        """
+        Constructor
+        
+        @param parent parent of this item
+        @param dvar variable name (string)
+        @param dvalue value string (string)
+        @param dtype type string (string)
+        @param frmnr frame number (0 is the current frame) (int)
+        @param globalScope flag indicating global (True) or local (False)
+            variables
+        """
+        VariableItem.__init__(self, parent, dvar, dvalue, dtype)
+        self.attachDummy()
+        self.populated = False
+        
+        self.framenr = frmnr
+        self.globalScope = globalScope
+
+    def expand(self):
+        """
+        Public method to expand the item.
+        """
+        self.deleteChildren()
+        self.populated = True
+        
+        pathlist = [self._buildKey()]
+        par = self.parent()
+        
+        # step 1: get a pathlist up to the requested variable
+        while par is not None:
+            pathlist.insert(0, par._buildKey())
+            par = par.parent()
+        
+        # step 2: request the variable from the debugger
+        variablesFilter = e5App().getObject("DebugUI").variablesFilter(
+            self.globalScope)
+        e5App().getObject("DebugServer").remoteClientVariable(
+            self.globalScope, variablesFilter, pathlist, self.framenr)
+
+
+class ArrayElementVarItem(VariableItem):
+    """
+    Class implementing a VariableItem that represents an array element.
+    """
+    def __init__(self, parent, dvar, dvalue, dtype):
+        """
+        Constructor
+        
+        @param parent parent of this item
+        @param dvar variable name (string)
+        @param dvalue value string (string)
+        @param dtype type string (string)
+        """
+        VariableItem.__init__(self, parent, dvar, dvalue, dtype)
+        
+        """
+        Array elements have numbers as names, but the key must be
+        right justified and zero filled to 6 decimal places. Then
+        element 2 will have a key of '000002' and appear before
+        element 10 with a key of '000010'
+        """
+        col0Str = self.text(0)
+        self.setText(0, "{0:6d}".format(int(col0Str)))
+
+
+class SpecialArrayElementVarItem(SpecialVarItem):
+    """
+    Class implementing a QTreeWidgetItem that represents a special array
+    variable node.
+    """
+    def __init__(self, parent, dvar, dvalue, dtype, frmnr, globalScope):
+        """
+        Constructor
+        
+        @param parent parent of this item
+        @param dvar variable name (string)
+        @param dvalue value string (string)
+        @param dtype type string (string)
+        @param frmnr frame number (0 is the current frame) (int)
+        @param globalScope flag indicating global (True) or local (False)
+            variables
+        """
+        SpecialVarItem.__init__(self, parent, dvar, dvalue, dtype, frmnr,
+                                globalScope)
+        
+        """
+        Array elements have numbers as names, but the key must be
+        right justified and zero filled to 6 decimal places. Then
+        element 2 will have a key of '000002' and appear before
+        element 10 with a key of '000010'
+        """
+        # strip off [], () or {}
+        col0Str, indicators = VariableItem.extractIndicators(self.text(0))
+        self.setText(0, "{0:6d}{1}".format(int(col0Str), indicators))
+
+
+class VariablesViewer(QTreeWidget):
+    """
+    Class implementing the variables viewer widget.
+    
+    This widget is used to display the variables of the program being
+    debugged in a tree. Compound types will be shown with
+    their main entry first. Once the subtree has been expanded, the
+    individual entries will be shown. Double clicking an entry will
+    popup a dialog showing the variables parameters in a more readable
+    form. This is especially useful for lengthy strings.
+    
+    This widget has two modes for displaying the global and the local
+    variables.
+    """
+    def __init__(self, viewer, globalScope, parent=None):
+        """
+        Constructor
+        
+        @param viewer reference to the debug viewer object (DebugViewer)
+        @param globalScope flag indicating global (True) or local (False)
+            variables
+        @param parent the parent (QWidget)
+        """
+        super(VariablesViewer, self).__init__(parent)
+        
+        self.__debugViewer = viewer
+        self.__globalScope = globalScope
+        
+        indicatorPattern = "|".join([QRegExp.escape(indicator)
+                                     for indicator in VariableItem.Indicators])
+        self.rx_class = QRegExp('<.*(instance|object) at 0x.*>')
+        self.rx_class2 = QRegExp('class .*')
+        self.rx_class3 = QRegExp('<class .* at 0x.*>')
+        self.dvar_rx_class1 = QRegExp(
+            r'<.*(instance|object) at 0x.*>({0})'.format(indicatorPattern))
+        self.dvar_rx_class2 = QRegExp(
+            r'<class .* at 0x.*>({0})'.format(indicatorPattern))
+        self.dvar_rx_array_element = QRegExp(r'^\d+$')
+        self.dvar_rx_special_array_element = QRegExp(
+            r'^\d+({0})$'.format(indicatorPattern))
+        self.rx_nonprintable = QRegExp(r"""(\\x\d\d)+""")
+        
+        self.framenr = 0
+        
+        self.loc = Preferences.getSystem("StringEncoding")
+        
+        self.openItems = []
+        
+        self.setRootIsDecorated(True)
+        self.setAlternatingRowColors(True)
+        self.setSelectionBehavior(QAbstractItemView.SelectRows)
+        
+        if self.__globalScope:
+            self.setWindowTitle(self.tr("Global Variables"))
+            self.setHeaderLabels([
+                self.tr("Globals"),
+                self.tr("Value"),
+                self.tr("Type")])
+            self.setWhatsThis(self.tr(
+                """<b>The Global Variables Viewer Window</b>"""
+                """<p>This window displays the global variables"""
+                """ of the debugged program.</p>"""
+            ))
+        else:
+            self.setWindowTitle(self.tr("Local Variables"))
+            self.setHeaderLabels([
+                self.tr("Locals"),
+                self.tr("Value"),
+                self.tr("Type")])
+            self.setWhatsThis(self.tr(
+                """<b>The Local Variables Viewer Window</b>"""
+                """<p>This window displays the local variables"""
+                """ of the debugged program.</p>"""
+            ))
+        
+        header = self.header()
+        header.setSortIndicator(0, Qt.AscendingOrder)
+        header.setSortIndicatorShown(True)
+        if qVersionTuple() >= (5, 0, 0):
+            header.setSectionsClickable(True)
+        else:
+            header.setClickable(True)
+        header.sectionClicked.connect(self.__sectionClicked)
+        header.resizeSection(0, 120)    # variable column
+        header.resizeSection(1, 150)    # value column
+        
+        self.__createPopupMenus()
+        self.setContextMenuPolicy(Qt.CustomContextMenu)
+        self.customContextMenuRequested.connect(self.__showContextMenu)
+        
+        self.itemExpanded.connect(self.__expandItemSignal)
+        self.itemCollapsed.connect(self.collapseItem)
+        
+        self.resortEnabled = True
+        
+    def __createPopupMenus(self):
+        """
+        Private method to generate the popup menus.
+        """
+        self.menu = QMenu()
+        self.menu.addAction(self.tr("Show Details..."), self.__showDetails)
+        self.menu.addAction(self.tr("Refresh"), self.__refreshView)
+        self.menu.addSeparator()
+        self.menu.addAction(self.tr("Configure..."), self.__configure)
+        
+        self.backMenu = QMenu()
+        self.backMenu.addAction(self.tr("Refresh"), self.__refreshView)
+        self.backMenu.addSeparator()
+        self.backMenu.addAction(self.tr("Configure..."), self.__configure)
+        
+    def __showContextMenu(self, coord):
+        """
+        Private slot to show the context menu.
+        
+        @param coord the position of the mouse pointer (QPoint)
+        """
+        gcoord = self.mapToGlobal(coord)
+        if self.itemAt(coord) is not None:
+            self.menu.popup(gcoord)
+        else:
+            self.backMenu.popup(gcoord)
+        
+    def __findItem(self, slist, column, node=None):
+        """
+        Private method to search for an item.
+        
+        It is used to find a specific item in column,
+        that is a child of node. If node is None, a child of the
+        QTreeWidget is searched.
+        
+        @param slist searchlist (list of strings)
+        @param column index of column to search in (int)
+        @param node start point of the search
+        @return the found item or None
+        """
+        if node is None:
+            count = self.topLevelItemCount()
+        else:
+            count = node.childCount()
+        
+        if column == 0:
+            searchStr = VariableItem.extractId(slist[0])[0]
+        else:
+            searchStr = slist[0]
+        
+        for index in range(count):
+            if node is None:
+                itm = self.topLevelItem(index)
+            else:
+                itm = node.child(index)
+            if itm.text(column) == searchStr:
+                if len(slist) > 1:
+                    itm = self.__findItem(slist[1:], column, itm)
+                return itm
+        
+        return None
+        
+    def showVariables(self, vlist, frmnr):
+        """
+        Public method to show variables in a list.
+        
+        @param vlist the list of variables to be displayed. Each
+                listentry is a tuple of three values.
+                <ul>
+                <li>the variable name (string)</li>
+                <li>the variables type (string)</li>
+                <li>the variables value (string)</li>
+                </ul>
+        @param frmnr frame number (0 is the current frame) (int)
+        """
+        self.current = self.currentItem()
+        if self.current:
+            self.curpathlist = self.__buildTreePath(self.current)
+        self.clear()
+        self.__scrollToItem = None
+        self.framenr = frmnr
+        
+        if len(vlist):
+            self.resortEnabled = False
+            for (var, vtype, value) in vlist:
+                self.__addItem(None, vtype, var, value)
+            
+            # re-expand tree
+            openItems = sorted(self.openItems[:])
+            self.openItems = []
+            for itemPath in openItems:
+                itm = self.__findItem(itemPath, 0)
+                if itm is not None:
+                    self.expandItem(itm)
+                else:
+                    self.openItems.append(itemPath)
+            
+            if self.current:
+                citm = self.__findItem(self.curpathlist, 0)
+                if citm:
+                    self.setCurrentItem(citm)
+                    citm.setSelected(True)
+                    self.scrollToItem(citm, QAbstractItemView.PositionAtTop)
+                    self.current = None
+            
+            self.resortEnabled = True
+            self.__resort()
+
+    def showVariable(self, vlist):
+        """
+        Public method to show variables in a list.
+        
+        @param vlist the list of subitems to be displayed.
+                The first element gives the path of the
+                parent variable. Each other listentry is
+                a tuple of three values.
+                <ul>
+                <li>the variable name (string)</li>
+                <li>the variables type (string)</li>
+                <li>the variables value (string)</li>
+                </ul>
+        """
+        resortEnabled = self.resortEnabled
+        self.resortEnabled = False
+        if self.current is None:
+            self.current = self.currentItem()
+            if self.current:
+                self.curpathlist = self.__buildTreePath(self.current)
+        
+        if vlist:
+            itm = self.__findItem(vlist[0], 0)
+            for var, vtype, value in vlist[1:]:
+                self.__addItem(itm, vtype, var, value)
+
+        # re-expand tree
+        openItems = sorted(self.openItems[:])
+        self.openItems = []
+        for itemPath in openItems:
+            itm = self.__findItem(itemPath, 0)
+            if itm is not None and not itm.isExpanded():
+                if itm.populated:
+                    self.blockSignals(True)
+                    itm.setExpanded(True)
+                    self.blockSignals(False)
+                else:
+                    self.expandItem(itm)
+        self.openItems = openItems[:]
+            
+        if self.current:
+            citm = self.__findItem(self.curpathlist, 0)
+            if citm:
+                self.setCurrentItem(citm)
+                citm.setSelected(True)
+                if self.__scrollToItem:
+                    self.scrollToItem(self.__scrollToItem,
+                                      QAbstractItemView.PositionAtTop)
+                else:
+                    self.scrollToItem(citm, QAbstractItemView.PositionAtTop)
+                self.current = None
+        elif self.__scrollToItem:
+            self.scrollToItem(self.__scrollToItem,
+                              QAbstractItemView.PositionAtTop)
+        
+        self.resortEnabled = resortEnabled
+        self.__resort()
+
+    def __generateItem(self, parent, dvar, dvalue, dtype, isSpecial=False):
+        """
+        Private method used to generate a VariableItem.
+        
+        @param parent parent of the item to be generated
+        @param dvar variable name (string)
+        @param dvalue value string (string)
+        @param dtype type string (string)
+        @param isSpecial flag indicating that a special node should be
+            generated (boolean)
+        @return The item that was generated (VariableItem).
+        """
+        if isSpecial and \
+           (self.dvar_rx_class1.exactMatch(dvar) or
+                self.dvar_rx_class2.exactMatch(dvar)):
+            isSpecial = False
+        
+        if self.rx_class2.exactMatch(dtype):
+            return SpecialVarItem(
+                parent, dvar, dvalue, dtype[7:-1], self.framenr,
+                self.__globalScope)
+        elif dtype != "void *" and \
+            (self.rx_class.exactMatch(dvalue) or
+             self.rx_class3.exactMatch(dvalue) or
+             isSpecial):
+            if self.dvar_rx_special_array_element.exactMatch(dvar):
+                return SpecialArrayElementVarItem(
+                    parent, dvar, dvalue, dtype, self.framenr,
+                    self.__globalScope)
+            else:
+                return SpecialVarItem(parent, dvar, dvalue, dtype,
+                                      self.framenr, self.__globalScope)
+        elif dtype in ["numpy.ndarray", "django.MultiValueDict",
+                       "array.array"]:
+            return SpecialVarItem(
+                parent, dvar, self.tr("{0} items").format(dvalue), dtype,
+                self.framenr, self.__globalScope)
+        else:
+            if self.dvar_rx_array_element.exactMatch(dvar):
+                return ArrayElementVarItem(parent, dvar, dvalue, dtype)
+            else:
+                return VariableItem(parent, dvar, dvalue, dtype)
+        
+    def __addItem(self, parent, vtype, var, value):
+        """
+        Private method used to add an item to the list.
+        
+        If the item is of a type with subelements (i.e. list, dictionary,
+        tuple), these subelements are added by calling this method recursively.
+        
+        @param parent the parent of the item to be added
+            (QTreeWidgetItem or None)
+        @param vtype the type of the item to be added
+            (string)
+        @param var the variable name (string)
+        @param value the value string (string)
+        @return The item that was added to the listview (QTreeWidgetItem).
+        """
+        if parent is None:
+            parent = self
+        try:
+            dvar = '{0}{1}'.format(var, VariableItem.Type2Indicators[vtype])
+        except KeyError:
+            dvar = var
+        dvtype = self.__getDispType(vtype)
+        
+        if vtype in ['list', 'tuple', 'dict', 'set', 'frozenset']:
+            itm = self.__generateItem(parent, dvar,
+                                      self.tr("{0} items").format(value),
+                                      dvtype, True)
+        elif vtype in ['unicode', 'str']:
+            if self.rx_nonprintable.indexIn(value) != -1:
+                sval = value
+            else:
+                try:
+                    sval = eval(value)
+                except Exception:
+                    sval = value
+            itm = self.__generateItem(parent, dvar, str(sval), dvtype)
+        
+        else:
+            itm = self.__generateItem(parent, dvar, value, dvtype)
+            
+        return itm
+
+    def __getDispType(self, vtype):
+        """
+        Private method used to get the display string for type vtype.
+        
+        @param vtype the type, the display string should be looked up for
+              (string)
+        @return displaystring (string)
+        """
+        try:
+            dvtype = self.tr(ConfigVarTypeDispStrings[vtype])
+        except KeyError:
+            if vtype == 'classobj':
+                dvtype = self.tr(ConfigVarTypeDispStrings['instance'])
+            else:
+                dvtype = vtype
+        return dvtype
+    
+    def __refreshView(self):
+        """
+        Private slot to refresh the view.
+        """
+        if self.__globalScope:
+            self.__debugViewer.setGlobalsFilter()
+        else:
+            self.__debugViewer.setLocalsFilter()
+    
+    def mouseDoubleClickEvent(self, mouseEvent):
+        """
+        Protected method of QAbstractItemView.
+        
+        Reimplemented to disable expanding/collapsing of items when
+        double-clicking. Instead the double-clicked entry is opened.
+        
+        @param mouseEvent the mouse event object (QMouseEvent)
+        """
+        itm = self.itemAt(mouseEvent.pos())
+        self.__showVariableDetails(itm)
+        
+    def __showDetails(self):
+        """
+        Private slot to show details about the selected variable.
+        """
+        itm = self.currentItem()
+        self.__showVariableDetails(itm)
+        
+    def __showVariableDetails(self, itm):
+        """
+        Private method to show details about a variable.
+        
+        @param itm reference to the variable item
+        """
+        if itm is None:
+            return
+        
+        val = itm.getValue()
+        
+        if not val:
+            return  # do not display anything, if the variable has no value
+            
+        vtype = itm.text(2)
+        name = VariableItem.extractIndicators(itm.text(0).strip())[0]
+        
+        par = itm.parent()
+        if name.startswith("["):    # numpy.ndarray, array.array
+            nlist = []
+        else:
+            nlist = [name]
+        
+        # build up the fully qualified name
+        while par is not None:
+            pname, indicators = VariableItem.extractIndicators(
+                par.text(0).strip())
+            if indicators:
+                if nlist[0].endswith("."):
+                    nlist[0] = '[{0}].'.format(nlist[0][:-1])
+                else:
+                    nlist[0] = '[{0}]'.format(nlist[0])
+                if not pname.startswith("["):   # numpy.ndarray, array.array
+                    nlist.insert(0, pname)
+            else:
+                if par.text(2) == "django.MultiValueDict":
+                    nlist[0] = 'getlist({0})'.format(nlist[0])
+                elif par.text(2) == "numpy.ndarray":
+                    if nlist[0][0].isalpha():
+                        if nlist[0] in ["min", "max", "mean"]:
+                            nlist[0] = ".{0}()".format(nlist[0])
+                        else:
+                            nlist[0] = ".{0}".format(nlist[0])
+                    nlist.insert(0, pname)
+                else:
+                    nlist.insert(0, '{0}.'.format(pname))
+            par = par.parent()
+            
+        name = ''.join(nlist)
+        # now show the dialog
+        from .VariableDetailDialog import VariableDetailDialog
+        dlg = VariableDetailDialog(name, vtype, val)
+        dlg.exec_()
+    
+    def __buildTreePath(self, itm):
+        """
+        Private method to build up a path from the top to an item.
+        
+        @param itm item to build the path for (QTreeWidgetItem)
+        @return list of names denoting the path from the top (list of strings)
+        """
+        name = itm.text(0)
+        pathlist = [name]
+        
+        par = itm.parent()
+        # build up a path from the top to the item
+        while par is not None:
+            pname = par.text(0)
+            pathlist.insert(0, pname)
+            par = par.parent()
+        
+        return pathlist[:]
+    
+    def __expandItemSignal(self, parentItem):
+        """
+        Private slot to handle the expanded signal.
+        
+        @param parentItem reference to the item being expanded
+            (QTreeWidgetItem)
+        """
+        self.expandItem(parentItem)
+        self.__scrollToItem = parentItem
+        
+    def expandItem(self, parentItem):
+        """
+        Public slot to handle the expanded signal.
+        
+        @param parentItem reference to the item being expanded
+            (QTreeWidgetItem)
+        """
+        pathlist = self.__buildTreePath(parentItem)
+        self.openItems.append(pathlist)
+        if parentItem.populated:
+            return
+        
+        try:
+            parentItem.expand()
+        except AttributeError:
+            super(VariablesViewer, self).expandItem(parentItem)
+
+    def collapseItem(self, parentItem):
+        """
+        Public slot to handle the collapsed signal.
+        
+        @param parentItem reference to the item being collapsed
+            (QTreeWidgetItem)
+        """
+        pathlist = self.__buildTreePath(parentItem)
+        self.openItems.remove(pathlist)
+        
+        try:
+            parentItem.collapse()
+        except AttributeError:
+            super(VariablesViewer, self).collapseItem(parentItem)
+    
+    def __sectionClicked(self):
+        """
+        Private method handling a click onto a header section.
+        """
+        self.__resort()
+    
+    def __resort(self, parent=None):
+        """
+        Private method to resort the tree.
+        
+        @param parent reference to a parent item
+        @type QTreeWidgetItem
+        """
+        if self.resortEnabled:
+            if parent is not None:
+                parent.sortChildren(self.sortColumn(),
+                                    self.header().sortIndicatorOrder())
+            else:
+                self.sortItems(self.sortColumn(),
+                               self.header().sortIndicatorOrder())
+    
+    def handleResetUI(self):
+        """
+        Public method to reset the VariablesViewer.
+        """
+        self.clear()
+        self.openItems = []
+    
+    def __configure(self):
+        """
+        Private method to open the configuration dialog.
+        """
+        e5App().getObject("UserInterface")\
+            .showPreferences("debuggerGeneralPage")

eric ide

mercurial