Exemple #1
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.projectChanged.connect(self.__onProjectChanged)

        if Settings().showIgnoredExcViewer == False:
            self.__onShowHide(True)
        return

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

    def __createLayout(self):
        " Creates the widget layout "

        verticalLayout = QVBoxLayout(self)
        verticalLayout.setContentsMargins(0, 0, 0, 0)
        verticalLayout.setSpacing(0)

        self.headerFrame = QFrame()
        self.headerFrame.setFrameStyle(QFrame.StyledPanel)
        self.headerFrame.setAutoFillBackground(True)
        headerPalette = self.headerFrame.palette()
        headerBackground = headerPalette.color(QPalette.Background)
        headerBackground.setRgb(min(headerBackground.red() + 30, 255),
                                min(headerBackground.green() + 30, 255),
                                min(headerBackground.blue() + 30, 255))
        headerPalette.setColor(QPalette.Background, headerBackground)
        self.headerFrame.setPalette(headerPalette)
        self.headerFrame.setFixedHeight(24)

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

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

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

        headerLayout = QHBoxLayout()
        headerLayout.setContentsMargins(1, 1, 1, 1)
        headerLayout.addSpacerItem(fixedSpacer)
        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(PixmapCache().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(
            PixmapCache().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)
        return

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

    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(PixmapCache().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(PixmapCache().getIcon('less.png'))
            self.__showHideButton.setToolTip("Hide ignored exceptions list")

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

            Settings().showIgnoredExcViewer = True
        return

    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)
        return

    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())
        return

    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)
        return

    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.ignoredExcpt)
        else:
            self.__ignored = list(Settings().ignoredExceptions)

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

    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)
        return

    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()
        return

    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()
        return

    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([])
        return

    def isIgnored(self, exceptionType):
        " Returns True if this exception type should be ignored "
        return exceptionType in self.__ignored
    def __createRecentFilesLayout( self ):
        " Creates the upper part - recent files "
        headerFrame = QFrame()
        headerFrame.setFrameStyle( QFrame.StyledPanel )
        headerFrame.setAutoFillBackground( True )
        headerPalette = headerFrame.palette()
        headerBackground = headerPalette.color( QPalette.Background )
        headerBackground.setRgb( min( headerBackground.red() + 30, 255 ),
                                 min( headerBackground.green() + 30, 255 ),
                                 min( headerBackground.blue() + 30, 255 ) )
        headerPalette.setColor( QPalette.Background, headerBackground )
        headerFrame.setPalette( headerPalette )
        headerFrame.setFixedHeight( 24 )

        recentFilesLabel = QLabel()
        recentFilesLabel.setText( "Recent files" )

        headerLayout = QHBoxLayout()
        headerLayout.setContentsMargins( 3, 0, 0, 0 )
        headerLayout.addWidget( recentFilesLabel )
        headerFrame.setLayout( headerLayout )

        self.recentFilesView = QTreeWidget()
        self.recentFilesView.setAlternatingRowColors( True )
        self.recentFilesView.setRootIsDecorated( False )
        self.recentFilesView.setItemsExpandable( False )
        self.recentFilesView.setSortingEnabled( True )
        self.recentFilesView.setItemDelegate( NoOutlineHeightDelegate( 4 ) )
        self.recentFilesView.setUniformRowHeights( True )

        self.__filesHeaderItem = QTreeWidgetItem( [ "", "File",
                                                    "Absolute path" ] )
        self.recentFilesView.setHeaderItem( self.__filesHeaderItem )
        self.recentFilesView.header().setSortIndicator( 1, Qt.AscendingOrder )

        self.connect( self.recentFilesView,
                      SIGNAL( "itemSelectionChanged()" ),
                      self.__fileSelectionChanged )
        self.connect( self.recentFilesView,
                      SIGNAL( "itemActivated(QTreeWidgetItem *, int)" ),
                      self.__fileActivated )

        # Toolbar part - buttons
        self.openFileButton = QAction( PixmapCache().getIcon( 'openitem.png' ),
                                       'Open the highlighted file', self )
        self.connect( self.openFileButton, SIGNAL( "triggered()" ),
                      self.__openFile )
        self.copyFilePathButton = QAction( \
                        PixmapCache().getIcon( 'copytoclipboard.png' ),
                        'Copy path to clipboard', self )
        self.connect( self.copyFilePathButton, SIGNAL( "triggered()" ),
                      self.__filePathToClipboard )
        spacer = QWidget()
        spacer.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Expanding )
        self.trashFileButton = QAction( PixmapCache().getIcon( 'delitem.png' ),
                                        'Remove selected (not from the disk)',
                                        self )
        self.connect( self.trashFileButton, SIGNAL( "triggered()" ),
                      self.__deleteFile )

        self.upperToolbar = QToolBar()
        self.upperToolbar.setMovable( False )
        self.upperToolbar.setAllowedAreas( Qt.TopToolBarArea )
        self.upperToolbar.setIconSize( QSize( 16, 16 ) )
        self.upperToolbar.setFixedHeight( 28 )
        self.upperToolbar.setContentsMargins( 0, 0, 0, 0 )
        self.upperToolbar.addAction( self.openFileButton )
        self.upperToolbar.addAction( self.copyFilePathButton )
        self.upperToolbar.addWidget( spacer )
        self.upperToolbar.addAction( self.trashFileButton )

        recentFilesLayout = QVBoxLayout()
        recentFilesLayout.setContentsMargins( 0, 0, 0, 0 )
        recentFilesLayout.setSpacing( 0 )
        recentFilesLayout.addWidget( headerFrame )
        recentFilesLayout.addWidget( self.upperToolbar )
        recentFilesLayout.addWidget( self.recentFilesView )

        upperContainer = QWidget()
        upperContainer.setContentsMargins( 0, 0, 0, 0 )
        upperContainer.setLayout( recentFilesLayout )
        return upperContainer
Exemple #3
0
class WatchPointViewer(QWidget):
    " Implements the watch point viewer for a debugger "

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

        self.__currentItem = None

        self.__createPopupMenu()
        self.__createLayout(wpointModel)

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

        if Settings().showWatchPointViewer == False:
            self.__onShowHide(True)
        return

    def __createPopupMenu(self):
        " Creates the popup menu "
        #        self.__excptMenu = QMenu()
        #        self.__removeMenuItem = self.__excptMenu.addAction(
        #                    "Remove from ignore list", self.__onRemoveFromIgnore )
        return

    def __createLayout(self, wpointModel):
        " Creates the widget layout "

        verticalLayout = QVBoxLayout(self)
        verticalLayout.setContentsMargins(0, 0, 0, 0)
        verticalLayout.setSpacing(0)

        self.headerFrame = QFrame()
        self.headerFrame.setFrameStyle(QFrame.StyledPanel)
        self.headerFrame.setAutoFillBackground(True)
        headerPalette = self.headerFrame.palette()
        headerBackground = headerPalette.color(QPalette.Background)
        headerBackground.setRgb(min(headerBackground.red() + 30, 255),
                                min(headerBackground.green() + 30, 255),
                                min(headerBackground.blue() + 30, 255))
        headerPalette.setColor(QPalette.Background, headerBackground)
        self.headerFrame.setPalette(headerPalette)
        self.headerFrame.setFixedHeight(24)

        self.__watchpointLabel = QLabel("Watchpoints")

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

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

        headerLayout = QHBoxLayout()
        headerLayout.setContentsMargins(1, 1, 1, 1)
        headerLayout.addSpacerItem(fixedSpacer)
        headerLayout.addWidget(self.__watchpointLabel)
        headerLayout.addSpacerItem(expandingSpacer)
        headerLayout.addWidget(self.__showHideButton)
        self.headerFrame.setLayout(headerLayout)

        self.__wpointsList = WatchPointView(self, wpointModel)

        self.__enableButton = QToolButton()
        self.__enableButton.setIcon(PixmapCache().getIcon('add.png'))
        self.__enableButton.setFixedSize(24, 24)
        self.__enableButton.setToolTip("Enable/disable the watchpoint")
        self.__enableButton.setFocusPolicy(Qt.NoFocus)
        self.__enableButton.setEnabled(False)
        self.__enableButton.clicked.connect(self.__onEnableDisable)

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

        self.__jumpToCodeButton = QToolButton()
        self.__jumpToCodeButton.setIcon(PixmapCache().getIcon('gotoline.png'))
        self.__jumpToCodeButton.setFixedSize(24, 24)
        self.__jumpToCodeButton.setToolTip("Jump to the code")
        self.__jumpToCodeButton.setFocusPolicy(Qt.NoFocus)
        self.__jumpToCodeButton.setEnabled(False)
        self.__jumpToCodeButton.clicked.connect(self.__onJumpToCode)

        toolbarLayout = QHBoxLayout()
        toolbarLayout.addWidget(self.__enableButton)
        toolbarLayout.addSpacerItem(expandingSpacer)
        toolbarLayout.addWidget(self.__jumpToCodeButton)

        self.connect(self.__wpointsList, SIGNAL("itemSelectionChanged()"),
                     self.__onSelectionChanged)

        verticalLayout.addWidget(self.headerFrame)
        verticalLayout.addLayout(toolbarLayout)
        verticalLayout.addWidget(self.__wpointsList)
        return

    def clear(self):
        " Clears the content "
        #        self.__wpointsList.clear()
        self.__updateTitle()
        self.__jumpToCodeButton.setEnabled(False)
        self.__currentItem = None
        return

    def __onJumpToCode(self):
        " Jumps to the corresponding source code line "
        return

    def __onShowHide(self, startup=False):
        " Triggered when show/hide button is clicked "
        if startup or self.__wpointsList.isVisible():
            self.__wpointsList.setVisible(False)
            self.__enableButton.setVisible(False)
            self.__jumpToCodeButton.setVisible(False)
            self.__showHideButton.setIcon(PixmapCache().getIcon('more.png'))
            self.__showHideButton.setToolTip("Show watchpoints list")

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

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

            Settings().showWatchPointViewer = False
        else:
            self.__wpointsList.setVisible(True)
            self.__enableButton.setVisible(True)
            self.__jumpToCodeButton.setVisible(True)
            self.__showHideButton.setIcon(PixmapCache().getIcon('less.png'))
            self.__showHideButton.setToolTip("Hide watchpoints list")

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

            Settings().showWatchPointViewer = True
        return

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

    def __updateTitle(self):
        " Updates the section title "
        count = self.getTotalCount()
        if count == 0:
            self.__watchpointLabel.setText("Watchpoints")
        else:
            self.__watchpointLabel.setText("Watchpoints (total: " +
                                           str(count) + ")")
        return

    def getTotalCount(self):
        " Provides the total number of watch points "
        count = 0
        return count

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

    def __onEnableDisable(self):
        " Triggered when a breakpoint should be enabled/disabled "
        return
