コード例 #1
0
ファイル: bpointviewer.py プロジェクト: topin89/codimension
class BreakPointViewer(QWidget):
    """Implements the break point viewer for a debugger"""
    def __init__(self, parent, bpointsModel):
        QWidget.__init__(self, parent)

        self.__currentItem = None
        self.__createLayout(bpointsModel)

        GlobalData().project.sigProjectChanged.connect(self.__onProjectChanged)
        GlobalData().project.sigProjectAboutToUnload.connect(
            self.__onProjectAboutToUnload)
        self.bpointsList.sigSelectionChanged.connect(self.__onSelectionChanged)
        bpointsModel.sigBreakpoinsChanged.connect(self.__onModelChanged)

    def setFocus(self):
        """Sets the widget focus"""
        self.bpointsList.setFocus()

    def __createLayout(self, bpointsModel):
        """Creates the widget layout"""
        verticalLayout = QVBoxLayout(self)
        verticalLayout.setContentsMargins(0, 0, 0, 0)
        verticalLayout.setSpacing(0)

        self.headerFrame = QFrame()
        self.headerFrame.setObjectName('bpheader')
        self.headerFrame.setStyleSheet('QFrame#bpheader {' +
                                       getLabelStyle(self) + '}')
        self.headerFrame.setFixedHeight(HEADER_HEIGHT)

        self.__breakpointLabel = QLabel("Breakpoints")

        headerLayout = QHBoxLayout()
        headerLayout.setContentsMargins(0, 0, 0, 0)
        headerLayout.addSpacing(3)
        headerLayout.addWidget(self.__breakpointLabel)
        self.headerFrame.setLayout(headerLayout)

        self.bpointsList = BreakPointView(self, bpointsModel)

        self.__editButton = QAction(getIcon('bpprops.png'),
                                    "Edit breakpoint properties", self)
        self.__editButton.triggered.connect(self.__onEdit)
        self.__editButton.setEnabled(False)

        self.__jumpToCodeButton = QAction(getIcon('gotoline.png'),
                                          "Jump to the code", self)
        self.__jumpToCodeButton.triggered.connect(self.__onJumpToCode)
        self.__jumpToCodeButton.setEnabled(False)

        self.__enableButton = QAction(getIcon('bpenable.png'),
                                      "Enable selected breakpoint", self)
        self.__enableButton.triggered.connect(self.__onEnableDisable)
        self.__enableButton.setEnabled(False)

        self.__disableButton = QAction(getIcon('bpdisable.png'),
                                       "Disable selected breakpoint", self)
        self.__disableButton.triggered.connect(self.__onEnableDisable)
        self.__disableButton.setEnabled(False)

        self.__enableAllButton = QAction(getIcon('bpenableall.png'),
                                         "Enable all the breakpoint", self)
        self.__enableAllButton.triggered.connect(self.__onEnableAll)
        self.__enableAllButton.setEnabled(False)

        self.__disableAllButton = QAction(getIcon('bpdisableall.png'),
                                          "Disable all the breakpoint", self)
        self.__disableAllButton.triggered.connect(self.__onDisableAll)
        self.__disableAllButton.setEnabled(False)

        self.__delButton = QAction(getIcon('delitem.png'),
                                   "Delete selected breakpoint", self)
        self.__delButton.triggered.connect(self.__onDel)
        self.__delButton.setEnabled(False)

        self.__delAllButton = QAction(getIcon('bpdelall.png'),
                                      "Delete all the breakpoint", self)
        self.__delAllButton.triggered.connect(self.__onDelAll)
        self.__delAllButton.setEnabled(False)

        # Toolbar
        self.toolbar = QToolBar()
        self.toolbar.setOrientation(Qt.Horizontal)
        self.toolbar.setMovable(False)
        self.toolbar.setAllowedAreas(Qt.TopToolBarArea)
        self.toolbar.setIconSize(QSize(16, 16))
        self.toolbar.setFixedHeight(28)
        self.toolbar.setContentsMargins(0, 0, 0, 0)
        self.toolbar.addAction(self.__editButton)
        self.toolbar.addAction(self.__jumpToCodeButton)
        fixedSpacer2 = QWidget()
        fixedSpacer2.setFixedWidth(5)
        self.toolbar.addWidget(fixedSpacer2)
        self.toolbar.addAction(self.__enableButton)
        self.toolbar.addAction(self.__enableAllButton)
        fixedSpacer3 = QWidget()
        fixedSpacer3.setFixedWidth(5)
        self.toolbar.addWidget(fixedSpacer3)
        self.toolbar.addAction(self.__disableButton)
        self.toolbar.addAction(self.__disableAllButton)
        expandingSpacer = QWidget()
        expandingSpacer.setSizePolicy(QSizePolicy.Expanding,
                                      QSizePolicy.Expanding)
        fixedSpacer4 = QWidget()
        fixedSpacer4.setFixedWidth(5)
        self.toolbar.addWidget(fixedSpacer4)
        self.toolbar.addWidget(expandingSpacer)
        self.toolbar.addAction(self.__delButton)
        fixedSpacer5 = QWidget()
        fixedSpacer5.setFixedWidth(5)
        self.toolbar.addWidget(fixedSpacer5)
        self.toolbar.addAction(self.__delAllButton)

        verticalLayout.addWidget(self.headerFrame)
        verticalLayout.addWidget(self.toolbar)
        verticalLayout.addWidget(self.bpointsList)

    def clear(self):
        """Clears the content"""
        self.__onDelAll()
        self.__updateBreakpointsLabel()
        self.__currentItem = None

    def __updateBreakpointsLabel(self):
        """Updates the breakpoints header label"""
        enableCount, \
        disableCount = self.bpointsList.model().sourceModel().getCounts()
        total = enableCount + disableCount
        if total > 0:
            self.__breakpointLabel.setText("Breakpoints (total: " +
                                           str(total) + ")")
        else:
            self.__breakpointLabel.setText("Breakpoints")

    def __onProjectChanged(self, what):
        """Triggered when a project is changed"""
        if what != CodimensionProject.CompleteProject:
            return

        self.clear()
        model = self.bpointsList.model().sourceModel()
        project = GlobalData().project
        if project.isLoaded():
            bpoints = project.breakpoints
        else:
            bpoints = Settings().breakpoints

        for bpoint in bpoints:
            newBpoint = Breakpoint()
            try:
                if not newBpoint.deserialize(bpoint):
                    # Non valid
                    continue
            except:
                continue
            # Need to check if it still points to a breakable line
            line = newBpoint.getLineNumber()
            fileName = newBpoint.getAbsoluteFileName()
            breakableLines = getBreakpointLines(fileName, None, True)
            if breakableLines is not None and line in breakableLines:
                model.addBreakpoint(newBpoint)
            else:
                logging.warning("Breakpoint at " + fileName + ":" + str(line) +
                                " does not point to a breakable "
                                "line anymore (the file is invalid or was "
                                "modified outside of the "
                                "IDE etc.). The breakpoint is deleted.")

    def __onProjectAboutToUnload(self):
        """Triggered before the project is unloaded"""
        self.__serializeBreakpoints()

    def __serializeBreakpoints(self):
        """Saves the breakpoints into a file"""
        model = self.bpointsList.model().sourceModel()

        project = GlobalData().project
        if project.isLoaded():
            project.breakpoints = model.serialize()
        else:
            Settings().breakpoints = model.serialize()

    def __onSelectionChanged(self, index):
        """Triggered when the current item is changed"""
        if index.isValid():
            srcModel = self.bpointsList.model().sourceModel()
            sindex = self.bpointsList.toSourceIndex(index)
            self.__currentItem = srcModel.getBreakPointByIndex(sindex)
        else:
            self.__currentItem = None
        self.__updateButtons()

    def __updateButtons(self):
        """Updates the buttons status"""
        enableCount, \
        disableCount = self.bpointsList.model().sourceModel().getCounts()

        if self.__currentItem is None:
            self.__editButton.setEnabled(False)
            self.__enableButton.setEnabled(False)
            self.__disableButton.setEnabled(False)
            self.__jumpToCodeButton.setEnabled(False)
            self.__delButton.setEnabled(False)
        else:
            self.__editButton.setEnabled(True)
            self.__enableButton.setEnabled(not self.__currentItem.isEnabled())
            self.__disableButton.setEnabled(self.__currentItem.isEnabled())
            self.__jumpToCodeButton.setEnabled(True)
            self.__delButton.setEnabled(True)

        self.__enableAllButton.setEnabled(disableCount > 0)
        self.__disableAllButton.setEnabled(enableCount > 0)
        self.__delAllButton.setEnabled(enableCount + disableCount > 0)

    def __onEnableDisable(self):
        """Triggered when a breakpoint should be enabled/disabled"""
        if self.__currentItem is not None:
            if self.__currentItem.isEnabled():
                self.bpointsList.disableBreak()
            else:
                self.bpointsList.enableBreak()

    def __onEdit(self):
        """Triggered when a breakpoint should be edited"""
        if self.__currentItem is None:
            return

        dlg = BreakpointEditDialog(self.__currentItem)
        if dlg.exec_() == QDialog.Accepted:
            newBpoint = dlg.getData()
            if newBpoint == self.__currentItem:
                return
            model = self.bpointsList.model().sourceModel()
            index = model.getBreakPointIndex(
                self.__currentItem.getAbsoluteFileName(),
                self.__currentItem.getLineNumber())
            model.setBreakPointByIndex(index, newBpoint)
            self.bpointsList.layoutDisplay()

    def __onJumpToCode(self):
        """Triggered when should jump to source"""
        if self.__currentItem is None:
            return
        self.bpointsList.jumpToCode(self.__currentItem.getAbsoluteFileName(),
                                    self.__currentItem.getLineNumber())

    def __onEnableAll(self):
        """Triggered when all the breakpoints should be enabled"""
        self.bpointsList.enableAllBreaks()

    def __onDisableAll(self):
        """Triggered when all the breakpoints should be disabled"""
        self.bpointsList.disableAllBreaks()

    def __onDel(self):
        """Triggered when a breakpoint should be deleted"""
        if self.__currentItem is not None:
            self.bpointsList.deleteBreak()

    def __onDelAll(self):
        """Triggered when all the breakpoints should be deleted"""
        self.bpointsList.deleteAllBreaks()

    def __onModelChanged(self):
        """Triggered when something has changed in any of the breakpoints"""
        self.__updateBreakpointsLabel()
        self.__updateButtons()
        self.bpointsList.layoutDisplay()

        self.__serializeBreakpoints()
