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 ImageViewer(QMainWindow): def __init__(self, img): super(ImageViewer, self).__init__() self.image = img # viewer frame self.frame_viewer = QFrame() self.view_L = SliceBox(self.image) self.view_L.setFrameShape(QFrame.Box) # self.view_L.setSlice(self.image) self.view_L.setMinimumSize(QSize(1,1)) sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.view_L.setSizePolicy(sizePolicy) self.view_R = SliceBox(self.image) self.view_R.setFrameShape(QFrame.Box) # self.view_R.setSlice(self.image) self.view_R.setMinimumSize(QSize(1,1)) sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.view_R.setSizePolicy(sizePolicy) self.view_R.setVisible(False) self.layout_viewer = QHBoxLayout() self.layout_viewer.addWidget(self.view_L) self.layout_viewer.addWidget(self.view_R) self.frame_viewer.setLayout(self.layout_viewer) #tlacitkovy frame self.frame_btn = QFrame() self.btn = QPushButton('test') self.layout_btn = QHBoxLayout() self.layout_btn.addWidget(self.btn) self.frame_btn.setLayout(self.layout_btn) #centralni frame obsahujici frame s viewery a frame s tlacitkem self.frame_c = QFrame() self.layout_v = QVBoxLayout() self.layout_v.addWidget(self.frame_viewer) self.layout_v.addWidget(self.frame_btn) self.frame_c.setLayout(self.layout_v) self.setCentralWidget(self.frame_c) self.two_views = False self.btn.clicked.connect(self.btn_callback) def btn_callback(self): self.two_views = not self.two_views if self.two_views: self.view_R.setVisible(True) new_w = self.frame_viewer.width() / 2 new_h = self.frame_viewer.height() / 2 self.view_L.resizeSlice(new_w, new_h) self.view_R.resizeSlice(new_w, new_h) else: self.view_R.setVisible(False) def resizeEvent(self, event): # TODO: oba labely at maji stejnou velikost pass
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
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 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
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 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
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
class StackViewer(QWidget): " Implements the stack viewer for a debugger " def __init__(self, debugger, parent=None): QWidget.__init__(self, parent) self.__debugger = debugger self.currentStack = None self.currentFrame = 0 self.__createPopupMenu() self.__createLayout() if Settings().showStackViewer == False: self.__onShowHide(True) return def __createPopupMenu(self): " Creates the popup menu " self.__framesMenu = QMenu() self.__setCurrentMenuItem = self.__framesMenu.addAction( "Set current (single click)", self.__onSetCurrent) self.__jumpMenuItem = self.__framesMenu.addAction( "Set current and jump to the source (double click)", self.__onSetCurrentAndJump) return def __createLayout(self): " Creates the widget layout " verticalLayout = QVBoxLayout(self) verticalLayout.setContentsMargins(0, 0, 0, 0) verticalLayout.setSpacing(0) self.headerFrame = QFrame() self.headerFrame.setFrameStyle(QFrame.StyledPanel) self.headerFrame.setAutoFillBackground(True) headerPalette = self.headerFrame.palette() headerBackground = headerPalette.color(QPalette.Background) headerBackground.setRgb(min(headerBackground.red() + 30, 255), min(headerBackground.green() + 30, 255), min(headerBackground.blue() + 30, 255)) headerPalette.setColor(QPalette.Background, headerBackground) self.headerFrame.setPalette(headerPalette) self.headerFrame.setFixedHeight(24) self.__stackLabel = QLabel("Stack") expandingSpacer = QSpacerItem(10, 10, QSizePolicy.Expanding) fixedSpacer = QSpacerItem(3, 3) self.__showHideButton = QToolButton() self.__showHideButton.setAutoRaise(True) self.__showHideButton.setIcon(PixmapCache().getIcon('less.png')) self.__showHideButton.setFixedSize(20, 20) self.__showHideButton.setToolTip("Hide frames list") self.__showHideButton.setFocusPolicy(Qt.NoFocus) self.__showHideButton.clicked.connect(self.__onShowHide) headerLayout = QHBoxLayout() headerLayout.setContentsMargins(0, 0, 0, 0) headerLayout.addSpacerItem(fixedSpacer) headerLayout.addWidget(self.__stackLabel) headerLayout.addSpacerItem(expandingSpacer) headerLayout.addWidget(self.__showHideButton) self.headerFrame.setLayout(headerLayout) self.__framesList = QTreeWidget(self) self.__framesList.setSortingEnabled(False) # I might not need that because of two reasons: # - the window has no focus # - the window has custom current indicator # self.__framesList.setAlternatingRowColors( True ) self.__framesList.setRootIsDecorated(False) self.__framesList.setItemsExpandable(False) self.__framesList.setUniformRowHeights(True) self.__framesList.setSelectionMode(QAbstractItemView.NoSelection) self.__framesList.setSelectionBehavior(QAbstractItemView.SelectRows) self.__framesList.setItemDelegate(NoOutlineHeightDelegate(4)) self.__framesList.setFocusPolicy(Qt.NoFocus) self.__framesList.setContextMenuPolicy(Qt.CustomContextMenu) self.__framesList.itemClicked.connect(self.__onFrameClicked) self.__framesList.itemDoubleClicked.connect( self.__onFrameDoubleClicked) self.__framesList.customContextMenuRequested.connect( self.__showContextMenu) self.__framesList.setHeaderLabels( ["", "File:line", "Function", "Full path"]) verticalLayout.addWidget(self.headerFrame) verticalLayout.addWidget(self.__framesList) return def __onShowHide(self, startup=False): " Triggered when show/hide button is clicked " if startup or self.__framesList.isVisible(): self.__framesList.setVisible(False) self.__showHideButton.setIcon(PixmapCache().getIcon('more.png')) self.__showHideButton.setToolTip("Show frames list") self.__minH = self.minimumHeight() self.__maxH = self.maximumHeight() self.setMinimumHeight(self.headerFrame.height()) self.setMaximumHeight(self.headerFrame.height()) Settings().showStackViewer = False else: self.__framesList.setVisible(True) self.__showHideButton.setIcon(PixmapCache().getIcon('less.png')) self.__showHideButton.setToolTip("Hide frames list") self.setMinimumHeight(self.__minH) self.setMaximumHeight(self.__maxH) Settings().showStackViewer = True return def clear(self): " Clears the content " self.__framesList.clear() self.currentStack = None self.__stackLabel.setText("Stack") return def __resizeColumns(self): " Resize the files list columns " self.__framesList.header().setStretchLastSection(True) self.__framesList.header().resizeSections(QHeaderView.ResizeToContents) self.__framesList.header().resizeSection(0, 22) self.__framesList.header().setResizeMode(0, QHeaderView.Fixed) return def populate(self, stack): " Sets the new call stack and selects the first item in it " self.clear() self.currentStack = stack self.currentFrame = 0 frameNumber = 0 for s in stack: if len(s) == 2: # This is when an exception comes funcName = "" else: funcName = s[2] item = StackFrameItem(s[0], s[1], funcName, frameNumber) self.__framesList.addTopLevelItem(item) frameNumber += 1 self.__resizeColumns() self.__framesList.topLevelItem(0).setCurrent(True) self.__stackLabel.setText("Stack (total: " + str(len(stack)) + ")") return def getFrameNumber(self): " Provides the current frame number " return self.currentFrame def __onFrameClicked(self, item, column): " Triggered when a frame is clicked " if item.isCurrent(): return # Hide the current indicator self.__framesList.topLevelItem(self.currentFrame).setCurrent(False) # Show the new indicator self.currentFrame = item.getFrameNumber() for index in xrange(self.__framesList.topLevelItemCount()): item = self.__framesList.topLevelItem(index) if item.getFrameNumber() == self.currentFrame: item.setCurrent(True) self.__debugger.remoteClientVariables(1, self.currentFrame) # globals self.__debugger.remoteClientVariables(0, self.currentFrame) # locals return def __onFrameDoubleClicked(self, item, column): " Triggered when a frame is double clicked " # The frame has been switched already because the double click # signal always comes after the single click one fileName = item.getFilename() lineNumber = item.getLineNumber() editorsManager = GlobalData().mainWindow.editorsManager() editorsManager.openFile(fileName, lineNumber) editor = editorsManager.currentWidget().getEditor() editor.gotoLine(lineNumber) editorsManager.currentWidget().setFocus() return def __showContextMenu(self, coord): " Shows the frames list context menu " self.__contextItem = self.__framesList.itemAt(coord) if self.__contextItem is not None: self.__setCurrentMenuItem.setEnabled( not self.__contextItem.isCurrent()) self.__framesMenu.popup(QCursor.pos()) return def __onSetCurrent(self): " Context menu item handler " self.__onFrameClicked(self.__contextItem, 0) return def __onSetCurrentAndJump(self): " Context menu item handler " self.__onFrameClicked(self.__contextItem, 0) self.__onFrameDoubleClicked(self.__contextItem, 0) return def switchControl(self, isInIDE): " Switches the UI depending where the control flow is " self.__framesList.setEnabled(isInIDE) return
class IgnoredExceptionsViewer( QWidget ): " Implements the client exceptions viewer for a debugger " def __init__( self, parent = None ): QWidget.__init__( self, parent ) self.__createPopupMenu() self.__createLayout() self.__ignored = [] self.__currentItem = None GlobalData().project.projectChanged.connect( self.__onProjectChanged ) if Settings().showIgnoredExcViewer == False: self.__onShowHide( True ) return def __createPopupMenu( self ): " Creates the popup menu " self.__excptMenu = QMenu() self.__removeMenuItem = self.__excptMenu.addAction( PixmapCache().getIcon( 'ignexcptdel.png' ), "Remove from ignore list", self.__onRemoveFromIgnore ) return def __createLayout( self ): " Creates the widget layout " verticalLayout = QVBoxLayout( self ) verticalLayout.setContentsMargins( 0, 0, 0, 0 ) verticalLayout.setSpacing( 0 ) self.headerFrame = QFrame() self.headerFrame.setFrameStyle( QFrame.StyledPanel ) self.headerFrame.setAutoFillBackground( True ) headerPalette = self.headerFrame.palette() headerBackground = headerPalette.color( QPalette.Background ) headerBackground.setRgb( min( headerBackground.red() + 30, 255 ), min( headerBackground.green() + 30, 255 ), min( headerBackground.blue() + 30, 255 ) ) headerPalette.setColor( QPalette.Background, headerBackground ) self.headerFrame.setPalette( headerPalette ) self.headerFrame.setFixedHeight( 24 ) self.__excptLabel = QLabel( "Ignored exception types" ) expandingSpacer = QSpacerItem( 10, 10, QSizePolicy.Expanding ) fixedSpacer = QSpacerItem( 3, 3 ) self.__showHideButton = QToolButton() self.__showHideButton.setAutoRaise( True ) self.__showHideButton.setIcon( PixmapCache().getIcon( 'less.png' ) ) self.__showHideButton.setFixedSize( 20, 20 ) self.__showHideButton.setToolTip( "Hide ignored exceptions list" ) self.__showHideButton.setFocusPolicy( Qt.NoFocus ) self.__showHideButton.clicked.connect( self.__onShowHide ) headerLayout = QHBoxLayout() headerLayout.setContentsMargins( 1, 1, 1, 1 ) headerLayout.addSpacerItem( fixedSpacer ) headerLayout.addWidget( self.__excptLabel ) headerLayout.addSpacerItem( expandingSpacer ) headerLayout.addWidget( self.__showHideButton ) self.headerFrame.setLayout( headerLayout ) self.exceptionsList = QTreeWidget( self ) self.exceptionsList.setSortingEnabled( False ) self.exceptionsList.setAlternatingRowColors( True ) self.exceptionsList.setRootIsDecorated( False ) self.exceptionsList.setItemsExpandable( True ) self.exceptionsList.setUniformRowHeights( True ) self.exceptionsList.setSelectionMode( QAbstractItemView.SingleSelection ) self.exceptionsList.setSelectionBehavior( QAbstractItemView.SelectRows ) self.exceptionsList.setItemDelegate( NoOutlineHeightDelegate( 4 ) ) self.exceptionsList.setContextMenuPolicy( Qt.CustomContextMenu ) self.exceptionsList.customContextMenuRequested.connect( self.__showContextMenu ) self.exceptionsList.itemSelectionChanged.connect( self.__onSelectionChanged ) self.exceptionsList.setHeaderLabels( [ "Exception type" ] ) self.__excTypeEdit = QLineEdit() self.__excTypeEdit.setFixedHeight( 26 ) self.__excTypeEdit.textChanged.connect( self.__onNewFilterChanged ) self.__excTypeEdit.returnPressed.connect( self.__onAddExceptionFilter ) self.__addButton = QPushButton( "Add" ) # self.__addButton.setFocusPolicy( Qt.NoFocus ) self.__addButton.setEnabled( False ) self.__addButton.clicked.connect( self.__onAddExceptionFilter ) expandingSpacer2 = QWidget() expandingSpacer2.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Expanding ) self.__removeButton = QAction( PixmapCache().getIcon( 'delitem.png' ), "Remove selected exception type", self ) self.__removeButton.triggered.connect( self.__onRemoveFromIgnore ) self.__removeButton.setEnabled( False ) fixedSpacer1 = QWidget() fixedSpacer1.setFixedWidth( 5 ) self.__removeAllButton = QAction( PixmapCache().getIcon( 'ignexcptdelall.png' ), "Remove all the exception types", self ) self.__removeAllButton.triggered.connect( self.__onRemoveAllFromIgnore ) self.__removeAllButton.setEnabled( False ) self.toolbar = QToolBar() self.toolbar.setOrientation( Qt.Horizontal ) self.toolbar.setMovable( False ) self.toolbar.setAllowedAreas( Qt.TopToolBarArea ) self.toolbar.setIconSize( QSize( 16, 16 ) ) self.toolbar.setFixedHeight( 28 ) self.toolbar.setContentsMargins( 0, 0, 0, 0 ) self.toolbar.addWidget( expandingSpacer2 ) self.toolbar.addAction( self.__removeButton ) self.toolbar.addWidget( fixedSpacer1 ) self.toolbar.addAction( self.__removeAllButton ) addLayout = QHBoxLayout() addLayout.setContentsMargins( 1, 1, 1, 1 ) addLayout.setSpacing( 1 ) addLayout.addWidget( self.__excTypeEdit ) addLayout.addWidget( self.__addButton ) verticalLayout.addWidget( self.headerFrame ) verticalLayout.addWidget( self.toolbar ) verticalLayout.addWidget( self.exceptionsList ) verticalLayout.addLayout( addLayout ) return def clear( self ): " Clears the content " self.exceptionsList.clear() self.__excTypeEdit.clear() self.__addButton.setEnabled( False ) self.__ignored = [] self.__currentItem = None self.__updateTitle() return def __onShowHide( self, startup = False ): " Triggered when show/hide button is clicked " if startup or self.exceptionsList.isVisible(): self.exceptionsList.setVisible( False ) self.__excTypeEdit.setVisible( False ) self.__addButton.setVisible( False ) self.__removeButton.setVisible( False ) self.__removeAllButton.setVisible( False ) self.__showHideButton.setIcon( PixmapCache().getIcon( 'more.png' ) ) self.__showHideButton.setToolTip( "Show ignored exceptions list" ) self.__minH = self.minimumHeight() self.__maxH = self.maximumHeight() self.setMinimumHeight( self.headerFrame.height() ) self.setMaximumHeight( self.headerFrame.height() ) Settings().showIgnoredExcViewer = False else: self.exceptionsList.setVisible( True ) self.__excTypeEdit.setVisible( True ) self.__addButton.setVisible( True ) self.__removeButton.setVisible( True ) self.__removeAllButton.setVisible( True ) self.__showHideButton.setIcon( PixmapCache().getIcon( 'less.png' ) ) self.__showHideButton.setToolTip( "Hide ignored exceptions list" ) self.setMinimumHeight( self.__minH ) self.setMaximumHeight( self.__maxH ) Settings().showIgnoredExcViewer = True return def __onSelectionChanged( self ): " Triggered when the current item is changed " selected = list( self.exceptionsList.selectedItems() ) if selected: self.__currentItem = selected[ 0 ] self.__removeButton.setEnabled( True ) else: self.__currentItem = None self.__removeButton.setEnabled( False ) return def __showContextMenu( self, coord ): " Shows the frames list context menu " contextItem = self.exceptionsList.itemAt( coord ) if contextItem is not None: self.__currentItem = contextItem self.__excptMenu.popup( QCursor.pos() ) return def __updateTitle( self ): " Updates the section title " count = self.exceptionsList.topLevelItemCount() if count == 0: self.__excptLabel.setText( "Ignored exception types" ) else: self.__excptLabel.setText( "Ignored exception types (total: " + str( count ) + ")" ) self.__removeAllButton.setEnabled( count != 0 ) return def __onProjectChanged( self, what ): " Triggered when a project is changed " if what != CodimensionProject.CompleteProject: return self.clear() project = GlobalData().project if project.isLoaded(): self.__ignored = list( project.ignoredExcpt ) else: self.__ignored = list( Settings().ignoredExceptions ) for exceptionType in self.__ignored: item = QTreeWidgetItem( self.exceptionsList ) item.setText( 0, exceptionType ) self.__updateTitle() return def __onNewFilterChanged( self, text ): " Triggered when the text is changed " text = str( text ).strip() if text == "": self.__addButton.setEnabled( False ) return if " " in text: self.__addButton.setEnabled( False ) return if text in self.__ignored: self.__addButton.setEnabled( False ) return self.__addButton.setEnabled( True ) return def __onAddExceptionFilter( self ): " Adds an item into the ignored exceptions list " text = self.__excTypeEdit.text().strip() self.addExceptionFilter( text ) def addExceptionFilter( self, excType ): " Adds a new item into the ignored exceptions list " if excType == "": return if " " in excType: return if excType in self.__ignored: return item = QTreeWidgetItem( self.exceptionsList ) item.setText( 0, excType ) project = GlobalData().project if project.isLoaded(): project.addExceptionFilter( excType ) else: Settings().addExceptionFilter( excType ) self.__ignored.append( excType ) self.__updateTitle() return def __onRemoveFromIgnore( self ): " Removes an item from the ignored exception types list " if self.__currentItem is None: return text = self.__currentItem.text( 0 ) # Find the item index and remove it index = 0 while True: if self.exceptionsList.topLevelItem( index ).text( 0 ) == text: self.exceptionsList.takeTopLevelItem( index ) break index += 1 project = GlobalData().project if project.isLoaded(): project.deleteExceptionFilter( text ) else: Settings().deleteExceptionFilter( text ) self.__ignored.remove( text ) self.__updateTitle() return def __onRemoveAllFromIgnore( self ): " Triggered when all the ignored exceptions should be deleted " self.clear() project = GlobalData().project if project.isLoaded(): project.setExceptionFilters( [] ) else: Settings().setExceptionFilters( [] ) return def isIgnored( self, exceptionType ): " Returns True if this exception type should be ignored " return exceptionType in self.__ignored