class ClientExceptionsViewer( QWidget ):
    " Implements the client exceptions viewer for a debugger "

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

        self.__ignoredExceptionsViewer = ignoredExceptionsViewer
        self.__currentItem = None

        self.__createPopupMenu()
        self.__createLayout()

        GlobalData().project.projectChanged.connect( self.__onProjectChanged )
        return

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

    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 )
        return

    def __createLayout( self ):
        " Creates the widget layout "

        verticalLayout = QVBoxLayout( self )
        verticalLayout.setContentsMargins( 0, 0, 0, 0 )
        verticalLayout.setSpacing( 0 )

        self.headerFrame = QFrame()
        self.headerFrame.setFrameStyle( QFrame.StyledPanel )
        self.headerFrame.setAutoFillBackground( True )
        headerPalette = self.headerFrame.palette()
        headerBackground = headerPalette.color( QPalette.Background )
        headerBackground.setRgb( min( headerBackground.red() + 30, 255 ),
                                 min( headerBackground.green() + 30, 255 ),
                                 min( headerBackground.blue() + 30, 255 ) )
        headerPalette.setColor( QPalette.Background, headerBackground )
        self.headerFrame.setPalette( headerPalette )
        self.headerFrame.setFixedHeight( 24 )

        self.__excptLabel = QLabel( "Exceptions" )

        fixedSpacer = QSpacerItem( 3, 3 )

        headerLayout = QHBoxLayout()
        headerLayout.setContentsMargins( 0, 0, 0, 0 )
        headerLayout.addSpacerItem( fixedSpacer )
        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(
            PixmapCache().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(
            PixmapCache().getIcon( 'gotoline.png' ),
            "Jump to the code", self )
        self.__jumpToCodeButton.triggered.connect( self.__onJumpToCode )
        self.__jumpToCodeButton.setEnabled( False )

        self.__delAllButton = QAction(
            PixmapCache().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" ] )

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

    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.emit( SIGNAL( 'ClientExceptionsCleared' ) )
        return

    def __onExceptionDoubleClicked( self, item, column ):
        " Triggered when an exception is double clicked "
        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.

        return

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

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

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

    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 )
        return

    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()
        return

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

    def addException( self, exceptionType, exceptionMessage,
                            stackTrace ):
        " Adds the exception to the view "
        for index in xrange( 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 )
        return

    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" )
        return

    def getTotalCount( self ):
        " Provides the total number of exceptions "
        count = 0
        for index in xrange( 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()
        return

    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 )
        return
class RecentProjectsViewer( QWidget ):
    " Recent projects viewer implementation "

    def __init__( self, parent = None ):
        QWidget.__init__( self, parent )

        self.__projectContextItem = None
        self.__fileContextItem = None

        self.upper = self.__createRecentFilesLayout()
        self.lower = self.__createRecentProjectsLayout()
        self.__createProjectPopupMenu()
        self.__createFilePopupMenu()

        layout = QVBoxLayout()
        layout.setContentsMargins( 1, 1, 1, 1 )
        splitter = QSplitter( Qt.Vertical )
        splitter.addWidget( self.upper )
        splitter.addWidget( self.lower )
        splitter.setCollapsible( 0, False )
        splitter.setCollapsible( 1, False )

        layout.addWidget( splitter )
        self.setLayout( layout )

        self.__populateProjects()
        self.__populateFiles()
        self.__updateProjectToolbarButtons()
        self.__updateFileToolbarButtons()

        # Debugging mode support
        self.__debugMode = False
        parent.debugModeChanged.connect( self.__onDebugMode )
        return

    def setTooltips( self, switchOn ):
        " Switches the tooltips mode "
        for index in xrange( 0, self.recentFilesView.topLevelItemCount() ):
            self.recentFilesView.topLevelItem( index ).updateIconAndTooltip()
        for index in xrange( 0, self.projectsView.topLevelItemCount() ):
            self.projectsView.topLevelItem( index ).updateTooltip()
        return

    def __createFilePopupMenu( self ):
        " create the recent files popup menu "
        self.__fileMenu = QMenu( self.recentFilesView )
        self.__openMenuItem = self.__fileMenu.addAction( \
                                PixmapCache().getIcon( 'openitem.png' ),
                                'Open', self.__openFile )
        self.__copyPathFileMenuItem = self.__fileMenu.addAction( \
                        PixmapCache().getIcon( 'copytoclipboard.png' ),
                        'Copy path to clipboard', self.__filePathToClipboard )
        self.__fileMenu.addSeparator()
        self.__delFileMenuItem = self.__fileMenu.addAction( \
                                PixmapCache().getIcon( 'trash.png' ),
                                'Delete from recent',
                                self.__deleteFile )
        self.recentFilesView.setContextMenuPolicy( Qt.CustomContextMenu )
        self.connect( self.recentFilesView,
                      SIGNAL( "customContextMenuRequested(const QPoint &)" ),
                      self.__handleShowFileContextMenu )

        self.connect( GlobalData().project, SIGNAL( 'recentFilesChanged' ),
                      self.__populateFiles )
        return


    def __createProjectPopupMenu( self ):
        " Creates the recent project popup menu "
        self.__projectMenu = QMenu( self.projectsView )
        self.__prjLoadMenuItem = self.__projectMenu.addAction( \
                                PixmapCache().getIcon( 'load.png' ),
                                'Load',
                                self.__loadProject )
        self.__projectMenu.addSeparator()
        self.__propsMenuItem = self.__projectMenu.addAction( \
                                PixmapCache().getIcon( 'smalli.png' ),
                                'Properties',
                                self.__viewProperties )
        self.__prjCopyPathMenuItem = self.__projectMenu.addAction( \
                                PixmapCache().getIcon( 'copytoclipboard.png' ),
                                'Copy path to clipboard',
                                self.__prjPathToClipboard )
        self.__projectMenu.addSeparator()
        self.__delPrjMenuItem = self.__projectMenu.addAction( \
                                PixmapCache().getIcon( 'trash.png' ),
                                'Delete from recent',
                                self.__deleteProject )
        self.projectsView.setContextMenuPolicy( Qt.CustomContextMenu )
        self.connect( self.projectsView,
                      SIGNAL( "customContextMenuRequested(const QPoint &)" ),
                      self.__handleShowPrjContextMenu )

        self.connect( Settings().iInstance, SIGNAL( 'recentListChanged' ),
                      self.__populateProjects )
        GlobalData().project.projectChanged.connect( self.__projectChanged )
        return

    def __createRecentFilesLayout( self ):
        " Creates the upper part - recent files "
        headerFrame = QFrame()
        headerFrame.setFrameStyle( QFrame.StyledPanel )
        headerFrame.setAutoFillBackground( True )
        headerPalette = headerFrame.palette()
        headerBackground = headerPalette.color( QPalette.Background )
        headerBackground.setRgb( min( headerBackground.red() + 30, 255 ),
                                 min( headerBackground.green() + 30, 255 ),
                                 min( headerBackground.blue() + 30, 255 ) )
        headerPalette.setColor( QPalette.Background, headerBackground )
        headerFrame.setPalette( headerPalette )
        headerFrame.setFixedHeight( 24 )

        recentFilesLabel = QLabel()
        recentFilesLabel.setText( "Recent files" )

        headerLayout = QHBoxLayout()
        headerLayout.setContentsMargins( 3, 0, 0, 0 )
        headerLayout.addWidget( recentFilesLabel )
        headerFrame.setLayout( headerLayout )

        self.recentFilesView = QTreeWidget()
        self.recentFilesView.setAlternatingRowColors( True )
        self.recentFilesView.setRootIsDecorated( False )
        self.recentFilesView.setItemsExpandable( False )
        self.recentFilesView.setSortingEnabled( True )
        self.recentFilesView.setItemDelegate( NoOutlineHeightDelegate( 4 ) )
        self.recentFilesView.setUniformRowHeights( True )

        self.__filesHeaderItem = QTreeWidgetItem( [ "", "File",
                                                    "Absolute path" ] )
        self.recentFilesView.setHeaderItem( self.__filesHeaderItem )
        self.recentFilesView.header().setSortIndicator( 1, Qt.AscendingOrder )

        self.connect( self.recentFilesView,
                      SIGNAL( "itemSelectionChanged()" ),
                      self.__fileSelectionChanged )
        self.connect( self.recentFilesView,
                      SIGNAL( "itemActivated(QTreeWidgetItem *, int)" ),
                      self.__fileActivated )

        # Toolbar part - buttons
        self.openFileButton = QAction( PixmapCache().getIcon( 'openitem.png' ),
                                       'Open the highlighted file', self )
        self.connect( self.openFileButton, SIGNAL( "triggered()" ),
                      self.__openFile )
        self.copyFilePathButton = QAction( \
                        PixmapCache().getIcon( 'copytoclipboard.png' ),
                        'Copy path to clipboard', self )
        self.connect( self.copyFilePathButton, SIGNAL( "triggered()" ),
                      self.__filePathToClipboard )
        spacer = QWidget()
        spacer.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Expanding )
        self.trashFileButton = QAction( PixmapCache().getIcon( 'delitem.png' ),
                                        'Remove selected (not from the disk)',
                                        self )
        self.connect( self.trashFileButton, SIGNAL( "triggered()" ),
                      self.__deleteFile )

        self.upperToolbar = QToolBar()
        self.upperToolbar.setMovable( False )
        self.upperToolbar.setAllowedAreas( Qt.TopToolBarArea )
        self.upperToolbar.setIconSize( QSize( 16, 16 ) )
        self.upperToolbar.setFixedHeight( 28 )
        self.upperToolbar.setContentsMargins( 0, 0, 0, 0 )
        self.upperToolbar.addAction( self.openFileButton )
        self.upperToolbar.addAction( self.copyFilePathButton )
        self.upperToolbar.addWidget( spacer )
        self.upperToolbar.addAction( self.trashFileButton )

        recentFilesLayout = QVBoxLayout()
        recentFilesLayout.setContentsMargins( 0, 0, 0, 0 )
        recentFilesLayout.setSpacing( 0 )
        recentFilesLayout.addWidget( headerFrame )
        recentFilesLayout.addWidget( self.upperToolbar )
        recentFilesLayout.addWidget( self.recentFilesView )

        upperContainer = QWidget()
        upperContainer.setContentsMargins( 0, 0, 0, 0 )
        upperContainer.setLayout( recentFilesLayout )
        return upperContainer

    def getRecentFilesToolbar( self ):
        " Provides a reference to the recent files toolbar "
        return self.upperToolbar

    def __createRecentProjectsLayout( self ):
        " Creates the bottom layout "
        self.headerFrame = QFrame()
        self.headerFrame.setFrameStyle( QFrame.StyledPanel )
        self.headerFrame.setAutoFillBackground( True )
        headerPalette = self.headerFrame.palette()
        headerBackground = headerPalette.color( QPalette.Background )
        headerBackground.setRgb( min( headerBackground.red() + 30, 255 ),
                                 min( headerBackground.green() + 30, 255 ),
                                 min( headerBackground.blue() + 30, 255 ) )
        headerPalette.setColor( QPalette.Background, headerBackground )
        self.headerFrame.setPalette( headerPalette )
        self.headerFrame.setFixedHeight( 24 )

        recentProjectsLabel = QLabel()
        recentProjectsLabel.setText( "Recent projects" )

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

        self.__showHideButton = QToolButton()
        self.__showHideButton.setAutoRaise( True )
        self.__showHideButton.setIcon( PixmapCache().getIcon( 'less.png' ) )
        self.__showHideButton.setFixedSize( 20, 20 )
        self.__showHideButton.setToolTip( "Hide recent projects list" )
        self.__showHideButton.setFocusPolicy( Qt.NoFocus )
        self.connect( self.__showHideButton, SIGNAL( 'clicked()' ),
                      self.__onShowHide )

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

        # Toolbar part - buttons
        self.loadButton = QAction( PixmapCache().getIcon( 'load.png' ),
                                   'Load the highlighted project', self )
        self.connect( self.loadButton, SIGNAL( "triggered()" ),
                      self.__loadProject )
        self.propertiesButton = QAction( PixmapCache().getIcon( 'smalli.png' ),
                                         'Show the highlighted project ' \
                                         'properties', self )
        self.connect( self.propertiesButton, SIGNAL( "triggered()" ),
                      self.__viewProperties )
        self.copyPrjPathButton = QAction( \
                        PixmapCache().getIcon( 'copytoclipboard.png' ),
                        'Copy path to clipboard', self )
        self.connect( self.copyPrjPathButton, SIGNAL( "triggered()" ),
                      self.__prjPathToClipboard )
        spacer = QWidget()
        spacer.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Expanding )
        self.trashButton = QAction( PixmapCache().getIcon( 'delitem.png' ),
                                    'Remove selected (not from the disk)',
                                    self )
        self.connect( self.trashButton, SIGNAL( "triggered()" ),
                      self.__deleteProject )

        self.lowerToolbar = QToolBar()
        self.lowerToolbar.setMovable( False )
        self.lowerToolbar.setAllowedAreas( Qt.TopToolBarArea )
        self.lowerToolbar.setIconSize( QSize( 16, 16 ) )
        self.lowerToolbar.setFixedHeight( 28 )
        self.lowerToolbar.setContentsMargins( 0, 0, 0, 0 )
        self.lowerToolbar.addAction( self.loadButton )
        self.lowerToolbar.addAction( self.propertiesButton )
        self.lowerToolbar.addAction( self.copyPrjPathButton )
        self.lowerToolbar.addWidget( spacer )
        self.lowerToolbar.addAction( self.trashButton )

        self.projectsView = QTreeWidget()
        self.projectsView.setAlternatingRowColors( True )
        self.projectsView.setRootIsDecorated( False )
        self.projectsView.setItemsExpandable( False )
        self.projectsView.setSortingEnabled( True )
        self.projectsView.setItemDelegate( NoOutlineHeightDelegate( 4 ) )
        self.projectsView.setUniformRowHeights( True )

        self.__projectsHeaderItem = QTreeWidgetItem( [ "", "Project",
                                                       "Absolute path" ] )
        self.projectsView.setHeaderItem( self.__projectsHeaderItem )

        self.projectsView.header().setSortIndicator( 1, Qt.AscendingOrder )
        self.connect( self.projectsView,
                      SIGNAL( "itemActivated(QTreeWidgetItem *, int)" ),
                      self.__projectActivated )
        self.connect( self.projectsView,
                      SIGNAL( "itemSelectionChanged()" ),
                      self.__projectSelectionChanged )

        recentProjectsLayout = QVBoxLayout()
        recentProjectsLayout.setContentsMargins( 0, 0, 0, 0 )
        recentProjectsLayout.setSpacing( 0 )
        recentProjectsLayout.addWidget( self.headerFrame )
        recentProjectsLayout.addWidget( self.lowerToolbar )
        recentProjectsLayout.addWidget( self.projectsView )

        lowerContainer = QWidget()
        lowerContainer.setContentsMargins( 0, 0, 0, 0 )
        lowerContainer.setLayout( recentProjectsLayout )
        return lowerContainer

    def getRecentProjectsToolbar( self ):
        " Provides a reference to the projects toolbar "
        return self.lowerToolbar

    def __projectSelectionChanged( self ):
        " Handles the projects changed selection "
        selected = list( self.projectsView.selectedItems() )

        if selected:
            self.__projectContextItem = selected[ 0 ]
        else:
            self.__projectContextItem = None

        self.__updateProjectToolbarButtons()
        return

    def __fileSelectionChanged( self ):
        " Handles the files changed selection "
        selected = list( self.recentFilesView.selectedItems() )

        if selected:
            self.__fileContextItem = selected[ 0 ]
        else:
            self.__fileContextItem = None
        self.__updateFileToolbarButtons()
        return

    def __updateProjectToolbarButtons( self ):
        " Updates the toolbar buttons depending on the __projectContextItem "
        if self.__projectContextItem is None:
            self.loadButton.setEnabled( False )
            self.propertiesButton.setEnabled( False )
            self.copyPrjPathButton.setEnabled( False )
            self.trashButton.setEnabled( False )
        else:
            enabled = self.__projectContextItem.isValid()
            isCurrentProject = self.__projectContextItem.isCurrent()

            self.propertiesButton.setEnabled( enabled )
            self.copyPrjPathButton.setEnabled( True )
            self.loadButton.setEnabled( enabled and
                                        not isCurrentProject and
                                        not self.__debugMode )
            self.trashButton.setEnabled( not isCurrentProject )
        return

    def __updateFileToolbarButtons( self ):
        " Updates the toolbar buttons depending on the __fileContextItem "
        enabled = self.__fileContextItem is not None
        self.openFileButton.setEnabled( enabled )
        self.copyFilePathButton.setEnabled( enabled )
        self.trashFileButton.setEnabled( enabled )
        return

    def __handleShowPrjContextMenu( self, coord ):
        " Show the project item context menu "
        self.__projectContextItem = self.projectsView.itemAt( coord )
        if self.__projectContextItem is None:
            return

        enabled = self.__projectContextItem.isValid()
        isCurrentProject = self.__projectContextItem.isCurrent()

        self.__propsMenuItem.setEnabled( enabled )
        self.__delPrjMenuItem.setEnabled( not isCurrentProject )