コード例 #2
0
class CallTraceViewer(QWidget):
    """Implements the call trace viewer"""
    def __init__(self, debugger, parent=None):
        QWidget.__init__(self, parent)

        self.__debugger = debugger
        self.__createLayout()

        self.__debugger.sigClientCallTrace.connect(self.__onCallTrace)
        GlobalData().project.sigProjectChanged.connect(self.__onProjectChanged)

    def __onProjectChanged(self, what):
        """Triggered when a project is changed"""
        if what == CodimensionProject.CompleteProject:
            self.clear()
            self.calltraceList.onProjectChanged()

    def __createLayout(self):
        """Creates the widget layout"""
        verticalLayout = QVBoxLayout(self)
        verticalLayout.setContentsMargins(0, 0, 0, 0)
        verticalLayout.setSpacing(0)

        self.__calltraceLabel = QLabel("Call Trace", self)

        self.headerFrame = QFrame()
        self.headerFrame.setObjectName('calltraceheader')
        self.headerFrame.setStyleSheet('QFrame#calltraceheader {' +
                                       getLabelStyle(self.__calltraceLabel) +
                                       '}')
        self.headerFrame.setFixedHeight(HEADER_HEIGHT)

        headerLayout = QHBoxLayout()
        headerLayout.setContentsMargins(0, 0, 0, 0)
        headerLayout.addSpacing(3)
        headerLayout.addWidget(self.__calltraceLabel)
        self.headerFrame.setLayout(headerLayout)

        self.calltraceList = CallTraceBrowser(self)

        self.__startButton = QAction(getIcon('calltracestart.png'),
                                     "Start call tracing", self)
        self.__startButton.triggered.connect(self.__onStart)
        self.__startButton.setEnabled(not Settings()['calltrace'])

        self.__stopButton = QAction(getIcon('calltracestop.png'),
                                    "Stop call tracing", self)
        self.__stopButton.triggered.connect(self.__onStop)
        self.__stopButton.setEnabled(Settings()['calltrace'])

        self.__resizeButton = QAction(getIcon('resizecolumns.png'),
                                      "Resize the columns to their contents",
                                      self)
        self.__resizeButton.triggered.connect(self.__onResize)
        self.__resizeButton.setEnabled(True)

        self.__clearButton = QAction(getIcon('trash.png'), "Clear", self)
        self.__clearButton.triggered.connect(self.__onClear)
        self.__clearButton.setEnabled(False)

        self.__copyButton = QAction(getIcon('copymenu.png'),
                                    "Copy to clipboard", self)
        self.__copyButton.triggered.connect(self.__onCopy)
        self.__copyButton.setEnabled(False)

        # Toolbar
        self.toolbar = QToolBar()
        self.toolbar.setOrientation(Qt.Horizontal)
        self.toolbar.setMovable(False)
        self.toolbar.setAllowedAreas(Qt.TopToolBarArea)
        self.toolbar.setIconSize(QSize(16, 16))
        self.toolbar.setFixedHeight(28)
        self.toolbar.setContentsMargins(0, 0, 0, 0)
        self.toolbar.addAction(self.__startButton)
        self.toolbar.addAction(self.__stopButton)

        fixedSpacer2 = QWidget()
        fixedSpacer2.setFixedWidth(15)
        self.toolbar.addWidget(fixedSpacer2)
        self.toolbar.addAction(self.__resizeButton)
        self.toolbar.addAction(self.__copyButton)
        expandingSpacer = QWidget()
        expandingSpacer.setSizePolicy(QSizePolicy.Expanding,
                                      QSizePolicy.Expanding)
        fixedSpacer4 = QWidget()
        fixedSpacer4.setFixedWidth(5)
        self.toolbar.addWidget(fixedSpacer4)
        self.toolbar.addWidget(expandingSpacer)
        self.toolbar.addAction(self.__clearButton)

        verticalLayout.addWidget(self.headerFrame)
        verticalLayout.addWidget(self.toolbar)
        verticalLayout.addWidget(self.calltraceList)

    def __onCallTrace(self, isCall, fromFile, fromLine, fromFunction, toFile,
                      toLine, toFunction):
        """Call trace message received"""
        self.calltraceList.addCallTrace(isCall, fromFile, fromLine,
                                        fromFunction, toFile, toLine,
                                        toFunction)
        self.__clearButton.setEnabled(True)
        self.__copyButton.setEnabled(True)
        self.__updateHeader()

    def __updateHeader(self):
        """Updates the header"""
        count = self.calltraceList.count
        if count:
            self.__calltraceLabel.setText('Call Trace (' + str(count) + ')')
        else:
            self.__calltraceLabel.setText('Call Trace')

    def __onStart(self):
        """Start collecting calltrace"""
        self.__startButton.setEnabled(False)
        self.__stopButton.setEnabled(True)
        Settings()['calltrace'] = True
        self.__debugger.startCalltrace()

    def __onStop(self):
        """Stop collecting calltrace"""
        self.__startButton.setEnabled(True)
        self.__stopButton.setEnabled(False)
        Settings()['calltrace'] = False
        self.__debugger.stopCalltrace()

    def __onResize(self):
        """Resize the columns to its width"""
        for column in range(self.calltraceList.columnCount()):
            self.calltraceList.resizeColumnToContents(column)

    def __onClear(self):
        """Clears the view"""
        self.calltraceList.clear()
        self.__clearButton.setEnabled(False)
        self.__copyButton.setEnabled(False)
        self.__updateHeader()

    def clear(self):
        """Clears the view"""
        self.__onClear()

    def __onCopy(self):
        """Copy the content as text to clipboard"""
        content = []
        lhsMaxLength = 0
        try:
            item = self.calltraceList.topLevelItem(0)
            while item is not None:
                call = '<-'
                if item.data(0, Qt.UserRole):
                    call = '->'
                lhs = item.text(1)
                lhsLength = len(lhs)
                lhsMaxLength = max(lhsMaxLength, lhsLength)

                content.append([lhs, lhsLength, call + ' ' + item.text(2)])
                item = self.calltraceList.itemBelow(item)

            for index in range(len(content)):
                content[index] = \
                    content[index][0] + \
                    ' ' * (lhsMaxLength - content[index][1] + 1) + \
                    content[index][2]

            QApplication.clipboard().setText('\n'.join(content))
        except Exception as exc:
            logging.error('Error copying the call trace to clipboard: ' +
                          str(exc))
