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 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
def __createLayout(self, pathsToCommit, pathsToIgnore): " Creates the dialog layout " self.resize(640, 480) self.setSizeGripEnabled(True) vboxLayout = QVBoxLayout(self) # Paths to commit part commitHeaderFrame = QFrame() commitHeaderFrame.setFrameStyle(QFrame.StyledPanel) commitHeaderFrame.setAutoFillBackground(True) self.__setLightPalette(commitHeaderFrame) commitHeaderFrame.setFixedHeight(24) expandingCommitSpacer = QSpacerItem(10, 10, QSizePolicy.Expanding) self.__selectAllButton = QToolButton() self.__selectAllButton.setAutoRaise(True) self.__selectAllButton.setIcon( PixmapCache().getIcon(pluginHomeDir + 'svnselectall.png')) self.__selectAllButton.setFixedSize(20, 20) self.__selectAllButton.setToolTip("Select all") self.__selectAllButton.setFocusPolicy(Qt.NoFocus) self.__selectAllButton.clicked.connect(self.__onSelectAll) commitHeaderLayout = QHBoxLayout() commitHeaderLayout.setContentsMargins(3, 0, 0, 0) commitHeaderLayout.addWidget( QLabel("Paths to commit (total: " + str(len(pathsToCommit)) + ")")) commitHeaderLayout.addSpacerItem(expandingCommitSpacer) commitHeaderLayout.addWidget(self.__selectAllButton) commitHeaderFrame.setLayout(commitHeaderLayout) vboxLayout.addWidget(commitHeaderFrame) self.__pathToCommitView = QTreeWidget() self.__configTable(self.__pathToCommitView) self.__pathToCommitHeader = QTreeWidgetItem(["", "Path", "Status", ""]) self.__pathToCommitView.setHeaderItem(self.__pathToCommitHeader) self.__pathToCommitView.header().setSortIndicator( PATH_COL, Qt.AscendingOrder) self.__pathToCommitView.itemChanged.connect(self.__onCommitPathChanged) vboxLayout.addWidget(self.__pathToCommitView) # Paths to ignore part headerFrame = QFrame() headerFrame.setFrameStyle(QFrame.StyledPanel) headerFrame.setAutoFillBackground(True) self.__setLightPalette(headerFrame) headerFrame.setFixedHeight(24) ignoreLabel = QLabel("Ignored paths (total: " + str(len(pathsToIgnore)) + ")") expandingSpacer = QSpacerItem(10, 10, QSizePolicy.Expanding) self.__showHideIgnoredButton = QToolButton() self.__showHideIgnoredButton.setAutoRaise(True) self.__showHideIgnoredButton.setIcon(PixmapCache().getIcon('less.png')) self.__showHideIgnoredButton.setFixedSize(20, 20) self.__showHideIgnoredButton.setToolTip("Show ignored path list") self.__showHideIgnoredButton.setFocusPolicy(Qt.NoFocus) self.__showHideIgnoredButton.clicked.connect(self.__onShowHideIgnored) ignoredHeaderLayout = QHBoxLayout() ignoredHeaderLayout.setContentsMargins(3, 0, 0, 0) ignoredHeaderLayout.addWidget(ignoreLabel) ignoredHeaderLayout.addSpacerItem(expandingSpacer) ignoredHeaderLayout.addWidget(self.__showHideIgnoredButton) headerFrame.setLayout(ignoredHeaderLayout) vboxLayout.addWidget(headerFrame) self.__pathToIgnoreView = QTreeWidget() self.__configTable(self.__pathToIgnoreView) self.__pathToIgnoreView.setVisible(False) pathToIgnoreHeader = QTreeWidgetItem(["Path", "Status"]) self.__pathToIgnoreView.setHeaderItem(pathToIgnoreHeader) self.__pathToIgnoreView.header().setSortIndicator(0, Qt.AscendingOrder) vboxLayout.addWidget(self.__pathToIgnoreView) # Message part vboxLayout.addWidget(QLabel("Message")) self.__message = QTextEdit() self.__message.setAcceptRichText(False) metrics = QFontMetrics(self.__message.font()) rect = metrics.boundingRect("X") self.__message.setFixedHeight(rect.height() * 4 + 5) vboxLayout.addWidget(self.__message) # Diff part diffHeaderFrame = QFrame() diffHeaderFrame.setFrameStyle(QFrame.StyledPanel) diffHeaderFrame.setAutoFillBackground(True) self.__setLightPalette(diffHeaderFrame) diffHeaderFrame.setFixedHeight(24) diffLabel = QLabel("Diff") diffExpandingSpacer = QSpacerItem(10, 10, QSizePolicy.Expanding) self.__showHideDiffButton = QToolButton() self.__showHideDiffButton.setAutoRaise(True) self.__showHideDiffButton.setIcon(PixmapCache().getIcon('less.png')) self.__showHideDiffButton.setFixedSize(20, 20) self.__showHideDiffButton.setToolTip("Show diff") self.__showHideDiffButton.setFocusPolicy(Qt.NoFocus) self.__showHideDiffButton.clicked.connect(self.__onShowHideDiff) diffLayout = QHBoxLayout() diffLayout.setContentsMargins(3, 0, 0, 0) diffLayout.addWidget(diffLabel) diffLayout.addSpacerItem(diffExpandingSpacer) diffLayout.addWidget(self.__showHideDiffButton) diffHeaderFrame.setLayout(diffLayout) self.__diffViewer = DiffTabWidget() self.__diffViewer.setHTML(self.NODIFF) self.__diffViewer.setVisible(False) vboxLayout.addWidget(diffHeaderFrame) vboxLayout.addWidget(self.__diffViewer) # Buttons at the bottom buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.__OKButton = buttonBox.button(QDialogButtonBox.Ok) self.__OKButton.setText("Commit") buttonBox.button(QDialogButtonBox.Cancel).setDefault(True) buttonBox.accepted.connect(self.userAccept) buttonBox.rejected.connect(self.close) vboxLayout.addWidget(buttonBox) return
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 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
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
def __createLayout( self ): " Creates the dialog layout " self.resize( 640, 480 ) self.setSizeGripEnabled( True ) vboxLayout = QVBoxLayout( self ) # Revisions to compare compareGroupbox = QGroupBox( self ) compareGroupbox.setTitle( "Revisions to compare" ) sizePolicy = QSizePolicy( QSizePolicy.Expanding, QSizePolicy.Preferred ) sizePolicy.setHorizontalStretch( 0 ) sizePolicy.setVerticalStretch( 0 ) sizePolicy.setHeightForWidth( compareGroupbox.sizePolicy().hasHeightForWidth() ) compareGroupbox.setSizePolicy( sizePolicy ) revisionLayout = QHBoxLayout( compareGroupbox ) self.__lhsRevisionLabel = QLabel() self.__lhsRevisionLabel.setFrameStyle( QFrame.StyledPanel ) self.__lhsResetButton = QToolButton() self.__lhsResetButton.setIcon( PixmapCache().getIcon( pluginHomeDir + 'svnclearrev.png' ) ) self.__lhsResetButton.setFocusPolicy( Qt.NoFocus ) self.__lhsResetButton.setEnabled( False ) self.__lhsResetButton.setToolTip( "Reset revision to compare" ) self.__lhsResetButton.clicked.connect( self.__onLHSReset ) self.__rhsRevisionLabel = QLabel() self.__rhsRevisionLabel.setFrameStyle( QFrame.StyledPanel ) self.__rhsResetButton = QToolButton() self.__rhsResetButton.setIcon( PixmapCache().getIcon( pluginHomeDir + 'svnclearrev.png' ) ) self.__rhsResetButton.setFocusPolicy( Qt.NoFocus ) self.__rhsResetButton.setEnabled( False ) self.__rhsResetButton.setToolTip( "Reset revision to compare" ) self.__rhsResetButton.clicked.connect( self.__onRHSReset ) lhsLayout = QHBoxLayout() lhsLayout.addWidget( self.__lhsRevisionLabel ) lhsLayout.addWidget( self.__lhsResetButton ) rhsLayout = QHBoxLayout() rhsLayout.addWidget( self.__rhsRevisionLabel ) rhsLayout.addWidget( self.__rhsResetButton ) bothLayout = QVBoxLayout() bothLayout.addLayout( lhsLayout ) bothLayout.addLayout( rhsLayout ) revisionLayout.addLayout( bothLayout ) self.__diffButton = QToolButton() self.__diffButton.setText( "Diff" ) self.__diffButton.setFocusPolicy( Qt.NoFocus ) self.__diffButton.setEnabled( False ) self.__diffButton.clicked.connect( self.__onDiff ) revisionLayout.addWidget( self.__diffButton ) vboxLayout.addWidget( compareGroupbox ) # Log table logHeaderFrame = QFrame() logHeaderFrame.setFrameStyle( QFrame.StyledPanel ) logHeaderFrame.setAutoFillBackground( True ) self.__setLightPalette( logHeaderFrame ) logHeaderFrame.setFixedHeight( 24 ) logHeaderLayout = QHBoxLayout() logHeaderLayout.setContentsMargins( 3, 0, 0, 0 ) logHeaderLayout.addWidget( QLabel( "Subversion log of " + self.__path ) ) logHeaderFrame.setLayout( logHeaderLayout ) vboxLayout.addWidget( logHeaderFrame ) self.__logView = QTreeWidget() self.__logView.setAlternatingRowColors( True ) self.__logView.setRootIsDecorated( False ) self.__logView.setItemsExpandable( False ) self.__logView.setSortingEnabled( True ) self.__logView.setItemDelegate( NoOutlineHeightDelegate( 4 ) ) self.__logViewHeader = QTreeWidgetItem( [ "", "", "Revision", "Date", "Author", "Message" ] ) self.__logView.setHeaderItem( self.__logViewHeader ) self.__logView.header().setSortIndicator( REVISION_COL, Qt.AscendingOrder ) self.__logView.itemChanged.connect( self.__onLogViewChanged ) vboxLayout.addWidget( self.__logView ) # Diff part diffHeaderFrame = QFrame() diffHeaderFrame.setFrameStyle( QFrame.StyledPanel ) diffHeaderFrame.setAutoFillBackground( True ) self.__setLightPalette( diffHeaderFrame ) diffHeaderFrame.setFixedHeight( 24 ) diffLabel = QLabel( "Diff" ) diffExpandingSpacer = QSpacerItem( 10, 10, QSizePolicy.Expanding ) self.__showHideDiffButton = QToolButton() self.__showHideDiffButton.setAutoRaise( True ) self.__showHideDiffButton.setIcon( PixmapCache().getIcon( 'less.png' ) ) self.__showHideDiffButton.setFixedSize( 20, 20 ) self.__showHideDiffButton.setToolTip( "Show diff" ) self.__showHideDiffButton.setFocusPolicy( Qt.NoFocus ) self.__showHideDiffButton.clicked.connect( self.__onShowHideDiff ) diffLayout = QHBoxLayout() diffLayout.setContentsMargins( 3, 0, 0, 0 ) diffLayout.addWidget( diffLabel ) diffLayout.addSpacerItem( diffExpandingSpacer ) diffLayout.addWidget( self.__showHideDiffButton ) diffHeaderFrame.setLayout( diffLayout ) self.__diffViewer = DiffTabWidget() self.__diffViewer.setHTML( self.NODIFF ) self.__diffViewer.setVisible( False ) vboxLayout.addWidget( diffHeaderFrame ) vboxLayout.addWidget( self.__diffViewer ) # Buttons at the bottom buttonBox = QDialogButtonBox( self ) buttonBox.setOrientation( Qt.Horizontal ) buttonBox.setStandardButtons( QDialogButtonBox.Ok ) buttonBox.button( QDialogButtonBox.Ok ).setDefault( True ) buttonBox.accepted.connect( self.close ) vboxLayout.addWidget( buttonBox ) return
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
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
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 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
def __createLayout( self, pathsToCommit, pathsToIgnore ): " Creates the dialog layout " self.resize( 640, 480 ) self.setSizeGripEnabled( True ) vboxLayout = QVBoxLayout( self ) # Paths to commit part commitHeaderFrame = QFrame() commitHeaderFrame.setFrameStyle( QFrame.StyledPanel ) commitHeaderFrame.setAutoFillBackground( True ) self.__setLightPalette( commitHeaderFrame ) commitHeaderFrame.setFixedHeight( 24 ) expandingCommitSpacer = QSpacerItem( 10, 10, QSizePolicy.Expanding ) self.__selectAllButton = QToolButton() self.__selectAllButton.setAutoRaise( True ) self.__selectAllButton.setIcon( PixmapCache().getIcon( pluginHomeDir + 'svnselectall.png' ) ) self.__selectAllButton.setFixedSize( 20, 20 ) self.__selectAllButton.setToolTip( "Select all" ) self.__selectAllButton.setFocusPolicy( Qt.NoFocus ) self.__selectAllButton.clicked.connect( self.__onSelectAll ) commitHeaderLayout = QHBoxLayout() commitHeaderLayout.setContentsMargins( 3, 0, 0, 0 ) commitHeaderLayout.addWidget( QLabel( "Paths to commit (total: " + str( len( pathsToCommit ) ) + ")" ) ) commitHeaderLayout.addSpacerItem( expandingCommitSpacer ) commitHeaderLayout.addWidget( self.__selectAllButton ) commitHeaderFrame.setLayout( commitHeaderLayout ) vboxLayout.addWidget( commitHeaderFrame ) self.__pathToCommitView = QTreeWidget() self.__configTable( self.__pathToCommitView ) self.__pathToCommitHeader = QTreeWidgetItem( [ "", "Path", "Status", "" ] ) self.__pathToCommitView.setHeaderItem( self.__pathToCommitHeader ) self.__pathToCommitView.header().setSortIndicator( PATH_COL, Qt.AscendingOrder ) self.__pathToCommitView.itemChanged.connect( self.__onCommitPathChanged ) vboxLayout.addWidget( self.__pathToCommitView ) # Paths to ignore part headerFrame = QFrame() headerFrame.setFrameStyle( QFrame.StyledPanel ) headerFrame.setAutoFillBackground( True ) self.__setLightPalette( headerFrame ) headerFrame.setFixedHeight( 24 ) ignoreLabel = QLabel( "Ignored paths (total: " + str( len( pathsToIgnore ) ) + ")" ) expandingSpacer = QSpacerItem( 10, 10, QSizePolicy.Expanding ) self.__showHideIgnoredButton = QToolButton() self.__showHideIgnoredButton.setAutoRaise( True ) self.__showHideIgnoredButton.setIcon( PixmapCache().getIcon( 'less.png' ) ) self.__showHideIgnoredButton.setFixedSize( 20, 20 ) self.__showHideIgnoredButton.setToolTip( "Show ignored path list" ) self.__showHideIgnoredButton.setFocusPolicy( Qt.NoFocus ) self.__showHideIgnoredButton.clicked.connect( self.__onShowHideIgnored ) ignoredHeaderLayout = QHBoxLayout() ignoredHeaderLayout.setContentsMargins( 3, 0, 0, 0 ) ignoredHeaderLayout.addWidget( ignoreLabel ) ignoredHeaderLayout.addSpacerItem( expandingSpacer ) ignoredHeaderLayout.addWidget( self.__showHideIgnoredButton ) headerFrame.setLayout( ignoredHeaderLayout ) vboxLayout.addWidget( headerFrame ) self.__pathToIgnoreView = QTreeWidget() self.__configTable( self.__pathToIgnoreView ) self.__pathToIgnoreView.setVisible( False ) pathToIgnoreHeader = QTreeWidgetItem( [ "Path", "Status" ] ) self.__pathToIgnoreView.setHeaderItem( pathToIgnoreHeader ) self.__pathToIgnoreView.header().setSortIndicator( 0, Qt.AscendingOrder ) vboxLayout.addWidget( self.__pathToIgnoreView ) # Message part vboxLayout.addWidget( QLabel( "Message" ) ) self.__message = QTextEdit() self.__message.setAcceptRichText( False ) metrics = QFontMetrics( self.__message.font() ) rect = metrics.boundingRect( "X" ) self.__message.setFixedHeight( rect.height() * 4 + 5 ) vboxLayout.addWidget( self.__message ) # Diff part diffHeaderFrame = QFrame() diffHeaderFrame.setFrameStyle( QFrame.StyledPanel ) diffHeaderFrame.setAutoFillBackground( True ) self.__setLightPalette( diffHeaderFrame ) diffHeaderFrame.setFixedHeight( 24 ) diffLabel = QLabel( "Diff" ) diffExpandingSpacer = QSpacerItem( 10, 10, QSizePolicy.Expanding ) self.__showHideDiffButton = QToolButton() self.__showHideDiffButton.setAutoRaise( True ) self.__showHideDiffButton.setIcon( PixmapCache().getIcon( 'less.png' ) ) self.__showHideDiffButton.setFixedSize( 20, 20 ) self.__showHideDiffButton.setToolTip( "Show diff" ) self.__showHideDiffButton.setFocusPolicy( Qt.NoFocus ) self.__showHideDiffButton.clicked.connect( self.__onShowHideDiff ) diffLayout = QHBoxLayout() diffLayout.setContentsMargins( 3, 0, 0, 0 ) diffLayout.addWidget( diffLabel ) diffLayout.addSpacerItem( diffExpandingSpacer ) diffLayout.addWidget( self.__showHideDiffButton ) diffHeaderFrame.setLayout( diffLayout ) self.__diffViewer = DiffTabWidget() self.__diffViewer.setHTML( self.NODIFF ) self.__diffViewer.setVisible( False ) vboxLayout.addWidget( diffHeaderFrame ) vboxLayout.addWidget( self.__diffViewer ) # Buttons at the bottom buttonBox = QDialogButtonBox( self ) buttonBox.setOrientation( Qt.Horizontal ) buttonBox.setStandardButtons( QDialogButtonBox.Ok | QDialogButtonBox.Cancel ) self.__OKButton = buttonBox.button( QDialogButtonBox.Ok ) self.__OKButton.setText( "Commit" ) buttonBox.button( QDialogButtonBox.Cancel ).setDefault( True ) buttonBox.accepted.connect( self.userAccept ) buttonBox.rejected.connect( self.close ) vboxLayout.addWidget( buttonBox ) return
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
class titleFrame(QWidget): __text = "" __icon = None __mainLayout = None __label = None __iconLabel = None __kde = False def __init__(self, text, icon = None, parent = None): QWidget.__init__(self, parent) self.__text = text self.__icon = icon self.__topLayout = QVBoxLayout() self.setLayout(self.__topLayout) try: from PyKDE4.kdeui import KTitleWidget self.__titleWidget = KTitleWidget() self.__topLayout.addWidget(self.__titleWidget) self.__kde = True except: self.__mainFrame = QFrame() self.__topLayout.addWidget(self.__mainFrame) self.__label = QLabel() self.__iconLabel = QLabel() self.__mainLayout = QHBoxLayout() self.init() self.setText(text) if not icon is None: self.setIcon(icon) def init(self): self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) font = QFont() font.setBold(True) font.setItalic(True) self.__label.setFont(font) self.__mainLayout.setAlignment(Qt.AlignVCenter) self.__mainLayout.addWidget(self.__iconLabel) self.__mainLayout.addWidget(self.__label) self.__mainLayout.addStretch(1) self.__mainFrame.setAutoFillBackground(True) self.__mainFrame.setFrameStyle(QFrame.Box) self.__mainFrame.setFrameShadow(QFrame.Sunken) self.__mainFrame.setBackgroundRole(QPalette.Base) self.__mainFrame.setLayout(self.__mainLayout) def setText(self, text): if self.__kde: self.__titleWidget.setText(text) else: self.__label.setText(text) def setIcon(self, icon): if self.__kde: self.__titleWidget.setPixmap(QPixmap(icon)) else: self.__iconLabel.setPixmap(QPixmap(icon))
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
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
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 __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
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 __createLayout(self): " Creates the dialog layout " self.resize(640, 480) self.setSizeGripEnabled(True) vboxLayout = QVBoxLayout(self) # Revisions to compare compareGroupbox = QGroupBox(self) compareGroupbox.setTitle("Revisions to compare") sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( compareGroupbox.sizePolicy().hasHeightForWidth()) compareGroupbox.setSizePolicy(sizePolicy) revisionLayout = QHBoxLayout(compareGroupbox) self.__lhsRevisionLabel = QLabel() self.__lhsRevisionLabel.setFrameStyle(QFrame.StyledPanel) self.__lhsResetButton = QToolButton() self.__lhsResetButton.setIcon(PixmapCache().getIcon(pluginHomeDir + 'svnclearrev.png')) self.__lhsResetButton.setFocusPolicy(Qt.NoFocus) self.__lhsResetButton.setEnabled(False) self.__lhsResetButton.setToolTip("Reset revision to compare") self.__lhsResetButton.clicked.connect(self.__onLHSReset) self.__rhsRevisionLabel = QLabel() self.__rhsRevisionLabel.setFrameStyle(QFrame.StyledPanel) self.__rhsResetButton = QToolButton() self.__rhsResetButton.setIcon(PixmapCache().getIcon(pluginHomeDir + 'svnclearrev.png')) self.__rhsResetButton.setFocusPolicy(Qt.NoFocus) self.__rhsResetButton.setEnabled(False) self.__rhsResetButton.setToolTip("Reset revision to compare") self.__rhsResetButton.clicked.connect(self.__onRHSReset) lhsLayout = QHBoxLayout() lhsLayout.addWidget(self.__lhsRevisionLabel) lhsLayout.addWidget(self.__lhsResetButton) rhsLayout = QHBoxLayout() rhsLayout.addWidget(self.__rhsRevisionLabel) rhsLayout.addWidget(self.__rhsResetButton) bothLayout = QVBoxLayout() bothLayout.addLayout(lhsLayout) bothLayout.addLayout(rhsLayout) revisionLayout.addLayout(bothLayout) self.__diffButton = QToolButton() self.__diffButton.setText("Diff") self.__diffButton.setFocusPolicy(Qt.NoFocus) self.__diffButton.setEnabled(False) self.__diffButton.clicked.connect(self.__onDiff) revisionLayout.addWidget(self.__diffButton) vboxLayout.addWidget(compareGroupbox) # Log table logHeaderFrame = QFrame() logHeaderFrame.setFrameStyle(QFrame.StyledPanel) logHeaderFrame.setAutoFillBackground(True) self.__setLightPalette(logHeaderFrame) logHeaderFrame.setFixedHeight(24) logHeaderLayout = QHBoxLayout() logHeaderLayout.setContentsMargins(3, 0, 0, 0) logHeaderLayout.addWidget(QLabel("Subversion log of " + self.__path)) logHeaderFrame.setLayout(logHeaderLayout) vboxLayout.addWidget(logHeaderFrame) self.__logView = QTreeWidget() self.__logView.setAlternatingRowColors(True) self.__logView.setRootIsDecorated(False) self.__logView.setItemsExpandable(False) self.__logView.setSortingEnabled(True) self.__logView.setItemDelegate(NoOutlineHeightDelegate(4)) self.__logViewHeader = QTreeWidgetItem( ["", "", "Revision", "Date", "Author", "Message"]) self.__logView.setHeaderItem(self.__logViewHeader) self.__logView.header().setSortIndicator(REVISION_COL, Qt.AscendingOrder) self.__logView.itemChanged.connect(self.__onLogViewChanged) vboxLayout.addWidget(self.__logView) # Diff part diffHeaderFrame = QFrame() diffHeaderFrame.setFrameStyle(QFrame.StyledPanel) diffHeaderFrame.setAutoFillBackground(True) self.__setLightPalette(diffHeaderFrame) diffHeaderFrame.setFixedHeight(24) diffLabel = QLabel("Diff") diffExpandingSpacer = QSpacerItem(10, 10, QSizePolicy.Expanding) self.__showHideDiffButton = QToolButton() self.__showHideDiffButton.setAutoRaise(True) self.__showHideDiffButton.setIcon(PixmapCache().getIcon('less.png')) self.__showHideDiffButton.setFixedSize(20, 20) self.__showHideDiffButton.setToolTip("Show diff") self.__showHideDiffButton.setFocusPolicy(Qt.NoFocus) self.__showHideDiffButton.clicked.connect(self.__onShowHideDiff) diffLayout = QHBoxLayout() diffLayout.setContentsMargins(3, 0, 0, 0) diffLayout.addWidget(diffLabel) diffLayout.addSpacerItem(diffExpandingSpacer) diffLayout.addWidget(self.__showHideDiffButton) diffHeaderFrame.setLayout(diffLayout) self.__diffViewer = DiffTabWidget() self.__diffViewer.setHTML(self.NODIFF) self.__diffViewer.setVisible(False) vboxLayout.addWidget(diffHeaderFrame) vboxLayout.addWidget(self.__diffViewer) # Buttons at the bottom buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Ok) buttonBox.button(QDialogButtonBox.Ok).setDefault(True) buttonBox.accepted.connect(self.close) vboxLayout.addWidget(buttonBox) return
class XLoaderWidget(QWidget): """ """ Mode = enum('Spinner', 'Progress') MOVIE = None def __init__( self, parent = None, style='gray' ): super(XLoaderWidget, self).__init__( parent ) # define properties self._currentMode = None self._showSubProgress = False self.setAttribute(Qt.WA_DeleteOnClose) # udpate the palette palette = self.palette() if style == 'white': palette.setColor( palette.Window, QColor(255, 255, 255, 180) ) else: palette.setColor( palette.Window, QColor( 80, 80, 80, 180 ) ) palette.setColor( palette.Base, Qt.gray ) palette.setColor( palette.AlternateBase, Qt.lightGray ) palette.setColor( palette.WindowText, Qt.gray ) self.setPalette(palette) # create the movie label self._movieLabel = QLabel(self) self._movieLabel.setAlignment(Qt.AlignCenter) self._movieLabel.setMovie(XLoaderWidget.getMovie()) self._movieLabel.setPalette(palette) self._smallMovieLabel = QLabel(self) self._smallMovieLabel.setAlignment(Qt.AlignCenter) self._smallMovieLabel.setMovie(XLoaderWidget.getMovie()) self._smallMovieLabel.setPalette(palette) self._smallMovieLabel.hide() # create text label self._messageLabel = QLabel(self) self._messageLabel.setAlignment(Qt.AlignCenter) self._messageLabel.setText('Loading...') self._messageLabel.setPalette(palette) # create primary progress bar self._primaryProgressBar = XLoaderProgressBar(self) self._subProgressBar = XLoaderProgressBar(self) self._primaryProgressBar.setPalette(palette) self._subProgressBar.setPalette(palette) # create the loader widget self._loaderFrame = QFrame(self) self._loaderFrame.setFrameShape(QFrame.Box) self._loaderFrame.setAutoFillBackground(True) self._loaderFrame.setFixedWidth(160) self._loaderFrame.setFixedHeight(60) if style == 'white': palette.setColor(palette.Window, QColor('white')) else: palette.setColor(palette.Window, QColor(85, 85, 85)) self._loaderFrame.setPalette(palette) layout = QVBoxLayout() layout.addWidget(self._movieLabel) layout.addWidget(self._primaryProgressBar) layout.addWidget(self._subProgressBar) layout.addStretch() layout.addWidget(self._messageLabel) self._loaderFrame.setLayout(layout) # set default properties self.setAutoFillBackground(True) # layout the controls layout = QVBoxLayout() layout.addStretch(1) layout.addWidget(self._loaderFrame) layout.addWidget(self._smallMovieLabel) layout.addStretch(1) hlayout = QHBoxLayout() hlayout.addStretch(1) hlayout.addLayout(layout) hlayout.addStretch(1) self.setLayout(hlayout) self.setCurrentMode(XLoaderWidget.Mode.Spinner) # create connections def currentMode( self ): """ Returns the current mode that this loader's in. :return <XLoaderWidget.Mode> """ return self._currentMode def eventFilter( self, object, event ): """ Resizes this widget with the parent when its resize event is triggered. :param object | <QObject> event | <QEvent> :return <bool> | consumed """ if event.type() == event.Resize: self.resize(event.size()) elif event.type() == event.Move: self.move(event.pos()) elif event.type() == event.Close: self.setParent(None) self.deleteLater() return False def increment( self, amount=1): """ Increments the main progress bar by amount. """ self._primaryProgressBar.setValue(self.value() + amount) def incrementSub( self, amount=1): """ Increments the sub-progress bar by amount. """ self._subProgressBar.setValue(self.subValue() + amount) def message( self ): """ Returns the current message being displayed in the loader. :return <str> """ return self._messageLabel.text() def movie(self): """ Returns the movie linked with this loader. :return <QMovie> """ return self._movieLabel.movie() def resize(self, size): """ Handles when the loader is too small for an area. :param event | <QResizeEvent> """ super(XLoaderWidget, self).resize(size) # show small loader if size.width() < self._loaderFrame.width() or \ size.height() < self._loaderFrame.height(): self._loaderFrame.hide() self._smallMovieLabel.show() # show regular loader else: self._loaderFrame.show() self._smallMovieLabel.hide() def subValue( self ): """ Returns the value of the sub progress bar. :return <int> """ return self._subProgressBar.value() def setCurrentMode( self, mode ): """ Sets what mode this loader will be in. :param mode | <XLoaderWidget.Mode> """ if ( mode == self._currentMode ): return self._currentMode = mode ajax = mode == XLoaderWidget.Mode.Spinner self._movieLabel.setVisible(ajax) self._primaryProgressBar.setVisible(not ajax) self._subProgressBar.setVisible(not ajax and self._showSubProgress) def setMessage( self, message ): """ Sets the loading message to display. :param message | <str> """ self._messageLabel.setText(message) def setMovie( self, movie ): """ Sets the movie for this loader to the inputed movie. :param movie | <QMovie> """ self._movieLabel.setMovie(movie) self._smallMovieLabel.setMovie(movie) def setTotal( self, amount ): """ Sets the total amount for the main progress bar. :param amount | <int> """ self._primaryProgressBar.setValue(0) self._primaryProgressBar.setMaximum(amount) if amount: self.setCurrentMode(XLoaderWidget.Mode.Progress) def setSubTotal( self, amount ): """ Sets the total value for the sub progress bar. :param amount | <int> """ self._subProgressBar.setValue(0) self._subProgressBar.setMaximum(amount) if amount: self.setShowSubProgress(True) def setSubValue( self, value ): """ Sets the current value for the sub progress bar. :param value | <int> """ self._subProgressBar.setValue(value) def setShowSubProgress( self, state ): """ Toggles whether or not the sub progress bar should be visible. :param state | <bool> """ ajax = self.currentMode() == XLoaderWidget.Mode.Spinner self._showSubProgress = state self._subProgressBar.setVisible(not ajax and state) def setValue(self, value): """ Sets the current value for the primary progress bar. :param value | <int> """ self._primaryProgressBar.setValue(value) def showSubProgress( self ): """ Returns whether or not the sub progress bar is visible when not in ajax mode. :return <bool> """ return self._showSubProgress def subValue( self ): """ Returns the sub value for this loader. :return <int> """ return self._subProgressBar.value() def value( self ): """ Returns the value for the primary progress bar. :return <int> """ return self._primaryProgressBar.value() @staticmethod def getMovie(): """ Returns the movie instance for the loader widget. :return <QMovie> """ if not XLoaderWidget.MOVIE: filename = projexui.resources.find('img/ajax_loader.gif') XLoaderWidget.MOVIE = QMovie() XLoaderWidget.MOVIE.setFileName(filename) XLoaderWidget.MOVIE.start() return XLoaderWidget.MOVIE @staticmethod def start(widget, processEvents=True, style=None, movie=None): """ Starts a loader widget on the inputed widget. :param widget | <QWidget> :return <XLoaderWidget> """ if style is None: style = os.environ.get('PROJEXUI_LOADER_STYLE', 'gray') # there is a bug with the way the loader is handled in a splitter, # so bypass it parent = widget.parent() while isinstance(parent, QSplitter): parent = parent.parent() # retrieve the loader widget loader = getattr(widget, '_private_xloader_widget', None) if not loader: loader = XLoaderWidget(parent, style) # make sure that if the widget is destroyed, the loader closes widget.destroyed.connect(loader.deleteLater) setattr(widget, '_private_xloader_widget', loader) setattr(widget, '_private_xloader_count', 0) loader.move(widget.pos()) if widget.isVisible(): loader.show() if movie: loader.setMovie(movie) widget.installEventFilter(loader) else: count = getattr(widget, '_private_xloader_count', 0) setattr(widget, '_private_xloader_count', count + 1) loader.resize(widget.size()) return loader @staticmethod def stop(widget, force=False): """ Stops a loader widget on the inputed widget. :param widget | <QWidget> """ # make sure we have a widget to stop loader = getattr(widget, '_private_xloader_widget', None) if not loader: return # decrement the number of times this loader was created for the widget # to allow for stacked closure count = getattr(widget, '_private_xloader_count', 0) if force or count <= 1: # close out the loader widget setattr(widget, '_private_xloader_count', 0) setattr(widget, '_private_xloader_widget', None) loader.close() loader.setParent(None) loader.deleteLater() else: setattr(widget, '_private_xloader_count', count - 1) @staticmethod def stopAll(widget): """ Stops all loader widgets from this parent down, cleaning out the \ memory for them. :param widget | <QWidget> """ for loader in widget.findChildren(XLoaderWidget): loader.setParent(None) loader.deleteLater()
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