#        fName = self.__projectContextItem.getFilename()
        self.__prjLoadMenuItem.setEnabled( enabled and \
                                           not isCurrentProject and \
                                           not self.__debugMode )

        self.__projectMenu.popup( QCursor.pos() )
        return

    def __sortProjects( self ):
        " Sort the project items "
        self.projectsView.sortItems( \
                self.projectsView.sortColumn(),
                self.projectsView.header().sortIndicatorOrder() )
        return

    def __sortFiles( self ):
        " Sort the file items "
        self.recentFilesView.sortItems( \
                self.recentFilesView.sortColumn(),
                self.recentFilesView.header().sortIndicatorOrder() )
        return

    def __resizeProjectColumns( self ):
        """ Resize the projects list columns """
        self.projectsView.header().setStretchLastSection( True )
        self.projectsView.header().resizeSections( \
                                    QHeaderView.ResizeToContents )
        self.projectsView.header().resizeSection( 0, 22 )
        self.projectsView.header().setResizeMode( 0, QHeaderView.Fixed )
        return

    def __resizeFileColumns( self ):
        " Resize the files list columns "
        self.recentFilesView.header().setStretchLastSection( True )
        self.recentFilesView.header().resizeSections( \
                                    QHeaderView.ResizeToContents )
        self.recentFilesView.header().resizeSection( 0, 22 )
        self.recentFilesView.header().setResizeMode( 0, QHeaderView.Fixed )
        return

    def __projectActivated( self, item, column ):
        " Handles the double click (or Enter) on the item "
        self.__projectContextItem = item
        self.__loadProject()
        return

    def __fileActivated( self, item, column ):
        " Handles the double click (or Enter) on a file item "
        self.__fileContextItem = item
        self.__openFile()
        return

    def __viewProperties( self ):
        " Handles the 'view properties' context menu item "
        if self.__projectContextItem is None:
            return
        if not self.__projectContextItem.isValid():
            return

        if self.__projectContextItem.isCurrent():
            # This is the current project - it can be edited
            project = GlobalData().project
            dialog = ProjectPropertiesDialog( project )
            if dialog.exec_() == QDialog.Accepted:
                importDirs = []
                for index in xrange( dialog.importDirList.count() ):
                    importDirs.append( dialog.importDirList.item( index ).text() )

                scriptName = dialog.scriptEdit.text().strip()
                relativePath = relpath( scriptName, project.getProjectDir() )
                if not relativePath.startswith( '..' ):
                    scriptName = relativePath

                project.updateProperties(
                    scriptName, importDirs,
                    dialog.creationDateEdit.text().strip(),
                    dialog.authorEdit.text().strip(),
                    dialog.licenseEdit.text().strip(),
                    dialog.copyrightEdit.text().strip(),
                    dialog.versionEdit.text().strip(),
                    dialog.emailEdit.text().strip(),
                    dialog.descriptionEdit.toPlainText().strip() )
        else:
            # This is not the current project - it can be viewed
            fName = self.__projectContextItem.getFilename()
            dialog = ProjectPropertiesDialog( fName )
            dialog.exec_()
        return

    def __deleteProject( self ):
        " Handles the 'delete from recent' context menu item "
        if self.__projectContextItem is None:
            return

        # Removal from the visible list is done via a signal which comes back
        # from settings
        fName = self.__projectContextItem.getFilename()
        Settings().deleteRecentProject( fName )
        return

    def __loadProject( self ):
        " handles 'Load' context menu item "
        if self.__projectContextItem is None:
            return
        if not self.__projectContextItem.isValid():
            return
        if self.__debugMode:
            return

        projectFileName = self.__projectContextItem.getFilename()

        if self.__projectContextItem.isCurrent():
            GlobalData().mainWindow.openFile( projectFileName, -1 )
            return  # This is the current project, open for text editing

        QApplication.processEvents()
        QApplication.setOverrideCursor( QCursor( Qt.WaitCursor ) )
        if os.path.exists( projectFileName ):
            mainWin = GlobalData().mainWindow
            editorsManager = mainWin.editorsManagerWidget.editorsManager
            if editorsManager.closeRequest():
                prj = GlobalData().project
                prj.setTabsStatus( editorsManager.getTabsStatus() )
                editorsManager.closeAll()
                prj.loadProject( projectFileName )
                mainWin.activateProjectTab()
        else:
            logging.error( "The project " + \
                           os.path.basename( projectFileName ) + \
                           " disappeared from the file system." )
            self.__populateProjects()
        QApplication.restoreOverrideCursor()
        return

    def __populateProjects( self ):
        " Populates the recent projects "
        self.projectsView.clear()
        for item in Settings().recentProjects:
            self.projectsView.addTopLevelItem( RecentProjectViewItem( item ) )

        self.__sortProjects()
        self.__resizeProjectColumns()
        self.__updateProjectToolbarButtons()
        return

    def __populateFiles( self ):
        " Populates the recent files "
        self.recentFilesView.clear()
        for path in GlobalData().project.recentFiles:
            self.recentFilesView.addTopLevelItem( RecentFileViewItem( path ) )

        self.__sortFiles()
        self.__resizeFileColumns()
        self.__updateFileToolbarButtons()
        return

    def __projectChanged( self, what ):
        " Triggered when the current project is changed "
        if what == CodimensionProject.CompleteProject:
            self.__populateProjects()
            self.__populateFiles()
            return

        if what == CodimensionProject.Properties:
            # Update the corresponding tooltip
            items = self.projectsView.findItems( GlobalData().project.fileName,
                                                 Qt.MatchExactly, 2 )
            if len( items ) != 1:
                logging.error( "Unexpected number of matched projects: " + \
                               str( len( items ) ) )
                return

            items[ 0 ].updateTooltip()
            return

    def __openFile( self ):
        " Handles 'open' file menu item "
        self.__fileContextItem.updateIconAndTooltip()
        fName = self.__fileContextItem.getFilename()

        if not self.__fileContextItem.isValid():
            logging.warning( "Cannot open " + fName )
            return

        fileType = detectFileType( fName )
        if fileType == PixmapFileType:
            GlobalData().mainWindow.openPixmapFile( fName )
            return

        GlobalData().mainWindow.openFile( fName, -1 )
        return

    def __deleteFile( self ):
        " Handles 'delete from recent' file menu item "
        self.removeRecentFile( self.__fileContextItem.getFilename() )
        return

    def __handleShowFileContextMenu( self, coord ):
        " File context menu "
        self.__fileContextItem = self.recentFilesView.itemAt( coord )
        if self.__fileContextItem is not None:
            self.__fileMenu.popup( QCursor.pos() )
        return

    def __filePathToClipboard( self ):
        " Copies the file item path to the clipboard "
        if self.__fileContextItem is not None:
            QApplication.clipboard().setText( \
                    self.__fileContextItem.getFilename() )
        return

    def __prjPathToClipboard( self ):
        " Copies the project item path to the clipboard "
        if self.__projectContextItem is not None:
            QApplication.clipboard().setText( \
                    self.__projectContextItem.getFilename() )
        return

    def onFileUpdated( self, fileName, uuid ):
        " Triggered when the file is updated: python or project "
        realPath = os.path.realpath( fileName )

        count = self.recentFilesView.topLevelItemCount()
        for index in xrange( 0, count ):
            item = self.recentFilesView.topLevelItem( index )

            itemRealPath = os.path.realpath( item.getFilename() )
            if realPath == itemRealPath:
                item.updateIconAndTooltip()
                break

        for index in xrange( 0, self.projectsView.topLevelItemCount() ):
            item = self.projectsView.topLevelItem( index )

            itemRealPath = os.path.realpath( item.getFilename() )
            if realPath == itemRealPath:
                item.updateTooltip()
                break
        return

    def __onShowHide( self ):
        " Triggered when show/hide button is clicked "
        if self.projectsView.isVisible():
            self.projectsView.setVisible( False )
            self.lowerToolbar.setVisible( False )
            self.__showHideButton.setIcon( PixmapCache().getIcon( 'more.png' ) )
            self.__showHideButton.setToolTip( "Show recent projects list" )

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

            self.lower.setMinimumHeight( self.headerFrame.height() )
            self.lower.setMaximumHeight( self.headerFrame.height() )
        else:
            self.projectsView.setVisible( True )
            self.lowerToolbar.setVisible( True )
            self.__showHideButton.setIcon( PixmapCache().getIcon( 'less.png' ) )
            self.__showHideButton.setToolTip( "Hide recent projects list" )

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

    def __onDebugMode( self, newState ):
        " Triggered when debug mode has changed "
        self.__debugMode = newState

        # Disable the load project button
        self.__updateProjectToolbarButtons()
        return

    def removeRecentFile( self, fName ):
        " Removes a single file from the recent files list "
        GlobalData().project.removeRecentFile( fName )

        for index in xrange( self.recentFilesView.topLevelItemCount() ):
            candidate = self.recentFilesView.topLevelItem( index )
            if candidate.getFilename() == fName:
                self.recentFilesView.takeTopLevelItem( index )
                return
        return
