def __createLayout(self, labelText): """Creates the dialog layout""" self.resize(600, 250) self.setSizeGripEnabled(True) # Top level layout layout = QVBoxLayout(self) layout.addWidget(QLabel(labelText)) self.__newCaption = QTextEdit() self.__newCaption.setFont(getZoomedMonoFont()) self.__newCaption.setAcceptRichText(False) layout.addWidget(self.__newCaption) # Buttons at the bottom 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.accept) buttonBox.rejected.connect(self.close) layout.addWidget(buttonBox) self.__newCaption.setFocus()
def __createLayout(self): """Creates the dialog layout""" self.resize(450, 150) self.setSizeGripEnabled(True) verticalLayout = QVBoxLayout(self) gridLayout = QGridLayout() # Link gridLayout.addWidget(QLabel('Link', self), 0, 0, 1, 1) self.linkEdit = QLineEdit(self) self.linkEdit.setClearButtonEnabled(True) self.linkEdit.setToolTip( 'A link to a file or to an external web resource') gridLayout.addWidget(self.linkEdit, 0, 1, 1, 1) self.linkEdit.textChanged.connect(self.__validate) self.fileButton = QPushButton(self) self.fileButton.setText('...') self.fileButton.setToolTip('Select an existing or non existing file') gridLayout.addWidget(self.fileButton, 0, 2, 1, 1) self.fileButton.clicked.connect(self.__onSelectPath) self.createCheckBox = QCheckBox( 'Create a markdown file if does not exist', self) self.createCheckBox.setChecked(False) gridLayout.addWidget(self.createCheckBox, 1, 1, 1, 1) self.createCheckBox.stateChanged.connect(self.__validate) # Anchor gridLayout.addWidget(QLabel('Anchor', self), 2, 0, 1, 1) self.anchorEdit = QLineEdit(self) self.anchorEdit.setClearButtonEnabled(True) gridLayout.addWidget(self.anchorEdit, 2, 1, 1, 1) self.anchorEdit.textChanged.connect(self.__validate) # Title titleLabel = QLabel('Title', self) titleLabel.setAlignment(Qt.AlignTop) gridLayout.addWidget(titleLabel, 3, 0, 1, 1) self.titleEdit = QTextEdit() self.titleEdit.setTabChangesFocus(True) self.titleEdit.setAcceptRichText(False) self.titleEdit.setFont(getZoomedMonoFont()) self.titleEdit.setToolTip( 'If provided then will be displayed in the rectangle') gridLayout.addWidget(self.titleEdit, 3, 1, 1, 1) # Buttons at the bottom 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.accept) buttonBox.rejected.connect(self.close) verticalLayout.addLayout(gridLayout) verticalLayout.addWidget(buttonBox) self.linkEdit.setFocus()
def createLogWindow(self): """Creates a dockable RO editor for logging""" self.logWidget = QTextEdit() self.logWidget.setReadOnly(True) self.logWidget.setFontFamily("Courier") self.logWidget.setFontPointSize(12.0) logDockWidget = QDockWidget("Log", self) logDockWidget.setObjectName("LogDockWidget") logDockWidget.setAllowedAreas(Qt.BottomDockWidgetArea) logDockWidget.setWidget(self.logWidget) self.addDockWidget(Qt.BottomDockWidgetArea, logDockWidget)
class ReplaceTextDialog(QDialog): """Replace text input dialog""" def __init__(self, windowTitle, labelText, parent=None): QDialog.__init__(self, parent) self.setWindowTitle(windowTitle) self.__createLayout(labelText) def __createLayout(self, labelText): """Creates the dialog layout""" self.resize(600, 250) self.setSizeGripEnabled(True) # Top level layout layout = QVBoxLayout(self) layout.addWidget(QLabel(labelText)) self.__newCaption = QTextEdit() self.__newCaption.setFont(getZoomedMonoFont()) self.__newCaption.setAcceptRichText(False) layout.addWidget(self.__newCaption) # Buttons at the bottom 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.accept) buttonBox.rejected.connect(self.close) layout.addWidget(buttonBox) self.__newCaption.setFocus() def setText(self, txt): """Sets the text to be edited""" self.__newCaption.setPlainText(txt) def text(self): """Provides the new text""" return self.__newCaption.toPlainText()
def __createLayout(self, varName, varType, varValue, isGlobal): """Creates the dialog layout""" varTypeParts = varType.split() if varTypeParts[0].lower() in ["string", "unicode", "qstring"]: length = str(len(varValue)) lines = str(len(varValue.splitlines())) varType = varType.split("(")[0].strip() + \ " (lines: " + lines + ", characters: " + length + ")" self.resize(600, 250) self.setSizeGripEnabled(True) # Top level layout layout = QVBoxLayout(self) gridLayout = QGridLayout() gridLayout.setSpacing(4) varScopeLabel = QLabel("Scope:") gridLayout.addWidget(varScopeLabel, 0, 0, Qt.AlignCenter) if isGlobal: varScopeValue = FramedLabelWithDoubleClick("Global") else: varScopeValue = FramedLabelWithDoubleClick("Local") varScopeValue.setToolTip("Double click to copy") varScopeValue.setStyleSheet(getLabelStyle(self)) font = varScopeValue.font() font.setFamily(GlobalData().skin['monoFont'].family()) gridLayout.addWidget(varScopeValue, 0, 1) varNameLabel = QLabel("Name:") gridLayout.addWidget(varNameLabel, 1, 0, Qt.AlignCenter) varNameValue = FramedLabelWithDoubleClick(varName) varNameValue.setToolTip("Double click to copy") varNameValue.setStyleSheet(getLabelStyle(self)) gridLayout.addWidget(varNameValue, 1, 1) varTypeLabel = QLabel("Type:") gridLayout.addWidget(varTypeLabel, 2, 0, Qt.AlignCenter) varTypeValue = FramedLabelWithDoubleClick(varType) varTypeValue.setToolTip("Double click to copy") varTypeValue.setStyleSheet(getLabelStyle(self)) gridLayout.addWidget(varTypeValue, 2, 1) varValueLabel = QLabel("Value:") gridLayout.addWidget(varValueLabel, 3, 0, Qt.AlignTop) varValueValue = QTextEdit() varValueValue.setReadOnly(True) varValueValue.setFont(getZoomedMonoFont()) # varValueValue.setLineWrapMode(QTextEdit.NoWrap) varValueValue.setAcceptRichText(False) varValueValue.setPlainText(varValue) gridLayout.addWidget(varValueValue, 3, 1) layout.addLayout(gridLayout) # Buttons at the bottom 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) varValueValue.setFocus()
class MainWindow(QMainWindow): """Main application window""" def __init__(self, verbose, fName, warning): QMainWindow.__init__(self) self.logWidget = None self.view = None self.scene = None self.fName = fName self.verbose = verbose self.cFlow = None self.resize(1400, 800) self.updateWindowTitle() self.statusBar() self.createToolbar() self.createLogWindow() self.createGraphicsView() self.setCentralWidget(self.view) if verbose: self.logMessage("Using cdmcfparser version " + VERSION) if warning: self.logMessage(warning) if fName: # To yeld the main message processing loop kickOffTimer = QTimer() kickOffTimer.singleShot(200, self.proceedWithFile) def createToolbar(self): """There are a few buttons on the main window toolbar. They are: open, reload, zoom out, zoom in, debug, clear log """ openButton = QAction(QIcon('icons/open.png'), 'Open (Ctrl+O)', self) openButton.setShortcut('Ctrl+O') openButton.setStatusTip('Open python file') openButton.triggered.connect(self.openButtonClicked) reloadButton = QAction(QIcon('icons/reload.png'), 'Reload (F5)', self) reloadButton.setShortcut('F5') reloadButton.setStatusTip('Reload python file') reloadButton.triggered.connect(self.reloadButtonClicked) zoomoutButton = QAction(QIcon('icons/zoomOut.png'), 'Zoom Out (Ctrl+-)', self) zoomoutButton.setShortcut('Ctrl+-') zoomoutButton.setStatusTip('Zoom Out') zoomoutButton.triggered.connect(self.zoomOut) zoominButton = QAction(QIcon('icons/zoomIn.png'), 'Zoom In (Ctrl++)', self) zoominButton.setShortcut('Ctrl++') zoominButton.setStatusTip('Zoom In') zoominButton.triggered.connect(self.zoomIn) clearLogButton = QAction(QIcon('icons/clear.png'), 'Clear log (Ctrl+R)', self) clearLogButton.setShortcut('Ctrl+R') clearLogButton.setStatusTip('Clear log') clearLogButton.triggered.connect(self.clearButtonClicked) # A few separators separator = QAction(self) separator.setSeparator(True) separator1 = QAction(self) separator1.setSeparator(True) toolbar = self.addToolBar('Toolbar') toolbar.setIconSize(QSize(48, 48)) toolbar.addAction(openButton) toolbar.addAction(reloadButton) toolbar.addAction(separator) toolbar.addAction(zoomoutButton) toolbar.addAction(zoominButton) toolbar.addAction(separator1) toolbar.addAction(clearLogButton) def createLogWindow(self): """Creates a dockable RO editor for logging""" self.logWidget = QTextEdit() self.logWidget.setReadOnly(True) self.logWidget.setFontFamily("Courier") self.logWidget.setFontPointSize(12.0) logDockWidget = QDockWidget("Log", self) logDockWidget.setObjectName("LogDockWidget") logDockWidget.setAllowedAreas(Qt.BottomDockWidgetArea) logDockWidget.setWidget(self.logWidget) self.addDockWidget(Qt.BottomDockWidgetArea, logDockWidget) def zoomIn(self): """zoom in the main window""" self.view.zoomIn() def zoomOut(self): """zoom out the main window""" self.view.zoomOut() def reloadButtonClicked(self): """reload button has been clicked""" self.proceedWithFile() def clearButtonClicked(self): """Deletes all the messages from the log window""" self.logWidget.clear() def createGraphicsView(self): """Creates the central widget""" self.scene = QGraphicsScene(self) self.view = CFGraphicsView(self) self.view.setScene(self.scene) def updateWindowTitle(self): """updates the main window title with the current so file""" if self.fName: self.setWindowTitle('Control flow for: ' + self.fName) else: self.setWindowTitle('Control flow for: no file selected') def logMessage(self, message): """Makes a log message visible in the user interface""" timestamp = datetime.datetime.now().strftime('%m-%d-%y %H:%M:%S.%f') self.logWidget.append(timestamp + " " + message) self.logWidget.update() def openButtonClicked(self): """Brings up an open dialogue""" # By some unknown reasons the following simple way of getting a file is # not working: # fileName = QFileDialog.getOpenFileName(self, 'Open file', # QDir.currentPath()) # # There is however a workaround. Here it is: dialog = QFileDialog(self) if dialog.exec_() != QDialog.Accepted: return fileNames = dialog.selectedFiles() fileName = str(fileNames[0]) if not os.path.exists(fileName): QMessageBox.critical( self, 'Error', 'The selected file (' + fileName + ') does not exist') return # Check that the file is a python one warning = isPythonFile(fileName) if warning is not None: QMessageBox.critical(self, 'Error', warning) return # set the new file name self.fName = fileName self.updateWindowTitle() # initiate the process self.proceedWithFile() def proceedWithFile(self, needToParse=True): """Taks the file from settings and processes it""" if needToParse: if self.verbose: self.logMessage("Parsing file " + self.fName) self.cFlow = getControlFlowFromFile(self.fName) if self.verbose: self.logMessage("Parsed file:") self.logMessage(formatFlow(str(self.cFlow))) if len(self.cFlow.errors) != 0: self.logMessage("No drawing due to parsing errors") return if len(self.cFlow.warnings) != 0: self.logMessage("Parser warnings: ") for warn in self.cFlow.warnings: self.logMessage(str(warn[0]) + ": " + warn[1]) else: if self.cFlow is None: self.logMessage("No control flow object") return if len(self.cFlow.errors) != 0: self.logMessage("No drawing due to parsing errors") return self.scene.clear() if self.verbose: self.logMessage("Layouting ...") try: # To pick up possibly changed settings importlib.reload(cflowsettings) cflowSettings = cflowsettings.getDefaultCflowSettings(self) if DEBUG: cflowSettings.debug = True # Top level canvas has no adress and no parent canvas canvas = vcanvas.VirtualCanvas(cflowSettings, None, None, None) canvas.layout(self.cFlow, CellElement.FILE_SCOPE) if self.verbose: self.logMessage("Layout is done:") self.logMessage(str(canvas)) self.logMessage("Rendering ...") width, height = canvas.render() if self.verbose: self.logMessage("Rendering is done. Scene size: " + str(width) + "x" + str(height) + ". Drawing ...") self.scene.setSceneRect(0, 0, width, height) canvas.draw(self.scene, 0, 0) except Exception as exc: self.logMessage("Exception:\n" + str(exc)) raise if self.verbose: self.logMessage("Drawing is done.")
class SVNPluginPropsDialog(QDialog): """SVN plugin properties dialog""" def __init__(self, plugin, client, path, parent=None): QDialog.__init__(self, parent) self.__plugin = plugin self.__client = client self.__path = path self.__createLayout() self.setWindowTitle("SVN Properties of " + path) self.__populate() self.__propsView.setFocus() def __populate(self): """Populate the properties list""" # Get the currently selected name selectedName = None selected = list(self.__propsView.selectedItems()) if selected: selectedName = str(selected[0].text(0)) self.__propsView.clear() properties = readProperties(self.__client, self.__path) if properties: for itemPath, itemProps in properties: if self.__path == itemPath or \ self.__path == itemPath + os.path.sep: for name, value in itemProps.iteritems(): name = str(name).strip() value = str(value).strip() newItem = QTreeWidgetItem([name, value]) self.__propsView.addTopLevelItem(newItem) self.__resizePropsView() self.__sortPropsView() if selectedName: index = 0 for index in range(0, self.__propsView.topLevelItemCount()): item = self.__propsView.topLevelItem(index) if selectedName == item.text(0): item.setSelected(True) def __resizePropsView(self): """Resizes the properties table""" self.__propsView.header().setStretchLastSection(True) self.__propsView.header().resizeSections(QHeaderView.ResizeToContents) def __sortPropsView(self): """Sorts the properties table""" self.__propsView.sortItems( self.__propsView.sortColumn(), self.__propsView.header().sortIndicatorOrder()) def __createLayout(self): """Creates the dialog layout""" self.resize(640, 480) self.setSizeGripEnabled(True) vboxLayout = QVBoxLayout(self) hLayout = QHBoxLayout() self.__propsView = QTreeWidget() self.__propsView.setAlternatingRowColors(True) self.__propsView.setRootIsDecorated(False) self.__propsView.setItemsExpandable(False) self.__propsView.setSortingEnabled(True) self.__propsView.setItemDelegate(NoOutlineHeightDelegate(4)) self.__propsView.itemSelectionChanged.connect( self.__propsSelectionChanged) propsViewHeader = QTreeWidgetItem(["Property Name", "Property Value"]) self.__propsView.setHeaderItem(propsViewHeader) self.__propsView.header().setSortIndicator(0, Qt.DescendingOrder) hLayout.addWidget(self.__propsView) self.__delButton = QToolButton() self.__delButton.setText("Delete") self.__delButton.setFocusPolicy(Qt.NoFocus) self.__delButton.setEnabled(False) self.__delButton.clicked.connect(self.__onDel) hLayout.addWidget(self.__delButton, 0, Qt.AlignBottom) vboxLayout.addLayout(hLayout) # Set property part setGroupbox = QGroupBox(self) setGroupbox.setTitle("Set Property") setLayout = QGridLayout(setGroupbox) setLayout.addWidget(QLabel("Name"), 0, 0, Qt.AlignTop | Qt.AlignRight) setLayout.addWidget(QLabel("Value"), 1, 0, Qt.AlignTop | Qt.AlignRight) self.__nameEdit = QLineEdit() self.__nameEdit.textChanged.connect(self.__nameChanged) setLayout.addWidget(self.__nameEdit, 0, 1) self.__valueEdit = QTextEdit() self.__valueEdit.setAcceptRichText(False) self.__valueEdit.textChanged.connect(self.__valueChanged) metrics = QFontMetrics(self.__valueEdit.font()) rect = metrics.boundingRect("X") self.__valueEdit.setFixedHeight(rect.height() * 4 + 5) setLayout.addWidget(self.__valueEdit, 1, 1) self.__setButton = QToolButton() self.__setButton.setText("Set") self.__setButton.setFocusPolicy(Qt.NoFocus) self.__setButton.setEnabled(False) self.__setButton.clicked.connect(self.__onSet) setLayout.addWidget(self.__setButton, 1, 2, Qt.AlignBottom | Qt.AlignHCenter) sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( setGroupbox.sizePolicy().hasHeightForWidth()) setGroupbox.setSizePolicy(sizePolicy) vboxLayout.addWidget(setGroupbox) # 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) def __onSet(self): """Triggered when propery set is clicked""" name = self.__nameEdit.text().strip() value = self.__valueEdit.toPlainText().strip() try: commitInfo = self.__client.propset(name, value, self.__path) if commitInfo: logging.info(str(commitInfo)) self.__populate() self.__plugin.notifyPathChanged(self.__path) self.__nameEdit.clear() self.__valueEdit.clear() self.__propsView.setFocus() except pysvn.ClientError as exc: message = exc.args[0] logging.error(message) except Exception as exc: logging.error(str(exc)) except: logging.error("Unknown property setting error") def __propsSelectionChanged(self): """Selection of a property has changed""" selected = list(self.__propsView.selectedItems()) self.__delButton.setEnabled(len(selected) > 0) def __onDel(self): """Triggered when a property del is clicked""" selected = list(self.__propsView.selectedItems()) if len(selected) == 0: self.__delButton.setEnabled(False) return name = str(selected[0].text(0)) res = QMessageBox.warning( self, "Deleting Property", "You are about to delete <b>" + name + "</b> SVN property from " + self.__path + ".\nAre you sure?", QMessageBox.StandardButtons(QMessageBox.Cancel | QMessageBox.Yes), QMessageBox.Cancel) if res != QMessageBox.Yes: return try: self.__client.propdel(name, self.__path) self.__populate() self.__plugin.notifyPathChanged(self.__path) self.__propsView.setFocus() except pysvn.ClientError as exc: message = exc.args[0] logging.error(message) except Exception as exc: logging.error(str(exc)) except: logging.error("Unknown property deleting error") def __nameChanged(self, text): """Triggered when a property name to set is changed""" self.__updateSetButton() def __valueChanged(self): """Triggered when a property value to set is changed""" self.__updateSetButton() def __updateSetButton(self): """Updates the 'Set' button state""" name = self.__nameEdit.text().strip() value = self.__valueEdit.toPlainText().strip() self.__setButton.setEnabled(name != "" and value != "")
def __createLayout(self): """Creates the dialog layout""" self.resize(640, 480) self.setSizeGripEnabled(True) vboxLayout = QVBoxLayout(self) hLayout = QHBoxLayout() self.__propsView = QTreeWidget() self.__propsView.setAlternatingRowColors(True) self.__propsView.setRootIsDecorated(False) self.__propsView.setItemsExpandable(False) self.__propsView.setSortingEnabled(True) self.__propsView.setItemDelegate(NoOutlineHeightDelegate(4)) self.__propsView.itemSelectionChanged.connect( self.__propsSelectionChanged) propsViewHeader = QTreeWidgetItem(["Property Name", "Property Value"]) self.__propsView.setHeaderItem(propsViewHeader) self.__propsView.header().setSortIndicator(0, Qt.DescendingOrder) hLayout.addWidget(self.__propsView) self.__delButton = QToolButton() self.__delButton.setText("Delete") self.__delButton.setFocusPolicy(Qt.NoFocus) self.__delButton.setEnabled(False) self.__delButton.clicked.connect(self.__onDel) hLayout.addWidget(self.__delButton, 0, Qt.AlignBottom) vboxLayout.addLayout(hLayout) # Set property part setGroupbox = QGroupBox(self) setGroupbox.setTitle("Set Property") setLayout = QGridLayout(setGroupbox) setLayout.addWidget(QLabel("Name"), 0, 0, Qt.AlignTop | Qt.AlignRight) setLayout.addWidget(QLabel("Value"), 1, 0, Qt.AlignTop | Qt.AlignRight) self.__nameEdit = QLineEdit() self.__nameEdit.textChanged.connect(self.__nameChanged) setLayout.addWidget(self.__nameEdit, 0, 1) self.__valueEdit = QTextEdit() self.__valueEdit.setAcceptRichText(False) self.__valueEdit.textChanged.connect(self.__valueChanged) metrics = QFontMetrics(self.__valueEdit.font()) rect = metrics.boundingRect("X") self.__valueEdit.setFixedHeight(rect.height() * 4 + 5) setLayout.addWidget(self.__valueEdit, 1, 1) self.__setButton = QToolButton() self.__setButton.setText("Set") self.__setButton.setFocusPolicy(Qt.NoFocus) self.__setButton.setEnabled(False) self.__setButton.clicked.connect(self.__onSet) setLayout.addWidget(self.__setButton, 1, 2, Qt.AlignBottom | Qt.AlignHCenter) sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( setGroupbox.sizePolicy().hasHeightForWidth()) setGroupbox.setSizePolicy(sizePolicy) vboxLayout.addWidget(setGroupbox) # 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 SVNPluginCommitDialog(QDialog): """SVN Plugin commit dialog""" NODIFF = '<html><body bgcolor="#ffffe6"></body></html>' def __init__(self, plugin, pathsToCommit, pathsToIgnore, parent=None): QDialog.__init__(self, parent) self.__plugin = plugin self.__createLayout(pathsToCommit, pathsToIgnore) self.setWindowTitle("SVN commit") # Fill the lists for item in pathsToCommit: newItem = QTreeWidgetItem(["", item[0], STATUS[item[1]]]) newItem.setCheckState(CHECK_COL, Qt.Checked) newItem.setToolTip(PATH_COL, item[0]) newItem.setToolTip(STATUS_COL, STATUS[item[1]]) self.__pathToCommitView.addTopLevelItem(newItem) diffButton = self.__createDiffButton() diffButton.path = item[0] diffButton.status = item[1] if os.path.isdir(item[0]) or item[1] in [IND_REPLACED] \ or not isFileSearchable(item[0]): diffButton.setEnabled(False) diffButton.setToolTip("Diff is not available") else: diffButton.setEnabled(True) diffButton.setToolTip("Click to see diff") self.__pathToCommitView.setItemWidget(newItem, DIFF_COL, diffButton) self.__resizeCommitPaths() self.__sortCommitPaths() for item in pathsToIgnore: newItem = QTreeWidgetItem([item[0], STATUS[item[1]]]) newItem.setToolTip(0, item[0]) newItem.setToolTip(1, STATUS[item[1]]) self.__pathToIgnoreView.addTopLevelItem(newItem) self.__pathToIgnoreView.header().resizeSections( QHeaderView.ResizeToContents) self.__updateSelectAllStatus() self.__updateOKStatus() self.__message.setFocus() def __resizeCommitPaths(self): """Resizes the plugins table""" self.__pathToCommitView.header().setStretchLastSection(False) self.__pathToCommitView.header().resizeSections( QHeaderView.ResizeToContents) self.__pathToCommitView.header().resizeSection(CHECK_COL, 28) self.__pathToCommitView.header().setResizeMode(CHECK_COL, QHeaderView.Fixed) # By some reasons, to have PATH_COL visually adjustable the only STATUS_COL # must be set to be stretchable, so there is a comment below. # self.__pathToCommitView.header().setResizeMode( PATH_COL, QHeaderView.Stretch ) self.__pathToCommitView.header().setResizeMode(STATUS_COL, QHeaderView.Stretch) self.__pathToCommitView.header().resizeSection(DIFF_COL, 24) self.__pathToCommitView.header().setResizeMode(DIFF_COL, QHeaderView.Fixed) def __sortCommitPaths(self): """Sorts the commit paths table""" self.__pathToCommitView.sortItems( self.__pathToCommitView.sortColumn(), self.__pathToCommitView.header().sortIndicatorOrder()) def __createDiffButton(self): """Creates a diff button for a path""" button = DiffButton() self.connect(button, SIGNAL('CustomClick'), self.onDiff) return button @staticmethod def __setLightPalette(frame): """Creates a lighter paletter 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) @staticmethod def __configTable(table): """Sets common properties for a table""" table.setAlternatingRowColors(True) table.setRootIsDecorated(False) table.setItemsExpandable(False) table.setSortingEnabled(True) table.setItemDelegate(NoOutlineHeightDelegate(4)) table.setUniformRowHeights(True) def __createLayout(self, pathsToCommit, pathsToIgnore): """Creates the dialog layout""" self.resize(640, 480) self.setSizeGripEnabled(True) vboxLayout = QVBoxLayout(self) # Paths to commit part commitHeaderFrame = QFrame() commitHeaderFrame.setFrameStyle(QFrame.StyledPanel) commitHeaderFrame.setAutoFillBackground(True) self.__setLightPalette(commitHeaderFrame) commitHeaderFrame.setFixedHeight(24) expandingCommitSpacer = QSpacerItem(10, 10, QSizePolicy.Expanding) self.__selectAllButton = QToolButton() self.__selectAllButton.setAutoRaise(True) self.__selectAllButton.setIcon( getIcon(pluginHomeDir + 'svnselectall.png')) self.__selectAllButton.setFixedSize(20, 20) self.__selectAllButton.setToolTip("Select all") self.__selectAllButton.setFocusPolicy(Qt.NoFocus) self.__selectAllButton.clicked.connect(self.__onSelectAll) commitHeaderLayout = QHBoxLayout() commitHeaderLayout.setContentsMargins(3, 0, 0, 0) commitHeaderLayout.addWidget( QLabel("Paths to commit (total: " + str(len(pathsToCommit)) + ")")) commitHeaderLayout.addSpacerItem(expandingCommitSpacer) commitHeaderLayout.addWidget(self.__selectAllButton) commitHeaderFrame.setLayout(commitHeaderLayout) vboxLayout.addWidget(commitHeaderFrame) self.__pathToCommitView = QTreeWidget() self.__configTable(self.__pathToCommitView) self.__pathToCommitHeader = QTreeWidgetItem(["", "Path", "Status", ""]) self.__pathToCommitView.setHeaderItem(self.__pathToCommitHeader) self.__pathToCommitView.header().setSortIndicator( PATH_COL, Qt.AscendingOrder) self.__pathToCommitView.itemChanged.connect(self.__onCommitPathChanged) vboxLayout.addWidget(self.__pathToCommitView) # Paths to ignore part headerFrame = QFrame() headerFrame.setFrameStyle(QFrame.StyledPanel) headerFrame.setAutoFillBackground(True) self.__setLightPalette(headerFrame) headerFrame.setFixedHeight(24) ignoreLabel = QLabel("Ignored paths (total: " + str(len(pathsToIgnore)) + ")") expandingSpacer = QSpacerItem(10, 10, QSizePolicy.Expanding) self.__showHideIgnoredButton = QToolButton() self.__showHideIgnoredButton.setAutoRaise(True) self.__showHideIgnoredButton.setIcon(getIcon('less.png')) self.__showHideIgnoredButton.setFixedSize(20, 20) self.__showHideIgnoredButton.setToolTip("Show ignored path list") self.__showHideIgnoredButton.setFocusPolicy(Qt.NoFocus) self.__showHideIgnoredButton.clicked.connect(self.__onShowHideIgnored) ignoredHeaderLayout = QHBoxLayout() ignoredHeaderLayout.setContentsMargins(3, 0, 0, 0) ignoredHeaderLayout.addWidget(ignoreLabel) ignoredHeaderLayout.addSpacerItem(expandingSpacer) ignoredHeaderLayout.addWidget(self.__showHideIgnoredButton) headerFrame.setLayout(ignoredHeaderLayout) vboxLayout.addWidget(headerFrame) self.__pathToIgnoreView = QTreeWidget() self.__configTable(self.__pathToIgnoreView) self.__pathToIgnoreView.setVisible(False) pathToIgnoreHeader = QTreeWidgetItem(["Path", "Status"]) self.__pathToIgnoreView.setHeaderItem(pathToIgnoreHeader) self.__pathToIgnoreView.header().setSortIndicator(0, Qt.AscendingOrder) vboxLayout.addWidget(self.__pathToIgnoreView) # Message part vboxLayout.addWidget(QLabel("Message")) self.__message = QTextEdit() self.__message.setAcceptRichText(False) metrics = QFontMetrics(self.__message.font()) rect = metrics.boundingRect("X") self.__message.setFixedHeight(rect.height() * 4 + 5) vboxLayout.addWidget(self.__message) # Diff part diffHeaderFrame = QFrame() diffHeaderFrame.setFrameStyle(QFrame.StyledPanel) diffHeaderFrame.setAutoFillBackground(True) self.__setLightPalette(diffHeaderFrame) diffHeaderFrame.setFixedHeight(24) diffLabel = QLabel("Diff") diffExpandingSpacer = QSpacerItem(10, 10, QSizePolicy.Expanding) self.__showHideDiffButton = QToolButton() self.__showHideDiffButton.setAutoRaise(True) self.__showHideDiffButton.setIcon(getIcon('less.png')) self.__showHideDiffButton.setFixedSize(20, 20) self.__showHideDiffButton.setToolTip("Show diff") self.__showHideDiffButton.setFocusPolicy(Qt.NoFocus) self.__showHideDiffButton.clicked.connect(self.__onShowHideDiff) diffLayout = QHBoxLayout() diffLayout.setContentsMargins(3, 0, 0, 0) diffLayout.addWidget(diffLabel) diffLayout.addSpacerItem(diffExpandingSpacer) diffLayout.addWidget(self.__showHideDiffButton) diffHeaderFrame.setLayout(diffLayout) self.__diffViewer = DiffTabWidget() self.__diffViewer.setHTML(self.NODIFF) self.__diffViewer.setVisible(False) vboxLayout.addWidget(diffHeaderFrame) vboxLayout.addWidget(self.__diffViewer) # Buttons at the bottom buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.__OKButton = buttonBox.button(QDialogButtonBox.Ok) self.__OKButton.setText("Commit") buttonBox.button(QDialogButtonBox.Cancel).setDefault(True) buttonBox.accepted.connect(self.userAccept) buttonBox.rejected.connect(self.close) vboxLayout.addWidget(buttonBox) def __onShowHideDiff(self): 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 __onShowHideIgnored(self): if self.__pathToIgnoreView.isVisible(): self.__pathToIgnoreView.setVisible(False) self.__showHideIgnoredButton.setIcon(getIcon('less.png')) self.__showHideIgnoredButton.setToolTip("Show ignored path list") else: self.__pathToIgnoreView.setVisible(True) self.__showHideIgnoredButton.setIcon(getIcon('more.png')) self.__showHideIgnoredButton.setToolTip("Hide ignored path list") def userAccept(self): """ Triggered when the user clicks OK""" # Collect the list of checked paths self.commitMessage = self.__message.toPlainText().strip() self.commitPaths = [] index = 0 while index < self.__pathToCommitView.topLevelItemCount(): item = self.__pathToCommitView.topLevelItem(index) if item.checkState(0) == Qt.Checked: path = str(item.text(1)) if os.path.isdir(path) and not os.path.islink(path) and \ not path.endswith(os.path.sep): path += os.path.sep self.commitPaths.append(path) index += 1 self.accept() def __getCheckedCount(self): """Provides the number of selected items in the commit paths section""" index = 0 checkedCount = 0 while index < self.__pathToCommitView.topLevelItemCount(): item = self.__pathToCommitView.topLevelItem(index) if item.checkState(0) == Qt.Checked: checkedCount += 1 index += 1 return checkedCount def __updateSelectAllStatus(self): """Updates the select all status button""" total = self.__pathToCommitView.topLevelItemCount() if total == 0 or total == self.__getCheckedCount(): self.__selectAllButton.setEnabled(False) else: self.__selectAllButton.setEnabled(True) def __updateOKStatus(self): """Updates the OK button status""" self.__OKButton.setEnabled(self.__getCheckedCount() > 0) def __onCommitPathChanged(self, item, column): """Triggered when an item is changed""" self.__updateSelectAllStatus() self.__updateOKStatus() def __onSelectAll(self): """Triggered when select all button is clicked""" index = 0 while index < self.__pathToCommitView.topLevelItemCount(): item = self.__pathToCommitView.topLevelItem(index) item.setCheckState(0, Qt.Checked) index += 1 self.__updateSelectAllStatus() self.__updateOKStatus() def onDiff(self, path, status): """Triggered when diff for the path is called""" if not path: return QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) try: # Status is one of the following: # IND_ADDED, IND_DELETED, IND_MERGED, IND_MODIFIED_LR, IND_MODIFIED_L, IND_CONFLICTED repositoryContent = "" localContent = "" if status != IND_ADDED: client = self.__plugin.getSVNClient( self.__plugin.getSettings()) repositoryContent = client.cat(path) if status != IND_DELETED: with open(path) as f: localContent = f.read() diff = difflib.unified_diff(repositoryContent.splitlines(), localContent.splitlines()) nodiffMessage = path + " has no difference to the " \ "repository at revision HEAD" if diff is None: QApplication.restoreOverrideCursor() logging.info(nodiffMessage) return # There are changes, so replace the text and tell about the changes diffAsText = '\n'.join(list(diff)) if diffAsText.strip() == '': QApplication.restoreOverrideCursor() logging.info(nodiffMessage) return source = "+++ local " + os.path.basename(path) diffAsText = diffAsText.replace("+++ ", source, 1) diffAsText = diffAsText.replace("--- ", "--- repository at revision HEAD", 1) self.__diffViewer.setHTML( parse_from_memory(diffAsText, False, True)) if not self.__diffViewer.isVisible(): self.__onShowHideDiff() except Exception as exc: logging.error(str(exc)) except: logging.error("Unknown error while calculating difference for " + path) QApplication.restoreOverrideCursor()
def __createLayout(self, pathsToCommit, pathsToIgnore): """Creates the dialog layout""" self.resize(640, 480) self.setSizeGripEnabled(True) vboxLayout = QVBoxLayout(self) # Paths to commit part commitHeaderFrame = QFrame() commitHeaderFrame.setFrameStyle(QFrame.StyledPanel) commitHeaderFrame.setAutoFillBackground(True) self.__setLightPalette(commitHeaderFrame) commitHeaderFrame.setFixedHeight(24) expandingCommitSpacer = QSpacerItem(10, 10, QSizePolicy.Expanding) self.__selectAllButton = QToolButton() self.__selectAllButton.setAutoRaise(True) self.__selectAllButton.setIcon( getIcon(pluginHomeDir + 'svnselectall.png')) self.__selectAllButton.setFixedSize(20, 20) self.__selectAllButton.setToolTip("Select all") self.__selectAllButton.setFocusPolicy(Qt.NoFocus) self.__selectAllButton.clicked.connect(self.__onSelectAll) commitHeaderLayout = QHBoxLayout() commitHeaderLayout.setContentsMargins(3, 0, 0, 0) commitHeaderLayout.addWidget( QLabel("Paths to commit (total: " + str(len(pathsToCommit)) + ")")) commitHeaderLayout.addSpacerItem(expandingCommitSpacer) commitHeaderLayout.addWidget(self.__selectAllButton) commitHeaderFrame.setLayout(commitHeaderLayout) vboxLayout.addWidget(commitHeaderFrame) self.__pathToCommitView = QTreeWidget() self.__configTable(self.__pathToCommitView) self.__pathToCommitHeader = QTreeWidgetItem(["", "Path", "Status", ""]) self.__pathToCommitView.setHeaderItem(self.__pathToCommitHeader) self.__pathToCommitView.header().setSortIndicator( PATH_COL, Qt.AscendingOrder) self.__pathToCommitView.itemChanged.connect(self.__onCommitPathChanged) vboxLayout.addWidget(self.__pathToCommitView) # Paths to ignore part headerFrame = QFrame() headerFrame.setFrameStyle(QFrame.StyledPanel) headerFrame.setAutoFillBackground(True) self.__setLightPalette(headerFrame) headerFrame.setFixedHeight(24) ignoreLabel = QLabel("Ignored paths (total: " + str(len(pathsToIgnore)) + ")") expandingSpacer = QSpacerItem(10, 10, QSizePolicy.Expanding) self.__showHideIgnoredButton = QToolButton() self.__showHideIgnoredButton.setAutoRaise(True) self.__showHideIgnoredButton.setIcon(getIcon('less.png')) self.__showHideIgnoredButton.setFixedSize(20, 20) self.__showHideIgnoredButton.setToolTip("Show ignored path list") self.__showHideIgnoredButton.setFocusPolicy(Qt.NoFocus) self.__showHideIgnoredButton.clicked.connect(self.__onShowHideIgnored) ignoredHeaderLayout = QHBoxLayout() ignoredHeaderLayout.setContentsMargins(3, 0, 0, 0) ignoredHeaderLayout.addWidget(ignoreLabel) ignoredHeaderLayout.addSpacerItem(expandingSpacer) ignoredHeaderLayout.addWidget(self.__showHideIgnoredButton) headerFrame.setLayout(ignoredHeaderLayout) vboxLayout.addWidget(headerFrame) self.__pathToIgnoreView = QTreeWidget() self.__configTable(self.__pathToIgnoreView) self.__pathToIgnoreView.setVisible(False) pathToIgnoreHeader = QTreeWidgetItem(["Path", "Status"]) self.__pathToIgnoreView.setHeaderItem(pathToIgnoreHeader) self.__pathToIgnoreView.header().setSortIndicator(0, Qt.AscendingOrder) vboxLayout.addWidget(self.__pathToIgnoreView) # Message part vboxLayout.addWidget(QLabel("Message")) self.__message = QTextEdit() self.__message.setAcceptRichText(False) metrics = QFontMetrics(self.__message.font()) rect = metrics.boundingRect("X") self.__message.setFixedHeight(rect.height() * 4 + 5) vboxLayout.addWidget(self.__message) # Diff part diffHeaderFrame = QFrame() diffHeaderFrame.setFrameStyle(QFrame.StyledPanel) diffHeaderFrame.setAutoFillBackground(True) self.__setLightPalette(diffHeaderFrame) diffHeaderFrame.setFixedHeight(24) diffLabel = QLabel("Diff") diffExpandingSpacer = QSpacerItem(10, 10, QSizePolicy.Expanding) self.__showHideDiffButton = QToolButton() self.__showHideDiffButton.setAutoRaise(True) self.__showHideDiffButton.setIcon(getIcon('less.png')) self.__showHideDiffButton.setFixedSize(20, 20) self.__showHideDiffButton.setToolTip("Show diff") self.__showHideDiffButton.setFocusPolicy(Qt.NoFocus) self.__showHideDiffButton.clicked.connect(self.__onShowHideDiff) diffLayout = QHBoxLayout() diffLayout.setContentsMargins(3, 0, 0, 0) diffLayout.addWidget(diffLabel) diffLayout.addSpacerItem(diffExpandingSpacer) diffLayout.addWidget(self.__showHideDiffButton) diffHeaderFrame.setLayout(diffLayout) self.__diffViewer = DiffTabWidget() self.__diffViewer.setHTML(self.NODIFF) self.__diffViewer.setVisible(False) vboxLayout.addWidget(diffHeaderFrame) vboxLayout.addWidget(self.__diffViewer) # Buttons at the bottom buttonBox = QDialogButtonBox(self) buttonBox.setOrientation(Qt.Horizontal) buttonBox.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) self.__OKButton = buttonBox.button(QDialogButtonBox.Ok) self.__OKButton.setText("Commit") buttonBox.button(QDialogButtonBox.Cancel).setDefault(True) buttonBox.accepted.connect(self.userAccept) buttonBox.rejected.connect(self.close) vboxLayout.addWidget(buttonBox)
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))
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 DocLinkAnchorDialog(QDialog): """Replace text input dialog""" def __init__(self, windowTitle, cmlDocComment, fileName, parent): QDialog.__init__(self, parent) # Name of a file from which the doc link is created/edited self.__fileName = fileName self.setWindowTitle(windowTitle + ' documentation link and/or anchor') self.__createLayout() self.__invalidInputColor = GlobalData().skin['invalidInputPaper'] self.__validInputColor = self.linkEdit.palette().color( self.linkEdit.backgroundRole()) if cmlDocComment is not None: self.__populate(cmlDocComment) def __createLayout(self): """Creates the dialog layout""" self.resize(450, 150) self.setSizeGripEnabled(True) verticalLayout = QVBoxLayout(self) gridLayout = QGridLayout() # Link gridLayout.addWidget(QLabel('Link', self), 0, 0, 1, 1) self.linkEdit = QLineEdit(self) self.linkEdit.setClearButtonEnabled(True) self.linkEdit.setToolTip( 'A link to a file or to an external web resource') gridLayout.addWidget(self.linkEdit, 0, 1, 1, 1) self.linkEdit.textChanged.connect(self.__validate) self.fileButton = QPushButton(self) self.fileButton.setText('...') self.fileButton.setToolTip('Select an existing or non existing file') gridLayout.addWidget(self.fileButton, 0, 2, 1, 1) self.fileButton.clicked.connect(self.__onSelectPath) self.createCheckBox = QCheckBox( 'Create a markdown file if does not exist', self) self.createCheckBox.setChecked(False) gridLayout.addWidget(self.createCheckBox, 1, 1, 1, 1) self.createCheckBox.stateChanged.connect(self.__validate) # Anchor gridLayout.addWidget(QLabel('Anchor', self), 2, 0, 1, 1) self.anchorEdit = QLineEdit(self) self.anchorEdit.setClearButtonEnabled(True) gridLayout.addWidget(self.anchorEdit, 2, 1, 1, 1) self.anchorEdit.textChanged.connect(self.__validate) # Title titleLabel = QLabel('Title', self) titleLabel.setAlignment(Qt.AlignTop) gridLayout.addWidget(titleLabel, 3, 0, 1, 1) self.titleEdit = QTextEdit() self.titleEdit.setTabChangesFocus(True) self.titleEdit.setAcceptRichText(False) self.titleEdit.setToolTip( 'If provided then will be displayed in the rectangle') gridLayout.addWidget(self.titleEdit, 3, 1, 1, 1) # Buttons at the bottom 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.accept) buttonBox.rejected.connect(self.close) verticalLayout.addLayout(gridLayout) verticalLayout.addWidget(buttonBox) self.linkEdit.setFocus() def setTitle(self, txt): """Sets the title text to be edited""" self.titleEdit.setPlainText(txt) def title(self): """Provides the new title text""" return self.titleEdit.toPlainText() def needToCreate(self): return self.createCheckBox.isEnabled( ) and self.createCheckBox.isChecked() def __populate(self, cmlDocComment): """Populates the fields from the comment""" if cmlDocComment.link: self.linkEdit.setText(cmlDocComment.link) if cmlDocComment.anchor: self.anchorEdit.setText(cmlDocComment.anchor) if cmlDocComment.title: self.setTitle(cmlDocComment.getTitle()) def __onSelectPath(self): """Select file or directory""" options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog selectedPath = QFileDialog.getOpenFileName(self, 'Select documentation file', self.linkEdit.text(), options=options) if isinstance(selectedPath, tuple): selectedPath = selectedPath[0] if selectedPath: self.linkEdit.setText(os.path.normpath(selectedPath)) def __setLinkValid(self): """Sets the link edit valid""" self.linkEdit.setToolTip( 'A link to a file or to an external web resource') setLineEditBackground(self.linkEdit, self.__validInputColor, self.__validInputColor) def __setLinkInvalid(self, msg): """Sets the link edit invalid""" self.linkEdit.setToolTip(msg) setLineEditBackground(self.linkEdit, self.__invalidInputColor, self.__invalidInputColor) def __validateLink(self): """Validates the link field content""" txt = self.linkEdit.text().strip() if txt == '' or txt.startswith('http://') or txt.startswith( 'https://'): self.__setLinkValid() self.createCheckBox.setEnabled(False) return True if txt.endswith(os.path.sep): self.__setLinkInvalid('A link must be a file, not a directory') return False # Not a link; it is supposed to be a file or a creatable file # However the invalid values will also be acceptable self.createCheckBox.setEnabled(True) fromFile = None if self.__fileName: if os.path.isabs(self.__fileName): fromFile = self.__fileName fName, anchor, errMsg = preResolveLinkPath( txt, fromFile, self.createCheckBox.isChecked()) del anchor if fName: self.__setLinkValid() return True self.__setLinkInvalid(errMsg) return not self.createCheckBox.isChecked() def __setAnchorValid(self): """Sets the anchor edit valid""" self.anchorEdit.setToolTip( 'Anchor may not contain neither spaces nor tabs') setLineEditBackground(self.anchorEdit, self.__invalidInputColor, self.__validInputColor) def __setAnchorInvalid(self): """Sets the anchor edit invalid""" self.anchorEdit.setToolTip( 'Anchor is used to refer to it from the other files') setLineEditBackground(self.anchorEdit, self.__validInputColor, self.__validInputColor) def __validateAnchor(self): """Validates the anchor field""" txt = self.anchorEdit.text().strip() if ' ' in txt or '\t' in txt: self.__setAnchorValid() return False self.__setAnchorInvalid() return True def __validate(self, _=None): """Validates the input fields and sets the OK button enable""" self.__OKButton.setToolTip('') valid = self.__validateAnchor() and self.__validateLink() if valid: if not self.linkEdit.text().strip() and not self.anchorEdit.text( ).strip(): valid = False self.__OKButton.setToolTip( 'At least one of the items: link or anchor must be provided' ) self.__OKButton.setEnabled(valid) return valid