Debugger/WatchPointViewer.py

changeset 0
de9c2efb9d02
child 12
1d8dd9706f46
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Debugger/WatchPointViewer.py	Mon Dec 28 16:03:33 2009 +0000
@@ -0,0 +1,422 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2005 - 2009 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing the watch expression viewer widget.
+"""
+
+from PyQt4.QtCore import *
+from PyQt4.QtGui import *
+
+from E4Gui.E4Application import e4App
+
+from EditWatchpointDialog import EditWatchpointDialog
+
+import Utilities
+
+class WatchPointViewer(QTreeView):
+    """
+    Class implementing the watch expression viewer widget.
+    
+    Watch expressions will be shown with all their details. They can be modified through
+    the context menu of this widget.
+    """
+    def __init__(self, parent = None):
+        """
+        Constructor
+        
+        @param parent the parent (QWidget)
+        """
+        QTreeView.__init__(self,parent)
+        self.setObjectName("WatchExpressionViewer")
+        
+        self.__model = None
+        
+        self.setItemsExpandable(False)
+        self.setRootIsDecorated(False)
+        self.setAlternatingRowColors(True)
+        self.setSelectionMode(QAbstractItemView.ExtendedSelection)
+        self.setSelectionBehavior(QAbstractItemView.SelectRows)
+        
+        self.setWindowTitle(self.trUtf8("Watchpoints"))
+        
+        self.setContextMenuPolicy(Qt.CustomContextMenu)
+        self.connect(self,SIGNAL('customContextMenuRequested(const QPoint &)'),
+                     self.__showContextMenu)
+        self.connect(self,SIGNAL('doubleClicked(const QModelIndex &)'),
+                     self.__doubleClicked)
+        
+        self.__createPopupMenus()
+        
+    def setModel(self, model):
+        """
+        Public slot to set the watch expression model.
+        
+        @param reference to the watch expression model (WatchPointModel)
+        """
+        self.__model = model
+        
+        self.sortingModel = QSortFilterProxyModel()
+        self.sortingModel.setSourceModel(self.__model)
+        QTreeView.setModel(self, self.sortingModel)
+        
+        header = self.header()
+        header.setSortIndicator(0, Qt.AscendingOrder)
+        header.setSortIndicatorShown(True)
+        header.setClickable(True)
+        
+        self.setSortingEnabled(True)
+        
+        self.__layoutDisplay()
+        
+    def __layoutDisplay(self):
+        """
+        Private slot to perform a layout operation.
+        """
+        self.doItemsLayout()
+        self.__resizeColumns()
+        self.__resort()
+        
+    def __resizeColumns(self):
+        """
+        Private slot to resize the view when items get added, edited or deleted.
+        """
+        self.header().resizeSections(QHeaderView.ResizeToContents)
+        self.header().setStretchLastSection(True)
+    
+    def __resort(self):
+        """
+        Private slot to resort the tree.
+        """
+        self.model().sort(self.header().sortIndicatorSection(), 
+                          self.header().sortIndicatorOrder())
+        
+    def __toSourceIndex(self, index):
+        """
+        Private slot to convert an index to a source index.
+        
+        @param index index to be converted (QModelIndex)
+        """
+        return self.sortingModel.mapToSource(index)
+        
+    def __fromSourceIndex(self, sindex):
+        """
+        Private slot to convert a source index to an index.
+        
+        @param sindex source index to be converted (QModelIndex)
+        """
+        return self.sortingModel.mapFromSource(sindex)
+        
+    def __setRowSelected(self, index, selected = True):
+        """
+        Private slot to select a complete row.
+        
+        @param index index determining the row to be selected (QModelIndex)
+        @param selected flag indicating the action (bool)
+        """
+        if not index.isValid():
+            return
+        
+        if selected:
+            flags = QItemSelectionModel.SelectionFlags(\
+                QItemSelectionModel.ClearAndSelect | QItemSelectionModel.Rows)
+        else:
+            flags = QItemSelectionModel.SelectionFlags(\
+                QItemSelectionModel.Deselect | QItemSelectionModel.Rows)
+        self.selectionModel().select(index, flags)
+        
+    def __createPopupMenus(self):
+        """
+        Private method to generate the popup menus.
+        """
+        self.menu = QMenu()
+        self.menu.addAction(self.trUtf8("Add"), self.__addWatchPoint)
+        self.menu.addAction(self.trUtf8("Edit..."), self.__editWatchPoint)
+        self.menu.addSeparator()
+        self.menu.addAction(self.trUtf8("Enable"), self.__enableWatchPoint)
+        self.menu.addAction(self.trUtf8("Enable all"), self.__enableAllWatchPoints)
+        self.menu.addSeparator()
+        self.menu.addAction(self.trUtf8("Disable"), self.__disableWatchPoint)
+        self.menu.addAction(self.trUtf8("Disable all"), self.__disableAllWatchPoints)
+        self.menu.addSeparator()
+        self.menu.addAction(self.trUtf8("Delete"), self.__deleteWatchPoint)
+        self.menu.addAction(self.trUtf8("Delete all"), self.__deleteAllWatchPoints)
+        self.menu.addSeparator()
+        self.menu.addAction(self.trUtf8("Configure..."), self.__configure)
+
+        self.backMenuActions = {}
+        self.backMenu = QMenu()
+        self.backMenu.addAction(self.trUtf8("Add"), self.__addWatchPoint)
+        self.backMenuActions["EnableAll"] = \
+            self.backMenu.addAction(self.trUtf8("Enable all"), 
+                self.__enableAllWatchPoints)
+        self.backMenuActions["DisableAll"] = \
+            self.backMenu.addAction(self.trUtf8("Disable all"), 
+                self.__disableAllWatchPoints)
+        self.backMenuActions["DeleteAll"] = \
+            self.backMenu.addAction(self.trUtf8("Delete all"), 
+                self.__deleteAllWatchPoints)
+        self.backMenu.addSeparator()
+        self.backMenu.addAction(self.trUtf8("Configure..."), self.__configure)
+        self.connect(self.backMenu, SIGNAL('aboutToShow()'), self.__showBackMenu)
+
+        self.multiMenu = QMenu()
+        self.multiMenu.addAction(self.trUtf8("Add"), self.__addWatchPoint)
+        self.multiMenu.addSeparator()
+        self.multiMenu.addAction(self.trUtf8("Enable selected"), 
+            self.__enableSelectedWatchPoints)
+        self.multiMenu.addAction(self.trUtf8("Enable all"), self.__enableAllWatchPoints)
+        self.multiMenu.addSeparator()
+        self.multiMenu.addAction(self.trUtf8("Disable selected"), 
+            self.__disableSelectedWatchPoints)
+        self.multiMenu.addAction(self.trUtf8("Disable all"), self.__disableAllWatchPoints)
+        self.multiMenu.addSeparator()
+        self.multiMenu.addAction(self.trUtf8("Delete selected"), 
+            self.__deleteSelectedWatchPoints)
+        self.multiMenu.addAction(self.trUtf8("Delete all"), self.__deleteAllWatchPoints)
+        self.multiMenu.addSeparator()
+        self.multiMenu.addAction(self.trUtf8("Configure..."), self.__configure)
+    
+    def __showContextMenu(self, coord):
+        """
+        Private slot to show the context menu.
+        
+        @param coord the position of the mouse pointer (QPoint)
+        """
+        cnt = self.__getSelectedItemsCount()
+        if cnt <= 1:
+            index = self.indexAt(coord)
+            if index.isValid():
+                cnt = 1
+                self.__setRowSelected(index)
+        coord = self.mapToGlobal(coord)
+        if cnt > 1:
+            self.multiMenu.popup(coord)
+        elif cnt == 1:
+            self.menu.popup(coord)
+        else:
+            self.backMenu.popup(coord)
+    
+    def __clearSelection(self):
+        """
+        Private slot to clear the selection.
+        """
+        for index in self.selectedIndexes():
+            self.__setRowSelected(index, False)
+            
+    def __findDuplicates(self, cond, special, showMessage = False, index = QModelIndex()):
+        """
+        Private method to check, if an entry already exists.
+        
+        @param cond condition to check (string)
+        @param special special condition to check (string)
+        @param showMessage flag indicating a message should be shown,
+            if a duplicate entry is found (boolean)
+        @param index index that should not be considered duplicate (QModelIndex)
+        @return flag indicating a duplicate entry (boolean)
+        """
+        idx = self.__model.getWatchPointIndex(cond, special)
+        duplicate = idx.isValid() and idx.internalPointer() != index.internalPointer()
+        if showMessage and duplicate:
+            if not special:
+                msg = self.trUtf8("""<p>A watch expression '<b>{0}</b>'"""
+                                  """ already exists.</p>""")\
+                        .format(Utilities.html_encode(cond))
+            else:
+                msg = self.trUtf8("""<p>A watch expression '<b>{0}</b>'"""
+                                  """ for the variable <b>{1}</b> already exists.</p>""")\
+                        .format(special, Utilities.html_encode(cond))
+            QMessageBox.warning(None,
+                self.trUtf8("Watch expression already exists"),
+                msg)
+        
+        return duplicate
+    
+    def __clearSelection(self):
+        """
+        Private slot to clear the selection.
+        """
+        for index in self.selectedIndexes():
+            self.__setRowSelected(index, False)
+            
+    def __addWatchPoint(self):
+        """
+        Private slot to handle the add watch expression context menu entry.
+        """
+        dlg = EditWatchpointDialog(("", False, True, 0, ""), self)
+        if dlg.exec_() == QDialog.Accepted:
+            cond, temp, enabled, ignorecount, special = dlg.getData()
+            if not self.__findDuplicates(cond, special, True):
+                self.__model.addWatchPoint(cond, special, (temp, enabled, ignorecount))
+                self.__resizeColumns()
+                self.__resort()
+
+    def __doubleClicked(self, index):
+        """
+        Private slot to handle the double clicked signal.
+        
+        @param index index of the entry that was double clicked (QModelIndex)
+        """
+        if index.isValid():
+            self.__doEditWatchPoint(index)
+
+    def __editWatchPoint(self):
+        """
+        Private slot to handle the edit watch expression context menu entry.
+        """
+        index = self.currentIndex()
+        if index.isValid():
+            self.__doEditWatchPoint(index)
+    
+    def __doEditWatchPoint(self, index):
+        """
+        Private slot to edit a watch expression.
+        
+        @param index index of watch expression to be edited (QModelIndex)
+        """
+        sindex = self.__toSourceIndex(index)
+        if sindex.isValid():
+            wp = self.__model.getWatchPointByIndex(sindex)
+            if not wp:
+                return
+            
+            cond, special, temp, enabled, count = wp[:5]
+            
+            dlg = EditWatchpointDialog(\
+                (cond, temp, enabled, count, special), self)
+            if dlg.exec_() == QDialog.Accepted:
+                cond, temp, enabled, count, special = dlg.getData()
+                if not self.__findDuplicates(cond, special, True, index):
+                    self.__model.setWatchPointByIndex(sindex, 
+                        cond, special, (temp, enabled, count))
+                    self.__resizeColumns()
+                    self.__resort()
+
+    def __setWpEnabled(self, index, enabled):
+        """
+        Private method to set the enabled status of a watch expression.
+        
+        @param index index of watch expression to be enabled/disabled (QModelIndex)
+        @param enabled flag indicating the enabled status to be set (boolean)
+        """
+        sindex = self.__toSourceIndex(index)
+        if sindex.isValid():
+            self.__model.setWatchPointEnabledByIndex(sindex, enabled)
+        
+    def __enableWatchPoint(self):
+        """
+        Private slot to handle the enable watch expression context menu entry.
+        """
+        index = self.currentIndex()
+        self.__setWpEnabled(index, True)
+        self.__resizeColumns()
+        self.__resort()
+
+    def __enableAllWatchPoints(self):
+        """
+        Private slot to handle the enable all watch expressions context menu entry.
+        """
+        index = self.model().index(0, 0)
+        while index.isValid():
+            self.__setWpEnabled(index, True)
+            index = self.indexBelow(index)
+        self.__resizeColumns()
+        self.__resort()
+
+    def __enableSelectedWatchPoints(self):
+        """
+        Private slot to handle the enable selected watch expressions context menu entry.
+        """
+        for index in self.selectedIndexes():
+            if index.column() == 0:
+                self.__setWpEnabled(index, True)
+        self.__resizeColumns()
+        self.__resort()
+
+    def __disableWatchPoint(self):
+        """
+        Private slot to handle the disable watch expression context menu entry.
+        """
+        index = self.currentIndex()
+        self.__setWpEnabled(index, False)
+        self.__resizeColumns()
+        self.__resort()
+
+    def __disableAllWatchPoints(self):
+        """
+        Private slot to handle the disable all watch expressions context menu entry.
+        """
+        index = self.model().index(0, 0)
+        while index.isValid():
+            self.__setWpEnabled(index, False)
+            index = self.indexBelow(index)
+        self.__resizeColumns()
+        self.__resort()
+
+    def __disableSelectedWatchPoints(self):
+        """
+        Private slot to handle the disable selected watch expressions context menu entry.
+        """
+        for index in self.selectedIndexes():
+            if index.column() == 0:
+                self.__setWpEnabled(index, False)
+        self.__resizeColumns()
+        self.__resort()
+
+    def __deleteWatchPoint(self):
+        """
+        Private slot to handle the delete watch expression context menu entry.
+        """
+        index = self.currentIndex()
+        sindex = self.__toSourceIndex(index)
+        if sindex.isValid():
+            self.__model.deleteWatchPointByIndex(sindex)
+        
+    def __deleteAllWatchPoints(self):
+        """
+        Private slot to handle the delete all watch expressions context menu entry.
+        """
+        self.__model.deleteAll()
+
+    def __deleteSelectedWatchPoints(self):
+        """
+        Private slot to handle the delete selected watch expressions context menu entry.
+        """
+        idxList = []
+        for index in self.selectedIndexes():
+            sindex = self.__toSourceIndex(index)
+            if sindex.isValid() and index.column() == 0:
+                lastrow = index.row()
+                idxList.append(sindex)
+        self.__model.deleteWatchPoints(idxList)
+
+    def __showBackMenu(self):
+        """
+        Private slot to handle the aboutToShow signal of the background menu.
+        """
+        if self.model().rowCount() == 0:
+            self.backMenuActions["EnableAll"].setEnabled(False)
+            self.backMenuActions["DisableAll"].setEnabled(False)
+            self.backMenuActions["DeleteAll"].setEnabled(False)
+        else:
+            self.backMenuActions["EnableAll"].setEnabled(True)
+            self.backMenuActions["DisableAll"].setEnabled(True)
+            self.backMenuActions["DeleteAll"].setEnabled(True)
+
+    def __getSelectedItemsCount(self):
+        """
+        Private method to get the count of items selected.
+        
+        @return count of items selected (integer)
+        """
+        count = len(self.selectedIndexes()) / (self.__model.columnCount()-1)
+        # column count is 1 greater than selectable
+        return count
+    
+    def __configure(self):
+        """
+        Private method to open the configuration dialog.
+        """
+        e4App().getObject("UserInterface").showPreferences("debuggerGeneralPage")

eric ide

mercurial