Exemple #6
0
class ThreadsViewer(QWidget):
    " Implements the threads viewer for a debugger "

    def __init__(self, debugger, parent=None):
        QWidget.__init__(self, parent)

        self.__debugger = debugger
        self.__createLayout()

        if Settings().showThreadViewer == False:
            self.__onShowHide(True)
        return

    def __createLayout(self):
        " Creates the widget layout "

        verticalLayout = QVBoxLayout(self)
        verticalLayout.setContentsMargins(0, 0, 0, 0)
        verticalLayout.setSpacing(0)

        self.headerFrame = QFrame()
        self.headerFrame.setFrameStyle(QFrame.StyledPanel)
        self.headerFrame.setAutoFillBackground(True)
        headerPalette = self.headerFrame.palette()
        headerBackground = headerPalette.color(QPalette.Background)
        headerBackground.setRgb(min(headerBackground.red() + 30, 255),
                                min(headerBackground.green() + 30, 255),
                                min(headerBackground.blue() + 30, 255))
        headerPalette.setColor(QPalette.Background, headerBackground)
        self.headerFrame.setPalette(headerPalette)
        self.headerFrame.setFixedHeight(24)

        self.__threadsLabel = QLabel("Threads")

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

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

        headerLayout = QHBoxLayout()
        headerLayout.setContentsMargins(0, 0, 0, 0)
        headerLayout.addSpacerItem(fixedSpacer)
        headerLayout.addWidget(self.__threadsLabel)
        headerLayout.addSpacerItem(expandingSpacer)
        headerLayout.addWidget(self.__showHideButton)
        self.headerFrame.setLayout(headerLayout)

        self.__threadsList = QTreeWidget()
        self.__threadsList.setSortingEnabled(False)
        # I might not need that because of two reasons:
        # - the window has no focus
        # - the window has custom current indicator
        # self.__threadsList.setAlternatingRowColors( True )
        self.__threadsList.setRootIsDecorated(False)
        self.__threadsList.setItemsExpandable(False)
        self.__threadsList.setUniformRowHeights(True)
        self.__threadsList.setSelectionMode(QAbstractItemView.NoSelection)
        self.__threadsList.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.__threadsList.setItemDelegate(NoOutlineHeightDelegate(4))
        self.__threadsList.setFocusPolicy(Qt.NoFocus)

        self.__threadsList.itemClicked.connect(self.__onThreadClicked)
        self.__threadsList.setHeaderLabels(["", "Name", "State", "TID"])

        verticalLayout.addWidget(self.headerFrame)
        verticalLayout.addWidget(self.__threadsList)
        return

    def __onShowHide(self, startup=False):
        " Triggered when show/hide button is clicked "
        if startup or self.__threadsList.isVisible():
            self.__threadsList.setVisible(False)
            self.__showHideButton.setIcon(PixmapCache().getIcon('more.png'))
            self.__showHideButton.setToolTip("Show threads list")

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

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

            Settings().showThreadViewer = False
        else:
            self.__threadsList.setVisible(True)
            self.__showHideButton.setIcon(PixmapCache().getIcon('less.png'))
            self.__showHideButton.setToolTip("Hide threads list")

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

            Settings().showThreadViewer = True
        return

    def __resizeColumns(self):
        " Resize the files list columns "
        self.__threadsList.header().setStretchLastSection(True)
        self.__threadsList.header().resizeSections(
            QHeaderView.ResizeToContents)
        self.__threadsList.header().resizeSection(0, 22)
        self.__threadsList.header().setResizeMode(0, QHeaderView.Fixed)
        return

    def clear(self):
        " Clears the content "
        self.__threadsList.clear()
        self.__threadsLabel.setText("Threads")
        return

    def populate(self, currentThreadID, threadList):
        " Populates the thread list from the client "
        self.clear()
        for thread in threadList:
            if thread['broken']:
                state = "Waiting at breakpoint"
            else:
                state = "Running"
            item = ThreadItem(thread['id'], thread['name'], state)
            if thread['id'] == currentThreadID:
                item.setCurrent(True)
            self.__threadsList.addTopLevelItem(item)

        self.__resizeColumns()
        self.__threadsLabel.setText("Threads (total: " + str(len(threadList)) +
                                    ")")
        return

    def switchControl(self, isInIDE):
        " Switches the UI depending where the control flow is "
        self.__threadsList.setEnabled(isInIDE)
        return

    def __onThreadClicked(self, item, column):
        " Triggered when a thread is clicked "
        if item.isCurrent():
            return

        for index in xrange(self.__threadsList.topLevelItemCount()):
            listItem = self.__threadsList.topLevelItem(index)
            if listItem.isCurrent():
                listItem.setCurrent(False)
                break
        item.setCurrent(True)

        self.__debugger.remoteSetThread(item.getTID())
        return
Exemple #7
0
class StackViewer( QWidget ):
    " Implements the stack viewer for a debugger "

    def __init__( self, debugger, parent = None ):
        QWidget.__init__( self, parent )

        self.__debugger = debugger
        self.currentStack = None
        self.currentFrame = 0
        self.__createPopupMenu()
        self.__createLayout()

        if Settings().showStackViewer == False:
            self.__onShowHide( True )
        return

    def __createPopupMenu( self ):
        " Creates the popup menu "
        self.__framesMenu = QMenu()
        self.__setCurrentMenuItem = self.__framesMenu.addAction(
                    "Set current (single click)", self.__onSetCurrent )
        self.__jumpMenuItem = self.__framesMenu.addAction(
                    "Set current and jump to the source (double click)",
                    self.__onSetCurrentAndJump )
        return

    def __createLayout( self ):
        " Creates the widget layout "

        verticalLayout = QVBoxLayout( self )
        verticalLayout.setContentsMargins( 0, 0, 0, 0 )
        verticalLayout.setSpacing( 0 )

        self.headerFrame = QFrame()
        self.headerFrame.setFrameStyle( QFrame.StyledPanel )
        self.headerFrame.setAutoFillBackground( True )
        headerPalette = self.headerFrame.palette()
        headerBackground = headerPalette.color( QPalette.Background )
        headerBackground.setRgb( min( headerBackground.red() + 30, 255 ),
                                 min( headerBackground.green() + 30, 255 ),
                                 min( headerBackground.blue() + 30, 255 ) )
        headerPalette.setColor( QPalette.Background, headerBackground )
        self.headerFrame.setPalette( headerPalette )
        self.headerFrame.setFixedHeight( 24 )

        self.__stackLabel = QLabel( "Stack" )

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

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

        headerLayout = QHBoxLayout()
        headerLayout.setContentsMargins( 0, 0, 0, 0 )
        headerLayout.addSpacerItem( fixedSpacer )
        headerLayout.addWidget( self.__stackLabel )
        headerLayout.addSpacerItem( expandingSpacer )
        headerLayout.addWidget( self.__showHideButton )
        self.headerFrame.setLayout( headerLayout )

        self.__framesList = QTreeWidget( self )
        self.__framesList.setSortingEnabled( False )
        # I might not need that because of two reasons:
        # - the window has no focus
        # - the window has custom current indicator
        # self.__framesList.setAlternatingRowColors( True )
        self.__framesList.setRootIsDecorated( False )
        self.__framesList.setItemsExpandable( False )
        self.__framesList.setUniformRowHeights( True )
        self.__framesList.setSelectionMode( QAbstractItemView.NoSelection )
        self.__framesList.setSelectionBehavior( QAbstractItemView.SelectRows )
        self.__framesList.setItemDelegate( NoOutlineHeightDelegate( 4 ) )
        self.__framesList.setFocusPolicy( Qt.NoFocus )
        self.__framesList.setContextMenuPolicy( Qt.CustomContextMenu )

        self.__framesList.itemClicked.connect( self.__onFrameClicked )
        self.__framesList.itemDoubleClicked.connect( self.__onFrameDoubleClicked )
        self.__framesList.customContextMenuRequested.connect( self.__showContextMenu )

        self.__framesList.setHeaderLabels( [ "", "File:line", "Function",
                                             "Full path" ] )

        verticalLayout.addWidget( self.headerFrame )
        verticalLayout.addWidget( self.__framesList )
        return

    def __onShowHide( self, startup = False ):
        " Triggered when show/hide button is clicked "
        if startup or self.__framesList.isVisible():
            self.__framesList.setVisible( False )
            self.__showHideButton.setIcon( PixmapCache().getIcon( 'more.png' ) )
            self.__showHideButton.setToolTip( "Show frames list" )

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

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

            Settings().showStackViewer = False
        else:
            self.__framesList.setVisible( True )
            self.__showHideButton.setIcon( PixmapCache().getIcon( 'less.png' ) )
            self.__showHideButton.setToolTip( "Hide frames list" )

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

            Settings().showStackViewer = True
        return

    def clear( self ):
        " Clears the content "
        self.__framesList.clear()
        self.currentStack = None
        self.__stackLabel.setText( "Stack" )
        return

    def __resizeColumns( self ):
        " Resize the files list columns "
        self.__framesList.header().setStretchLastSection( True )
        self.__framesList.header().resizeSections(
                                    QHeaderView.ResizeToContents )
        self.__framesList.header().resizeSection( 0, 22 )
        self.__framesList.header().setResizeMode( 0, QHeaderView.Fixed )
        return


    def populate( self, stack ):
        " Sets the new call stack and selects the first item in it "
        self.clear()

        self.currentStack = stack
        self.currentFrame = 0
        frameNumber = 0
        for s in stack:
            if len( s ) == 2:
                # This is when an exception comes
                funcName = ""
            else:
                funcName = s[ 2 ]
            item = StackFrameItem( s[ 0 ], s[ 1 ], funcName, frameNumber )
            self.__framesList.addTopLevelItem( item )
            frameNumber += 1
        self.__resizeColumns()
        self.__framesList.topLevelItem( 0 ).setCurrent( True )
        self.__stackLabel.setText( "Stack (total: " +
                                   str( len( stack ) ) + ")" )
        return

    def getFrameNumber( self ):
        " Provides the current frame number "
        return self.currentFrame

    def __onFrameClicked( self, item, column ):
        " Triggered when a frame is clicked "
        if item.isCurrent():
            return

        # Hide the current indicator
        self.__framesList.topLevelItem( self.currentFrame ).setCurrent( False )

        # Show the new indicator
        self.currentFrame = item.getFrameNumber()
        for index in xrange( self.__framesList.topLevelItemCount() ):
            item = self.__framesList.topLevelItem( index )
            if item.getFrameNumber() == self.currentFrame:
                item.setCurrent( True )
        self.__debugger.remoteClientVariables( 1, self.currentFrame )  # globals
        self.__debugger.remoteClientVariables( 0, self.currentFrame )  # locals
        return

    def __onFrameDoubleClicked( self, item, column ):
        " Triggered when a frame is double clicked "
        # The frame has been switched already because the double click
        # signal always comes after the single click one
        fileName = item.getFilename()
        lineNumber = item.getLineNumber()

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

    def __showContextMenu( self, coord ):
        " Shows the frames list context menu "
        self.__contextItem = self.__framesList.itemAt( coord )
        if self.__contextItem is not None:
            self.__setCurrentMenuItem.setEnabled(
                                not self.__contextItem.isCurrent() )
            self.__framesMenu.popup( QCursor.pos() )
        return

    def __onSetCurrent( self ):
        " Context menu item handler "
        self.__onFrameClicked( self.__contextItem, 0 )
        return

    def __onSetCurrentAndJump( self ):
        " Context menu item handler "
        self.__onFrameClicked( self.__contextItem, 0 )
        self.__onFrameDoubleClicked( self.__contextItem, 0 )
        return

    def switchControl( self, isInIDE ):
        " Switches the UI depending where the control flow is "
        self.__framesList.setEnabled( isInIDE )
        return