コード例 #3
0
class ClientExceptionsViewer(QWidget):

    """Implements the client exceptions viewer for a debugger"""

    sigClientExceptionsCleared = pyqtSignal()

    def __init__(self, parent, ignoredExceptionsViewer):
        QWidget.__init__(self, parent)

        self.__ignoredExceptionsViewer = ignoredExceptionsViewer
        self.__currentItem = None

        self.__createPopupMenu()
        self.__createLayout()

        GlobalData().project.sigProjectChanged.connect(self.__onProjectChanged)

    def setFocus(self):
        """Sets the widget focus"""
        self.exceptionsList.setFocus()

    def __createPopupMenu(self):
        """Creates the popup menu"""
        self.__excptMenu = QMenu()
        self.__addToIgnoreMenuItem = self.__excptMenu.addAction(
            "Add to ignore list", self.__onAddToIgnore)
        self.__jumpToCodeMenuItem = self.__excptMenu.addAction(
            "Jump to code", self.__onJumpToCode)

    def __createLayout(self):
        """Creates the widget layout"""
        verticalLayout = QVBoxLayout(self)
        verticalLayout.setContentsMargins(0, 0, 0, 0)
        verticalLayout.setSpacing(0)

        self.__excptLabel = QLabel("Exceptions", self)

        self.headerFrame = QFrame()
        self.headerFrame.setObjectName('excpt')
        self.headerFrame.setStyleSheet('QFrame#excpt {' +
                                       getLabelStyle(self.__excptLabel) + '}')
        self.headerFrame.setFixedHeight(HEADER_HEIGHT)

        headerLayout = QHBoxLayout()
        headerLayout.setContentsMargins(0, 0, 0, 0)
        headerLayout.addSpacing(3)
        headerLayout.addWidget(self.__excptLabel)
        self.headerFrame.setLayout(headerLayout)

        self.exceptionsList = QTreeWidget(self)
        self.exceptionsList.setSortingEnabled(False)
        self.exceptionsList.setAlternatingRowColors(True)
        self.exceptionsList.setRootIsDecorated(True)
        self.exceptionsList.setItemsExpandable(True)
        self.exceptionsList.setUniformRowHeights(True)
        self.exceptionsList.setSelectionMode(QAbstractItemView.SingleSelection)
        self.exceptionsList.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.exceptionsList.setItemDelegate(NoOutlineHeightDelegate(4))
        self.exceptionsList.setContextMenuPolicy(Qt.CustomContextMenu)

        self.__addToIgnoreButton = QAction(
            getIcon('add.png'), "Add exception to the list of ignored", self)
        self.__addToIgnoreButton.triggered.connect(self.__onAddToIgnore)
        self.__addToIgnoreButton.setEnabled(False)

        expandingSpacer = QWidget()
        expandingSpacer.setSizePolicy(QSizePolicy.Expanding,
                                      QSizePolicy.Expanding)

        self.__jumpToCodeButton = QAction(
            getIcon('gotoline.png'), "Jump to the code", self)
        self.__jumpToCodeButton.triggered.connect(self.__onJumpToCode)
        self.__jumpToCodeButton.setEnabled(False)

        self.__delAllButton = QAction(
            getIcon('trash.png'), "Delete all the client exceptions", self)
        self.__delAllButton.triggered.connect(self.__onDelAll)
        self.__delAllButton.setEnabled(False)

        self.toolbar = QToolBar()
        self.toolbar.setOrientation(Qt.Horizontal)
        self.toolbar.setMovable(False)
        self.toolbar.setAllowedAreas(Qt.TopToolBarArea)
        self.toolbar.setIconSize(QSize(16, 16))
        self.toolbar.setFixedHeight(28)
        self.toolbar.setContentsMargins(0, 0, 0, 0)
        self.toolbar.addAction(self.__addToIgnoreButton)
        self.toolbar.addAction(self.__jumpToCodeButton)
        self.toolbar.addWidget(expandingSpacer)
        self.toolbar.addAction(self.__delAllButton)

        self.exceptionsList.itemDoubleClicked.connect(
            self.__onExceptionDoubleClicked)
        self.exceptionsList.customContextMenuRequested.connect(
            self.__showContextMenu)
        self.exceptionsList.itemSelectionChanged.connect(
            self.__onSelectionChanged)

        self.exceptionsList.setHeaderLabels(["Exception",
                                             "Function", "Arguments"])

        verticalLayout.addWidget(self.headerFrame)
        verticalLayout.addWidget(self.toolbar)
        verticalLayout.addWidget(self.exceptionsList)

    def clear(self):
        """Clears the content"""
        self.exceptionsList.clear()
        self.__updateExceptionsLabel()
        self.__addToIgnoreButton.setEnabled(False)
        self.__jumpToCodeButton.setEnabled(False)
        self.__delAllButton.setEnabled(False)
        self.__currentItem = None
        self.sigClientExceptionsCleared.emit()

    def __onExceptionDoubleClicked(self, item, column):
        """Triggered when an exception is double clicked"""
        del item    # unused argument
        del column  # unused argument
        if self.__currentItem is not None:
            if self.__currentItem.getType() == STACK_FRAME_ITEM:
                self.__onJumpToCode()
                return

            # This is an exception item itself.
            # Open a separate dialog window with th detailed info.

    def __showContextMenu(self, coord):
        """Shows the frames list context menu"""
        self.__currentItem = self.exceptionsList.itemAt(coord)

        self.__addToIgnoreMenuItem.setEnabled(
            self.__addToIgnoreButton.isEnabled())
        self.__jumpToCodeMenuItem.setEnabled(
            self.__jumpToCodeButton.isEnabled())

        if self.__currentItem is not None:
            self.__excptMenu.popup(QCursor.pos())

    def __onAddToIgnore(self):
        """Adds an exception into the ignore list"""
        if self.__currentItem is not None:
            self.__ignoredExceptionsViewer.addExceptionFilter(
                str(self.__currentItem.getExceptionType()))
            self.__addToIgnoreButton.setEnabled(False)

    def __onJumpToCode(self):
        """Jumps to the corresponding source code line"""
        if self.__currentItem is not None:
            if self.__currentItem.getType() == STACK_FRAME_ITEM:
                fileName = self.__currentItem.getFileName()
                if '<' not in fileName and '>' not in fileName:
                    lineNumber = self.__currentItem.getLineNumber()

                    editorsManager = GlobalData().mainWindow.editorsManager()
                    editorsManager.openFile(fileName, lineNumber)
                    editor = editorsManager.currentWidget().getEditor()
                    editor.gotoLine(lineNumber)
                    editorsManager.currentWidget().setFocus()

    def __onDelAll(self):
        """Triggered when all the exceptions should be deleted"""
        self.clear()

    def addException(self, exceptionType, exceptionMessage, stackTrace):
        """Adds the exception to the view"""
        for index in range(self.exceptionsList.topLevelItemCount()):
            item = self.exceptionsList.topLevelItem(index)
            if item.equal(exceptionType, exceptionMessage, stackTrace):
                item.incrementCounter()
                self.exceptionsList.clearSelection()
                self.exceptionsList.setCurrentItem(item)
                self.__updateExceptionsLabel()
                return

        item = ExceptionItem(self.exceptionsList, exceptionType,
                             exceptionMessage, stackTrace)
        self.exceptionsList.clearSelection()
        self.exceptionsList.setCurrentItem(item)
        self.__updateExceptionsLabel()
        self.__delAllButton.setEnabled(True)

    def __updateExceptionsLabel(self):
        """Updates the exceptions header label"""
        total = self.getTotalCount()
        if total > 0:
            self.__excptLabel.setText("Exceptions (total: " + str(total) + ")")
        else:
            self.__excptLabel.setText("Exceptions")

    def getTotalCount(self):
        """Provides the total number of exceptions"""
        count = 0
        for index in range(self.exceptionsList.topLevelItemCount()):
            count += self.exceptionsList.topLevelItem(index).getCount()
        return count

    def __onProjectChanged(self, what):
        """Triggered when a project is changed"""
        if what == CodimensionProject.CompleteProject:
            self.clear()

    def __onSelectionChanged(self):
        """Triggered when the current item is changed"""
        selected = list(self.exceptionsList.selectedItems())
        if selected:
            self.__currentItem = selected[0]
            if self.__currentItem.getType() == STACK_FRAME_ITEM:
                fileName = self.__currentItem.getFileName()
                if '<' in fileName or '>' in fileName:
                    self.__jumpToCodeButton.setEnabled(False)
                else:
                    self.__jumpToCodeButton.setEnabled(True)
                self.__addToIgnoreButton.setEnabled(False)
            else:
                self.__jumpToCodeButton.setEnabled(False)
                excType = str(self.__currentItem.getExceptionType())
                if self.__ignoredExceptionsViewer.isIgnored(excType) or \
                   " " in excType or excType.startswith("unhandled"):
                    self.__addToIgnoreButton.setEnabled(False)
                else:
                    self.__addToIgnoreButton.setEnabled(True)
        else:
            self.__currentItem = None
            self.__addToIgnoreButton.setEnabled(False)
            self.__jumpToCodeButton.setEnabled(False)
