def __createLayout(self): """Creates the widget layout""" verticalLayout = QVBoxLayout(self) verticalLayout.setContentsMargins(0, 0, 0, 0) verticalLayout.setSpacing(0) self.__excptLabel = QLabel("Ignored exception types", self) self.headerFrame = QFrame() self.headerFrame.setObjectName('ignexcpt') self.headerFrame.setStyleSheet('QFrame#ignexcpt {' + getLabelStyle(self.__excptLabel) + '}') self.headerFrame.setFixedHeight(HEADER_HEIGHT) expandingSpacer = QSpacerItem(10, 10, QSizePolicy.Expanding) self.__showHideButton = QToolButton() self.__showHideButton.setAutoRaise(True) self.__showHideButton.setIcon(getIcon('less.png')) self.__showHideButton.setFixedSize(HEADER_BUTTON, HEADER_BUTTON) self.__showHideButton.setToolTip("Hide ignored exceptions list") self.__showHideButton.setFocusPolicy(Qt.NoFocus) self.__showHideButton.clicked.connect(self.__onShowHide) headerLayout = QHBoxLayout() headerLayout.setContentsMargins(0, 0, 0, 0) headerLayout.addSpacing(3) headerLayout.addWidget(self.__excptLabel) headerLayout.addSpacerItem(expandingSpacer) headerLayout.addWidget(self.__showHideButton) self.headerFrame.setLayout(headerLayout) self.exceptionsList = QTreeWidget(self) self.exceptionsList.setSortingEnabled(False) self.exceptionsList.setAlternatingRowColors(True) self.exceptionsList.setRootIsDecorated(False) self.exceptionsList.setItemsExpandable(True) self.exceptionsList.setUniformRowHeights(True) self.exceptionsList.setSelectionMode(QAbstractItemView.SingleSelection) self.exceptionsList.setSelectionBehavior(QAbstractItemView.SelectRows) self.exceptionsList.setItemDelegate(NoOutlineHeightDelegate(4)) self.exceptionsList.setContextMenuPolicy(Qt.CustomContextMenu) self.exceptionsList.customContextMenuRequested.connect( self.__showContextMenu) self.exceptionsList.itemSelectionChanged.connect( self.__onSelectionChanged) self.exceptionsList.setHeaderLabels(["Exception type"]) self.__excTypeEdit = QLineEdit() self.__excTypeEdit.setFixedHeight(26) self.__excTypeEdit.textChanged.connect(self.__onNewFilterChanged) self.__excTypeEdit.returnPressed.connect(self.__onAddExceptionFilter) self.__addButton = QPushButton("Add") # self.__addButton.setFocusPolicy(Qt.NoFocus) self.__addButton.setEnabled(False) self.__addButton.clicked.connect(self.__onAddExceptionFilter) expandingSpacer2 = QWidget() expandingSpacer2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.__removeButton = QAction(getIcon('delitem.png'), "Remove selected exception type", self) self.__removeButton.triggered.connect(self.__onRemoveFromIgnore) self.__removeButton.setEnabled(False) fixedSpacer1 = QWidget() fixedSpacer1.setFixedWidth(5) self.__removeAllButton = QAction(getIcon('ignexcptdelall.png'), "Remove all the exception types", self) self.__removeAllButton.triggered.connect(self.__onRemoveAllFromIgnore) self.__removeAllButton.setEnabled(False) self.toolbar = QToolBar() self.toolbar.setOrientation(Qt.Horizontal) self.toolbar.setMovable(False) self.toolbar.setAllowedAreas(Qt.TopToolBarArea) self.toolbar.setIconSize(QSize(16, 16)) self.toolbar.setFixedHeight(28) self.toolbar.setContentsMargins(0, 0, 0, 0) self.toolbar.addWidget(expandingSpacer2) self.toolbar.addAction(self.__removeButton) self.toolbar.addWidget(fixedSpacer1) self.toolbar.addAction(self.__removeAllButton) addLayout = QHBoxLayout() addLayout.setContentsMargins(1, 1, 1, 1) addLayout.setSpacing(1) addLayout.addWidget(self.__excTypeEdit) addLayout.addWidget(self.__addButton) verticalLayout.addWidget(self.headerFrame) verticalLayout.addWidget(self.toolbar) verticalLayout.addWidget(self.exceptionsList) verticalLayout.addLayout(addLayout)
def __createLayout(self): """Creates the dialog layout""" self.resize(640, 480) self.setSizeGripEnabled(True) vboxLayout = QVBoxLayout(self) # Revisions to compare compareGroupbox = QGroupBox(self) compareGroupbox.setTitle("Revisions to compare") sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( compareGroupbox.sizePolicy().hasHeightForWidth()) compareGroupbox.setSizePolicy(sizePolicy) revisionLayout = QHBoxLayout(compareGroupbox) self.__lhsRevisionLabel = QLabel() self.__lhsRevisionLabel.setFrameStyle(QFrame.StyledPanel) self.__lhsResetButton = QToolButton() self.__lhsResetButton.setIcon( getIcon(pluginHomeDir + 'svnclearrev.png')) self.__lhsResetButton.setFocusPolicy(Qt.NoFocus) self.__lhsResetButton.setEnabled(False) self.__lhsResetButton.setToolTip("Reset revision to compare") self.__lhsResetButton.clicked.connect(self.__onLHSReset) self.__rhsRevisionLabel = QLabel() self.__rhsRevisionLabel.setFrameStyle(QFrame.StyledPanel) self.__rhsResetButton = QToolButton() self.__rhsResetButton.setIcon( getIcon(pluginHomeDir + 'svnclearrev.png')) self.__rhsResetButton.setFocusPolicy(Qt.NoFocus) self.__rhsResetButton.setEnabled(False) self.__rhsResetButton.setToolTip("Reset revision to compare") self.__rhsResetButton.clicked.connect(self.__onRHSReset) lhsLayout = QHBoxLayout() lhsLayout.addWidget(self.__lhsRevisionLabel) lhsLayout.addWidget(self.__lhsResetButton) rhsLayout = QHBoxLayout() rhsLayout.addWidget(self.__rhsRevisionLabel) rhsLayout.addWidget(self.__rhsResetButton) bothLayout = QVBoxLayout() bothLayout.addLayout(lhsLayout) bothLayout.addLayout(rhsLayout) revisionLayout.addLayout(bothLayout) self.__diffButton = QToolButton() self.__diffButton.setText("Diff") self.__diffButton.setFocusPolicy(Qt.NoFocus) self.__diffButton.setEnabled(False) self.__diffButton.clicked.connect(self.__onDiff) revisionLayout.addWidget(self.__diffButton) vboxLayout.addWidget(compareGroupbox) # Log table logHeaderFrame = QFrame() logHeaderFrame.setFrameStyle(QFrame.StyledPanel) logHeaderFrame.setAutoFillBackground(True) self.__setLightPalette(logHeaderFrame) logHeaderFrame.setFixedHeight(24) logHeaderLayout = QHBoxLayout() logHeaderLayout.setContentsMargins(3, 0, 0, 0) logHeaderLayout.addWidget(QLabel("Subversion log of " + self.__path)) logHeaderFrame.setLayout(logHeaderLayout) vboxLayout.addWidget(logHeaderFrame) self.__logView = QTreeWidget() self.__logView.setAlternatingRowColors(True) self.__logView.setRootIsDecorated(False) self.__logView.setItemsExpandable(False) self.__logView.setSortingEnabled(True) self.__logView.setItemDelegate(NoOutlineHeightDelegate(4)) self.__logViewHeader = QTreeWidgetItem( ["", "", "Revision", "Date", "Author", "Message"]) self.__logView.setHeaderItem(self.__logViewHeader) self.__logView.header().setSortIndicator(REVISION_COL, Qt.AscendingOrder) self.__logView.itemChanged.connect(self.__onLogViewChanged) vboxLayout.addWidget(self.__logView) # Diff part diffHeaderFrame = QFrame() diffHeaderFrame.setFrameStyle(QFrame.StyledPanel) diffHeaderFrame.setAutoFillBackground(True) self.__setLightPalette(diffHeaderFrame) diffHeaderFrame.setFixedHeight(24) diffLabel = QLabel("Diff") diffExpandingSpacer = QSpacerItem(10, 10, QSizePolicy.Expanding) self.__showHideDiffButton = QToolButton() self.__showHideDiffButton.setAutoRaise(True) self.__showHideDiffButton.setIcon(getIcon('less.png')) self.__showHideDiffButton.setFixedSize(20, 20) self.__showHideDiffButton.setToolTip("Show diff") self.__showHideDiffButton.setFocusPolicy(Qt.NoFocus) self.__showHideDiffButton.clicked.connect(self.__onShowHideDiff) diffLayout = QHBoxLayout() diffLayout.setContentsMargins(3, 0, 0, 0) diffLayout.addWidget(diffLabel) diffLayout.addSpacerItem(diffExpandingSpacer) diffLayout.addWidget(self.__showHideDiffButton) diffHeaderFrame.setLayout(diffLayout) self.__diffViewer = DiffTabWidget() self.__diffViewer.setHTML(self.NODIFF) self.__diffViewer.setVisible(False) vboxLayout.addWidget(diffHeaderFrame) vboxLayout.addWidget(self.__diffViewer) # Buttons at the bottom buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Ok) buttonBox.button(QDialogButtonBox.Ok).setDefault(True) buttonBox.accepted.connect(self.close) vboxLayout.addWidget(buttonBox)
class IgnoredExceptionsViewer(QWidget): """Implements the client exceptions viewer for a debugger""" def __init__(self, parent=None): QWidget.__init__(self, parent) self.__createPopupMenu() self.__createLayout() self.__ignored = [] self.__currentItem = None GlobalData().project.sigProjectChanged.connect(self.__onProjectChanged) if not Settings()['showIgnoredExcViewer']: self.__onShowHide(True) def __createPopupMenu(self): """Creates the popup menu""" self.__excptMenu = QMenu() self.__removeMenuItem = self.__excptMenu.addAction( getIcon('ignexcptdel.png'), "Remove from ignore list", self.__onRemoveFromIgnore) def __createLayout(self): """Creates the widget layout""" verticalLayout = QVBoxLayout(self) verticalLayout.setContentsMargins(0, 0, 0, 0) verticalLayout.setSpacing(0) self.__excptLabel = QLabel("Ignored exception types", self) self.headerFrame = QFrame() self.headerFrame.setObjectName('ignexcpt') self.headerFrame.setStyleSheet('QFrame#ignexcpt {' + getLabelStyle(self.__excptLabel) + '}') self.headerFrame.setFixedHeight(HEADER_HEIGHT) expandingSpacer = QSpacerItem(10, 10, QSizePolicy.Expanding) self.__showHideButton = QToolButton() self.__showHideButton.setAutoRaise(True) self.__showHideButton.setIcon(getIcon('less.png')) self.__showHideButton.setFixedSize(HEADER_BUTTON, HEADER_BUTTON) self.__showHideButton.setToolTip("Hide ignored exceptions list") self.__showHideButton.setFocusPolicy(Qt.NoFocus) self.__showHideButton.clicked.connect(self.__onShowHide) headerLayout = QHBoxLayout() headerLayout.setContentsMargins(0, 0, 0, 0) headerLayout.addSpacing(3) headerLayout.addWidget(self.__excptLabel) headerLayout.addSpacerItem(expandingSpacer) headerLayout.addWidget(self.__showHideButton) self.headerFrame.setLayout(headerLayout) self.exceptionsList = QTreeWidget(self) self.exceptionsList.setSortingEnabled(False) self.exceptionsList.setAlternatingRowColors(True) self.exceptionsList.setRootIsDecorated(False) self.exceptionsList.setItemsExpandable(True) self.exceptionsList.setUniformRowHeights(True) self.exceptionsList.setSelectionMode(QAbstractItemView.SingleSelection) self.exceptionsList.setSelectionBehavior(QAbstractItemView.SelectRows) self.exceptionsList.setItemDelegate(NoOutlineHeightDelegate(4)) self.exceptionsList.setContextMenuPolicy(Qt.CustomContextMenu) self.exceptionsList.customContextMenuRequested.connect( self.__showContextMenu) self.exceptionsList.itemSelectionChanged.connect( self.__onSelectionChanged) self.exceptionsList.setHeaderLabels(["Exception type"]) self.__excTypeEdit = QLineEdit() self.__excTypeEdit.setFixedHeight(26) self.__excTypeEdit.textChanged.connect(self.__onNewFilterChanged) self.__excTypeEdit.returnPressed.connect(self.__onAddExceptionFilter) self.__addButton = QPushButton("Add") # self.__addButton.setFocusPolicy(Qt.NoFocus) self.__addButton.setEnabled(False) self.__addButton.clicked.connect(self.__onAddExceptionFilter) expandingSpacer2 = QWidget() expandingSpacer2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.__removeButton = QAction(getIcon('delitem.png'), "Remove selected exception type", self) self.__removeButton.triggered.connect(self.__onRemoveFromIgnore) self.__removeButton.setEnabled(False) fixedSpacer1 = QWidget() fixedSpacer1.setFixedWidth(5) self.__removeAllButton = QAction(getIcon('ignexcptdelall.png'), "Remove all the exception types", self) self.__removeAllButton.triggered.connect(self.__onRemoveAllFromIgnore) self.__removeAllButton.setEnabled(False) self.toolbar = QToolBar() self.toolbar.setOrientation(Qt.Horizontal) self.toolbar.setMovable(False) self.toolbar.setAllowedAreas(Qt.TopToolBarArea) self.toolbar.setIconSize(QSize(16, 16)) self.toolbar.setFixedHeight(28) self.toolbar.setContentsMargins(0, 0, 0, 0) self.toolbar.addWidget(expandingSpacer2) self.toolbar.addAction(self.__removeButton) self.toolbar.addWidget(fixedSpacer1) self.toolbar.addAction(self.__removeAllButton) addLayout = QHBoxLayout() addLayout.setContentsMargins(1, 1, 1, 1) addLayout.setSpacing(1) addLayout.addWidget(self.__excTypeEdit) addLayout.addWidget(self.__addButton) verticalLayout.addWidget(self.headerFrame) verticalLayout.addWidget(self.toolbar) verticalLayout.addWidget(self.exceptionsList) verticalLayout.addLayout(addLayout) def clear(self): """Clears the content""" self.exceptionsList.clear() self.__excTypeEdit.clear() self.__addButton.setEnabled(False) self.__ignored = [] self.__currentItem = None self.__updateTitle() def __onShowHide(self, startup=False): """Triggered when show/hide button is clicked""" if startup or self.exceptionsList.isVisible(): self.exceptionsList.setVisible(False) self.__excTypeEdit.setVisible(False) self.__addButton.setVisible(False) self.__removeButton.setVisible(False) self.__removeAllButton.setVisible(False) self.__showHideButton.setIcon(getIcon('more.png')) self.__showHideButton.setToolTip("Show ignored exceptions list") self.__minH = self.minimumHeight() self.__maxH = self.maximumHeight() self.setMinimumHeight(self.headerFrame.height()) self.setMaximumHeight(self.headerFrame.height()) Settings()['showIgnoredExcViewer'] = False else: self.exceptionsList.setVisible(True) self.__excTypeEdit.setVisible(True) self.__addButton.setVisible(True) self.__removeButton.setVisible(True) self.__removeAllButton.setVisible(True) self.__showHideButton.setIcon(getIcon('less.png')) self.__showHideButton.setToolTip("Hide ignored exceptions list") self.setMinimumHeight(self.__minH) self.setMaximumHeight(self.__maxH) Settings()['showIgnoredExcViewer'] = True def __onSelectionChanged(self): """Triggered when the current item is changed""" selected = list(self.exceptionsList.selectedItems()) if selected: self.__currentItem = selected[0] self.__removeButton.setEnabled(True) else: self.__currentItem = None self.__removeButton.setEnabled(False) def __showContextMenu(self, coord): """Shows the frames list context menu""" contextItem = self.exceptionsList.itemAt(coord) if contextItem is not None: self.__currentItem = contextItem self.__excptMenu.popup(QCursor.pos()) def __updateTitle(self): """Updates the section title""" count = self.exceptionsList.topLevelItemCount() if count == 0: self.__excptLabel.setText("Ignored exception types") else: self.__excptLabel.setText("Ignored exception types (total: " + str(count) + ")") self.__removeAllButton.setEnabled(count != 0) def __onProjectChanged(self, what): """Triggered when a project is changed""" if what != CodimensionProject.CompleteProject: return self.clear() project = GlobalData().project if project.isLoaded(): self.__ignored = list(project.exceptionFilters) else: self.__ignored = Settings()['ignoredExceptions'] for exceptionType in self.__ignored: item = QTreeWidgetItem(self.exceptionsList) item.setText(0, exceptionType) self.__updateTitle() def __onNewFilterChanged(self, text): """Triggered when the text is changed""" text = str(text).strip() if text == "": self.__addButton.setEnabled(False) return if " " in text: self.__addButton.setEnabled(False) return if text in self.__ignored: self.__addButton.setEnabled(False) return self.__addButton.setEnabled(True) def __onAddExceptionFilter(self): """Adds an item into the ignored exceptions list""" text = self.__excTypeEdit.text().strip() self.addExceptionFilter(text) def addExceptionFilter(self, excType): """Adds a new item into the ignored exceptions list""" if excType == "": return if " " in excType: return if excType in self.__ignored: return item = QTreeWidgetItem(self.exceptionsList) item.setText(0, excType) project = GlobalData().project if project.isLoaded(): project.addExceptionFilter(excType) else: Settings().addExceptionFilter(excType) self.__ignored.append(excType) self.__updateTitle() def __onRemoveFromIgnore(self): """Removes an item from the ignored exception types list""" if self.__currentItem is None: return text = self.__currentItem.text(0) # Find the item index and remove it index = 0 while True: if self.exceptionsList.topLevelItem(index).text(0) == text: self.exceptionsList.takeTopLevelItem(index) break index += 1 project = GlobalData().project if project.isLoaded(): project.deleteExceptionFilter(text) else: Settings().deleteExceptionFilter(text) self.__ignored.remove(text) self.__updateTitle() def __onRemoveAllFromIgnore(self): """Triggered when all the ignored exceptions should be deleted""" self.clear() project = GlobalData().project if project.isLoaded(): project.setExceptionFilters([]) else: Settings().setExceptionFilters([]) def isIgnored(self, exceptionType): """Returns True if this exception type should be ignored""" return exceptionType in self.__ignored
class PluginsDialog(QDialog): """Codimension plugins dialog""" def __init__(self, pluginManager, parent=None): QDialog.__init__(self, parent) self.setWindowTitle("Plugin Manager") self.__pluginManager = pluginManager self.__configFuncs = {} # int -> callable self.__createLayout() self.__populate() self.__pluginsView.setFocus() self.__inItemChange = False def __createLayout(self): """Creates the dialog layout""" self.resize(640, 480) self.setSizeGripEnabled(True) layout = QVBoxLayout() # Plugins list self.__pluginsView = QTreeWidget() self.__pluginsView.setAlternatingRowColors(True) self.__pluginsView.setRootIsDecorated(False) self.__pluginsView.setItemsExpandable(False) self.__pluginsView.setSortingEnabled(True) self.__pluginsView.setItemDelegate(NoOutlineHeightDelegate(4)) self.__pluginsView.setUniformRowHeights(True) # Alert | system/user | Enable | Name | Version self.__pluginsHeader = QTreeWidgetItem( ["", "", "", "Name", "Version", ""]) self.__pluginsView.setHeaderItem(self.__pluginsHeader) self.__pluginsView.header().setSortIndicator(NAME_COL, Qt.AscendingOrder) self.__pluginsView.itemSelectionChanged.connect( self.__pluginSelectionChanged) self.__pluginsView.itemChanged.connect(self.__onItemChanged) layout.addWidget(self.__pluginsView) # Detailed information detailsLabel = QLabel("Detailed information") layout.addWidget(detailsLabel) self.__details = QTreeWidget() self.__details.setAlternatingRowColors(False) self.__details.setRootIsDecorated(False) self.__details.setItemsExpandable(False) self.__details.setSortingEnabled(False) self.__details.setItemDelegate(NoOutlineHeightDelegate(4)) self.__details.setUniformRowHeights(True) detailsHeader = QTreeWidgetItem(["", ""]) self.__details.setHeaderItem(detailsHeader) self.__details.setHeaderHidden(True) metrics = QFontMetrics(self.__details.font()) rect = metrics.boundingRect("X") self.__details.setFixedHeight(rect.height() * 6 + 5) layout.addWidget(self.__details) # Errors/warnings errorsLabel = QLabel("Errors / warnings") layout.addWidget(errorsLabel) self.__errorsText = QTextEdit() self.__errorsText.setReadOnly(True) self.__errorsText.setAcceptRichText(False) metrics = QFontMetrics(self.__errorsText.font()) rect = metrics.boundingRect("X") self.__errorsText.setFixedHeight(rect.height() * 4 + 5) layout.addWidget(self.__errorsText) # Buttons box buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Ok) self.__OKButton = buttonBox.button(QDialogButtonBox.Ok) self.__OKButton.setDefault(True) buttonBox.accepted.connect(self.close) buttonBox.rejected.connect(self.close) layout.addWidget(buttonBox) self.setLayout(layout) def __createConfigButton(self): """Creates a configure button for a plugin""" button = SettingsButton() button.CustomClick.connect(self.onPluginSettings) return button def __populate(self): """Populates the list with the plugins""" index = 0 for category in self.__pluginManager.activePlugins: for cdmPlugin in self.__pluginManager.activePlugins[category]: newItem = PluginItem(self.__pluginManager, cdmPlugin, True, category) self.__pluginsView.addTopLevelItem(newItem) settingsButton = self.__createConfigButton() try: configFunction = cdmPlugin.getObject().getConfigFunction() if configFunction is None: settingsButton.setToolTip( "Plugin does not need configuring") settingsButton.setEnabled(False) else: settingsButton.setToolTip("Click to configure") settingsButton.setEnabled(True) self.__configFuncs[index] = configFunction settingsButton.index = index index += 1 except Exception: settingsButton.setToolTip("Bad plugin interface. No " "configuration function " "received.") settingsButton.setEnabled(False) self.__pluginsView.setItemWidget(newItem, SETTINGS_COL, settingsButton) for category in self.__pluginManager.inactivePlugins: for cdmPlugin in self.__pluginManager.inactivePlugins[category]: newItem = PluginItem(self.__pluginManager, cdmPlugin, False, category) self.__pluginsView.addTopLevelItem(newItem) settingsButton = self.__createConfigButton() try: configFunction = cdmPlugin.getObject().getConfigFunction() if configFunction is None: settingsButton.setToolTip( "Plugin does not need configuring") settingsButton.setEnabled(False) else: settingsButton.setToolTip( "Enable plugin and then click to configure") settingsButton.setEnabled(False) self.__configFuncs[index] = configFunction settingsButton.index = index index += 1 except: settingsButton.setToolTip("Bad plugin interface. No " "configuration function " "received.") settingsButton.setEnabled(False) self.__pluginsView.setItemWidget(newItem, SETTINGS_COL, settingsButton) for cdmPlugin in self.__pluginManager.unknownPlugins: newItem = PluginItem(self.__pluginManager, cdmPlugin, False, None) self.__pluginsView.addTopLevelItem(newItem) settingsButton = self.__createConfigButton() settingsButton.setToolTip("Unknown plugins are not configurable") settingsButton.setEnabled(False) self.__pluginsView.setItemWidget(newItem, SETTINGS_COL, settingsButton) self.__sortPlugins() self.__resizePlugins() def __sortPlugins(self): """Sorts the plugins table""" self.__pluginsView.sortItems( self.__pluginsView.sortColumn(), self.__pluginsView.header().sortIndicatorOrder()) def __resizePlugins(self): """Resizes the plugins table""" self.__pluginsView.header().setStretchLastSection(False) self.__pluginsView.header().resizeSections( QHeaderView.ResizeToContents) self.__pluginsView.header().resizeSection(STATE_COL, 28) self.__pluginsView.header().setSectionResizeMode( STATE_COL, QHeaderView.Fixed) self.__pluginsView.header().resizeSection(CONFLICT_COL, 28) self.__pluginsView.header().setSectionResizeMode( CONFLICT_COL, QHeaderView.Fixed) self.__pluginsView.header().resizeSection(TYPE_COL, 28) self.__pluginsView.header().setSectionResizeMode( TYPE_COL, QHeaderView.Fixed) self.__pluginsView.header().setSectionResizeMode( VERSION_COL, QHeaderView.Stretch) self.__pluginsView.header().resizeSection(SETTINGS_COL, 24) self.__pluginsView.header().setSectionResizeMode( SETTINGS_COL, QHeaderView.Fixed) def __pluginSelectionChanged(self): """Triggered when an item is selected""" selected = list(self.__pluginsView.selectedItems()) if selected: self.__updateDetails(selected[0]) else: self.__updateDetails(None) def __updateDetails(self, item): """Updates the content of the details and the error boxes""" self.__details.clear() self.__errorsText.setText("") if item is None: return self.__details.addTopLevelItem( QTreeWidgetItem(["Author", item.plugin.getAuthor()])) self.__details.addTopLevelItem( QTreeWidgetItem(["Path", os.path.normpath(item.plugin.getPath())])) self.__details.addTopLevelItem( QTreeWidgetItem(["Description", item.plugin.getDescription()])) self.__details.addTopLevelItem( QTreeWidgetItem(["Web site", item.plugin.getWebsite()])) copyright = item.plugin.getCopyright() if copyright is not None: if copyright.lower() != "unknown": self.__details.addTopLevelItem( QTreeWidgetItem(["Copyright", copyright])) for name in item.plugin.getDetails(): value = item.plugin.getDetails()[name] self.__details.addTopLevelItem(QTreeWidgetItem([name, value])) self.__errorsText.setText(item.plugin.conflictMessage) def __onItemChanged(self, item, column): """Triggered when an item is changed""" if self.__inItemChange: return if item.active: self.__inItemChange = True item.plugin.disable() item.active = False settingsButton = self.__pluginsView.itemWidget(item, SETTINGS_COL) settingsButton.setEnabled(False) if settingsButton.index != -1: settingsButton.setToolTip( "Enable plugin and then click to configure") if item.category in self.__pluginManager.inactivePlugins: self.__pluginManager. \ inactivePlugins[item.category].append(item.plugin) else: self.__pluginManager. \ inactivePlugins[item.category] = [item.plugin] self.__pluginManager. \ activePlugins[item.category].remove(item.plugin) self.__pluginManager.saveDisabledPlugins() self.__inItemChange = False self.__pluginManager.sendPluginDeactivated(item.plugin) return self.__inItemChange = True message = self.__pluginManager.checkConflict(item.plugin) if message is not None: item.setCheckState(STATE_COL, Qt.Unchecked) self.__errorsText.setText(message) self.__inItemChange = False return try: item.plugin.enable() item.active = True if item.category in self.__pluginManager.activePlugins: self.__pluginManager. \ activePlugins[item.category].append(item.plugin) else: self.__pluginManager. \ activePlugins[item.category] = [item.plugin] self.__pluginManager. \ inactivePlugins[item.category].remove(item.plugin) self.__pluginManager.saveDisabledPlugins() self.__errorsText.setText("") item.setIcon(CONFLICT_COL, getIcon('empty.png')) item.setToolTip(CONFLICT_COL, "") settingsButton = self.__pluginsView.itemWidget(item, SETTINGS_COL) if settingsButton.index != -1: settingsButton.setToolTip("Click to configure") settingsButton.setEnabled(True) self.__pluginManager.sendPluginActivated(item.plugin) except Exception as exc: item.setCheckState(STATE_COL, Qt.Unchecked) self.__errorsText.setText( "Error activating the plugin, exception is generated:\n" + str(exc)) except: item.setCheckState(STATE_COL, Qt.Unchecked) self.__errorsText.setText( "Error activating the plugin, unknown exception") self.__inItemChange = False def onPluginSettings(self, index): """Triggered when a configuring function is called""" if index not in self.__configFuncs: return try: self.__configFuncs[index]() except Exception as exc: logging.error("Error calling the plugin configuration function. " "Message: " + str(exc))
class SVNPluginLogDialog(QDialog): """SVN plugin log dialog""" NODIFF = '<html><body bgcolor="#ffffe6"></body></html>' def __init__(self, plugin, client, path, logInfo, parent=None): QDialog.__init__(self, parent) self.__plugin = plugin self.__client = client self.__path = path self.__logInfo = logInfo self.__lhsSelected = None self.__rhsSelected = None self.__createLayout() self.setWindowTitle("SVN Log") lastIndex = len(self.__logInfo) - 1 index = 0 for log in self.__logInfo: newItem = LogItem(log) self.__logView.addTopLevelItem(newItem) if index != lastIndex: rev = log.revision.number nextRev = self.__logInfo[index + 1].revision.number diffButton = self.__createDiffButton( log.revision, self.__logInfo[index + 1].revision) if rev is not None and nextRev is not None: diffButton.setToolTip( "Click to see diff to the older revision (r." + str(rev) + " to r." + str(nextRev) + ")") else: diffButton.setEnabled(False) diffButton.setToolTip( "Could not determine current or previous revision") else: diffButton = self.__createDiffButton(None, None) diffButton.setEnabled(False) diffButton.setToolTip( "Diff to previous revision is not avalable for the first revision" ) self.__logView.setItemWidget(newItem, DIFFTONEXT_COL, diffButton) index += 1 self.__resizeLogView() self.__sortLogView() self.__logView.setFocus() def __createDiffButton(self, rev, prevRev): """Creates a diff button for a path""" button = DiffButton() button.rev = rev button.prevRev = prevRev self.connect(button, SIGNAL('CustomClick'), self.onDiffBetween) return button def __resizeLogView(self): """Resizes the plugins table""" self.__logView.header().setStretchLastSection(True) self.__logView.header().resizeSections(QHeaderView.ResizeToContents) self.__logView.header().resizeSection(SELECT_COL, 28) self.__logView.header().setResizeMode(SELECT_COL, QHeaderView.Fixed) self.__logView.header().resizeSection(DIFFTONEXT_COL, 24) self.__logView.header().setResizeMode(DIFFTONEXT_COL, QHeaderView.Fixed) def __sortLogView(self): """Sorts the log table""" self.__logView.sortItems(self.__logView.sortColumn(), self.__logView.header().sortIndicatorOrder()) def __createLayout(self): """Creates the dialog layout""" self.resize(640, 480) self.setSizeGripEnabled(True) vboxLayout = QVBoxLayout(self) # Revisions to compare compareGroupbox = QGroupBox(self) compareGroupbox.setTitle("Revisions to compare") sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( compareGroupbox.sizePolicy().hasHeightForWidth()) compareGroupbox.setSizePolicy(sizePolicy) revisionLayout = QHBoxLayout(compareGroupbox) self.__lhsRevisionLabel = QLabel() self.__lhsRevisionLabel.setFrameStyle(QFrame.StyledPanel) self.__lhsResetButton = QToolButton() self.__lhsResetButton.setIcon( getIcon(pluginHomeDir + 'svnclearrev.png')) self.__lhsResetButton.setFocusPolicy(Qt.NoFocus) self.__lhsResetButton.setEnabled(False) self.__lhsResetButton.setToolTip("Reset revision to compare") self.__lhsResetButton.clicked.connect(self.__onLHSReset) self.__rhsRevisionLabel = QLabel() self.__rhsRevisionLabel.setFrameStyle(QFrame.StyledPanel) self.__rhsResetButton = QToolButton() self.__rhsResetButton.setIcon( getIcon(pluginHomeDir + 'svnclearrev.png')) self.__rhsResetButton.setFocusPolicy(Qt.NoFocus) self.__rhsResetButton.setEnabled(False) self.__rhsResetButton.setToolTip("Reset revision to compare") self.__rhsResetButton.clicked.connect(self.__onRHSReset) lhsLayout = QHBoxLayout() lhsLayout.addWidget(self.__lhsRevisionLabel) lhsLayout.addWidget(self.__lhsResetButton) rhsLayout = QHBoxLayout() rhsLayout.addWidget(self.__rhsRevisionLabel) rhsLayout.addWidget(self.__rhsResetButton) bothLayout = QVBoxLayout() bothLayout.addLayout(lhsLayout) bothLayout.addLayout(rhsLayout) revisionLayout.addLayout(bothLayout) self.__diffButton = QToolButton() self.__diffButton.setText("Diff") self.__diffButton.setFocusPolicy(Qt.NoFocus) self.__diffButton.setEnabled(False) self.__diffButton.clicked.connect(self.__onDiff) revisionLayout.addWidget(self.__diffButton) vboxLayout.addWidget(compareGroupbox) # Log table logHeaderFrame = QFrame() logHeaderFrame.setFrameStyle(QFrame.StyledPanel) logHeaderFrame.setAutoFillBackground(True) self.__setLightPalette(logHeaderFrame) logHeaderFrame.setFixedHeight(24) logHeaderLayout = QHBoxLayout() logHeaderLayout.setContentsMargins(3, 0, 0, 0) logHeaderLayout.addWidget(QLabel("Subversion log of " + self.__path)) logHeaderFrame.setLayout(logHeaderLayout) vboxLayout.addWidget(logHeaderFrame) self.__logView = QTreeWidget() self.__logView.setAlternatingRowColors(True) self.__logView.setRootIsDecorated(False) self.__logView.setItemsExpandable(False) self.__logView.setSortingEnabled(True) self.__logView.setItemDelegate(NoOutlineHeightDelegate(4)) self.__logViewHeader = QTreeWidgetItem( ["", "", "Revision", "Date", "Author", "Message"]) self.__logView.setHeaderItem(self.__logViewHeader) self.__logView.header().setSortIndicator(REVISION_COL, Qt.AscendingOrder) self.__logView.itemChanged.connect(self.__onLogViewChanged) vboxLayout.addWidget(self.__logView) # Diff part diffHeaderFrame = QFrame() diffHeaderFrame.setFrameStyle(QFrame.StyledPanel) diffHeaderFrame.setAutoFillBackground(True) self.__setLightPalette(diffHeaderFrame) diffHeaderFrame.setFixedHeight(24) diffLabel = QLabel("Diff") diffExpandingSpacer = QSpacerItem(10, 10, QSizePolicy.Expanding) self.__showHideDiffButton = QToolButton() self.__showHideDiffButton.setAutoRaise(True) self.__showHideDiffButton.setIcon(getIcon('less.png')) self.__showHideDiffButton.setFixedSize(20, 20) self.__showHideDiffButton.setToolTip("Show diff") self.__showHideDiffButton.setFocusPolicy(Qt.NoFocus) self.__showHideDiffButton.clicked.connect(self.__onShowHideDiff) diffLayout = QHBoxLayout() diffLayout.setContentsMargins(3, 0, 0, 0) diffLayout.addWidget(diffLabel) diffLayout.addSpacerItem(diffExpandingSpacer) diffLayout.addWidget(self.__showHideDiffButton) diffHeaderFrame.setLayout(diffLayout) self.__diffViewer = DiffTabWidget() self.__diffViewer.setHTML(self.NODIFF) self.__diffViewer.setVisible(False) vboxLayout.addWidget(diffHeaderFrame) vboxLayout.addWidget(self.__diffViewer) # Buttons at the bottom buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Ok) buttonBox.button(QDialogButtonBox.Ok).setDefault(True) buttonBox.accepted.connect(self.close) vboxLayout.addWidget(buttonBox) @staticmethod def __setLightPalette(frame): """Creates a lighter palette for the widget background""" palette = frame.palette() background = palette.color(QPalette.Background) background.setRgb(min(background.red() + 30, 255), min(background.green() + 30, 255), min(background.blue() + 30, 255)) palette.setColor(QPalette.Background, background) frame.setPalette(palette) def __onShowHideDiff(self): """On/off the diff section""" if self.__diffViewer.isVisible(): self.__diffViewer.setVisible(False) self.__showHideDiffButton.setIcon(getIcon('less.png')) self.__showHideDiffButton.setToolTip("Show diff") else: self.__diffViewer.setVisible(True) self.__showHideDiffButton.setIcon(getIcon('more.png')) self.__showHideDiffButton.setToolTip("Hide diff") def onDiffBetween(self, rev, prevRev): """Called when diff is requested between revisions""" if not rev or not prevRev: return QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) try: lhsContent = self.__client.cat(self.__path, prevRev) rhsContent = self.__client.cat(self.__path, rev) except Exception as exc: QApplication.restoreOverrideCursor() logging.error(str(exc)) return except: QApplication.restoreOverrideCursor() logging.error("Unknown error while retrieving " + self.__path + " content from the repository.") return QApplication.restoreOverrideCursor() diff = difflib.unified_diff(lhsContent.splitlines(), rhsContent.splitlines()) nodiffMessage = self.__path + " has no difference from revision " + \ str(prevRev.number) + " to revision " + str(rev.number) if diff is None: logging.info(nodiffMessage) return # There are changes, so replace the text and tell about the changes diffAsText = '\n'.join(list(diff)) if diffAsText.strip() == '': logging.info(nodiffMessage) return lhs = "--- revision " + str(prevRev.number) diffAsText = diffAsText.replace("--- ", lhs, 1) rhs = "+++ revision " + str(rev.number) diffAsText = diffAsText.replace("+++ ", rhs, 1) self.__diffViewer.setHTML(parse_from_memory(diffAsText, False, True)) if not self.__diffViewer.isVisible(): self.__onShowHideDiff() def __onDiff(self): """Show diff between revisions""" self.onDiffBetween(self.__rhsSelected.revision, self.__lhsSelected.revision) def __onLogViewChanged(self, item, column): """Revision selected for diff""" if item.checkState(SELECT_COL) == Qt.Checked: # An item has been selected if self.__lhsSelected is None: self.__lhsSelected = item.logInfo self.__normalizeSelected() return if self.__rhsSelected is None: self.__rhsSelected = item.logInfo self.__normalizeSelected() return # Both of the places have been occupied. Pick the one to update. if item.logInfo.date > self.__rhsSelected.date: self.__rhsSelected = item.logInfo else: self.__lhsSelected = item.logInfo self.__normalizeSelected() else: # An item has been de-selected if self.__lhsSelected is not None: if self.__lhsSelected.revision.number == item.logInfo.revision.number: self.__lhsSelected = None elif self.__rhsSelected is not None: if self.__rhsSelected.revision.number == item.logInfo.revision.number: self.__rhsSelected = None self.__normalizeSelected() return def __onLHSReset(self): """Revision removed from diff""" if self.__lhsSelected is not None: self.__deselectRevision(self.__lhsSelected.revision.number) self.__lhsSelected = None self.__lhsRevisionLabel.setText("") self.__diffButton.setEnabled(False) self.__lhsResetButton.setEnabled(False) def __onRHSReset(self): """Revision removed from diff""" if self.__rhsSelected is not None: self.__deselectRevision(self.__rhsSelected.revision.number) self.__rhsSelected = None self.__rhsRevisionLabel.setText("") self.__diffButton.setEnabled(False) self.__rhsResetButton.setEnabled(False) def __deselectRevision(self, revNumber): """Deselects a revision in the list""" index = 0 while index < self.__logView.topLevelItemCount(): item = self.__logView.topLevelItem(index) if item.logInfo.revision.number == revNumber: item.setCheckState(SELECT_COL, Qt.Unchecked) break index += 1 def __normalizeSelected(self): """Puts the earliest revision first""" if self.__lhsSelected is not None and self.__rhsSelected is not None: # It might be necessary to exchange the versions if self.__rhsSelected.date < self.__lhsSelected.date: temp = self.__rhsSelected self.__rhsSelected = self.__lhsSelected self.__lhsSelected = temp self.__diffButton.setEnabled(True) else: self.__diffButton.setEnabled(False) if self.__lhsSelected is None: self.__lhsRevisionLabel.setText("") self.__lhsRevisionLabel.setToolTip("") self.__lhsResetButton.setEnabled(False) else: self.__lhsRevisionLabel.setText( str(self.__lhsSelected.revision.number) + " (" + timestampToString(self.__lhsSelected.date) + ")") self.__lhsRevisionLabel.setToolTip(str(self.__lhsSelected.message)) self.__lhsResetButton.setEnabled(True) if self.__rhsSelected is None: self.__rhsRevisionLabel.setText("") self.__rhsRevisionLabel.setToolTip("") self.__rhsResetButton.setEnabled(False) else: self.__rhsRevisionLabel.setText( str(self.__rhsSelected.revision.number) + " (" + timestampToString(self.__rhsSelected.date) + ")") self.__rhsRevisionLabel.setToolTip(str(self.__rhsSelected.message)) self.__rhsResetButton.setEnabled(True)
def __init__(self, parent=None): QTreeWidget.__init__(self, parent)
def __createLayout(self): """Creates the dialog layout""" self.resize(640, 480) self.setSizeGripEnabled(True) layout = QVBoxLayout() # Plugins list self.__pluginsView = QTreeWidget() self.__pluginsView.setAlternatingRowColors(True) self.__pluginsView.setRootIsDecorated(False) self.__pluginsView.setItemsExpandable(False) self.__pluginsView.setSortingEnabled(True) self.__pluginsView.setItemDelegate(NoOutlineHeightDelegate(4)) self.__pluginsView.setUniformRowHeights(True) # Alert | system/user | Enable | Name | Version self.__pluginsHeader = QTreeWidgetItem( ["", "", "", "Name", "Version", ""]) self.__pluginsView.setHeaderItem(self.__pluginsHeader) self.__pluginsView.header().setSortIndicator(NAME_COL, Qt.AscendingOrder) self.__pluginsView.itemSelectionChanged.connect( self.__pluginSelectionChanged) self.__pluginsView.itemChanged.connect(self.__onItemChanged) layout.addWidget(self.__pluginsView) # Detailed information detailsLabel = QLabel("Detailed information") layout.addWidget(detailsLabel) self.__details = QTreeWidget() self.__details.setAlternatingRowColors(False) self.__details.setRootIsDecorated(False) self.__details.setItemsExpandable(False) self.__details.setSortingEnabled(False) self.__details.setItemDelegate(NoOutlineHeightDelegate(4)) self.__details.setUniformRowHeights(True) detailsHeader = QTreeWidgetItem(["", ""]) self.__details.setHeaderItem(detailsHeader) self.__details.setHeaderHidden(True) metrics = QFontMetrics(self.__details.font()) rect = metrics.boundingRect("X") self.__details.setFixedHeight(rect.height() * 6 + 5) layout.addWidget(self.__details) # Errors/warnings errorsLabel = QLabel("Errors / warnings") layout.addWidget(errorsLabel) self.__errorsText = QTextEdit() self.__errorsText.setReadOnly(True) self.__errorsText.setAcceptRichText(False) metrics = QFontMetrics(self.__errorsText.font()) rect = metrics.boundingRect("X") self.__errorsText.setFixedHeight(rect.height() * 4 + 5) layout.addWidget(self.__errorsText) # Buttons box buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Ok) self.__OKButton = buttonBox.button(QDialogButtonBox.Ok) self.__OKButton.setDefault(True) buttonBox.accepted.connect(self.close) buttonBox.rejected.connect(self.close) layout.addWidget(buttonBox) self.setLayout(layout)
class SVNPluginStatusDialog(QDialog): """SVN Plugin status dialog""" def __init__(self, statusList, parent=None): QDialog.__init__(self, parent) # Split statuses paths = [] ignoredPaths = [] for status in statusList: if status[1] == IND_IGNORED: ignoredPaths.append(status) else: paths.append(status) self.__createLayout(paths, ignoredPaths) self.setWindowTitle("SVN status") # Fill the lists for item in paths: message = "" if item[2]: message = item[2] newItem = QTreeWidgetItem(["", item[0], STATUS[item[1]], message]) pixmap = getIndicatorPixmap(item[1]) if pixmap: newItem.setIcon(0, QIcon(pixmap)) newItem.setToolTip(1, item[0]) newItem.setToolTip(2, STATUS[item[1]]) if message: newItem.setToolTip(3, message) self.__pathView.addTopLevelItem(newItem) self.__pathView.header().resizeSections(QHeaderView.ResizeToContents) self.__pathView.header().resizeSection(0, 20) self.__pathView.header().setResizeMode(QHeaderView.Fixed) for item in ignoredPaths: newItem = QTreeWidgetItem([item[0], STATUS[item[1]]]) newItem.setToolTip(0, item[0]) newItem.setToolTip(1, STATUS[item[1]]) self.__ignoredPathView.addTopLevelItem(newItem) self.__ignoredPathView.header().resizeSections(QHeaderView.ResizeToContents) def __createLayout(self, paths, ignoredPaths): """Creates the dialog layout""" self.resize(640, 420) self.setSizeGripEnabled(True) vboxLayout = QVBoxLayout(self) # Paths to commit part vboxLayout.addWidget(QLabel("Paths (total: " + str(len(paths)) + ")")) self.__pathView = QTreeWidget() self.__pathView.setAlternatingRowColors(True) self.__pathView.setRootIsDecorated(False) self.__pathView.setItemsExpandable(False) self.__pathView.setSortingEnabled(True) self.__pathView.setItemDelegate(NoOutlineHeightDelegate(4)) self.__pathView.setUniformRowHeights(True) self.__pathHeader = QTreeWidgetItem(["", "Path", "Status", "Message"]) self.__pathView.setHeaderItem(self.__pathHeader) self.__pathView.header().setSortIndicator(1, Qt.AscendingOrder) vboxLayout.addWidget(self.__pathView) # Paths to ignore part vboxLayout.addWidget(QLabel("Ignored paths (total: " + str(len(ignoredPaths)) + ")")) self.__ignoredPathView = QTreeWidget() self.__ignoredPathView.setAlternatingRowColors(True) self.__ignoredPathView.setRootIsDecorated(False) self.__ignoredPathView.setItemsExpandable(False) self.__ignoredPathView.setSortingEnabled(True) self.__ignoredPathView.setItemDelegate(NoOutlineHeightDelegate(4)) self.__ignoredPathView.setUniformRowHeights(True) pathToIgnoreHeader = QTreeWidgetItem(["Path", "Status"]) self.__ignoredPathView.setHeaderItem(pathToIgnoreHeader) self.__ignoredPathView.header().setSortIndicator(0, Qt.AscendingOrder) vboxLayout.addWidget(self.__ignoredPathView) # Buttons at the bottom buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Ok) buttonBox.button(QDialogButtonBox.Ok).setDefault(True) buttonBox.accepted.connect(self.accept) vboxLayout.addWidget(buttonBox)
def __createLayout(self): """Creates the widget layout""" verticalLayout = QVBoxLayout(self) verticalLayout.setContentsMargins(0, 0, 0, 0) verticalLayout.setSpacing(0) self.__excptLabel = HeaderFitLabel(self) self.__excptLabel.setText('Ignored exception types') self.__excptLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.__excptLabel.setMinimumWidth(10) self.__showHideButton = QToolButton() self.__showHideButton.setAutoRaise(True) self.__showHideButton.setIcon(getIcon('less.png')) self.__showHideButton.setFixedSize(self.__excptLabel.height(), self.__excptLabel.height()) self.__showHideButton.setToolTip('Hide ignored exceptions list') self.__showHideButton.setFocusPolicy(Qt.NoFocus) self.__showHideButton.clicked.connect(self.onShowHide) self.headerToolbar = QToolBar(self) self.headerToolbar.setIconSize(QSize(16, 16)) self.headerToolbar.setContentsMargins(1, 1, 1, 1) self.headerToolbar.addWidget(self.__excptLabel) self.headerToolbar.addWidget(self.__showHideButton) 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) self.__removeButton = QAction(getIcon('delitem.png'), "Remove selected exception type", self) self.__removeButton.triggered.connect(self.__onRemoveFromIgnore) self.__removeButton.setEnabled(False) self.__removeAllButton = QAction(getIcon('ignexcptdelall.png'), "Remove all the exception types", self) self.__removeAllButton.triggered.connect(self.__onRemoveAllFromIgnore) self.__removeAllButton.setEnabled(False) self.toolbar = QToolBar() self.toolbar.setOrientation(Qt.Horizontal) self.toolbar.setMovable(False) self.toolbar.setAllowedAreas(Qt.TopToolBarArea) self.toolbar.setIconSize(QSize(16, 16)) self.toolbar.setFixedHeight(28) self.toolbar.setContentsMargins(0, 0, 0, 0) self.toolbar.addWidget(ToolBarExpandingSpacer(self.toolbar)) self.toolbar.addAction(self.__removeButton) self.toolbar.addWidget(ToolBarHSpacer(self.toolbar, 5)) 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.headerToolbar) verticalLayout.addWidget(self.toolbar) verticalLayout.addWidget(self.exceptionsList) verticalLayout.addLayout(addLayout)
def __createLayout(self, pluginHomeDir): """Creates the layout""" self.clearButton = QAction(getIcon('trash.png'), 'Clear', self) self.clearButton.triggered.connect(self.clear) self.outputButton = QAction(QIcon(pluginHomeDir + 'output.png'), 'Show pylint raw stdout and stderr', self) self.outputButton.triggered.connect(self.__showOutput) self.toolbar = QToolBar(self) self.toolbar.setOrientation(Qt.Vertical) self.toolbar.setMovable(False) self.toolbar.setAllowedAreas(Qt.RightToolBarArea) self.toolbar.setIconSize(QSize(16, 16)) self.toolbar.setFixedWidth(28) self.toolbar.setContentsMargins(0, 0, 0, 0) self.toolbar.addAction(self.outputButton) self.toolbar.addWidget(ToolBarExpandingSpacer(self.toolbar)) self.toolbar.addAction(self.clearButton) self.__resultsTree = QTreeWidget(self) self.__resultsTree.setAlternatingRowColors(True) self.__resultsTree.setRootIsDecorated(True) self.__resultsTree.setItemsExpandable(True) self.__resultsTree.setUniformRowHeights(True) self.__resultsTree.setItemDelegate(NoOutlineHeightDelegate(4)) headerLabels = ['Message type / line', 'id', 'Message'] self.__resultsTree.setHeaderLabels(headerLabels) self.__resultsTree.itemActivated.connect(self.__resultActivated) self.__fileLabel = HeaderFitPathLabel(None, self) self.__fileLabel.setAlignment(Qt.AlignLeft) self.__fileLabel.setMinimumWidth(50) self.__fileLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.__fileLabel.doubleClicked.connect(self.onPathLabelDoubleClick) self.__fileLabel.setContextMenuPolicy(Qt.CustomContextMenu) self.__fileLabel.customContextMenuRequested.connect( self.showPathLabelContextMenu) self.__rateLabel = HeaderLabel() self.__rateLabel.setToolTip('pylint analysis rate out of 10 ' '(previous run if there was one)') self.__timestampLabel = HeaderLabel() self.__timestampLabel.setToolTip('pylint analysis timestamp') self.__labelLayout = QHBoxLayout() self.__labelLayout.setSpacing(4) self.__labelLayout.addWidget(self.__fileLabel) self.__labelLayout.addWidget(self.__rateLabel) self.__labelLayout.addWidget(self.__timestampLabel) self.__vLayout = QVBoxLayout() self.__vLayout.setSpacing(4) self.__vLayout.addLayout(self.__labelLayout) self.__vLayout.addWidget(self.__resultsTree) self.__hLayout = QHBoxLayout() self.__hLayout.setContentsMargins(0, 0, 0, 0) self.__hLayout.setSpacing(0) self.__hLayout.addWidget(self.toolbar) self.__hLayout.addWidget(self.__noneLabel) self.__hLayout.addLayout(self.__vLayout) self.setLayout(self.__hLayout) self.__updateButtons()
class PylintResultViewer(QWidget): """Pylint results viewer""" def __init__(self, ide, pluginHomeDir, parent=None): QWidget.__init__(self, parent) self.__results = None self.__ide = ide self.__pluginHomeDir = pluginHomeDir self.__noneLabel = QLabel("\nNo results available") self.__noneLabel.setFrameShape(QFrame.StyledPanel) self.__noneLabel.setAlignment(Qt.AlignHCenter) font = self.__noneLabel.font() font.setPointSize(font.pointSize() + 4) self.__noneLabel.setFont(font) self.__noneLabel.setAutoFillBackground(True) noneLabelPalette = self.__noneLabel.palette() noneLabelPalette.setColor(QPalette.Background, GlobalData().skin['nolexerPaper']) self.__noneLabel.setPalette(noneLabelPalette) self.__createLayout(self.__pluginHomeDir) def __createLayout(self, pluginHomeDir): """Creates the layout""" self.clearButton = QAction(getIcon('trash.png'), 'Clear', self) self.clearButton.triggered.connect(self.clear) self.outputButton = QAction(QIcon(pluginHomeDir + 'output.png'), 'Show pylint raw stdout and stderr', self) self.outputButton.triggered.connect(self.__showOutput) self.toolbar = QToolBar(self) self.toolbar.setOrientation(Qt.Vertical) self.toolbar.setMovable(False) self.toolbar.setAllowedAreas(Qt.RightToolBarArea) self.toolbar.setIconSize(QSize(16, 16)) self.toolbar.setFixedWidth(28) self.toolbar.setContentsMargins(0, 0, 0, 0) self.toolbar.addAction(self.outputButton) self.toolbar.addWidget(ToolBarExpandingSpacer(self.toolbar)) self.toolbar.addAction(self.clearButton) self.__resultsTree = QTreeWidget(self) self.__resultsTree.setAlternatingRowColors(True) self.__resultsTree.setRootIsDecorated(True) self.__resultsTree.setItemsExpandable(True) self.__resultsTree.setUniformRowHeights(True) self.__resultsTree.setItemDelegate(NoOutlineHeightDelegate(4)) headerLabels = ['Message type / line', 'id', 'Message'] self.__resultsTree.setHeaderLabels(headerLabels) self.__resultsTree.itemActivated.connect(self.__resultActivated) self.__fileLabel = HeaderFitPathLabel(None, self) self.__fileLabel.setAlignment(Qt.AlignLeft) self.__fileLabel.setMinimumWidth(50) self.__fileLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.__fileLabel.doubleClicked.connect(self.onPathLabelDoubleClick) self.__fileLabel.setContextMenuPolicy(Qt.CustomContextMenu) self.__fileLabel.customContextMenuRequested.connect( self.showPathLabelContextMenu) self.__rateLabel = HeaderLabel() self.__rateLabel.setToolTip('pylint analysis rate out of 10 ' '(previous run if there was one)') self.__timestampLabel = HeaderLabel() self.__timestampLabel.setToolTip('pylint analysis timestamp') self.__labelLayout = QHBoxLayout() self.__labelLayout.setSpacing(4) self.__labelLayout.addWidget(self.__fileLabel) self.__labelLayout.addWidget(self.__rateLabel) self.__labelLayout.addWidget(self.__timestampLabel) self.__vLayout = QVBoxLayout() self.__vLayout.setSpacing(4) self.__vLayout.addLayout(self.__labelLayout) self.__vLayout.addWidget(self.__resultsTree) self.__hLayout = QHBoxLayout() self.__hLayout.setContentsMargins(0, 0, 0, 0) self.__hLayout.setSpacing(0) self.__hLayout.addWidget(self.toolbar) self.__hLayout.addWidget(self.__noneLabel) self.__hLayout.addLayout(self.__vLayout) self.setLayout(self.__hLayout) self.__updateButtons() def __updateButtons(self): """Updates the toolbar buttons approprietly""" self.clearButton.setEnabled(self.__results is not None) if self.__results is not None: stdout = self.__results.get('StdOut', None) stderr = self.__results.get('StdErr', None) self.outputButton.setEnabled(stdout is not None or stderr is not None) else: self.outputButton.setEnabled(False) def showResults(self, results): """Populates the analysis results""" self.clear() self.__noneLabel.setVisible(False) self.__fileLabel.setVisible(True) self.__rateLabel.setVisible(True) self.__timestampLabel.setVisible(True) self.__resultsTree.setVisible(True) self.__results = results self.__updateButtons() tooltip = ' '.join(['pylint results for', os.path.basename(results['FileName']), 'at', results['Timestamp']]) self.__ide.sideBars['bottom'].setTabToolTip('pylint', tooltip) self.__fileLabel.setPath(results['FileName']) if 'Rate' in results: text = str(results['Rate']) if 'PreviousRunRate' in results: text += ' (' + str(results['PreviousRunRate']) + ')' self.__rateLabel.setText(' ' + text + ' ') else: self.__rateLabel.setVisible(False) self.__timestampLabel.setText(results['Timestamp']) totalMessages = 0 totalMessages += self.__populateMessages('Errors') totalMessages += self.__populateMessages('Warnings') totalMessages += self.__populateMessages('Refactoring') totalMessages += self.__populateMessages('Cosmetics') # Update the header with the total number of matches headerLabels = ['Message type / line', 'id', 'Message (total messages: ' + str(totalMessages) + ')'] self.__resultsTree.setHeaderLabels(headerLabels) # Resizing self.__resultsTree.header().resizeSections( QHeaderView.ResizeToContents) def __populateMessages(self, title): """Populates the analysis messages""" count = len(self.__results[title[0]]) if count > 0: suffix = '' if count == 1 else 's' messageTypeItem = MessageTypeTableItem( [title, '', '(' + str(count) + ' message' + suffix + ')']) self.__resultsTree.addTopLevelItem(messageTypeItem) for item in self.__results[title[0]]: columns = [str(item[1]), item[3], item[2]] messageItem = MessageTableItem(columns) messageTypeItem.addChild(messageItem) messageTypeItem.setExpanded(True) return count def clear(self): """Clears the results view""" self.__results = None self.__updateButtons() tooltip = 'No results available' self.__ide.sideBars['bottom'].setTabToolTip('pylint', tooltip) self.__noneLabel.setVisible(True) self.__fileLabel.setVisible(False) self.__rateLabel.setVisible(False) self.__timestampLabel.setVisible(False) self.__resultsTree.setVisible(False) self.__resultsTree.clear() def __resultActivated(self, item, column): """Handles the double click (or Enter) on a message""" del column # unused argument if self.__results: if isinstance(item, MessageTableItem): fileName = self.__results['FileName'] lineNumber = int(item.data(0, Qt.DisplayRole)) self.__ide.mainWindow.openFile(fileName, lineNumber) def __showOutput(self): """Shows the analysis stdout and stderr""" if self.__results is None: return # Show a separate dialog PylintStdoutStderrViewer(self.__ide.mainWindow, self.__results).exec_() def onPathLabelDoubleClick(self): """Double click on the path label""" txt = self.__getPathLabelFilePath() if txt.lower(): QApplication.clipboard().setText(txt) def __getPathLabelFilePath(self): """Provides undecorated path label content""" txt = str(self.__fileLabel.getPath()) if txt.startswith('File: '): return txt.replace('File: ', '') return txt def showPathLabelContextMenu(self, pos): """Triggered when a context menu is requested for the path label""" contextMenu = QMenu(self) contextMenu.addAction(getIcon('copymenu.png'), 'Copy full path to clipboard (double click)', self.onPathLabelDoubleClick) contextMenu.addSeparator() contextMenu.addAction(getIcon(''), 'Copy directory path to clipboard', self.onCopyDirToClipboard) contextMenu.addAction(getIcon(''), 'Copy file name to clipboard', self.onCopyFileNameToClipboard) contextMenu.popup(self.__fileLabel.mapToGlobal(pos)) def onCopyDirToClipboard(self): """Copies the dir path of the current file into the clipboard""" txt = self.__getPathLabelFilePath() if txt.lower(): try: QApplication.clipboard().setText(os.path.dirname(txt) + os.path.sep) except: pass def onCopyFileNameToClipboard(self): """Copies the file name of the current file into the clipboard""" txt = self.__getPathLabelFilePath() if txt.lower(): try: QApplication.clipboard().setText(os.path.basename(txt)) except: pass
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 not Settings()['showThreadViewer']: self.__onShowHide(True) def __createLayout(self): """Creates the widget layout""" verticalLayout = QVBoxLayout(self) verticalLayout.setContentsMargins(0, 0, 0, 0) verticalLayout.setSpacing(0) self.__threadsLabel = QLabel("Threads", self) self.headerFrame = QFrame() self.headerFrame.setObjectName('threadheader') self.headerFrame.setStyleSheet('QFrame#threadheader {' + getLabelStyle(self.__threadsLabel) + '}') self.headerFrame.setFixedHeight(HEADER_HEIGHT) expandingSpacer = QSpacerItem(10, 10, QSizePolicy.Expanding) self.__showHideButton = QToolButton() self.__showHideButton.setAutoRaise(True) self.__showHideButton.setIcon(getIcon('less.png')) self.__showHideButton.setFixedSize(HEADER_BUTTON, HEADER_BUTTON) self.__showHideButton.setToolTip("Hide threads list") self.__showHideButton.setFocusPolicy(Qt.NoFocus) self.__showHideButton.clicked.connect(self.__onShowHide) headerLayout = QHBoxLayout() headerLayout.setContentsMargins(0, 0, 0, 0) headerLayout.addSpacing(3) headerLayout.addWidget(self.__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) 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(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(getIcon('less.png')) self.__showHideButton.setToolTip("Hide threads list") self.setMinimumHeight(self.__minH) self.setMaximumHeight(self.__maxH) Settings()['showThreadViewer'] = True 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().setSectionResizeMode(0, QHeaderView.Fixed) def clear(self): """Clears the content""" self.__threadsList.clear() self.__threadsLabel.setText("Threads") 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)) + ")") def switchControl(self, isInIDE): """Switches the UI depending where the control flow is""" self.__threadsList.setEnabled(isInIDE) # Arguments: item, column def __onThreadClicked(self, item, _): """Triggered when a thread is clicked""" if item.isCurrent(): return for index in range(self.__threadsList.topLevelItemCount()): listItem = self.__threadsList.topLevelItem(index) if listItem.isCurrent(): listItem.setCurrent(False) break item.setCurrent(True) self.__debugger.remoteSetThread(item.getTID())