Exemple #8
0
class RecentProjectsViewer(QWidget):
    " Recent projects viewer implementation "

    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        self.__projectContextItem = None
        self.__fileContextItem = None

        self.upper = self.__createRecentFilesLayout()
        self.lower = self.__createRecentProjectsLayout()
        self.__createProjectPopupMenu()
        self.__createFilePopupMenu()

        layout = QVBoxLayout()
        layout.setContentsMargins(1, 1, 1, 1)
        splitter = QSplitter(Qt.Vertical)
        splitter.addWidget(self.upper)
        splitter.addWidget(self.lower)
        splitter.setCollapsible(0, False)
        splitter.setCollapsible(1, False)

        layout.addWidget(splitter)
        self.setLayout(layout)

        self.__populateProjects()
        self.__populateFiles()
        self.__updateProjectToolbarButtons()
        self.__updateFileToolbarButtons()

        # Debugging mode support
        self.__debugMode = False
        parent.debugModeChanged.connect(self.__onDebugMode)
        return

    def setTooltips(self, switchOn):
        " Switches the tooltips mode "
        for index in xrange(0, self.recentFilesView.topLevelItemCount()):
            self.recentFilesView.topLevelItem(index).updateIconAndTooltip()
        for index in xrange(0, self.projectsView.topLevelItemCount()):
            self.projectsView.topLevelItem(index).updateTooltip()
        return

    def __createFilePopupMenu(self):
        " create the recent files popup menu "
        self.__fileMenu = QMenu(self.recentFilesView)
        self.__openMenuItem = self.__fileMenu.addAction(
            getIcon('openitem.png'), 'Open', self.__openFile)
        self.__copyPathFileMenuItem = self.__fileMenu.addAction(
            getIcon('copytoclipboard.png'), 'Copy path to clipboard',
            self.__filePathToClipboard)
        self.__fileMenu.addSeparator()
        self.__delFileMenuItem = self.__fileMenu.addAction(
            getIcon('trash.png'), 'Delete from recent', self.__deleteFile)
        self.recentFilesView.setContextMenuPolicy(Qt.CustomContextMenu)
        self.connect(self.recentFilesView,
                     SIGNAL("customContextMenuRequested(const QPoint &)"),
                     self.__handleShowFileContextMenu)

        self.connect(GlobalData().project, SIGNAL('recentFilesChanged'),
                     self.__populateFiles)
        return

    def __createProjectPopupMenu(self):
        " Creates the recent project popup menu "
        self.__projectMenu = QMenu(self.projectsView)
        self.__prjLoadMenuItem = self.__projectMenu.addAction(
            getIcon('load.png'), 'Load', self.__loadProject)
        self.__projectMenu.addSeparator()
        self.__propsMenuItem = self.__projectMenu.addAction(
            getIcon('smalli.png'), 'Properties', self.__viewProperties)
        self.__prjCopyPathMenuItem = self.__projectMenu.addAction(
            getIcon('copytoclipboard.png'), 'Copy path to clipboard',
            self.__prjPathToClipboard)
        self.__projectMenu.addSeparator()
        self.__delPrjMenuItem = self.__projectMenu.addAction(
            getIcon('trash.png'), 'Delete from recent', self.__deleteProject)
        self.projectsView.setContextMenuPolicy(Qt.CustomContextMenu)
        self.connect(self.projectsView,
                     SIGNAL("customContextMenuRequested(const QPoint &)"),
                     self.__handleShowPrjContextMenu)

        Settings().recentListChanged.connect(self.__populateProjects)
        GlobalData().project.projectChanged.connect(self.__projectChanged)
        return

    def __createRecentFilesLayout(self):
        " Creates the upper part - recent files "
        headerFrame = QFrame()
        headerFrame.setFrameStyle(QFrame.StyledPanel)
        headerFrame.setAutoFillBackground(True)
        headerPalette = headerFrame.palette()
        headerBackground = headerPalette.color(QPalette.Background)
        headerBackground.setRgb(min(headerBackground.red() + 30, 255),
                                min(headerBackground.green() + 30, 255),
                                min(headerBackground.blue() + 30, 255))
        headerPalette.setColor(QPalette.Background, headerBackground)
        headerFrame.setPalette(headerPalette)
        headerFrame.setFixedHeight(24)

        recentFilesLabel = QLabel()
        recentFilesLabel.setText("Recent files")

        headerLayout = QHBoxLayout()
        headerLayout.setContentsMargins(3, 0, 0, 0)
        headerLayout.addWidget(recentFilesLabel)
        headerFrame.setLayout(headerLayout)

        self.recentFilesView = QTreeWidget()
        self.recentFilesView.setAlternatingRowColors(True)
        self.recentFilesView.setRootIsDecorated(False)
        self.recentFilesView.setItemsExpandable(False)
        self.recentFilesView.setSortingEnabled(True)
        self.recentFilesView.setItemDelegate(NoOutlineHeightDelegate(4))
        self.recentFilesView.setUniformRowHeights(True)

        self.__filesHeaderItem = QTreeWidgetItem(["", "File", "Absolute path"])
        self.recentFilesView.setHeaderItem(self.__filesHeaderItem)
        self.recentFilesView.header().setSortIndicator(1, Qt.AscendingOrder)

        self.connect(self.recentFilesView, SIGNAL("itemSelectionChanged()"),
                     self.__fileSelectionChanged)
        self.connect(self.recentFilesView,
                     SIGNAL("itemActivated(QTreeWidgetItem *, int)"),
                     self.__fileActivated)

        # Toolbar part - buttons
        self.openFileButton = QAction(getIcon('openitem.png'),
                                      'Open the highlighted file', self)
        self.connect(self.openFileButton, SIGNAL("triggered()"),
                     self.__openFile)
        self.copyFilePathButton = QAction(getIcon('copytoclipboard.png'),
                                          'Copy path to clipboard', self)
        self.connect(self.copyFilePathButton, SIGNAL("triggered()"),
                     self.__filePathToClipboard)
        spacer = QWidget()
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.trashFileButton = QAction(getIcon('delitem.png'),
                                       'Remove selected (not from the disk)',
                                       self)
        self.connect(self.trashFileButton, SIGNAL("triggered()"),
                     self.__deleteFile)

        self.upperToolbar = QToolBar()
        self.upperToolbar.setMovable(False)
        self.upperToolbar.setAllowedAreas(Qt.TopToolBarArea)
        self.upperToolbar.setIconSize(QSize(16, 16))
        self.upperToolbar.setFixedHeight(28)
        self.upperToolbar.setContentsMargins(0, 0, 0, 0)
        self.upperToolbar.addAction(self.openFileButton)
        self.upperToolbar.addAction(self.copyFilePathButton)
        self.upperToolbar.addWidget(spacer)
        self.upperToolbar.addAction(self.trashFileButton)

        recentFilesLayout = QVBoxLayout()
        recentFilesLayout.setContentsMargins(0, 0, 0, 0)
        recentFilesLayout.setSpacing(0)
        recentFilesLayout.addWidget(headerFrame)
        recentFilesLayout.addWidget(self.upperToolbar)
        recentFilesLayout.addWidget(self.recentFilesView)

        upperContainer = QWidget()
        upperContainer.setContentsMargins(0, 0, 0, 0)
        upperContainer.setLayout(recentFilesLayout)
        return upperContainer

    def getRecentFilesToolbar(self):
        " Provides a reference to the recent files toolbar "
        return self.upperToolbar

    def __createRecentProjectsLayout(self):
        " Creates the bottom layout "
        self.headerFrame = QFrame()
        self.headerFrame.setFrameStyle(QFrame.StyledPanel)
        self.headerFrame.setAutoFillBackground(True)
        headerPalette = self.headerFrame.palette()
        headerBackground = headerPalette.color(QPalette.Background)
        headerBackground.setRgb(min(headerBackground.red() + 30, 255),
                                min(headerBackground.green() + 30, 255),
                                min(headerBackground.blue() + 30, 255))
        headerPalette.setColor(QPalette.Background, headerBackground)
        self.headerFrame.setPalette(headerPalette)
        self.headerFrame.setFixedHeight(24)

        recentProjectsLabel = QLabel()
        recentProjectsLabel.setText("Recent projects")

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

        self.__showHideButton = QToolButton()
        self.__showHideButton.setAutoRaise(True)
        self.__showHideButton.setIcon(getIcon('less.png'))
        self.__showHideButton.setFixedSize(20, 20)
        self.__showHideButton.setToolTip("Hide recent projects list")
        self.__showHideButton.setFocusPolicy(Qt.NoFocus)
        self.connect(self.__showHideButton, SIGNAL('clicked()'),
                     self.__onShowHide)

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

        # Toolbar part - buttons
        self.loadButton = QAction(getIcon('load.png'),
                                  'Load the highlighted project', self)
        self.connect(self.loadButton, SIGNAL("triggered()"),
                     self.__loadProject)
        self.propertiesButton = QAction(
            getIcon('smalli.png'), 'Show the highlighted project '
            'properties', self)
        self.connect(self.propertiesButton, SIGNAL("triggered()"),
                     self.__viewProperties)
        self.copyPrjPathButton = QAction(getIcon('copytoclipboard.png'),
                                         'Copy path to clipboard', self)
        self.connect(self.copyPrjPathButton, SIGNAL("triggered()"),
                     self.__prjPathToClipboard)
        spacer = QWidget()
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.trashButton = QAction(getIcon('delitem.png'),
                                   'Remove selected (not from the disk)', self)
        self.connect(self.trashButton, SIGNAL("triggered()"),
                     self.__deleteProject)

        self.lowerToolbar = QToolBar()
        self.lowerToolbar.setMovable(False)
        self.lowerToolbar.setAllowedAreas(Qt.TopToolBarArea)
        self.lowerToolbar.setIconSize(QSize(16, 16))
        self.lowerToolbar.setFixedHeight(28)
        self.lowerToolbar.setContentsMargins(0, 0, 0, 0)
        self.lowerToolbar.addAction(self.loadButton)
        self.lowerToolbar.addAction(self.propertiesButton)
        self.lowerToolbar.addAction(self.copyPrjPathButton)
        self.lowerToolbar.addWidget(spacer)
        self.lowerToolbar.addAction(self.trashButton)

        self.projectsView = QTreeWidget()
        self.projectsView.setAlternatingRowColors(True)
        self.projectsView.setRootIsDecorated(False)
        self.projectsView.setItemsExpandable(False)
        self.projectsView.setSortingEnabled(True)
        self.projectsView.setItemDelegate(NoOutlineHeightDelegate(4))
        self.projectsView.setUniformRowHeights(True)

        self.__projectsHeaderItem = QTreeWidgetItem(
            ["", "Project", "Absolute path"])
        self.projectsView.setHeaderItem(self.__projectsHeaderItem)

        self.projectsView.header().setSortIndicator(1, Qt.AscendingOrder)
        self.connect(self.projectsView,
                     SIGNAL("itemActivated(QTreeWidgetItem *, int)"),
                     self.__projectActivated)
        self.connect(self.projectsView, SIGNAL("itemSelectionChanged()"),
                     self.__projectSelectionChanged)

        recentProjectsLayout = QVBoxLayout()
        recentProjectsLayout.setContentsMargins(0, 0, 0, 0)
        recentProjectsLayout.setSpacing(0)
        recentProjectsLayout.addWidget(self.headerFrame)
        recentProjectsLayout.addWidget(self.lowerToolbar)
        recentProjectsLayout.addWidget(self.projectsView)

        lowerContainer = QWidget()
        lowerContainer.setContentsMargins(0, 0, 0, 0)
        lowerContainer.setLayout(recentProjectsLayout)
        return lowerContainer

    def getRecentProjectsToolbar(self):
        " Provides a reference to the projects toolbar "
        return self.lowerToolbar

    def __projectSelectionChanged(self):
        " Handles the projects changed selection "
        selected = list(self.projectsView.selectedItems())

        if selected:
            self.__projectContextItem = selected[0]
        else:
            self.__projectContextItem = None

        self.__updateProjectToolbarButtons()
        return

    def __fileSelectionChanged(self):
        " Handles the files changed selection "
        selected = list(self.recentFilesView.selectedItems())

        if selected:
            self.__fileContextItem = selected[0]
        else:
            self.__fileContextItem = None
        self.__updateFileToolbarButtons()
        return

    def __updateProjectToolbarButtons(self):
        " Updates the toolbar buttons depending on the __projectContextItem "
        if self.__projectContextItem is None:
            self.loadButton.setEnabled(False)
            self.propertiesButton.setEnabled(False)
            self.copyPrjPathButton.setEnabled(False)
            self.trashButton.setEnabled(False)
        else:
            enabled = self.__projectContextItem.isValid()
            isCurrentProject = self.__projectContextItem.isCurrent()

            self.propertiesButton.setEnabled(enabled)
            self.copyPrjPathButton.setEnabled(True)
            self.loadButton.setEnabled(enabled and not isCurrentProject
                                       and not self.__debugMode)
            self.trashButton.setEnabled(not isCurrentProject)
        return

    def __updateFileToolbarButtons(self):
        " Updates the toolbar buttons depending on the __fileContextItem "
        enabled = self.__fileContextItem is not None
        self.openFileButton.setEnabled(enabled)
        self.copyFilePathButton.setEnabled(enabled)
        self.trashFileButton.setEnabled(enabled)
        return

    def __handleShowPrjContextMenu(self, coord):
        " Show the project item context menu "
        self.__projectContextItem = self.projectsView.itemAt(coord)
        if self.__projectContextItem is None:
            return

        enabled = self.__projectContextItem.isValid()
        isCurrentProject = self.__projectContextItem.isCurrent()

        self.__propsMenuItem.setEnabled(enabled)
        self.__delPrjMenuItem.setEnabled(not isCurrentProject)
        #        fName = self.__projectContextItem.getFilename()
        self.__prjLoadMenuItem.setEnabled(enabled and not isCurrentProject
                                          and not self.__debugMode)

        self.__projectMenu.popup(QCursor.pos())
        return

    def __sortProjects(self):
        " Sort the project items "
        self.projectsView.sortItems( \
                self.projectsView.sortColumn(),
                self.projectsView.header().sortIndicatorOrder() )
        return

    def __sortFiles(self):
        " Sort the file items "
        self.recentFilesView.sortItems(
            self.recentFilesView.sortColumn(),
            self.recentFilesView.header().sortIndicatorOrder())
        return

    def __resizeProjectColumns(self):
        """ Resize the projects list columns """
        self.projectsView.header().setStretchLastSection(True)
        self.projectsView.header().resizeSections(QHeaderView.ResizeToContents)
        self.projectsView.header().resizeSection(0, 22)
        self.projectsView.header().setResizeMode(0, QHeaderView.Fixed)
        return

    def __resizeFileColumns(self):
        " Resize the files list columns "
        self.recentFilesView.header().setStretchLastSection(True)
        self.recentFilesView.header().resizeSections(
            QHeaderView.ResizeToContents)
        self.recentFilesView.header().resizeSection(0, 22)
        self.recentFilesView.header().setResizeMode(0, QHeaderView.Fixed)
        return

    def __projectActivated(self, item, column):
        " Handles the double click (or Enter) on the item "
        self.__projectContextItem = item
        self.__loadProject()
        return

    def __fileActivated(self, item, column):
        " Handles the double click (or Enter) on a file item "
        self.__fileContextItem = item
        self.__openFile()
        return

    def __viewProperties(self):
        " Handles the 'view properties' context menu item "
        if self.__projectContextItem is None:
            return
        if not self.__projectContextItem.isValid():
            return

        if self.__projectContextItem.isCurrent():
            # This is the current project - it can be edited
            project = GlobalData().project
            dialog = ProjectPropertiesDialog(project, self)
            if dialog.exec_() == QDialog.Accepted:
                importDirs = []
                for index in xrange(dialog.importDirList.count()):
                    importDirs.append(dialog.importDirList.item(index).text())

                scriptName = dialog.scriptEdit.text().strip()
                relativePath = relpath(scriptName, project.getProjectDir())
                if not relativePath.startswith('..'):
                    scriptName = relativePath

                project.updateProperties(
                    scriptName, importDirs,
                    dialog.creationDateEdit.text().strip(),
                    dialog.authorEdit.text().strip(),
                    dialog.licenseEdit.text().strip(),
                    dialog.copyrightEdit.text().strip(),
                    dialog.versionEdit.text().strip(),
                    dialog.emailEdit.text().strip(),
                    dialog.descriptionEdit.toPlainText().strip())
        else:
            # This is not the current project - it can be viewed
            fName = self.__projectContextItem.getFilename()
            dialog = ProjectPropertiesDialog(fName, self)
            dialog.exec_()
        return

    def __deleteProject(self):
        " Handles the 'delete from recent' context menu item "
        if self.__projectContextItem is None:
            return

        # Removal from the visible list is done via a signal which comes back
        # from settings
        fName = self.__projectContextItem.getFilename()
        Settings().deleteRecentProject(fName)
        return

    def __loadProject(self):
        " handles 'Load' context menu item "
        if self.__projectContextItem is None:
            return
        if not self.__projectContextItem.isValid():
            return
        if self.__debugMode:
            return

        projectFileName = self.__projectContextItem.getFilename()

        if self.__projectContextItem.isCurrent():
            GlobalData().mainWindow.openFile(projectFileName, -1)
            return  # This is the current project, open for text editing

        QApplication.processEvents()
        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
        if os.path.exists(projectFileName):
            mainWin = GlobalData().mainWindow
            editorsManager = mainWin.editorsManagerWidget.editorsManager
            if editorsManager.closeRequest():
                prj = GlobalData().project
                prj.setTabsStatus(editorsManager.getTabsStatus())
                editorsManager.closeAll()
                prj.loadProject(projectFileName)
                mainWin.activateProjectTab()
        else:
            logging.error("The project " + os.path.basename(projectFileName) +
                          " disappeared from the file system.")
            self.__populateProjects()
        QApplication.restoreOverrideCursor()
        return

    def __populateProjects(self):
        " Populates the recent projects "
        self.projectsView.clear()
        for item in Settings().recentProjects:
            self.projectsView.addTopLevelItem(RecentProjectViewItem(item))

        self.__sortProjects()
        self.__resizeProjectColumns()
        self.__updateProjectToolbarButtons()
        return

    def __populateFiles(self):
        " Populates the recent files "
        self.recentFilesView.clear()
        for path in GlobalData().project.recentFiles:
            self.recentFilesView.addTopLevelItem(RecentFileViewItem(path))

        self.__sortFiles()
        self.__resizeFileColumns()
        self.__updateFileToolbarButtons()
        return

    def __projectChanged(self, what):
        " Triggered when the current project is changed "
        if what == CodimensionProject.CompleteProject:
            self.__populateProjects()
            self.__populateFiles()
            return

        if what == CodimensionProject.Properties:
            # Update the corresponding tooltip
            items = self.projectsView.findItems(GlobalData().project.fileName,
                                                Qt.MatchExactly, 2)
            if len(items) != 1:
                logging.error("Unexpected number of matched projects: " +
                              str(len(items)))
                return

            items[0].updateTooltip()
            return

    def __openFile(self):
        " Handles 'open' file menu item "
        self.__fileContextItem.updateIconAndTooltip()
        fName = self.__fileContextItem.getFilename()

        if not self.__fileContextItem.isValid():
            logging.warning("Cannot open " + fName)
            return

        fileType = detectFileType(fName)
        if fileType == PixmapFileType:
            GlobalData().mainWindow.openPixmapFile(fName)
            return

        GlobalData().mainWindow.openFile(fName, -1)
        return

    def __deleteFile(self):
        " Handles 'delete from recent' file menu item "
        self.removeRecentFile(self.__fileContextItem.getFilename())
        return

    def __handleShowFileContextMenu(self, coord):
        " File context menu "
        self.__fileContextItem = self.recentFilesView.itemAt(coord)
        if self.__fileContextItem is not None:
            self.__fileMenu.popup(QCursor.pos())
        return

    def __filePathToClipboard(self):
        " Copies the file item path to the clipboard "
        if self.__fileContextItem is not None:
            QApplication.clipboard().setText(
                self.__fileContextItem.getFilename())
        return

    def __prjPathToClipboard(self):
        " Copies the project item path to the clipboard "
        if self.__projectContextItem is not None:
            QApplication.clipboard().setText(
                self.__projectContextItem.getFilename())
        return

    def onFileUpdated(self, fileName, uuid):
        " Triggered when the file is updated: python or project "
        realPath = os.path.realpath(fileName)

        count = self.recentFilesView.topLevelItemCount()
        for index in xrange(0, count):
            item = self.recentFilesView.topLevelItem(index)

            itemRealPath = os.path.realpath(item.getFilename())
            if realPath == itemRealPath:
                item.updateIconAndTooltip()
                break

        for index in xrange(0, self.projectsView.topLevelItemCount()):
            item = self.projectsView.topLevelItem(index)

            itemRealPath = os.path.realpath(item.getFilename())
            if realPath == itemRealPath:
                item.updateTooltip()
                break
        return

    def __onShowHide(self):
        " Triggered when show/hide button is clicked "
        if self.projectsView.isVisible():
            self.projectsView.setVisible(False)
            self.lowerToolbar.setVisible(False)
            self.__showHideButton.setIcon(getIcon('more.png'))
            self.__showHideButton.setToolTip("Show recent projects list")

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

            self.lower.setMinimumHeight(self.headerFrame.height())
            self.lower.setMaximumHeight(self.headerFrame.height())
        else:
            self.projectsView.setVisible(True)
            self.lowerToolbar.setVisible(True)
            self.__showHideButton.setIcon(getIcon('less.png'))
            self.__showHideButton.setToolTip("Hide recent projects list")

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

    def __onDebugMode(self, newState):
        " Triggered when debug mode has changed "
        self.__debugMode = newState

        # Disable the load project button
        self.__updateProjectToolbarButtons()
        return

    def removeRecentFile(self, fName):
        " Removes a single file from the recent files list "
        GlobalData().project.removeRecentFile(fName)

        for index in xrange(self.recentFilesView.topLevelItemCount()):
            candidate = self.recentFilesView.topLevelItem(index)
            if candidate.getFilename() == fName:
                self.recentFilesView.takeTopLevelItem(index)
                return
        return