コード例 #4
0
class IgnoredExceptionsViewer(QWidget):
    """Implements the client exceptions viewer for a debugger"""
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        self.__createPopupMenu()
        self.__createLayout()
        self.__ignored = []
        self.__currentItem = None

        GlobalData().project.sigProjectChanged.connect(self.__onProjectChanged)

        if not Settings()['showIgnoredExcViewer']:
            self.__onShowHide(True)

    def __createPopupMenu(self):
        """Creates the popup menu"""
        self.__excptMenu = QMenu()
        self.__removeMenuItem = self.__excptMenu.addAction(
            getIcon('ignexcptdel.png'), "Remove from ignore list",
            self.__onRemoveFromIgnore)

    def __createLayout(self):
        """Creates the widget layout"""
        verticalLayout = QVBoxLayout(self)
        verticalLayout.setContentsMargins(0, 0, 0, 0)
        verticalLayout.setSpacing(0)

        self.__excptLabel = QLabel("Ignored exception types", self)

        self.headerFrame = QFrame()
        self.headerFrame.setObjectName('ignexcpt')
        self.headerFrame.setStyleSheet('QFrame#ignexcpt {' +
                                       getLabelStyle(self.__excptLabel) + '}')
        self.headerFrame.setFixedHeight(HEADER_HEIGHT)

        expandingSpacer = QSpacerItem(10, 10, QSizePolicy.Expanding)

        self.__showHideButton = QToolButton()
        self.__showHideButton.setAutoRaise(True)
        self.__showHideButton.setIcon(getIcon('less.png'))
        self.__showHideButton.setFixedSize(HEADER_BUTTON, HEADER_BUTTON)
        self.__showHideButton.setToolTip("Hide ignored exceptions list")
        self.__showHideButton.setFocusPolicy(Qt.NoFocus)
        self.__showHideButton.clicked.connect(self.__onShowHide)

        headerLayout = QHBoxLayout()
        headerLayout.setContentsMargins(0, 0, 0, 0)
        headerLayout.addSpacing(3)
        headerLayout.addWidget(self.__excptLabel)
        headerLayout.addSpacerItem(expandingSpacer)
        headerLayout.addWidget(self.__showHideButton)
        self.headerFrame.setLayout(headerLayout)

        self.exceptionsList = QTreeWidget(self)
        self.exceptionsList.setSortingEnabled(False)
        self.exceptionsList.setAlternatingRowColors(True)
        self.exceptionsList.setRootIsDecorated(False)
        self.exceptionsList.setItemsExpandable(True)
        self.exceptionsList.setUniformRowHeights(True)
        self.exceptionsList.setSelectionMode(QAbstractItemView.SingleSelection)
        self.exceptionsList.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.exceptionsList.setItemDelegate(NoOutlineHeightDelegate(4))
        self.exceptionsList.setContextMenuPolicy(Qt.CustomContextMenu)

        self.exceptionsList.customContextMenuRequested.connect(
            self.__showContextMenu)
        self.exceptionsList.itemSelectionChanged.connect(
            self.__onSelectionChanged)
        self.exceptionsList.setHeaderLabels(["Exception type"])

        self.__excTypeEdit = QLineEdit()
        self.__excTypeEdit.setFixedHeight(26)
        self.__excTypeEdit.textChanged.connect(self.__onNewFilterChanged)
        self.__excTypeEdit.returnPressed.connect(self.__onAddExceptionFilter)
        self.__addButton = QPushButton("Add")
        # self.__addButton.setFocusPolicy(Qt.NoFocus)
        self.__addButton.setEnabled(False)
        self.__addButton.clicked.connect(self.__onAddExceptionFilter)

        expandingSpacer2 = QWidget()
        expandingSpacer2.setSizePolicy(QSizePolicy.Expanding,
                                       QSizePolicy.Expanding)

        self.__removeButton = QAction(getIcon('delitem.png'),
                                      "Remove selected exception type", self)
        self.__removeButton.triggered.connect(self.__onRemoveFromIgnore)
        self.__removeButton.setEnabled(False)

        fixedSpacer1 = QWidget()
        fixedSpacer1.setFixedWidth(5)

        self.__removeAllButton = QAction(getIcon('ignexcptdelall.png'),
                                         "Remove all the exception types",
                                         self)
        self.__removeAllButton.triggered.connect(self.__onRemoveAllFromIgnore)
        self.__removeAllButton.setEnabled(False)

        self.toolbar = QToolBar()
        self.toolbar.setOrientation(Qt.Horizontal)
        self.toolbar.setMovable(False)
        self.toolbar.setAllowedAreas(Qt.TopToolBarArea)
        self.toolbar.setIconSize(QSize(16, 16))
        self.toolbar.setFixedHeight(28)
        self.toolbar.setContentsMargins(0, 0, 0, 0)
        self.toolbar.addWidget(expandingSpacer2)
        self.toolbar.addAction(self.__removeButton)
        self.toolbar.addWidget(fixedSpacer1)
        self.toolbar.addAction(self.__removeAllButton)

        addLayout = QHBoxLayout()
        addLayout.setContentsMargins(1, 1, 1, 1)
        addLayout.setSpacing(1)
        addLayout.addWidget(self.__excTypeEdit)
        addLayout.addWidget(self.__addButton)

        verticalLayout.addWidget(self.headerFrame)
        verticalLayout.addWidget(self.toolbar)
        verticalLayout.addWidget(self.exceptionsList)
        verticalLayout.addLayout(addLayout)

    def clear(self):
        """Clears the content"""
        self.exceptionsList.clear()
        self.__excTypeEdit.clear()
        self.__addButton.setEnabled(False)
        self.__ignored = []
        self.__currentItem = None
        self.__updateTitle()

    def __onShowHide(self, startup=False):
        """Triggered when show/hide button is clicked"""
        if startup or self.exceptionsList.isVisible():
            self.exceptionsList.setVisible(False)
            self.__excTypeEdit.setVisible(False)
            self.__addButton.setVisible(False)
            self.__removeButton.setVisible(False)
            self.__removeAllButton.setVisible(False)
            self.__showHideButton.setIcon(getIcon('more.png'))
            self.__showHideButton.setToolTip("Show ignored exceptions list")

            self.__minH = self.minimumHeight()
            self.__maxH = self.maximumHeight()

            self.setMinimumHeight(self.headerFrame.height())
            self.setMaximumHeight(self.headerFrame.height())

            Settings()['showIgnoredExcViewer'] = False
        else:
            self.exceptionsList.setVisible(True)
            self.__excTypeEdit.setVisible(True)
            self.__addButton.setVisible(True)
            self.__removeButton.setVisible(True)
            self.__removeAllButton.setVisible(True)
            self.__showHideButton.setIcon(getIcon('less.png'))
            self.__showHideButton.setToolTip("Hide ignored exceptions list")

            self.setMinimumHeight(self.__minH)
            self.setMaximumHeight(self.__maxH)

            Settings()['showIgnoredExcViewer'] = True

    def __onSelectionChanged(self):
        """Triggered when the current item is changed"""
        selected = list(self.exceptionsList.selectedItems())
        if selected:
            self.__currentItem = selected[0]
            self.__removeButton.setEnabled(True)
        else:
            self.__currentItem = None
            self.__removeButton.setEnabled(False)

    def __showContextMenu(self, coord):
        """Shows the frames list context menu"""
        contextItem = self.exceptionsList.itemAt(coord)
        if contextItem is not None:
            self.__currentItem = contextItem
            self.__excptMenu.popup(QCursor.pos())

    def __updateTitle(self):
        """Updates the section title"""
        count = self.exceptionsList.topLevelItemCount()
        if count == 0:
            self.__excptLabel.setText("Ignored exception types")
        else:
            self.__excptLabel.setText("Ignored exception types (total: " +
                                      str(count) + ")")
        self.__removeAllButton.setEnabled(count != 0)

    def __onProjectChanged(self, what):
        """Triggered when a project is changed"""
        if what != CodimensionProject.CompleteProject:
            return

        self.clear()
        project = GlobalData().project
        if project.isLoaded():
            self.__ignored = list(project.exceptionFilters)
        else:
            self.__ignored = Settings()['ignoredExceptions']

        for exceptionType in self.__ignored:
            item = QTreeWidgetItem(self.exceptionsList)
            item.setText(0, exceptionType)
        self.__updateTitle()

    def __onNewFilterChanged(self, text):
        """Triggered when the text is changed"""
        text = str(text).strip()
        if text == "":
            self.__addButton.setEnabled(False)
            return
        if " " in text:
            self.__addButton.setEnabled(False)
            return

        if text in self.__ignored:
            self.__addButton.setEnabled(False)
            return

        self.__addButton.setEnabled(True)

    def __onAddExceptionFilter(self):
        """Adds an item into the ignored exceptions list"""
        text = self.__excTypeEdit.text().strip()
        self.addExceptionFilter(text)

    def addExceptionFilter(self, excType):
        """Adds a new item into the ignored exceptions list"""
        if excType == "":
            return
        if " " in excType:
            return
        if excType in self.__ignored:
            return

        item = QTreeWidgetItem(self.exceptionsList)
        item.setText(0, excType)

        project = GlobalData().project
        if project.isLoaded():
            project.addExceptionFilter(excType)
        else:
            Settings().addExceptionFilter(excType)
        self.__ignored.append(excType)
        self.__updateTitle()

    def __onRemoveFromIgnore(self):
        """Removes an item from the ignored exception types list"""
        if self.__currentItem is None:
            return

        text = self.__currentItem.text(0)

        # Find the item index and remove it
        index = 0
        while True:
            if self.exceptionsList.topLevelItem(index).text(0) == text:
                self.exceptionsList.takeTopLevelItem(index)
                break
            index += 1

        project = GlobalData().project
        if project.isLoaded():
            project.deleteExceptionFilter(text)
        else:
            Settings().deleteExceptionFilter(text)
        self.__ignored.remove(text)
        self.__updateTitle()

    def __onRemoveAllFromIgnore(self):
        """Triggered when all the ignored exceptions should be deleted"""
        self.clear()

        project = GlobalData().project
        if project.isLoaded():
            project.setExceptionFilters([])
        else:
            Settings().setExceptionFilters([])

    def isIgnored(self, exceptionType):
        """Returns True if this exception type should be ignored"""
        return exceptionType in self.__ignored