Exemple #9
0
    def __createRecentFilesLayout(self):
        " Creates the upper part - recent files "
        headerFrame = QFrame()
        headerFrame.setFrameStyle(QFrame.StyledPanel)
        headerFrame.setAutoFillBackground(True)
        headerPalette = headerFrame.palette()
        headerBackground = headerPalette.color(QPalette.Background)
        headerBackground.setRgb(min(headerBackground.red() + 30, 255),
                                min(headerBackground.green() + 30, 255),
                                min(headerBackground.blue() + 30, 255))
        headerPalette.setColor(QPalette.Background, headerBackground)
        headerFrame.setPalette(headerPalette)
        headerFrame.setFixedHeight(24)

        recentFilesLabel = QLabel()
        recentFilesLabel.setText("Recent files")

        headerLayout = QHBoxLayout()
        headerLayout.setContentsMargins(3, 0, 0, 0)
        headerLayout.addWidget(recentFilesLabel)
        headerFrame.setLayout(headerLayout)

        self.recentFilesView = QTreeWidget()
        self.recentFilesView.setAlternatingRowColors(True)
        self.recentFilesView.setRootIsDecorated(False)
        self.recentFilesView.setItemsExpandable(False)
        self.recentFilesView.setSortingEnabled(True)
        self.recentFilesView.setItemDelegate(NoOutlineHeightDelegate(4))
        self.recentFilesView.setUniformRowHeights(True)

        self.__filesHeaderItem = QTreeWidgetItem(["", "File", "Absolute path"])
        self.recentFilesView.setHeaderItem(self.__filesHeaderItem)
        self.recentFilesView.header().setSortIndicator(1, Qt.AscendingOrder)

        self.connect(self.recentFilesView, SIGNAL("itemSelectionChanged()"),
                     self.__fileSelectionChanged)
        self.connect(self.recentFilesView,
                     SIGNAL("itemActivated(QTreeWidgetItem *, int)"),
                     self.__fileActivated)

        # Toolbar part - buttons
        self.openFileButton = QAction(getIcon('openitem.png'),
                                      'Open the highlighted file', self)
        self.connect(self.openFileButton, SIGNAL("triggered()"),
                     self.__openFile)
        self.copyFilePathButton = QAction(getIcon('copytoclipboard.png'),
                                          'Copy path to clipboard', self)
        self.connect(self.copyFilePathButton, SIGNAL("triggered()"),
                     self.__filePathToClipboard)
        spacer = QWidget()
        spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.trashFileButton = QAction(getIcon('delitem.png'),
                                       'Remove selected (not from the disk)',
                                       self)
        self.connect(self.trashFileButton, SIGNAL("triggered()"),
                     self.__deleteFile)

        self.upperToolbar = QToolBar()
        self.upperToolbar.setMovable(False)
        self.upperToolbar.setAllowedAreas(Qt.TopToolBarArea)
        self.upperToolbar.setIconSize(QSize(16, 16))
        self.upperToolbar.setFixedHeight(28)
        self.upperToolbar.setContentsMargins(0, 0, 0, 0)
        self.upperToolbar.addAction(self.openFileButton)
        self.upperToolbar.addAction(self.copyFilePathButton)
        self.upperToolbar.addWidget(spacer)
        self.upperToolbar.addAction(self.trashFileButton)

        recentFilesLayout = QVBoxLayout()
        recentFilesLayout.setContentsMargins(0, 0, 0, 0)
        recentFilesLayout.setSpacing(0)
        recentFilesLayout.addWidget(headerFrame)
        recentFilesLayout.addWidget(self.upperToolbar)
        recentFilesLayout.addWidget(self.recentFilesView)

        upperContainer = QWidget()
        upperContainer.setContentsMargins(0, 0, 0, 0)
        upperContainer.setLayout(recentFilesLayout)
        return upperContainer
Exemple #10
0
    def __createLayout( self ):
        " Creates the widget layout "

        verticalLayout = QVBoxLayout( self )
        verticalLayout.setContentsMargins( 0, 0, 0, 0 )
        verticalLayout.setSpacing( 0 )

        headerFrame = QFrame()
        headerFrame.setFrameStyle( QFrame.StyledPanel )
        headerFrame.setAutoFillBackground( True )
        headerPalette = headerFrame.palette()
        headerBackground = headerPalette.color( QPalette.Background )
        headerBackground.setRgb( min( headerBackground.red() + 30, 255 ),
                                 min( headerBackground.green() + 30, 255 ),
                                 min( headerBackground.blue() + 30, 255 ) )
        headerPalette.setColor( QPalette.Background, headerBackground )
        headerFrame.setPalette( headerPalette )
        headerFrame.setFixedHeight( 24 )

        self.__headerLabel = QLabel( "Variables" )

        expandingSpacer = QSpacerItem( 10, 10, QSizePolicy.Expanding )
        fixedSpacer = QSpacerItem( 3, 3 )
        fixedSpacer1 = QSpacerItem( 5, 5 )

        self.__mcfButton = QToolButton()
        self.__mcfButton.setCheckable( True )
        self.__mcfButton.setChecked( self.__hideMCFFilter )
        self.__mcfButton.setIcon( PixmapCache().getIcon( 'dbgfltmcf.png' ) )
        self.__mcfButton.setFixedSize( 20, 20 )
        self.__mcfButton.setToolTip( "Show/hide modules, classes and functions" )
        self.__mcfButton.setFocusPolicy( Qt.NoFocus )
        self.__mcfButton.clicked.connect( self.__onMCFFilter )

        self.__globalAndLocalButton = QToolButton()
        self.__globalAndLocalButton.setCheckable( True )
        self.__globalAndLocalButton.setChecked( self.__filter == VariablesViewer.FilterGlobalAndLocal )
        self.__globalAndLocalButton.setIcon( PixmapCache().getIcon( 'dbgfltgl.png' ) )
        self.__globalAndLocalButton.setFixedSize( 20, 20 )
        self.__globalAndLocalButton.setToolTip( "Do not filter out global or local variables" )
        self.__globalAndLocalButton.setFocusPolicy( Qt.NoFocus )
        self.__globalAndLocalButton.clicked.connect( self.__onGlobalAndLocalFilter )

        self.__localOnlyButton = QToolButton()
        self.__localOnlyButton.setCheckable( True )
        self.__localOnlyButton.setChecked( self.__filter == VariablesViewer.FilterLocalOnly )
        self.__localOnlyButton.setIcon( PixmapCache().getIcon( 'dbgfltlo.png' ) )
        self.__localOnlyButton.setFixedSize( 20, 20 )
        self.__localOnlyButton.setToolTip( "Filter out global variables" )
        self.__localOnlyButton.setFocusPolicy( Qt.NoFocus )
        self.__localOnlyButton.clicked.connect( self.__onLocalFilter )

        self.__globalOnlyButton = QToolButton()
        self.__globalOnlyButton.setCheckable( True )
        self.__globalOnlyButton.setChecked( self.__filter == VariablesViewer.FilterGlobalOnly )
        self.__globalOnlyButton.setIcon( PixmapCache().getIcon( 'dbgfltgo.png' ) )
        self.__globalOnlyButton.setFixedSize( 20, 20 )
        self.__globalOnlyButton.setToolTip( "Filter out local variables" )
        self.__globalOnlyButton.setFocusPolicy( Qt.NoFocus )
        self.__globalOnlyButton.clicked.connect( self.__onGlobalFilter )

        self.__execStatement = CDMComboBox( True )
        self.__execStatement.setSizePolicy( QSizePolicy.Expanding,
                                            QSizePolicy.Expanding )
        self.__execStatement.lineEdit().setToolTip(
                                "Expression to be executed" )
        self.__execStatement.setFixedHeight( 26 )
        self.__execStatement.editTextChanged.connect( self.__execStatementChanged )
        self.__execStatement.enterClicked.connect( self.__onEnterInExec )
        self.__execButton = QPushButton( "Exec" )
        # self.__execButton.setFocusPolicy( Qt.NoFocus )
        self.__execButton.setEnabled( False )
        self.__execButton.clicked.connect( self.__onExec )

        self.__evalStatement = CDMComboBox( True )
        self.__evalStatement.setSizePolicy( QSizePolicy.Expanding,
                                            QSizePolicy.Expanding )
        self.__evalStatement.lineEdit().setToolTip(
                                "Expression to be evaluated" )
        self.__evalStatement.setFixedHeight( 26 )
        self.__evalStatement.editTextChanged.connect( self.__evalStatementChanged )
        self.__evalStatement.enterClicked.connect( self.__onEnterInEval )
        self.__evalButton = QPushButton( "Eval" )
        # self.__evalButton.setFocusPolicy( Qt.NoFocus )
        self.__evalButton.setEnabled( False )
        self.__evalButton.clicked.connect( self.__onEval )

        headerLayout = QHBoxLayout()
        headerLayout.setContentsMargins( 0, 0, 0, 0 )
        headerLayout.setSpacing( 0 )
        headerLayout.addSpacerItem( fixedSpacer )
        headerLayout.addWidget( self.__headerLabel )
        headerLayout.addSpacerItem( expandingSpacer )
        headerLayout.addWidget( self.__mcfButton )
        headerLayout.addSpacerItem( fixedSpacer1 )
        headerLayout.addWidget( self.__globalAndLocalButton )
        headerLayout.addWidget( self.__localOnlyButton )
        headerLayout.addWidget( self.__globalOnlyButton )
        headerFrame.setLayout( headerLayout )

        execEvalLayout = QGridLayout()
        execEvalLayout.setContentsMargins( 1, 1, 1, 1 )
        execEvalLayout.setSpacing( 1 )
        execEvalLayout.addWidget( self.__execStatement, 0, 0 )
        execEvalLayout.addWidget( self.__execButton, 0, 1 )
        execEvalLayout.addWidget( self.__evalStatement, 1, 0 )
        execEvalLayout.addWidget( self.__evalButton, 1, 1 )

        verticalLayout.addWidget( headerFrame )
        verticalLayout.addWidget( self.__browser )
        verticalLayout.addLayout( execEvalLayout )

        return
Exemple #11
0
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.projectChanged.connect( self.__onProjectChanged )
        self.connect( GlobalData().project, SIGNAL( 'projectAboutToUnload' ),
                      self.__onProjectAboutToUnload )
        self.connect( self.bpointsList,
                      SIGNAL( "selectionChanged" ),
                      self.__onSelectionChanged )
        self.connect( bpointsModel,
                      SIGNAL( 'BreakpoinsChanged' ),
                      self.__onModelChanged )
        return

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

    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.setFrameStyle( QFrame.StyledPanel )
        self.headerFrame.setAutoFillBackground( True )
        headerPalette = self.headerFrame.palette()
        headerBackground = headerPalette.color( QPalette.Background )
        headerBackground.setRgb( min( headerBackground.red() + 30, 255 ),
                                 min( headerBackground.green() + 30, 255 ),
                                 min( headerBackground.blue() + 30, 255 ) )
        headerPalette.setColor( QPalette.Background, headerBackground )
        self.headerFrame.setPalette( headerPalette )
        self.headerFrame.setFixedHeight( 24 )

        self.__breakpointLabel = QLabel( "Breakpoints" )

        fixedSpacer = QSpacerItem( 3, 3 )

        headerLayout = QHBoxLayout()
        headerLayout.setContentsMargins( 0, 0, 0, 0 )
        headerLayout.addSpacerItem( fixedSpacer )
        headerLayout.addWidget( self.__breakpointLabel )
        self.headerFrame.setLayout( headerLayout )

        self.bpointsList = BreakPointView( self, bpointsModel )

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

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

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

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

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

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

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

        self.__delAllButton = QAction(
            PixmapCache().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 )
        return

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

    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" )
        return

    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 bp in bpoints:
            newBpoint = Breakpoint()
            try:
                if not newBpoint.deserialize( bp ):
                    # 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." )
        return

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

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

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

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

    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 )
        return

    def __onEnableDisable( self ):
        " Triggered when a breakpoint should be enabled/disabled "
        if self.__currentItem is None:
            return

        if self.__currentItem.isEnabled():
            self.bpointsList.disableBreak()
        else:
            self.bpointsList.enableBreak()
        return

    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()
        return

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

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

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

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

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

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

        self.__serializeBreakpoints()
        return
Exemple #12
0
class ThreadsViewer( QWidget ):
    " Implements the threads viewer for a debugger "

    def __init__( self, debugger, parent = None ):
        QWidget.__init__( self, parent )

        self.__debugger = debugger
        self.__createLayout()

        if Settings().showThreadViewer == False:
            self.__onShowHide( True )
        return

    def __createLayout( self ):
        " Creates the widget layout "

        verticalLayout = QVBoxLayout( self )
        verticalLayout.setContentsMargins( 0, 0, 0, 0 )
        verticalLayout.setSpacing( 0 )

        self.headerFrame = QFrame()
        self.headerFrame.setFrameStyle( QFrame.StyledPanel )
        self.headerFrame.setAutoFillBackground( True )
        headerPalette = self.headerFrame.palette()
        headerBackground = headerPalette.color( QPalette.Background )
        headerBackground.setRgb( min( headerBackground.red() + 30, 255 ),
                                 min( headerBackground.green() + 30, 255 ),
                                 min( headerBackground.blue() + 30, 255 ) )
        headerPalette.setColor( QPalette.Background, headerBackground )
        self.headerFrame.setPalette( headerPalette )
        self.headerFrame.setFixedHeight( 24 )

        self.__threadsLabel = QLabel( "Threads" )

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

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

        headerLayout = QHBoxLayout()
        headerLayout.setContentsMargins( 0, 0, 0, 0 )
        headerLayout.addSpacerItem( fixedSpacer )
        headerLayout.addWidget( self.__threadsLabel )
        headerLayout.addSpacerItem( expandingSpacer )
        headerLayout.addWidget( self.__showHideButton )
        self.headerFrame.setLayout( headerLayout )

        self.__threadsList = QTreeWidget()
        self.__threadsList.setSortingEnabled( False )
        # I might not need that because of two reasons:
        # - the window has no focus
        # - the window has custom current indicator
        # self.__threadsList.setAlternatingRowColors( True )
        self.__threadsList.setRootIsDecorated( False )
        self.__threadsList.setItemsExpandable( False )
        self.__threadsList.setUniformRowHeights( True )
        self.__threadsList.setSelectionMode( QAbstractItemView.NoSelection )
        self.__threadsList.setSelectionBehavior( QAbstractItemView.SelectRows )
        self.__threadsList.setItemDelegate( NoOutlineHeightDelegate( 4 ) )
        self.__threadsList.setFocusPolicy( Qt.NoFocus )

        self.__threadsList.itemClicked.connect( self.__onThreadClicked )
        self.__threadsList.setHeaderLabels( [ "", "Name", "State", "TID" ] )

        verticalLayout.addWidget( self.headerFrame )
        verticalLayout.addWidget( self.__threadsList )
        return

    def __onShowHide( self, startup = False ):
        " Triggered when show/hide button is clicked "
        if startup or self.__threadsList.isVisible():
            self.__threadsList.setVisible( False )
            self.__showHideButton.setIcon( PixmapCache().getIcon( 'more.png' ) )
            self.__showHideButton.setToolTip( "Show threads list" )

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

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

            Settings().showThreadViewer = False
        else:
            self.__threadsList.setVisible( True )
            self.__showHideButton.setIcon( PixmapCache().getIcon( 'less.png' ) )
            self.__showHideButton.setToolTip( "Hide threads list" )

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

            Settings().showThreadViewer = True
        return

    def __resizeColumns( self ):
        " Resize the files list columns "
        self.__threadsList.header().setStretchLastSection( True )
        self.__threadsList.header().resizeSections(
                                    QHeaderView.ResizeToContents )
        self.__threadsList.header().resizeSection( 0, 22 )
        self.__threadsList.header().setResizeMode( 0, QHeaderView.Fixed )
        return

    def clear( self ):
        " Clears the content "
        self.__threadsList.clear()
        self.__threadsLabel.setText( "Threads" )
        return

    def populate( self, currentThreadID, threadList ):
        " Populates the thread list from the client "
        self.clear()
        for thread in threadList:
            if thread[ 'broken' ]:
                state = "Waiting at breakpoint"
            else:
                state = "Running"
            item = ThreadItem( thread[ 'id' ], thread[ 'name' ], state )
            if thread[ 'id' ] == currentThreadID:
                item.setCurrent( True )
            self.__threadsList.addTopLevelItem( item )

        self.__resizeColumns()
        self.__threadsLabel.setText( "Threads (total: " +
                                     str( len( threadList ) ) + ")" )
        return

    def switchControl( self, isInIDE ):
        " Switches the UI depending where the control flow is "
        self.__threadsList.setEnabled( isInIDE )
        return

    def __onThreadClicked( self, item, column ):
        " Triggered when a thread is clicked "
        if item.isCurrent():
            return

        for index in xrange( self.__threadsList.topLevelItemCount() ):
            listItem = self.__threadsList.topLevelItem( index )
            if listItem.isCurrent():
                listItem.setCurrent( False )
                break
        item.setCurrent( True )

        self.__debugger.remoteSetThread( item.getTID() )
        return
Exemple #13
0
class WatchPointViewer(QWidget):
    " Implements the watch point viewer for a debugger "

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

        self.__currentItem = None

        self.__createPopupMenu()
        self.__createLayout(wpointModel)

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

        if Settings().showWatchPointViewer == False:
            self.__onShowHide(True)
        return

    def __createPopupMenu(self):
        " Creates the popup menu "
        #        self.__excptMenu = QMenu()
        #        self.__removeMenuItem = self.__excptMenu.addAction(
        #                    "Remove from ignore list", self.__onRemoveFromIgnore )
        return

    def __createLayout(self, wpointModel):
        " Creates the widget layout "

        verticalLayout = QVBoxLayout(self)
        verticalLayout.setContentsMargins(0, 0, 0, 0)
        verticalLayout.setSpacing(0)

        self.headerFrame = QFrame()
        self.headerFrame.setFrameStyle(QFrame.StyledPanel)
        self.headerFrame.setAutoFillBackground(True)
        headerPalette = self.headerFrame.palette()
        headerBackground = headerPalette.color(QPalette.Background)
        headerBackground.setRgb(
            min(headerBackground.red() + 30, 255),
            min(headerBackground.green() + 30, 255),
            min(headerBackground.blue() + 30, 255),
        )
        headerPalette.setColor(QPalette.Background, headerBackground)
        self.headerFrame.setPalette(headerPalette)
        self.headerFrame.setFixedHeight(24)

        self.__watchpointLabel = QLabel("Watchpoints")

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

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

        headerLayout = QHBoxLayout()
        headerLayout.setContentsMargins(1, 1, 1, 1)
        headerLayout.addSpacerItem(fixedSpacer)
        headerLayout.addWidget(self.__watchpointLabel)
        headerLayout.addSpacerItem(expandingSpacer)
        headerLayout.addWidget(self.__showHideButton)
        self.headerFrame.setLayout(headerLayout)

        self.__wpointsList = WatchPointView(self, wpointModel)

        self.__enableButton = QToolButton()
        self.__enableButton.setIcon(PixmapCache().getIcon("add.png"))
        self.__enableButton.setFixedSize(24, 24)
        self.__enableButton.setToolTip("Enable/disable the watchpoint")
        self.__enableButton.setFocusPolicy(Qt.NoFocus)
        self.__enableButton.setEnabled(False)
        self.__enableButton.clicked.connect(self.__onEnableDisable)

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

        self.__jumpToCodeButton = QToolButton()
        self.__jumpToCodeButton.setIcon(PixmapCache().getIcon("gotoline.png"))
        self.__jumpToCodeButton.setFixedSize(24, 24)
        self.__jumpToCodeButton.setToolTip("Jump to the code")
        self.__jumpToCodeButton.setFocusPolicy(Qt.NoFocus)
        self.__jumpToCodeButton.setEnabled(False)
        self.__jumpToCodeButton.clicked.connect(self.__onJumpToCode)

        toolbarLayout = QHBoxLayout()
        toolbarLayout.addWidget(self.__enableButton)
        toolbarLayout.addSpacerItem(expandingSpacer)
        toolbarLayout.addWidget(self.__jumpToCodeButton)

        self.connect(self.__wpointsList, SIGNAL("itemSelectionChanged()"), self.__onSelectionChanged)

        verticalLayout.addWidget(self.headerFrame)
        verticalLayout.addLayout(toolbarLayout)
        verticalLayout.addWidget(self.__wpointsList)
        return

    def clear(self):
        " Clears the content "
        #        self.__wpointsList.clear()
        self.__updateTitle()
        self.__jumpToCodeButton.setEnabled(False)
        self.__currentItem = None
        return

    def __onJumpToCode(self):
        " Jumps to the corresponding source code line "
        return

    def __onShowHide(self, startup=False):
        " Triggered when show/hide button is clicked "
        if startup or self.__wpointsList.isVisible():
            self.__wpointsList.setVisible(False)
            self.__enableButton.setVisible(False)
            self.__jumpToCodeButton.setVisible(False)
            self.__showHideButton.setIcon(PixmapCache().getIcon("more.png"))
            self.__showHideButton.setToolTip("Show watchpoints list")

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

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

            Settings().showWatchPointViewer = False
        else:
            self.__wpointsList.setVisible(True)
            self.__enableButton.setVisible(True)
            self.__jumpToCodeButton.setVisible(True)
            self.__showHideButton.setIcon(PixmapCache().getIcon("less.png"))
            self.__showHideButton.setToolTip("Hide watchpoints list")

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

            Settings().showWatchPointViewer = True
        return

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

    def __updateTitle(self):
        " Updates the section title "
        count = self.getTotalCount()
        if count == 0:
            self.__watchpointLabel.setText("Watchpoints")
        else:
            self.__watchpointLabel.setText("Watchpoints (total: " + str(count) + ")")
        return

    def getTotalCount(self):
        " Provides the total number of watch points "
        count = 0
        return count

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

    def __onEnableDisable(self):
        " Triggered when a breakpoint should be enabled/disabled "
        return
Exemple #14
0
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.projectChanged.connect(self.__onProjectChanged)
        self.connect(GlobalData().project, SIGNAL('projectAboutToUnload'),
                     self.__onProjectAboutToUnload)
        self.connect(self.bpointsList, SIGNAL("selectionChanged"),
                     self.__onSelectionChanged)
        self.connect(bpointsModel, SIGNAL('BreakpoinsChanged'),
                     self.__onModelChanged)
        return

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

    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.setFrameStyle(QFrame.StyledPanel)
        self.headerFrame.setAutoFillBackground(True)
        headerPalette = self.headerFrame.palette()
        headerBackground = headerPalette.color(QPalette.Background)
        headerBackground.setRgb(min(headerBackground.red() + 30, 255),
                                min(headerBackground.green() + 30, 255),
                                min(headerBackground.blue() + 30, 255))
        headerPalette.setColor(QPalette.Background, headerBackground)
        self.headerFrame.setPalette(headerPalette)
        self.headerFrame.setFixedHeight(24)

        self.__breakpointLabel = QLabel("Breakpoints")

        fixedSpacer = QSpacerItem(3, 3)

        headerLayout = QHBoxLayout()
        headerLayout.setContentsMargins(0, 0, 0, 0)
        headerLayout.addSpacerItem(fixedSpacer)
        headerLayout.addWidget(self.__breakpointLabel)
        self.headerFrame.setLayout(headerLayout)

        self.bpointsList = BreakPointView(self, bpointsModel)

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

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

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

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

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

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

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

        self.__delAllButton = QAction(PixmapCache().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)
        return

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

    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")
        return

    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 bp in bpoints:
            newBpoint = Breakpoint()
            try:
                if not newBpoint.deserialize(bp):
                    # 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.")
        return

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

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

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

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

    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)
        return

    def __onEnableDisable(self):
        " Triggered when a breakpoint should be enabled/disabled "
        if self.__currentItem is None:
            return

        if self.__currentItem.isEnabled():
            self.bpointsList.disableBreak()
        else:
            self.bpointsList.enableBreak()
        return

    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()
        return

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

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

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

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

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

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

        self.__serializeBreakpoints()
        return
Exemple #15
0
class StackViewer(QWidget):
    " Implements the stack viewer for a debugger "

    def __init__(self, debugger, parent=None):
        QWidget.__init__(self, parent)

        self.__debugger = debugger
        self.currentStack = None
        self.currentFrame = 0
        self.__createPopupMenu()
        self.__createLayout()

        if Settings().showStackViewer == False:
            self.__onShowHide(True)
        return

    def __createPopupMenu(self):
        " Creates the popup menu "
        self.__framesMenu = QMenu()
        self.__setCurrentMenuItem = self.__framesMenu.addAction(
            "Set current (single click)", self.__onSetCurrent)
        self.__jumpMenuItem = self.__framesMenu.addAction(
            "Set current and jump to the source (double click)",
            self.__onSetCurrentAndJump)
        return

    def __createLayout(self):
        " Creates the widget layout "

        verticalLayout = QVBoxLayout(self)
        verticalLayout.setContentsMargins(0, 0, 0, 0)
        verticalLayout.setSpacing(0)

        self.headerFrame = QFrame()
        self.headerFrame.setFrameStyle(QFrame.StyledPanel)
        self.headerFrame.setAutoFillBackground(True)
        headerPalette = self.headerFrame.palette()
        headerBackground = headerPalette.color(QPalette.Background)
        headerBackground.setRgb(min(headerBackground.red() + 30, 255),
                                min(headerBackground.green() + 30, 255),
                                min(headerBackground.blue() + 30, 255))
        headerPalette.setColor(QPalette.Background, headerBackground)
        self.headerFrame.setPalette(headerPalette)
        self.headerFrame.setFixedHeight(24)

        self.__stackLabel = QLabel("Stack")

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

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

        headerLayout = QHBoxLayout()
        headerLayout.setContentsMargins(0, 0, 0, 0)
        headerLayout.addSpacerItem(fixedSpacer)
        headerLayout.addWidget(self.__stackLabel)
        headerLayout.addSpacerItem(expandingSpacer)
        headerLayout.addWidget(self.__showHideButton)
        self.headerFrame.setLayout(headerLayout)

        self.__framesList = QTreeWidget(self)
        self.__framesList.setSortingEnabled(False)
        # I might not need that because of two reasons:
        # - the window has no focus
        # - the window has custom current indicator
        # self.__framesList.setAlternatingRowColors( True )
        self.__framesList.setRootIsDecorated(False)
        self.__framesList.setItemsExpandable(False)
        self.__framesList.setUniformRowHeights(True)
        self.__framesList.setSelectionMode(QAbstractItemView.NoSelection)
        self.__framesList.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.__framesList.setItemDelegate(NoOutlineHeightDelegate(4))
        self.__framesList.setFocusPolicy(Qt.NoFocus)
        self.__framesList.setContextMenuPolicy(Qt.CustomContextMenu)

        self.__framesList.itemClicked.connect(self.__onFrameClicked)
        self.__framesList.itemDoubleClicked.connect(
            self.__onFrameDoubleClicked)
        self.__framesList.customContextMenuRequested.connect(
            self.__showContextMenu)

        self.__framesList.setHeaderLabels(
            ["", "File:line", "Function", "Full path"])

        verticalLayout.addWidget(self.headerFrame)
        verticalLayout.addWidget(self.__framesList)
        return

    def __onShowHide(self, startup=False):
        " Triggered when show/hide button is clicked "
        if startup or self.__framesList.isVisible():
            self.__framesList.setVisible(False)
            self.__showHideButton.setIcon(PixmapCache().getIcon('more.png'))
            self.__showHideButton.setToolTip("Show frames list")

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

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

            Settings().showStackViewer = False
        else:
            self.__framesList.setVisible(True)
            self.__showHideButton.setIcon(PixmapCache().getIcon('less.png'))
            self.__showHideButton.setToolTip("Hide frames list")

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

            Settings().showStackViewer = True
        return

    def clear(self):
        " Clears the content "
        self.__framesList.clear()
        self.currentStack = None
        self.__stackLabel.setText("Stack")
        return

    def __resizeColumns(self):
        " Resize the files list columns "
        self.__framesList.header().setStretchLastSection(True)
        self.__framesList.header().resizeSections(QHeaderView.ResizeToContents)
        self.__framesList.header().resizeSection(0, 22)
        self.__framesList.header().setResizeMode(0, QHeaderView.Fixed)
        return

    def populate(self, stack):
        " Sets the new call stack and selects the first item in it "
        self.clear()

        self.currentStack = stack
        self.currentFrame = 0
        frameNumber = 0
        for s in stack:
            if len(s) == 2:
                # This is when an exception comes
                funcName = ""
            else:
                funcName = s[2]
            item = StackFrameItem(s[0], s[1], funcName, frameNumber)
            self.__framesList.addTopLevelItem(item)
            frameNumber += 1
        self.__resizeColumns()
        self.__framesList.topLevelItem(0).setCurrent(True)
        self.__stackLabel.setText("Stack (total: " + str(len(stack)) + ")")
        return

    def getFrameNumber(self):
        " Provides the current frame number "
        return self.currentFrame

    def __onFrameClicked(self, item, column):
        " Triggered when a frame is clicked "
        if item.isCurrent():
            return

        # Hide the current indicator
        self.__framesList.topLevelItem(self.currentFrame).setCurrent(False)

        # Show the new indicator
        self.currentFrame = item.getFrameNumber()
        for index in xrange(self.__framesList.topLevelItemCount()):
            item = self.__framesList.topLevelItem(index)
            if item.getFrameNumber() == self.currentFrame:
                item.setCurrent(True)
        self.__debugger.remoteClientVariables(1, self.currentFrame)  # globals
        self.__debugger.remoteClientVariables(0, self.currentFrame)  # locals
        return

    def __onFrameDoubleClicked(self, item, column):
        " Triggered when a frame is double clicked "
        # The frame has been switched already because the double click
        # signal always comes after the single click one
        fileName = item.getFilename()
        lineNumber = item.getLineNumber()

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

    def __showContextMenu(self, coord):
        " Shows the frames list context menu "
        self.__contextItem = self.__framesList.itemAt(coord)
        if self.__contextItem is not None:
            self.__setCurrentMenuItem.setEnabled(
                not self.__contextItem.isCurrent())
            self.__framesMenu.popup(QCursor.pos())
        return

    def __onSetCurrent(self):
        " Context menu item handler "
        self.__onFrameClicked(self.__contextItem, 0)
        return

    def __onSetCurrentAndJump(self):
        " Context menu item handler "
        self.__onFrameClicked(self.__contextItem, 0)
        self.__onFrameDoubleClicked(self.__contextItem, 0)
        return

    def switchControl(self, isInIDE):
        " Switches the UI depending where the control flow is "
        self.__framesList.setEnabled(isInIDE)
        return
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.projectChanged.connect( self.__onProjectChanged )

        if Settings().showIgnoredExcViewer == False:
            self.__onShowHide( True )
        return

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

    def __createLayout( self ):
        " Creates the widget layout "

        verticalLayout = QVBoxLayout( self )
        verticalLayout.setContentsMargins( 0, 0, 0, 0 )
        verticalLayout.setSpacing( 0 )

        self.headerFrame = QFrame()
        self.headerFrame.setFrameStyle( QFrame.StyledPanel )
        self.headerFrame.setAutoFillBackground( True )
        headerPalette = self.headerFrame.palette()
        headerBackground = headerPalette.color( QPalette.Background )
        headerBackground.setRgb( min( headerBackground.red() + 30, 255 ),
                                 min( headerBackground.green() + 30, 255 ),
                                 min( headerBackground.blue() + 30, 255 ) )
        headerPalette.setColor( QPalette.Background, headerBackground )
        self.headerFrame.setPalette( headerPalette )
        self.headerFrame.setFixedHeight( 24 )

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

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

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

        headerLayout = QHBoxLayout()
        headerLayout.setContentsMargins( 1, 1, 1, 1 )
        headerLayout.addSpacerItem( fixedSpacer )
        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(
            PixmapCache().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(
            PixmapCache().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 )
        return

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

    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( PixmapCache().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( PixmapCache().getIcon( 'less.png' ) )
            self.__showHideButton.setToolTip( "Hide ignored exceptions list" )

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

            Settings().showIgnoredExcViewer = True
        return

    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 )
        return

    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() )
        return

    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 )
        return

    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.ignoredExcpt )
        else:
            self.__ignored = list( Settings().ignoredExceptions )

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

    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 )
        return

    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()
        return


    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()
        return

    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( [] )
        return

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