class PythonConsoleWidget(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) self.setWindowTitle(QCoreApplication.translate("PythonConsole", "Python Console")) self.settings = QSettings() self.shell = ShellScintilla(self) self.setFocusProxy(self.shell) self.shellOut = ShellOutputScintilla(self) self.tabEditorWidget = EditorTabWidget(self) ##------------ UI ------------------------------- self.splitterEditor = QSplitter(self) self.splitterEditor.setOrientation(Qt.Horizontal) self.splitterEditor.setHandleWidth(6) self.splitterEditor.setChildrenCollapsible(True) self.shellOutWidget = QWidget(self) self.shellOutWidget.setLayout(QVBoxLayout()) self.shellOutWidget.layout().setContentsMargins(0, 0, 0, 0) self.shellOutWidget.layout().addWidget(self.shellOut) self.splitter = QSplitter(self.splitterEditor) self.splitter.setOrientation(Qt.Vertical) self.splitter.setHandleWidth(3) self.splitter.setChildrenCollapsible(False) self.splitter.addWidget(self.shellOutWidget) self.splitter.addWidget(self.shell) #self.splitterEditor.addWidget(self.tabEditorWidget) self.splitterObj = QSplitter(self.splitterEditor) self.splitterObj.setHandleWidth(3) self.splitterObj.setOrientation(Qt.Horizontal) #self.splitterObj.setSizes([0, 0]) #self.splitterObj.setStretchFactor(0, 1) self.widgetEditor = QWidget(self.splitterObj) self.widgetFind = QWidget(self) self.listClassMethod = QTreeWidget(self.splitterObj) self.listClassMethod.setColumnCount(2) objInspLabel = QCoreApplication.translate("PythonConsole", "Object Inspector") self.listClassMethod.setHeaderLabels([objInspLabel, '']) self.listClassMethod.setColumnHidden(1, True) self.listClassMethod.setAlternatingRowColors(True) #self.splitterEditor.addWidget(self.widgetEditor) #self.splitterObj.addWidget(self.listClassMethod) #self.splitterObj.addWidget(self.widgetEditor) # Hide side editor on start up self.splitterObj.hide() self.listClassMethod.hide() # Hide search widget on start up self.widgetFind.hide() sizes = self.splitter.sizes() self.splitter.setSizes(sizes) ##----------------Restore Settings------------------------------------ self.restoreSettingsConsole() ##------------------Toolbar Editor------------------------------------- ## Action for Open File openFileBt = QCoreApplication.translate("PythonConsole", "Open file") self.openFileButton = QAction(self) self.openFileButton.setCheckable(False) self.openFileButton.setEnabled(True) self.openFileButton.setIcon(QgsApplication.getThemeIcon("console/iconOpenConsole.png")) self.openFileButton.setMenuRole(QAction.PreferencesRole) self.openFileButton.setIconVisibleInMenu(True) self.openFileButton.setToolTip(openFileBt) self.openFileButton.setText(openFileBt) openExtEditorBt = QCoreApplication.translate("PythonConsole", "Open in external editor") self.openInEditorButton = QAction(self) self.openInEditorButton.setCheckable(False) self.openInEditorButton.setEnabled(True) self.openInEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconShowEditorConsole.png")) self.openInEditorButton.setMenuRole(QAction.PreferencesRole) self.openInEditorButton.setIconVisibleInMenu(True) self.openInEditorButton.setToolTip(openExtEditorBt) self.openInEditorButton.setText(openExtEditorBt) ## Action for Save File saveFileBt = QCoreApplication.translate("PythonConsole", "Save") self.saveFileButton = QAction(self) self.saveFileButton.setCheckable(False) self.saveFileButton.setEnabled(False) self.saveFileButton.setIcon(QgsApplication.getThemeIcon("console/iconSaveConsole.png")) self.saveFileButton.setMenuRole(QAction.PreferencesRole) self.saveFileButton.setIconVisibleInMenu(True) self.saveFileButton.setToolTip(saveFileBt) self.saveFileButton.setText(saveFileBt) ## Action for Save File As saveAsFileBt = QCoreApplication.translate("PythonConsole", "Save As...") self.saveAsFileButton = QAction(self) self.saveAsFileButton.setCheckable(False) self.saveAsFileButton.setEnabled(True) self.saveAsFileButton.setIcon(QgsApplication.getThemeIcon("console/iconSaveAsConsole.png")) self.saveAsFileButton.setMenuRole(QAction.PreferencesRole) self.saveAsFileButton.setIconVisibleInMenu(True) self.saveAsFileButton.setToolTip(saveAsFileBt) self.saveAsFileButton.setText(saveAsFileBt) ## Action Cut cutEditorBt = QCoreApplication.translate("PythonConsole", "Cut") self.cutEditorButton = QAction(self) self.cutEditorButton.setCheckable(False) self.cutEditorButton.setEnabled(True) self.cutEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconCutEditorConsole.png")) self.cutEditorButton.setMenuRole(QAction.PreferencesRole) self.cutEditorButton.setIconVisibleInMenu(True) self.cutEditorButton.setToolTip(cutEditorBt) self.cutEditorButton.setText(cutEditorBt) ## Action Copy copyEditorBt = QCoreApplication.translate("PythonConsole", "Copy") self.copyEditorButton = QAction(self) self.copyEditorButton.setCheckable(False) self.copyEditorButton.setEnabled(True) self.copyEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconCopyEditorConsole.png")) self.copyEditorButton.setMenuRole(QAction.PreferencesRole) self.copyEditorButton.setIconVisibleInMenu(True) self.copyEditorButton.setToolTip(copyEditorBt) self.copyEditorButton.setText(copyEditorBt) ## Action Paste pasteEditorBt = QCoreApplication.translate("PythonConsole", "Paste") self.pasteEditorButton = QAction(self) self.pasteEditorButton.setCheckable(False) self.pasteEditorButton.setEnabled(True) self.pasteEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconPasteEditorConsole.png")) self.pasteEditorButton.setMenuRole(QAction.PreferencesRole) self.pasteEditorButton.setIconVisibleInMenu(True) self.pasteEditorButton.setToolTip(pasteEditorBt) self.pasteEditorButton.setText(pasteEditorBt) ## Action Run Script (subprocess) runScriptEditorBt = QCoreApplication.translate("PythonConsole", "Run script") self.runScriptEditorButton = QAction(self) self.runScriptEditorButton.setCheckable(False) self.runScriptEditorButton.setEnabled(True) self.runScriptEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconRunScriptConsole.png")) self.runScriptEditorButton.setMenuRole(QAction.PreferencesRole) self.runScriptEditorButton.setIconVisibleInMenu(True) self.runScriptEditorButton.setToolTip(runScriptEditorBt) self.runScriptEditorButton.setText(runScriptEditorBt) ## Action Run Script (subprocess) commentEditorBt = QCoreApplication.translate("PythonConsole", "Comment") self.commentEditorButton = QAction(self) self.commentEditorButton.setCheckable(False) self.commentEditorButton.setEnabled(True) self.commentEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconCommentEditorConsole.png")) self.commentEditorButton.setMenuRole(QAction.PreferencesRole) self.commentEditorButton.setIconVisibleInMenu(True) self.commentEditorButton.setToolTip(commentEditorBt) self.commentEditorButton.setText(commentEditorBt) ## Action Run Script (subprocess) uncommentEditorBt = QCoreApplication.translate("PythonConsole", "Uncomment") self.uncommentEditorButton = QAction(self) self.uncommentEditorButton.setCheckable(False) self.uncommentEditorButton.setEnabled(True) self.uncommentEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconUncommentEditorConsole.png")) self.uncommentEditorButton.setMenuRole(QAction.PreferencesRole) self.uncommentEditorButton.setIconVisibleInMenu(True) self.uncommentEditorButton.setToolTip(uncommentEditorBt) self.uncommentEditorButton.setText(uncommentEditorBt) ## Action for Object browser objList = QCoreApplication.translate("PythonConsole", "Object Inspector") self.objectListButton = QAction(self) self.objectListButton.setCheckable(True) self.objectListButton.setEnabled(self.settings.value("pythonConsole/enableObjectInsp", False, type=bool)) self.objectListButton.setIcon(QgsApplication.getThemeIcon("console/iconClassBrowserConsole.png")) self.objectListButton.setMenuRole(QAction.PreferencesRole) self.objectListButton.setIconVisibleInMenu(True) self.objectListButton.setToolTip(objList) self.objectListButton.setText(objList) ## Action for Find text findText = QCoreApplication.translate("PythonConsole", "Find Text") self.findTextButton = QAction(self) self.findTextButton.setCheckable(True) self.findTextButton.setEnabled(True) self.findTextButton.setIcon(QgsApplication.getThemeIcon("console/iconSearchEditorConsole.png")) self.findTextButton.setMenuRole(QAction.PreferencesRole) self.findTextButton.setIconVisibleInMenu(True) self.findTextButton.setToolTip(findText) self.findTextButton.setText(findText) ##----------------Toolbar Console------------------------------------- ## Action Show Editor showEditor = QCoreApplication.translate("PythonConsole", "Show editor") self.showEditorButton = QAction(self) self.showEditorButton.setEnabled(True) self.showEditorButton.setCheckable(True) self.showEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconShowEditorConsole.png")) self.showEditorButton.setMenuRole(QAction.PreferencesRole) self.showEditorButton.setIconVisibleInMenu(True) self.showEditorButton.setToolTip(showEditor) self.showEditorButton.setText(showEditor) ## Action for Clear button clearBt = QCoreApplication.translate("PythonConsole", "Clear console") self.clearButton = QAction(self) self.clearButton.setCheckable(False) self.clearButton.setEnabled(True) self.clearButton.setIcon(QgsApplication.getThemeIcon("console/iconClearConsole.png")) self.clearButton.setMenuRole(QAction.PreferencesRole) self.clearButton.setIconVisibleInMenu(True) self.clearButton.setToolTip(clearBt) self.clearButton.setText(clearBt) ## Action for settings optionsBt = QCoreApplication.translate("PythonConsole", "Settings") self.optionsButton = QAction(self) self.optionsButton.setCheckable(False) self.optionsButton.setEnabled(True) self.optionsButton.setIcon(QgsApplication.getThemeIcon("console/iconSettingsConsole.png")) self.optionsButton.setMenuRole(QAction.PreferencesRole) self.optionsButton.setIconVisibleInMenu(True) self.optionsButton.setToolTip(optionsBt) self.optionsButton.setText(optionsBt) ## Action menu for class actionClassBt = QCoreApplication.translate("PythonConsole", "Import Class") self.actionClass = QAction(self) self.actionClass.setCheckable(False) self.actionClass.setEnabled(True) self.actionClass.setIcon(QgsApplication.getThemeIcon("console/iconClassConsole.png")) self.actionClass.setMenuRole(QAction.PreferencesRole) self.actionClass.setIconVisibleInMenu(True) self.actionClass.setToolTip(actionClassBt) self.actionClass.setText(actionClassBt) ## Import Processing class loadProcessingBt = QCoreApplication.translate("PythonConsole", "Import Processing class") self.loadProcessingButton = QAction(self) self.loadProcessingButton.setCheckable(False) self.loadProcessingButton.setEnabled(True) self.loadProcessingButton.setIcon(QgsApplication.getThemeIcon("console/iconProcessingConsole.png")) self.loadProcessingButton.setMenuRole(QAction.PreferencesRole) self.loadProcessingButton.setIconVisibleInMenu(True) self.loadProcessingButton.setToolTip(loadProcessingBt) self.loadProcessingButton.setText(loadProcessingBt) ## Import QtCore class loadQtCoreBt = QCoreApplication.translate("PythonConsole", "Import PyQt.QtCore class") self.loadQtCoreButton = QAction(self) self.loadQtCoreButton.setCheckable(False) self.loadQtCoreButton.setEnabled(True) self.loadQtCoreButton.setIcon(QgsApplication.getThemeIcon("console/iconQtCoreConsole.png")) self.loadQtCoreButton.setMenuRole(QAction.PreferencesRole) self.loadQtCoreButton.setIconVisibleInMenu(True) self.loadQtCoreButton.setToolTip(loadQtCoreBt) self.loadQtCoreButton.setText(loadQtCoreBt) ## Import QtGui class loadQtGuiBt = QCoreApplication.translate("PythonConsole", "Import PyQt.QtGui class") self.loadQtGuiButton = QAction(self) self.loadQtGuiButton.setCheckable(False) self.loadQtGuiButton.setEnabled(True) self.loadQtGuiButton.setIcon(QgsApplication.getThemeIcon("console/iconQtGuiConsole.png")) self.loadQtGuiButton.setMenuRole(QAction.PreferencesRole) self.loadQtGuiButton.setIconVisibleInMenu(True) self.loadQtGuiButton.setToolTip(loadQtGuiBt) self.loadQtGuiButton.setText(loadQtGuiBt) ## Action for Run script runBt = QCoreApplication.translate("PythonConsole", "Run command") self.runButton = QAction(self) self.runButton.setCheckable(False) self.runButton.setEnabled(True) self.runButton.setIcon(QgsApplication.getThemeIcon("console/iconRunConsole.png")) self.runButton.setMenuRole(QAction.PreferencesRole) self.runButton.setIconVisibleInMenu(True) self.runButton.setToolTip(runBt) self.runButton.setText(runBt) ## Help action helpBt = QCoreApplication.translate("PythonConsole", "Help") self.helpButton = QAction(self) self.helpButton.setCheckable(False) self.helpButton.setEnabled(True) self.helpButton.setIcon(QgsApplication.getThemeIcon("console/iconHelpConsole.png")) self.helpButton.setMenuRole(QAction.PreferencesRole) self.helpButton.setIconVisibleInMenu(True) self.helpButton.setToolTip(helpBt) self.helpButton.setText(helpBt) self.toolBar = QToolBar() self.toolBar.setEnabled(True) self.toolBar.setFocusPolicy(Qt.NoFocus) self.toolBar.setContextMenuPolicy(Qt.DefaultContextMenu) self.toolBar.setLayoutDirection(Qt.LeftToRight) self.toolBar.setIconSize(QSize(16, 16)) self.toolBar.setMovable(False) self.toolBar.setFloatable(False) self.toolBar.addAction(self.clearButton) self.toolBar.addAction(self.actionClass) self.toolBar.addAction(self.runButton) self.toolBar.addSeparator() self.toolBar.addAction(self.showEditorButton) self.toolBar.addSeparator() self.toolBar.addAction(self.optionsButton) self.toolBar.addAction(self.helpButton) self.toolBarEditor = QToolBar() self.toolBarEditor.setEnabled(False) self.toolBarEditor.setFocusPolicy(Qt.NoFocus) self.toolBarEditor.setContextMenuPolicy(Qt.DefaultContextMenu) self.toolBarEditor.setLayoutDirection(Qt.LeftToRight) self.toolBarEditor.setIconSize(QSize(16, 16)) self.toolBarEditor.setMovable(False) self.toolBarEditor.setFloatable(False) self.toolBarEditor.addAction(self.openFileButton) self.toolBarEditor.addAction(self.openInEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.saveFileButton) self.toolBarEditor.addAction(self.saveAsFileButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.runScriptEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.findTextButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.cutEditorButton) self.toolBarEditor.addAction(self.copyEditorButton) self.toolBarEditor.addAction(self.pasteEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.commentEditorButton) self.toolBarEditor.addAction(self.uncommentEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.objectListButton) ## Menu Import Class self.classMenu = QMenu() self.classMenu.addAction(self.loadProcessingButton) self.classMenu.addAction(self.loadQtCoreButton) self.classMenu.addAction(self.loadQtGuiButton) cM = self.toolBar.widgetForAction(self.actionClass) cM.setMenu(self.classMenu) cM.setPopupMode(QToolButton.InstantPopup) self.widgetButton = QWidget() sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.widgetButton.sizePolicy().hasHeightForWidth()) self.widgetButton.setSizePolicy(sizePolicy) self.widgetButtonEditor = QWidget(self.widgetEditor) sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.widgetButtonEditor.sizePolicy().hasHeightForWidth()) self.widgetButtonEditor.setSizePolicy(sizePolicy) sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.shellOut.sizePolicy().hasHeightForWidth()) self.shellOut.setSizePolicy(sizePolicy) self.shellOut.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.shell.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) ##------------ Layout ------------------------------- self.mainLayout = QGridLayout(self) self.mainLayout.setMargin(0) self.mainLayout.setSpacing(0) self.mainLayout.addWidget(self.widgetButton, 0, 0, 1, 1) self.mainLayout.addWidget(self.splitterEditor, 0, 1, 1, 1) self.shellOutWidget.layout().insertWidget(0, self.toolBar) self.layoutEditor = QGridLayout(self.widgetEditor) self.layoutEditor.setMargin(0) self.layoutEditor.setSpacing(0) self.layoutEditor.addWidget(self.toolBarEditor, 0, 1, 1, 1) self.layoutEditor.addWidget(self.widgetButtonEditor, 1, 0, 2, 1) self.layoutEditor.addWidget(self.tabEditorWidget, 1, 1, 1, 1) self.layoutEditor.addWidget(self.widgetFind, 2, 1, 1, 1) ## Layout for the find widget self.layoutFind = QGridLayout(self.widgetFind) self.layoutFind.setContentsMargins(0, 0, 0, 0) self.lineEditFind = QgsFilterLineEdit() placeHolderTxt = QCoreApplication.translate("PythonConsole", "Enter text to find...") if pyqtconfig.Configuration().qt_version >= 0x40700: self.lineEditFind.setPlaceholderText(placeHolderTxt) else: self.lineEditFind.setToolTip(placeHolderTxt) self.findNextButton = QToolButton() self.findNextButton.setEnabled(False) toolTipfindNext = QCoreApplication.translate("PythonConsole", "Find Next") self.findNextButton.setToolTip(toolTipfindNext) self.findNextButton.setIcon(QgsApplication.getThemeIcon("console/iconSearchNextEditorConsole.png")) self.findNextButton.setIconSize(QSize(24, 24)) self.findNextButton.setAutoRaise(True) self.findPrevButton = QToolButton() self.findPrevButton.setEnabled(False) toolTipfindPrev = QCoreApplication.translate("PythonConsole", "Find Previous") self.findPrevButton.setToolTip(toolTipfindPrev) self.findPrevButton.setIcon(QgsApplication.getThemeIcon("console/iconSearchPrevEditorConsole.png")) self.findPrevButton.setIconSize(QSize(24, 24)) self.findPrevButton.setAutoRaise(True) self.caseSensitive = QCheckBox() caseSensTr = QCoreApplication.translate("PythonConsole", "Case Sensitive") self.caseSensitive.setText(caseSensTr) self.wholeWord = QCheckBox() wholeWordTr = QCoreApplication.translate("PythonConsole", "Whole Word") self.wholeWord.setText(wholeWordTr) self.wrapAround = QCheckBox() self.wrapAround.setChecked(True) wrapAroundTr = QCoreApplication.translate("PythonConsole", "Wrap Around") self.wrapAround.setText(wrapAroundTr) self.layoutFind.addWidget(self.lineEditFind, 0, 1, 1, 1) self.layoutFind.addWidget(self.findPrevButton, 0, 2, 1, 1) self.layoutFind.addWidget(self.findNextButton, 0, 3, 1, 1) self.layoutFind.addWidget(self.caseSensitive, 0, 4, 1, 1) self.layoutFind.addWidget(self.wholeWord, 0, 5, 1, 1) self.layoutFind.addWidget(self.wrapAround, 0, 6, 1, 1) ##------------ Add first Tab in Editor ------------------------------- #self.tabEditorWidget.newTabEditor(tabName='first', filename=None) ##------------ Signal ------------------------------- self.findTextButton.toggled.connect(self.findTextEditor) self.objectListButton.toggled.connect(self.toggleObjectListWidget) self.commentEditorButton.triggered.connect(self.commentCode) self.uncommentEditorButton.triggered.connect(self.uncommentCode) self.runScriptEditorButton.triggered.connect(self.runScriptEditor) self.cutEditorButton.triggered.connect(self.cutEditor) self.copyEditorButton.triggered.connect(self.copyEditor) self.pasteEditorButton.triggered.connect(self.pasteEditor) self.showEditorButton.toggled.connect(self.toggleEditor) self.clearButton.triggered.connect(self.shellOut.clearConsole) self.optionsButton.triggered.connect(self.openSettings) self.loadProcessingButton.triggered.connect(self.processing) self.loadQtCoreButton.triggered.connect(self.qtCore) self.loadQtGuiButton.triggered.connect(self.qtGui) self.runButton.triggered.connect(self.shell.entered) self.openFileButton.triggered.connect(self.openScriptFile) self.openInEditorButton.triggered.connect(self.openScriptFileExtEditor) self.saveFileButton.triggered.connect(self.saveScriptFile) self.saveAsFileButton.triggered.connect(self.saveAsScriptFile) self.helpButton.triggered.connect(self.openHelp) self.connect(self.listClassMethod, SIGNAL('itemClicked(QTreeWidgetItem*, int)'), self.onClickGoToLine) self.lineEditFind.returnPressed.connect(self._findText) self.findNextButton.clicked.connect(self._findNext) self.findPrevButton.clicked.connect(self._findPrev) self.lineEditFind.textChanged.connect(self._textFindChanged) def _findText(self): self.tabEditorWidget.currentWidget().newEditor.findText(True) def _findNext(self): self.tabEditorWidget.currentWidget().newEditor.findText(True) def _findPrev(self): self.tabEditorWidget.currentWidget().newEditor.findText(False) def _textFindChanged(self): if self.lineEditFind.text(): self.findNextButton.setEnabled(True) self.findPrevButton.setEnabled(True) else: self.lineEditFind.setStyleSheet('') self.findNextButton.setEnabled(False) self.findPrevButton.setEnabled(False) def onClickGoToLine(self, item, column): tabEditor = self.tabEditorWidget.currentWidget().newEditor if item.text(1) == 'syntaxError': check = tabEditor.syntaxCheck(fromContextMenu=False) if check and not tabEditor.isReadOnly(): self.tabEditorWidget.currentWidget().save() return linenr = int(item.text(1)) itemName = str(item.text(0)) charPos = itemName.find(' ') if charPos != -1: objName = itemName[0:charPos] else: objName = itemName tabEditor.goToLine(objName, linenr) def processing(self): self.shell.commandConsole('processing') def qtCore(self): self.shell.commandConsole('qtCore') def qtGui(self): self.shell.commandConsole('qtGui') def toggleEditor(self, checked): self.splitterObj.show() if checked else self.splitterObj.hide() if not self.tabEditorWidget: self.tabEditorWidget.enableToolBarEditor(checked) self.tabEditorWidget.restoreTabsOrAddNew() def toggleObjectListWidget(self, checked): self.listClassMethod.show() if checked else self.listClassMethod.hide() def findTextEditor(self, checked): self.widgetFind.show() if checked else self.widgetFind.hide() def pasteEditor(self): self.tabEditorWidget.currentWidget().newEditor.paste() def cutEditor(self): self.tabEditorWidget.currentWidget().newEditor.cut() def copyEditor(self): self.tabEditorWidget.currentWidget().newEditor.copy() def runScriptEditor(self): self.tabEditorWidget.currentWidget().newEditor.runScriptCode() def commentCode(self): self.tabEditorWidget.currentWidget().newEditor.commentEditorCode(True) def uncommentCode(self): self.tabEditorWidget.currentWidget().newEditor.commentEditorCode(False) def openScriptFileExtEditor(self): tabWidget = self.tabEditorWidget.currentWidget() path = tabWidget.path import subprocess try: subprocess.Popen([os.environ['EDITOR'], path]) except KeyError: QDesktopServices.openUrl(QUrl.fromLocalFile(path)) def openScriptFile(self): lastDirPath = self.settings.value("pythonConsole/lastDirPath", QDir.homePath()) openFileTr = QCoreApplication.translate("PythonConsole", "Open File") fileList = QFileDialog.getOpenFileNames( self, openFileTr, lastDirPath, "Script file (*.py)") if fileList: for pyFile in fileList: for i in range(self.tabEditorWidget.count()): tabWidget = self.tabEditorWidget.widget(i) if tabWidget.path == pyFile: self.tabEditorWidget.setCurrentWidget(tabWidget) break else: tabName = QFileInfo(pyFile).fileName() self.tabEditorWidget.newTabEditor(tabName, pyFile) lastDirPath = QFileInfo(pyFile).path() self.settings.setValue("pythonConsole/lastDirPath", pyFile) self.updateTabListScript(pyFile, action='append') def saveScriptFile(self): tabWidget = self.tabEditorWidget.currentWidget() try: tabWidget.save() except (IOError, OSError) as error: msgText = QCoreApplication.translate('PythonConsole', 'The file <b>{0}</b> could not be saved. Error: {1}').format(tabWidget.path, error.strerror) self.callWidgetMessageBarEditor(msgText, 2, False) def saveAsScriptFile(self, index=None): tabWidget = self.tabEditorWidget.currentWidget() if not index: index = self.tabEditorWidget.currentIndex() if not tabWidget.path: fileName = self.tabEditorWidget.tabText(index) + '.py' folder = self.settings.value("pythonConsole/lastDirPath", QDir.home()) pathFileName = os.path.join(folder, fileName) fileNone = True else: pathFileName = tabWidget.path fileNone = False saveAsFileTr = QCoreApplication.translate("PythonConsole", "Save File As") filename = QFileDialog.getSaveFileName(self, saveAsFileTr, pathFileName, "Script file (*.py)") if filename: try: tabWidget.save(filename) except (IOError, OSError) as error: msgText = QCoreApplication.translate('PythonConsole', 'The file <b>{0}</b> could not be saved. Error: {1}').format(tabWidget.path, error.strerror) self.callWidgetMessageBarEditor(msgText, 2, False) if fileNone: tabWidget.path = None else: tabWidget.path = pathFileName return if not fileNone: self.updateTabListScript(pathFileName, action='remove') def openHelp(self): QgsContextHelp.run("PythonConsole") def openSettings(self): if optionsDialog(self).exec_(): self.shell.refreshSettingsShell() self.shellOut.refreshSettingsOutput() self.tabEditorWidget.refreshSettingsEditor() def callWidgetMessageBar(self, text): self.shellOut.widgetMessageBar(iface, text) def callWidgetMessageBarEditor(self, text, level, timed): self.tabEditorWidget.widgetMessageBar(iface, text, level, timed) def updateTabListScript(self, script, action=None): if action == 'remove': self.tabListScript.remove(script) elif action == 'append': if not self.tabListScript: self.tabListScript = [] if script not in self.tabListScript: self.tabListScript.append(script) else: self.tabListScript = [] self.settings.setValue("pythonConsole/tabScripts", self.tabListScript) def saveSettingsConsole(self): self.settings.setValue("pythonConsole/splitterConsole", self.splitter.saveState()) self.settings.setValue("pythonConsole/splitterObj", self.splitterObj.saveState()) self.settings.setValue("pythonConsole/splitterEditor", self.splitterEditor.saveState()) self.shell.writeHistoryFile(True) def restoreSettingsConsole(self): storedTabScripts = self.settings.value("pythonConsole/tabScripts", []) self.tabListScript = storedTabScripts self.splitter.restoreState(self.settings.value("pythonConsole/splitterConsole", QByteArray())) self.splitterEditor.restoreState(self.settings.value("pythonConsole/splitterEditor", QByteArray())) self.splitterObj.restoreState(self.settings.value("pythonConsole/splitterObj", QByteArray()))
class PythonConsoleWidget(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) self.setWindowTitle( QCoreApplication.translate("PythonConsole", "Python Console")) self.settings = QSettings() self.shell = ShellScintilla(self) self.setFocusProxy(self.shell) self.shellOut = ShellOutputScintilla(self) self.tabEditorWidget = EditorTabWidget(self) ##------------ UI ------------------------------- self.splitterEditor = QSplitter(self) self.splitterEditor.setOrientation(Qt.Horizontal) self.splitterEditor.setHandleWidth(6) self.splitterEditor.setChildrenCollapsible(True) self.splitter = QSplitter(self.splitterEditor) self.splitter.setOrientation(Qt.Vertical) self.splitter.setHandleWidth(3) self.splitter.setChildrenCollapsible(False) self.splitter.addWidget(self.shellOut) self.splitter.addWidget(self.shell) #self.splitterEditor.addWidget(self.tabEditorWidget) self.splitterObj = QSplitter(self.splitterEditor) self.splitterObj.setHandleWidth(3) self.splitterObj.setOrientation(Qt.Horizontal) #self.splitterObj.setSizes([0, 0]) #self.splitterObj.setStretchFactor(0, 1) self.widgetEditor = QWidget(self.splitterObj) self.widgetFind = QWidget(self) self.listClassMethod = QTreeWidget(self.splitterObj) self.listClassMethod.setColumnCount(2) objInspLabel = QCoreApplication.translate("PythonConsole", "Object Inspector") self.listClassMethod.setHeaderLabels([objInspLabel, '']) self.listClassMethod.setColumnHidden(1, True) self.listClassMethod.setAlternatingRowColors(True) #self.splitterEditor.addWidget(self.widgetEditor) #self.splitterObj.addWidget(self.listClassMethod) #self.splitterObj.addWidget(self.widgetEditor) # Hide side editor on start up self.splitterObj.hide() self.listClassMethod.hide() # Hide search widget on start up self.widgetFind.hide() sizes = self.splitter.sizes() self.splitter.setSizes(sizes) ##----------------Restore Settings------------------------------------ self.restoreSettingsConsole() ##------------------Toolbar Editor------------------------------------- ## Action for Open File openFileBt = QCoreApplication.translate("PythonConsole", "Open file") self.openFileButton = QAction(self) self.openFileButton.setCheckable(False) self.openFileButton.setEnabled(True) self.openFileButton.setIcon( QgsApplication.getThemeIcon("console/iconOpenConsole.png")) self.openFileButton.setMenuRole(QAction.PreferencesRole) self.openFileButton.setIconVisibleInMenu(True) self.openFileButton.setToolTip(openFileBt) self.openFileButton.setText(openFileBt) ## Action for Save File saveFileBt = QCoreApplication.translate("PythonConsole", "Save") self.saveFileButton = QAction(self) self.saveFileButton.setCheckable(False) self.saveFileButton.setEnabled(False) self.saveFileButton.setIcon( QgsApplication.getThemeIcon("console/iconSaveConsole.png")) self.saveFileButton.setMenuRole(QAction.PreferencesRole) self.saveFileButton.setIconVisibleInMenu(True) self.saveFileButton.setToolTip(saveFileBt) self.saveFileButton.setText(saveFileBt) ## Action for Save File As saveAsFileBt = QCoreApplication.translate("PythonConsole", "Save As...") self.saveAsFileButton = QAction(self) self.saveAsFileButton.setCheckable(False) self.saveAsFileButton.setEnabled(True) self.saveAsFileButton.setIcon( QgsApplication.getThemeIcon("console/iconSaveAsConsole.png")) self.saveAsFileButton.setMenuRole(QAction.PreferencesRole) self.saveAsFileButton.setIconVisibleInMenu(True) self.saveAsFileButton.setToolTip(saveAsFileBt) self.saveAsFileButton.setText(saveAsFileBt) ## Action Cut cutEditorBt = QCoreApplication.translate("PythonConsole", "Cut") self.cutEditorButton = QAction(self) self.cutEditorButton.setCheckable(False) self.cutEditorButton.setEnabled(True) self.cutEditorButton.setIcon( QgsApplication.getThemeIcon("console/iconCutEditorConsole.png")) self.cutEditorButton.setMenuRole(QAction.PreferencesRole) self.cutEditorButton.setIconVisibleInMenu(True) self.cutEditorButton.setToolTip(cutEditorBt) self.cutEditorButton.setText(cutEditorBt) ## Action Copy copyEditorBt = QCoreApplication.translate("PythonConsole", "Copy") self.copyEditorButton = QAction(self) self.copyEditorButton.setCheckable(False) self.copyEditorButton.setEnabled(True) self.copyEditorButton.setIcon( QgsApplication.getThemeIcon("console/iconCopyEditorConsole.png")) self.copyEditorButton.setMenuRole(QAction.PreferencesRole) self.copyEditorButton.setIconVisibleInMenu(True) self.copyEditorButton.setToolTip(copyEditorBt) self.copyEditorButton.setText(copyEditorBt) ## Action Paste pasteEditorBt = QCoreApplication.translate("PythonConsole", "Paste") self.pasteEditorButton = QAction(self) self.pasteEditorButton.setCheckable(False) self.pasteEditorButton.setEnabled(True) self.pasteEditorButton.setIcon( QgsApplication.getThemeIcon("console/iconPasteEditorConsole.png")) self.pasteEditorButton.setMenuRole(QAction.PreferencesRole) self.pasteEditorButton.setIconVisibleInMenu(True) self.pasteEditorButton.setToolTip(pasteEditorBt) self.pasteEditorButton.setText(pasteEditorBt) ## Action Run Script (subprocess) runScriptEditorBt = QCoreApplication.translate("PythonConsole", "Run script") self.runScriptEditorButton = QAction(self) self.runScriptEditorButton.setCheckable(False) self.runScriptEditorButton.setEnabled(True) self.runScriptEditorButton.setIcon( QgsApplication.getThemeIcon("console/iconRunScriptConsole.png")) self.runScriptEditorButton.setMenuRole(QAction.PreferencesRole) self.runScriptEditorButton.setIconVisibleInMenu(True) self.runScriptEditorButton.setToolTip(runScriptEditorBt) self.runScriptEditorButton.setText(runScriptEditorBt) ## Action Run Script (subprocess) commentEditorBt = QCoreApplication.translate("PythonConsole", "Comment") self.commentEditorButton = QAction(self) self.commentEditorButton.setCheckable(False) self.commentEditorButton.setEnabled(True) self.commentEditorButton.setIcon( QgsApplication.getThemeIcon( "console/iconCommentEditorConsole.png")) self.commentEditorButton.setMenuRole(QAction.PreferencesRole) self.commentEditorButton.setIconVisibleInMenu(True) self.commentEditorButton.setToolTip(commentEditorBt) self.commentEditorButton.setText(commentEditorBt) ## Action Run Script (subprocess) uncommentEditorBt = QCoreApplication.translate("PythonConsole", "Uncomment") self.uncommentEditorButton = QAction(self) self.uncommentEditorButton.setCheckable(False) self.uncommentEditorButton.setEnabled(True) self.uncommentEditorButton.setIcon( QgsApplication.getThemeIcon( "console/iconUncommentEditorConsole.png")) self.uncommentEditorButton.setMenuRole(QAction.PreferencesRole) self.uncommentEditorButton.setIconVisibleInMenu(True) self.uncommentEditorButton.setToolTip(uncommentEditorBt) self.uncommentEditorButton.setText(uncommentEditorBt) ## Action for Object browser objList = QCoreApplication.translate("PythonConsole", "Object Inspector") self.objectListButton = QAction(self) self.objectListButton.setCheckable(True) self.objectListButton.setEnabled( self.settings.value("pythonConsole/enableObjectInsp", False, type=bool)) self.objectListButton.setIcon( QgsApplication.getThemeIcon("console/iconClassBrowserConsole.png")) self.objectListButton.setMenuRole(QAction.PreferencesRole) self.objectListButton.setIconVisibleInMenu(True) self.objectListButton.setToolTip(objList) self.objectListButton.setText(objList) ## Action for Find text findText = QCoreApplication.translate("PythonConsole", "Find Text") self.findTextButton = QAction(self) self.findTextButton.setCheckable(True) self.findTextButton.setEnabled(True) self.findTextButton.setIcon( QgsApplication.getThemeIcon("console/iconSearchEditorConsole.png")) self.findTextButton.setMenuRole(QAction.PreferencesRole) self.findTextButton.setIconVisibleInMenu(True) self.findTextButton.setToolTip(findText) self.findTextButton.setText(findText) ##----------------Toolbar Console------------------------------------- ## Action Show Editor showEditor = QCoreApplication.translate("PythonConsole", "Show editor") self.showEditorButton = QAction(self) self.showEditorButton.setEnabled(True) self.showEditorButton.setCheckable(True) self.showEditorButton.setIcon( QgsApplication.getThemeIcon("console/iconShowEditorConsole.png")) self.showEditorButton.setMenuRole(QAction.PreferencesRole) self.showEditorButton.setIconVisibleInMenu(True) self.showEditorButton.setToolTip(showEditor) self.showEditorButton.setText(showEditor) ## Action for Clear button clearBt = QCoreApplication.translate("PythonConsole", "Clear console") self.clearButton = QAction(self) self.clearButton.setCheckable(False) self.clearButton.setEnabled(True) self.clearButton.setIcon( QgsApplication.getThemeIcon("console/iconClearConsole.png")) self.clearButton.setMenuRole(QAction.PreferencesRole) self.clearButton.setIconVisibleInMenu(True) self.clearButton.setToolTip(clearBt) self.clearButton.setText(clearBt) ## Action for settings optionsBt = QCoreApplication.translate("PythonConsole", "Settings") self.optionsButton = QAction(self) self.optionsButton.setCheckable(False) self.optionsButton.setEnabled(True) self.optionsButton.setIcon( QgsApplication.getThemeIcon("console/iconSettingsConsole.png")) self.optionsButton.setMenuRole(QAction.PreferencesRole) self.optionsButton.setIconVisibleInMenu(True) self.optionsButton.setToolTip(optionsBt) self.optionsButton.setText(optionsBt) ## Action menu for class actionClassBt = QCoreApplication.translate("PythonConsole", "Import Class") self.actionClass = QAction(self) self.actionClass.setCheckable(False) self.actionClass.setEnabled(True) self.actionClass.setIcon( QgsApplication.getThemeIcon("console/iconClassConsole.png")) self.actionClass.setMenuRole(QAction.PreferencesRole) self.actionClass.setIconVisibleInMenu(True) self.actionClass.setToolTip(actionClassBt) self.actionClass.setText(actionClassBt) ## Import Processing class loadProcessingBt = QCoreApplication.translate( "PythonConsole", "Import Processing class") self.loadProcessingButton = QAction(self) self.loadProcessingButton.setCheckable(False) self.loadProcessingButton.setEnabled(True) self.loadProcessingButton.setIcon( QgsApplication.getThemeIcon("console/iconProcessingConsole.png")) self.loadProcessingButton.setMenuRole(QAction.PreferencesRole) self.loadProcessingButton.setIconVisibleInMenu(True) self.loadProcessingButton.setToolTip(loadProcessingBt) self.loadProcessingButton.setText(loadProcessingBt) ## Import QtCore class loadQtCoreBt = QCoreApplication.translate("PythonConsole", "Import PyQt.QtCore class") self.loadQtCoreButton = QAction(self) self.loadQtCoreButton.setCheckable(False) self.loadQtCoreButton.setEnabled(True) self.loadQtCoreButton.setIcon( QgsApplication.getThemeIcon("console/iconQtCoreConsole.png")) self.loadQtCoreButton.setMenuRole(QAction.PreferencesRole) self.loadQtCoreButton.setIconVisibleInMenu(True) self.loadQtCoreButton.setToolTip(loadQtCoreBt) self.loadQtCoreButton.setText(loadQtCoreBt) ## Import QtGui class loadQtGuiBt = QCoreApplication.translate("PythonConsole", "Import PyQt.QtGui class") self.loadQtGuiButton = QAction(self) self.loadQtGuiButton.setCheckable(False) self.loadQtGuiButton.setEnabled(True) self.loadQtGuiButton.setIcon( QgsApplication.getThemeIcon("console/iconQtGuiConsole.png")) self.loadQtGuiButton.setMenuRole(QAction.PreferencesRole) self.loadQtGuiButton.setIconVisibleInMenu(True) self.loadQtGuiButton.setToolTip(loadQtGuiBt) self.loadQtGuiButton.setText(loadQtGuiBt) ## Action for Run script runBt = QCoreApplication.translate("PythonConsole", "Run command") self.runButton = QAction(self) self.runButton.setCheckable(False) self.runButton.setEnabled(True) self.runButton.setIcon( QgsApplication.getThemeIcon("console/iconRunConsole.png")) self.runButton.setMenuRole(QAction.PreferencesRole) self.runButton.setIconVisibleInMenu(True) self.runButton.setToolTip(runBt) self.runButton.setText(runBt) ## Help action helpBt = QCoreApplication.translate("PythonConsole", "Help") self.helpButton = QAction(self) self.helpButton.setCheckable(False) self.helpButton.setEnabled(True) self.helpButton.setIcon( QgsApplication.getThemeIcon("console/iconHelpConsole.png")) self.helpButton.setMenuRole(QAction.PreferencesRole) self.helpButton.setIconVisibleInMenu(True) self.helpButton.setToolTip(helpBt) self.helpButton.setText(helpBt) self.toolBar = QToolBar() self.toolBar.setEnabled(True) self.toolBar.setFocusPolicy(Qt.NoFocus) self.toolBar.setContextMenuPolicy(Qt.DefaultContextMenu) self.toolBar.setLayoutDirection(Qt.LeftToRight) self.toolBar.setIconSize(QSize(24, 24)) self.toolBar.setOrientation(Qt.Vertical) self.toolBar.setMovable(True) self.toolBar.setFloatable(True) self.toolBar.addAction(self.clearButton) self.toolBar.addAction(self.actionClass) self.toolBar.addAction(self.runButton) self.toolBar.addSeparator() self.toolBar.addAction(self.showEditorButton) self.toolBar.addSeparator() self.toolBar.addAction(self.optionsButton) self.toolBar.addAction(self.helpButton) self.toolBarEditor = QToolBar() # self.toolBarEditor.setStyleSheet('QToolBar{background-color: rgb(%s, %s, %s' % tuple(bkgrcolor) + ');\ # border-right: 1px solid rgb(%s, %s, %s' % tuple(bordercl) + ');}') self.toolBarEditor.setEnabled(False) self.toolBarEditor.setFocusPolicy(Qt.NoFocus) self.toolBarEditor.setContextMenuPolicy(Qt.DefaultContextMenu) self.toolBarEditor.setLayoutDirection(Qt.LeftToRight) self.toolBarEditor.setIconSize(QSize(18, 18)) self.toolBarEditor.setOrientation(Qt.Vertical) self.toolBarEditor.setMovable(True) self.toolBarEditor.setFloatable(True) self.toolBarEditor.addAction(self.openFileButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.saveFileButton) self.toolBarEditor.addAction(self.saveAsFileButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.findTextButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.cutEditorButton) self.toolBarEditor.addAction(self.copyEditorButton) self.toolBarEditor.addAction(self.pasteEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.commentEditorButton) self.toolBarEditor.addAction(self.uncommentEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.objectListButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.runScriptEditorButton) ## Menu Import Class self.classMenu = QMenu() self.classMenu.addAction(self.loadProcessingButton) self.classMenu.addAction(self.loadQtCoreButton) self.classMenu.addAction(self.loadQtGuiButton) cM = self.toolBar.widgetForAction(self.actionClass) cM.setMenu(self.classMenu) cM.setPopupMode(QToolButton.InstantPopup) self.widgetButton = QWidget() sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.widgetButton.sizePolicy().hasHeightForWidth()) self.widgetButton.setSizePolicy(sizePolicy) self.widgetButtonEditor = QWidget(self.widgetEditor) sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.widgetButtonEditor.sizePolicy().hasHeightForWidth()) self.widgetButtonEditor.setSizePolicy(sizePolicy) sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.shellOut.sizePolicy().hasHeightForWidth()) self.shellOut.setSizePolicy(sizePolicy) self.shellOut.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.shell.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) ##------------ Layout ------------------------------- self.mainLayout = QGridLayout(self) self.mainLayout.setMargin(0) self.mainLayout.setSpacing(0) self.mainLayout.addWidget(self.widgetButton, 0, 0, 1, 1) self.mainLayout.addWidget(self.splitterEditor, 0, 1, 1, 1) self.layoutEditor = QGridLayout(self.widgetEditor) self.layoutEditor.setMargin(0) self.layoutEditor.setSpacing(0) self.layoutEditor.addWidget(self.widgetButtonEditor, 0, 0, 2, 1) self.layoutEditor.addWidget(self.tabEditorWidget, 0, 1, 1, 1) self.layoutEditor.addWidget(self.widgetFind, 1, 1, 1, 1) self.toolBarLayout = QGridLayout(self.widgetButton) self.toolBarLayout.setMargin(0) self.toolBarLayout.setSpacing(0) self.toolBarLayout.addWidget(self.toolBar) self.toolBarEditorLayout = QGridLayout(self.widgetButtonEditor) self.toolBarEditorLayout.setMargin(0) self.toolBarEditorLayout.setSpacing(0) self.toolBarEditorLayout.addWidget(self.toolBarEditor) ## Layout for the find widget self.layoutFind = QGridLayout(self.widgetFind) self.layoutFind.setContentsMargins(0, 0, 0, 0) self.lineEditFind = QgsFilterLineEdit() placeHolderTxt = QCoreApplication.translate("PythonConsole", "Enter text to find...") if pyqtconfig.Configuration().qt_version >= 0x40700: self.lineEditFind.setPlaceholderText(placeHolderTxt) else: self.lineEditFind.setToolTip(placeHolderTxt) self.findNextButton = QToolButton() self.findNextButton.setEnabled(False) toolTipfindNext = QCoreApplication.translate("PythonConsole", "Find Next") self.findNextButton.setToolTip(toolTipfindNext) self.findNextButton.setIcon( QgsApplication.getThemeIcon( "console/iconSearchNextEditorConsole.png")) self.findNextButton.setIconSize(QSize(24, 24)) self.findNextButton.setAutoRaise(True) self.findPrevButton = QToolButton() self.findPrevButton.setEnabled(False) toolTipfindPrev = QCoreApplication.translate("PythonConsole", "Find Previous") self.findPrevButton.setToolTip(toolTipfindPrev) self.findPrevButton.setIcon( QgsApplication.getThemeIcon( "console/iconSearchPrevEditorConsole.png")) self.findPrevButton.setIconSize(QSize(24, 24)) self.findPrevButton.setAutoRaise(True) self.caseSensitive = QCheckBox() caseSensTr = QCoreApplication.translate("PythonConsole", "Case Sensitive") self.caseSensitive.setText(caseSensTr) self.wholeWord = QCheckBox() wholeWordTr = QCoreApplication.translate("PythonConsole", "Whole Word") self.wholeWord.setText(wholeWordTr) self.wrapAround = QCheckBox() self.wrapAround.setChecked(True) wrapAroundTr = QCoreApplication.translate("PythonConsole", "Wrap Around") self.wrapAround.setText(wrapAroundTr) self.layoutFind.addWidget(self.lineEditFind, 0, 1, 1, 1) self.layoutFind.addWidget(self.findPrevButton, 0, 2, 1, 1) self.layoutFind.addWidget(self.findNextButton, 0, 3, 1, 1) self.layoutFind.addWidget(self.caseSensitive, 0, 4, 1, 1) self.layoutFind.addWidget(self.wholeWord, 0, 5, 1, 1) self.layoutFind.addWidget(self.wrapAround, 0, 6, 1, 1) ##------------ Add first Tab in Editor ------------------------------- #self.tabEditorWidget.newTabEditor(tabName='first', filename=None) ##------------ Signal ------------------------------- self.findTextButton.toggled.connect(self.findTextEditor) self.objectListButton.toggled.connect(self.toggleObjectListWidget) self.commentEditorButton.triggered.connect(self.commentCode) self.uncommentEditorButton.triggered.connect(self.uncommentCode) self.runScriptEditorButton.triggered.connect(self.runScriptEditor) self.cutEditorButton.triggered.connect(self.cutEditor) self.copyEditorButton.triggered.connect(self.copyEditor) self.pasteEditorButton.triggered.connect(self.pasteEditor) self.showEditorButton.toggled.connect(self.toggleEditor) self.clearButton.triggered.connect(self.shellOut.clearConsole) self.optionsButton.triggered.connect(self.openSettings) self.loadProcessingButton.triggered.connect(self.processing) self.loadQtCoreButton.triggered.connect(self.qtCore) self.loadQtGuiButton.triggered.connect(self.qtGui) self.runButton.triggered.connect(self.shell.entered) self.openFileButton.triggered.connect(self.openScriptFile) self.saveFileButton.triggered.connect(self.saveScriptFile) self.saveAsFileButton.triggered.connect(self.saveAsScriptFile) self.helpButton.triggered.connect(self.openHelp) self.connect(self.listClassMethod, SIGNAL('itemClicked(QTreeWidgetItem*, int)'), self.onClickGoToLine) self.lineEditFind.returnPressed.connect(self._findText) self.findNextButton.clicked.connect(self._findNext) self.findPrevButton.clicked.connect(self._findPrev) self.lineEditFind.textChanged.connect(self._textFindChanged) def _findText(self): self.tabEditorWidget.currentWidget().newEditor.findText(True) def _findNext(self): self.tabEditorWidget.currentWidget().newEditor.findText(True) def _findPrev(self): self.tabEditorWidget.currentWidget().newEditor.findText(False) def _textFindChanged(self): if self.lineEditFind.text(): self.findNextButton.setEnabled(True) self.findPrevButton.setEnabled(True) else: self.lineEditFind.setStyleSheet('') self.findNextButton.setEnabled(False) self.findPrevButton.setEnabled(False) def onClickGoToLine(self, item, column): tabEditor = self.tabEditorWidget.currentWidget().newEditor if item.text(1) == 'syntaxError': check = tabEditor.syntaxCheck(fromContextMenu=False) if check and not tabEditor.isReadOnly(): self.tabEditorWidget.currentWidget().save() return linenr = int(item.text(1)) itemName = str(item.text(0)) charPos = itemName.find(' ') if charPos != -1: objName = itemName[0:charPos] else: objName = itemName tabEditor.goToLine(objName, linenr) def processing(self): self.shell.commandConsole('processing') def qtCore(self): self.shell.commandConsole('qtCore') def qtGui(self): self.shell.commandConsole('qtGui') def toggleEditor(self, checked): self.splitterObj.show() if checked else self.splitterObj.hide() if not self.tabEditorWidget: self.tabEditorWidget.enableToolBarEditor(checked) self.tabEditorWidget.restoreTabsOrAddNew() def toggleObjectListWidget(self, checked): self.listClassMethod.show() if checked else self.listClassMethod.hide() def findTextEditor(self, checked): self.widgetFind.show() if checked else self.widgetFind.hide() def pasteEditor(self): self.tabEditorWidget.currentWidget().newEditor.paste() def cutEditor(self): self.tabEditorWidget.currentWidget().newEditor.cut() def copyEditor(self): self.tabEditorWidget.currentWidget().newEditor.copy() def runScriptEditor(self): self.tabEditorWidget.currentWidget().newEditor.runScriptCode() def commentCode(self): self.tabEditorWidget.currentWidget().newEditor.commentEditorCode(True) def uncommentCode(self): self.tabEditorWidget.currentWidget().newEditor.commentEditorCode(False) def openScriptFile(self): lastDirPath = self.settings.value("pythonConsole/lastDirPath", "") openFileTr = QCoreApplication.translate("PythonConsole", "Open File") fileList = QFileDialog.getOpenFileNames(self, openFileTr, lastDirPath, "Script file (*.py)") if fileList: for pyFile in fileList: for i in range(self.tabEditorWidget.count()): tabWidget = self.tabEditorWidget.widget(i) if tabWidget.path == pyFile: self.tabEditorWidget.setCurrentWidget(tabWidget) break else: tabName = QFileInfo(pyFile).fileName() self.tabEditorWidget.newTabEditor(tabName, pyFile) lastDirPath = QFileInfo(pyFile).path() self.settings.setValue("pythonConsole/lastDirPath", pyFile) self.updateTabListScript(pyFile, action='append') def saveScriptFile(self): tabWidget = self.tabEditorWidget.currentWidget() try: tabWidget.save() except (IOError, OSError), error: msgText = QCoreApplication.translate( 'PythonConsole', 'The file <b>{0}</b> could not be saved. Error: {1}').format( tabWidget.path, error.strerror) self.callWidgetMessageBarEditor(msgText, 2, False)
class PymetricsViewer( QWidget ): " Pymetrics tab widget " # Limits to colorize the McCabe score LittleRiskLimit = 10 ModerateRiskLimit = 20 HighRiskLimit = 50 # Options of providing a report SingleFile = 0 DirectoryFiles = 1 ProjectFiles = 2 SingleBuffer = 3 def __init__( self, parent = None ): QWidget.__init__( self, parent ) self.__reportUUID = "" self.__reportFileName = "" self.__reportOption = -1 self.__reportShown = False self.__report = None # Prepare members for reuse self.__noneLabel = QLabel( "\nNo results available" ) self.__noneLabel.setFrameShape( QFrame.StyledPanel ) self.__noneLabel.setAlignment( Qt.AlignHCenter ) self.__headerFont = self.__noneLabel.font() self.__headerFont.setPointSize( self.__headerFont.pointSize() + 4 ) self.__noneLabel.setFont( self.__headerFont ) self.__noneLabel.setAutoFillBackground( True ) noneLabelPalette = self.__noneLabel.palette() noneLabelPalette.setColor( QPalette.Background, GlobalData().skin.nolexerPaper ) self.__noneLabel.setPalette( noneLabelPalette ) self.__createLayout( parent ) self.__updateButtonsStatus() return def __createLayout( self, parent ): " Creates the toolbar and layout " # Buttons self.__mcCabeButton = QAction( PixmapCache().getIcon( 'tableview.png' ), 'Switch to McCabe only table view', self ) self.__mcCabeButton.setCheckable( True ) self.connect( self.__mcCabeButton, SIGNAL( 'toggled(bool)' ), self.__onMcCabe ) self.printButton = QAction( PixmapCache().getIcon( 'printer.png' ), 'Print', self ) #printButton.setShortcut( 'Ctrl+' ) self.connect( self.printButton, SIGNAL( 'triggered()' ), self.__onPrint ) self.printButton.setVisible( False ) self.printPreviewButton = QAction( PixmapCache().getIcon( 'printpreview.png' ), 'Print preview', self ) #printPreviewButton.setShortcut( 'Ctrl+' ) self.connect( self.printPreviewButton, SIGNAL( 'triggered()' ), self.__onPrintPreview ) self.printPreviewButton.setVisible( False ) spacer = QWidget() spacer.setSizePolicy( QSizePolicy.Expanding, QSizePolicy.Expanding ) self.clearButton = QAction( PixmapCache().getIcon( 'trash.png' ), 'Clear', self ) self.connect( self.clearButton, SIGNAL( 'triggered()' ), self.__clear ) # The toolbar 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.__mcCabeButton ) self.toolbar.addAction( self.printPreviewButton ) self.toolbar.addAction( self.printButton ) self.toolbar.addWidget( spacer ) self.toolbar.addAction( self.clearButton ) self.__totalResultsTree = QTreeWidget() self.__totalResultsTree.setAlternatingRowColors( True ) self.__totalResultsTree.setRootIsDecorated( True ) self.__totalResultsTree.setItemsExpandable( True ) self.__totalResultsTree.setUniformRowHeights( True ) self.__totalResultsTree.setItemDelegate( NoOutlineHeightDelegate( 4 ) ) headerLabels = [ "Path / name", "Value", "" ] self.__totalResultsTree.setHeaderLabels( headerLabels ) self.connect( self.__totalResultsTree, SIGNAL( "itemActivated(QTreeWidgetItem *, int)" ), self.__allItemActivated ) self.connect( self.__totalResultsTree, SIGNAL( "itemExpanded(QTreeWidgetItem *)" ), self.__onResultsExpanded ) self.__totalResultsTree.setColumnHidden( 2, True ) self.__totalResultsTree.hide() self.__mcCabeTable = QTreeWidget() self.__mcCabeTable.setAlternatingRowColors( True ) self.__mcCabeTable.setRootIsDecorated( False ) self.__mcCabeTable.setItemsExpandable( False ) self.__mcCabeTable.setSortingEnabled( True ) self.__mcCabeTable.setItemDelegate( NoOutlineHeightDelegate( 4 ) ) self.__mcCabeTable.setUniformRowHeights( True ) headerLabels = [ "", "File name", "Object", "McCabe Complexity" ] self.__mcCabeTable.setHeaderLabels( headerLabels ) self.connect( self.__mcCabeTable, SIGNAL( "itemActivated(QTreeWidgetItem *, int)" ), self.__mcCabeActivated ) self.__mcCabeTable.hide() 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.addWidget( self.__totalResultsTree ) self.__hLayout.addWidget( self.__mcCabeTable ) self.setLayout( self.__hLayout ) return def getTotalResultsWidget( self ): " Provides a reference to the total results widget " return self.__totalResultsTree def getMcCabeResultsWidget( self ): " Provides a reference to the McCabe results widget " return self.__mcCabeTable def __updateButtonsStatus( self ): " Updates the buttons status " self.__mcCabeButton.setEnabled( self.__reportShown ) self.printButton.setEnabled( self.__reportShown ) self.printPreviewButton.setEnabled( self.__reportShown ) self.clearButton.setEnabled( self.__reportShown ) return def __onResultsExpanded( self, item ): " An item has been expanded, so the column width should be adjusted " self.__totalResultsTree.header().resizeSections( QHeaderView.ResizeToContents ) return def __onPrint( self ): " Triggered when the print button is pressed " pass def __onPrintPreview( self ): " triggered when the print preview button is pressed " pass def __onMcCabe( self, state ): " Triggered when the metrics view is switched " if not self.__reportShown: return if state: self.__totalResultsTree.hide() self.__mcCabeTable.show() self.__mcCabeButton.setIcon( PixmapCache().getIcon( 'treeview.png' ) ) self.__mcCabeButton.setToolTip( "Switch to complete " "results tree view" ) else: self.__mcCabeTable.hide() self.__totalResultsTree.show() self.__mcCabeButton.setIcon( PixmapCache().getIcon( 'tableview.png' ) ) self.__mcCabeButton.setToolTip( "Switch to McCabe only table view" ) return def setFocus( self ): " Overridden setFocus " self.__hLayout.setFocus() return def __clear( self ): " Clears the content of the vertical layout " if not self.__reportShown: return self.__totalResultsTree.clear() self.__totalResultsTree.hide() self.__mcCabeTable.clear() self.__mcCabeTable.hide() self.__noneLabel.show() self.__report = None self.__reportShown = False self.__updateButtonsStatus() # self.resizeEvent() self.__mcCabeButton.setIcon( PixmapCache().getIcon( 'tableview.png' ) ) self.__mcCabeButton.setToolTip( "Switch to McCabe only table view" ) self.__mcCabeButton.setChecked( False ) self.__updateTooltip() return def __updateTooltip( self ): " Generates a signal with appropriate string message " if not self.__reportShown: tooltip = "No metrics available" elif self.__reportOption == self.DirectoryFiles: tooltip = "Metrics generated for directory: " + \ self.__reportFileName elif self.__reportOption == self.ProjectFiles: tooltip = "Metrics generated for the whole project" elif self.__reportOption == self.SingleFile: tooltip = "Metrics generated for file: " + self.__reportFileName elif self.__reportOption == self.SingleBuffer: tooltip = "Metrics generated for unsaved file: " + \ self.__reportFileName else: tooltip = "" self.emit( SIGNAL( 'updatePymetricsTooltip' ), tooltip ) return @staticmethod def __shouldShowFileName( table, column ): " Checks if the file name is the same " size = table.topLevelItemCount() if size == 0: return False index = size - 1 firstName = table.topLevelItem( index ).text( column ) index -= 1 while index >= 0: if table.topLevelItem( index ).text( column ) != firstName: return True index -= 1 return False def showReport( self, metrics, reportOption, fileName, uuid ): " Shows the pymetrics results " self.__clear() self.__noneLabel.hide() self.__report = metrics self.__reportUUID = uuid self.__reportFileName = fileName self.__reportOption = reportOption if len( metrics.report ) > 1: accumulatedBasic = self.__accumulateBasicMetrics() accItem = QTreeWidgetItem( [ "Cumulative basic metrics" ] ) self.__totalResultsTree.addTopLevelItem( accItem ) for key in accumulatedBasic: bmItem = [ BasicMetrics.metricsOfInterest[ key ], splitThousands( str( accumulatedBasic[ key ] ) ) ] basicMetric = QTreeWidgetItem( bmItem ) accItem.addChild( basicMetric ) # Add the complete information for fileName in metrics.report: if reportOption == self.SingleBuffer: fileItem = QTreeWidgetItem( [ "Editor buffer" ] ) else: fileItem = QTreeWidgetItem( [ fileName ] ) info = GlobalData().briefModinfoCache.get( fileName ) if info.docstring is not None: fileItem.setToolTip( 0, info.docstring.text ) else: fileItem.setToolTip( 0, "" ) self.__totalResultsTree.addTopLevelItem( fileItem ) # Messages part messages = metrics.report[ fileName ].messages if len( messages ) > 0: messagesItem = QTreeWidgetItem( [ "Messages" ] ) fileItem.addChild( messagesItem ) for message in messages: mItem = [ message, "", "E" ] messagesItem.addChild( QTreeWidgetItem( mItem ) ) # Basic metrics part basicItem = QTreeWidgetItem( [ "Basic metrics" ] ) fileItem.addChild( basicItem ) basic = metrics.report[ fileName ].basicMetrics for key in basic.metrics: bmItem = [ BasicMetrics.metricsOfInterest[ key ], str( basic.metrics[ key ] ) ] basicMetric = QTreeWidgetItem( bmItem ) basicItem.addChild( basicMetric ) # McCabe part mccabeItem = QTreeWidgetItem( [ "McCabe metrics" ] ) fileItem.addChild( mccabeItem ) mccabe = metrics.report[ fileName ].mcCabeMetrics.metrics for objName in mccabe: objItem = [ objName, str( mccabe[ objName ] ), "M" ] mccabeMetric = QTreeWidgetItem( objItem ) mccabeItem.addChild( mccabeMetric ) # COCOMO 2 part cocomo = [ "COCOMO 2", str( metrics.report[ fileName ].cocomo2Metrics.value ) ] cocomoItem = QTreeWidgetItem( cocomo ) fileItem.addChild( cocomoItem ) # Resizing the table self.__totalResultsTree.header().resizeSections( QHeaderView.ResizeToContents ) # Add McCabe complexity information for fileName in metrics.report: mccabe = metrics.report[ fileName ].mcCabeMetrics.metrics for objName in mccabe: values = [ "", fileName, objName, str( mccabe[ objName ] ) ] self.__mcCabeTable.addTopLevelItem( McCabeTableItem( values ) ) if not self.__shouldShowFileName( self.__mcCabeTable, 1 ): self.__mcCabeTable.setColumnHidden( 1, True ) # Resizing and sorting the table self.__mcCabeTable.header().setSortIndicator( 3, Qt.DescendingOrder ) self.__mcCabeTable.sortItems( 3, self.__mcCabeTable.header().sortIndicatorOrder() ) self.__mcCabeTable.header().resizeSections( QHeaderView.ResizeToContents ) # Show the complete information self.__mcCabeTable.hide() self.__totalResultsTree.show() self.__reportShown = True self.__updateButtonsStatus() self.__updateTooltip() # It helps, but why do I have flickering? QApplication.processEvents() return def __accumulateBasicMetrics( self ): " Accumulates basic metrics for all the processed files " basic = {} for fileName in self.__report.report: singleBasic = self.__report.report[ fileName ].basicMetrics.metrics for key in singleBasic: if not key.startswith( 'num' ): continue if key in basic: basic[ key ] += int( singleBasic[ key ] ) else: basic[ key ] = int( singleBasic[ key ] ) return basic def __mcCabeActivated( self, item, column ): " Handles the double click (or Enter) on the mccabe table item " objName = str( item.text( 2 ) ) if self.__reportOption == self.SingleBuffer: if os.path.isabs( self.__reportFileName ): fileName = self.__reportFileName else: fileName = "" else: fileName = str( item.text( 1 ) ) self.__onMcCabeObject( objName, fileName ) return def __allItemActivated( self, item, column ): " Handles the double click (or Enter) in the total results tree " # We process only the error messages and McCabe items hiddenColumnText = str( item.text( 2 ) ) if not hiddenColumnText in [ "M", "E" ]: return fileName = self.__getTreeItemFileName( item ) lineNumber = 0 if hiddenColumnText == "M": # This is McCabe item objName = str( item.text( 0 ) ) self.__onMcCabeObject( objName, fileName ) return elif hiddenColumnText == "E": # This is an error message message = str( item.text( 0 ) ) pos = message.find( "at line" ) if pos == -1: logging.error( "Unknown format of the message. " "Please inform the developers." ) return parts = message[ pos: ].split() try: lineNumber = int( parts[ 2 ].replace( ',', '' ) ) except: logging.error( "Unknown format of the message. " "Please inform the developers." ) return if fileName == "": # This is an unsaved buffer, try to find the editor by UUID mainWindow = GlobalData().mainWindow widget = mainWindow.getWidgetByUUID( self.__reportUUID ) if widget is None: logging.error( "The unsaved buffer has been closed" ) return # The widget was found, so jump to the required editor = widget.getEditor() editor.gotoLine( lineNumber ) editor.setFocus() return GlobalData().mainWindow.openFile( fileName, lineNumber ) return def __getTreeItemFileName( self, item ): " Identifies the tree view item file name " if self.__reportOption == self.SingleBuffer: if os.path.isabs( self.__reportFileName ): return self.__reportFileName return "" # The file name is always two levels up fileItem = item.parent().parent() return str( fileItem.text( 0 ) ) def __onMcCabeObject( self, objName, fileName ): " Called when the user activated McCabe item " info = None mainWindow = GlobalData().mainWindow widget = mainWindow.getWidgetByUUID( self.__reportUUID ) if widget is None: if fileName == "": logging.error( "The unsaved buffer has been closed" ) return # No widget, but we know the file name info = getBriefModuleInfoFromFile( fileName ) else: # The widget was found editor = widget.getEditor() # The editor content has been modified, so re-parse the buffer info = getBriefModuleInfoFromMemory( editor.text() ) parts = objName.split( '.' ) currentIndex = 0 functionsContainer = info.functions classesContainer = info.classes line = -1 if objName == "__main__" and len( parts ) == 1: # Special case - global file scope line = 1 currentIndex = 1 while currentIndex < len( parts ): found = False for func in functionsContainer: if func.name == parts[ currentIndex ]: if currentIndex == len( parts ) - 1: # Found, jump to the line line = func.line break functionsContainer = func.functions classesContainer = func.classes found = True break if line != -1: break if found: currentIndex += 1 continue for klass in classesContainer: if klass.name == parts[ currentIndex ]: if currentIndex == len( parts ) - 1: # Found, jump to the line line = klass.line break functionsContainer = klass.functions classesContainer = klass.classes found = True if line != -1: break if found: currentIndex += 1 continue # Not found logging.error( "Cannot find the " + objName ) return # Here we have the line number if widget is None: GlobalData().mainWindow.openFile( fileName, line ) else: editor = widget.getEditor() editor.gotoLine( line ) editor.setFocus() return def onFileUpdated( self, fileName, uuid ): " Called when a buffer is saved or saved as " if not self.__reportShown: return if self.__reportUUID != uuid: return # Currently shown report is for the saved buffer # File name is expected being absolute self.__reportFileName = fileName self.emit( SIGNAL( 'updatePymetricsTooltip' ), "Metrics generated for buffer saved as " + fileName ) return
class PymetricsViewer(QWidget): " Pymetrics tab widget " # Limits to colorize the McCabe score LittleRiskLimit = 10 ModerateRiskLimit = 20 HighRiskLimit = 50 # Options of providing a report SingleFile = 0 DirectoryFiles = 1 ProjectFiles = 2 SingleBuffer = 3 def __init__(self, parent=None): QWidget.__init__(self, parent) self.__reportUUID = "" self.__reportFileName = "" self.__reportOption = -1 self.__reportShown = False self.__report = None # Prepare members for reuse self.__noneLabel = QLabel("\nNo results available") self.__noneLabel.setFrameShape(QFrame.StyledPanel) self.__noneLabel.setAlignment(Qt.AlignHCenter) self.__headerFont = self.__noneLabel.font() self.__headerFont.setPointSize(self.__headerFont.pointSize() + 4) self.__noneLabel.setFont(self.__headerFont) self.__noneLabel.setAutoFillBackground(True) noneLabelPalette = self.__noneLabel.palette() noneLabelPalette.setColor(QPalette.Background, GlobalData().skin.nolexerPaper) self.__noneLabel.setPalette(noneLabelPalette) self.__createLayout(parent) self.__updateButtonsStatus() return def __createLayout(self, parent): " Creates the toolbar and layout " # Buttons self.__mcCabeButton = QAction(PixmapCache().getIcon('tableview.png'), 'Switch to McCabe only table view', self) self.__mcCabeButton.setCheckable(True) self.connect(self.__mcCabeButton, SIGNAL('toggled(bool)'), self.__onMcCabe) self.printButton = QAction(PixmapCache().getIcon('printer.png'), 'Print', self) #printButton.setShortcut( 'Ctrl+' ) self.connect(self.printButton, SIGNAL('triggered()'), self.__onPrint) self.printButton.setVisible(False) self.printPreviewButton = QAction( PixmapCache().getIcon('printpreview.png'), 'Print preview', self) #printPreviewButton.setShortcut( 'Ctrl+' ) self.connect(self.printPreviewButton, SIGNAL('triggered()'), self.__onPrintPreview) self.printPreviewButton.setVisible(False) spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.clearButton = QAction(PixmapCache().getIcon('trash.png'), 'Clear', self) self.connect(self.clearButton, SIGNAL('triggered()'), self.__clear) # The toolbar 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.__mcCabeButton) self.toolbar.addAction(self.printPreviewButton) self.toolbar.addAction(self.printButton) self.toolbar.addWidget(spacer) self.toolbar.addAction(self.clearButton) self.__totalResultsTree = QTreeWidget() self.__totalResultsTree.setAlternatingRowColors(True) self.__totalResultsTree.setRootIsDecorated(True) self.__totalResultsTree.setItemsExpandable(True) self.__totalResultsTree.setUniformRowHeights(True) self.__totalResultsTree.setItemDelegate(NoOutlineHeightDelegate(4)) headerLabels = ["Path / name", "Value", ""] self.__totalResultsTree.setHeaderLabels(headerLabels) self.connect(self.__totalResultsTree, SIGNAL("itemActivated(QTreeWidgetItem *, int)"), self.__allItemActivated) self.connect(self.__totalResultsTree, SIGNAL("itemExpanded(QTreeWidgetItem *)"), self.__onResultsExpanded) self.__totalResultsTree.setColumnHidden(2, True) self.__totalResultsTree.hide() self.__mcCabeTable = QTreeWidget() self.__mcCabeTable.setAlternatingRowColors(True) self.__mcCabeTable.setRootIsDecorated(False) self.__mcCabeTable.setItemsExpandable(False) self.__mcCabeTable.setSortingEnabled(True) self.__mcCabeTable.setItemDelegate(NoOutlineHeightDelegate(4)) self.__mcCabeTable.setUniformRowHeights(True) headerLabels = ["", "File name", "Object", "McCabe Complexity"] self.__mcCabeTable.setHeaderLabels(headerLabels) self.connect(self.__mcCabeTable, SIGNAL("itemActivated(QTreeWidgetItem *, int)"), self.__mcCabeActivated) self.__mcCabeTable.hide() 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.addWidget(self.__totalResultsTree) self.__hLayout.addWidget(self.__mcCabeTable) self.setLayout(self.__hLayout) return def getTotalResultsWidget(self): " Provides a reference to the total results widget " return self.__totalResultsTree def getMcCabeResultsWidget(self): " Provides a reference to the McCabe results widget " return self.__mcCabeTable def __updateButtonsStatus(self): " Updates the buttons status " self.__mcCabeButton.setEnabled(self.__reportShown) self.printButton.setEnabled(self.__reportShown) self.printPreviewButton.setEnabled(self.__reportShown) self.clearButton.setEnabled(self.__reportShown) return def __onResultsExpanded(self, item): " An item has been expanded, so the column width should be adjusted " self.__totalResultsTree.header().resizeSections( QHeaderView.ResizeToContents) return def __onPrint(self): " Triggered when the print button is pressed " pass def __onPrintPreview(self): " triggered when the print preview button is pressed " pass def __onMcCabe(self, state): " Triggered when the metrics view is switched " if not self.__reportShown: return if state: self.__totalResultsTree.hide() self.__mcCabeTable.show() self.__mcCabeButton.setIcon(PixmapCache().getIcon('treeview.png')) self.__mcCabeButton.setToolTip("Switch to complete " "results tree view") else: self.__mcCabeTable.hide() self.__totalResultsTree.show() self.__mcCabeButton.setIcon(PixmapCache().getIcon('tableview.png')) self.__mcCabeButton.setToolTip("Switch to McCabe only table view") return def setFocus(self): " Overridden setFocus " self.__hLayout.setFocus() return def __clear(self): " Clears the content of the vertical layout " if not self.__reportShown: return self.__totalResultsTree.clear() self.__totalResultsTree.hide() self.__mcCabeTable.clear() self.__mcCabeTable.hide() self.__noneLabel.show() self.__report = None self.__reportShown = False self.__updateButtonsStatus() # self.resizeEvent() self.__mcCabeButton.setIcon(PixmapCache().getIcon('tableview.png')) self.__mcCabeButton.setToolTip("Switch to McCabe only table view") self.__mcCabeButton.setChecked(False) self.__updateTooltip() return def __updateTooltip(self): " Generates a signal with appropriate string message " if not self.__reportShown: tooltip = "No metrics available" elif self.__reportOption == self.DirectoryFiles: tooltip = "Metrics generated for directory: " + \ self.__reportFileName elif self.__reportOption == self.ProjectFiles: tooltip = "Metrics generated for the whole project" elif self.__reportOption == self.SingleFile: tooltip = "Metrics generated for file: " + self.__reportFileName elif self.__reportOption == self.SingleBuffer: tooltip = "Metrics generated for unsaved file: " + \ self.__reportFileName else: tooltip = "" self.emit(SIGNAL('updatePymetricsTooltip'), tooltip) return @staticmethod def __shouldShowFileName(table, column): " Checks if the file name is the same " size = table.topLevelItemCount() if size == 0: return False index = size - 1 firstName = table.topLevelItem(index).text(column) index -= 1 while index >= 0: if table.topLevelItem(index).text(column) != firstName: return True index -= 1 return False def showReport(self, metrics, reportOption, fileName, uuid): " Shows the pymetrics results " self.__clear() self.__noneLabel.hide() self.__report = metrics self.__reportUUID = uuid self.__reportFileName = fileName self.__reportOption = reportOption if len(metrics.report) > 1: accumulatedBasic = self.__accumulateBasicMetrics() accItem = QTreeWidgetItem(["Cumulative basic metrics"]) self.__totalResultsTree.addTopLevelItem(accItem) for key in accumulatedBasic: bmItem = [ BasicMetrics.metricsOfInterest[key], splitThousands(str(accumulatedBasic[key])) ] basicMetric = QTreeWidgetItem(bmItem) accItem.addChild(basicMetric) # Add the complete information for fileName in metrics.report: if reportOption == self.SingleBuffer: fileItem = QTreeWidgetItem(["Editor buffer"]) else: fileItem = QTreeWidgetItem([fileName]) info = GlobalData().briefModinfoCache.get(fileName) if info.docstring is not None: fileItem.setToolTip(0, info.docstring.text) else: fileItem.setToolTip(0, "") self.__totalResultsTree.addTopLevelItem(fileItem) # Messages part messages = metrics.report[fileName].messages if len(messages) > 0: messagesItem = QTreeWidgetItem(["Messages"]) fileItem.addChild(messagesItem) for message in messages: mItem = [message, "", "E"] messagesItem.addChild(QTreeWidgetItem(mItem)) # Basic metrics part basicItem = QTreeWidgetItem(["Basic metrics"]) fileItem.addChild(basicItem) basic = metrics.report[fileName].basicMetrics for key in basic.metrics: bmItem = [ BasicMetrics.metricsOfInterest[key], str(basic.metrics[key]) ] basicMetric = QTreeWidgetItem(bmItem) basicItem.addChild(basicMetric) # McCabe part mccabeItem = QTreeWidgetItem(["McCabe metrics"]) fileItem.addChild(mccabeItem) mccabe = metrics.report[fileName].mcCabeMetrics.metrics for objName in mccabe: objItem = [objName, str(mccabe[objName]), "M"] mccabeMetric = QTreeWidgetItem(objItem) mccabeItem.addChild(mccabeMetric) # COCOMO 2 part cocomo = [ "COCOMO 2", str(metrics.report[fileName].cocomo2Metrics.value) ] cocomoItem = QTreeWidgetItem(cocomo) fileItem.addChild(cocomoItem) # Resizing the table self.__totalResultsTree.header().resizeSections( QHeaderView.ResizeToContents) # Add McCabe complexity information for fileName in metrics.report: mccabe = metrics.report[fileName].mcCabeMetrics.metrics for objName in mccabe: values = ["", fileName, objName, str(mccabe[objName])] self.__mcCabeTable.addTopLevelItem(McCabeTableItem(values)) if not self.__shouldShowFileName(self.__mcCabeTable, 1): self.__mcCabeTable.setColumnHidden(1, True) # Resizing and sorting the table self.__mcCabeTable.header().setSortIndicator(3, Qt.DescendingOrder) self.__mcCabeTable.sortItems( 3, self.__mcCabeTable.header().sortIndicatorOrder()) self.__mcCabeTable.header().resizeSections( QHeaderView.ResizeToContents) # Show the complete information self.__mcCabeTable.hide() self.__totalResultsTree.show() self.__reportShown = True self.__updateButtonsStatus() self.__updateTooltip() # It helps, but why do I have flickering? QApplication.processEvents() return def __accumulateBasicMetrics(self): " Accumulates basic metrics for all the processed files " basic = {} for fileName in self.__report.report: singleBasic = self.__report.report[fileName].basicMetrics.metrics for key in singleBasic: if not key.startswith('num'): continue if key in basic: basic[key] += int(singleBasic[key]) else: basic[key] = int(singleBasic[key]) return basic def __mcCabeActivated(self, item, column): " Handles the double click (or Enter) on the mccabe table item " objName = str(item.text(2)) if self.__reportOption == self.SingleBuffer: if os.path.isabs(self.__reportFileName): fileName = self.__reportFileName else: fileName = "" else: fileName = str(item.text(1)) self.__onMcCabeObject(objName, fileName) return def __allItemActivated(self, item, column): " Handles the double click (or Enter) in the total results tree " # We process only the error messages and McCabe items hiddenColumnText = str(item.text(2)) if not hiddenColumnText in ["M", "E"]: return fileName = self.__getTreeItemFileName(item) lineNumber = 0 if hiddenColumnText == "M": # This is McCabe item objName = str(item.text(0)) self.__onMcCabeObject(objName, fileName) return elif hiddenColumnText == "E": # This is an error message message = str(item.text(0)) pos = message.find("at line") if pos == -1: logging.error("Unknown format of the message. " "Please inform the developers.") return parts = message[pos:].split() try: lineNumber = int(parts[2].replace(',', '')) except: logging.error("Unknown format of the message. " "Please inform the developers.") return if fileName == "": # This is an unsaved buffer, try to find the editor by UUID mainWindow = GlobalData().mainWindow widget = mainWindow.getWidgetByUUID(self.__reportUUID) if widget is None: logging.error("The unsaved buffer has been closed") return # The widget was found, so jump to the required editor = widget.getEditor() editor.gotoLine(lineNumber) editor.setFocus() return GlobalData().mainWindow.openFile(fileName, lineNumber) return def __getTreeItemFileName(self, item): " Identifies the tree view item file name " if self.__reportOption == self.SingleBuffer: if os.path.isabs(self.__reportFileName): return self.__reportFileName return "" # The file name is always two levels up fileItem = item.parent().parent() return str(fileItem.text(0)) def __onMcCabeObject(self, objName, fileName): " Called when the user activated McCabe item " info = None mainWindow = GlobalData().mainWindow widget = mainWindow.getWidgetByUUID(self.__reportUUID) if widget is None: if fileName == "": logging.error("The unsaved buffer has been closed") return # No widget, but we know the file name info = getBriefModuleInfoFromFile(fileName) else: # The widget was found editor = widget.getEditor() # The editor content has been modified, so re-parse the buffer info = getBriefModuleInfoFromMemory(editor.text()) parts = objName.split('.') currentIndex = 0 functionsContainer = info.functions classesContainer = info.classes line = -1 if objName == "__main__" and len(parts) == 1: # Special case - global file scope line = 1 currentIndex = 1 while currentIndex < len(parts): found = False for func in functionsContainer: if func.name == parts[currentIndex]: if currentIndex == len(parts) - 1: # Found, jump to the line line = func.line break functionsContainer = func.functions classesContainer = func.classes found = True break if line != -1: break if found: currentIndex += 1 continue for klass in classesContainer: if klass.name == parts[currentIndex]: if currentIndex == len(parts) - 1: # Found, jump to the line line = klass.line break functionsContainer = klass.functions classesContainer = klass.classes found = True if line != -1: break if found: currentIndex += 1 continue # Not found logging.error("Cannot find the " + objName) return # Here we have the line number if widget is None: GlobalData().mainWindow.openFile(fileName, line) else: editor = widget.getEditor() editor.gotoLine(line) editor.setFocus() return def onFileUpdated(self, fileName, uuid): " Called when a buffer is saved or saved as " if not self.__reportShown: return if self.__reportUUID != uuid: return # Currently shown report is for the saved buffer # File name is expected being absolute self.__reportFileName = fileName self.emit(SIGNAL('updatePymetricsTooltip'), "Metrics generated for buffer saved as " + fileName) return
class Suggest(QObject): def __init__(self, parent): QObject.__init__(self, parent) self.editor = parent editor = self.editor self.popup = QTreeWidget() popup = self.popup popup.setWindowFlags(Qt.Popup) popup.setFocusPolicy(Qt.NoFocus) popup.setFocusProxy(parent) popup.setMouseTracking(True) popup.setColumnCount(1) popup.setUniformRowHeights(True) popup.setRootIsDecorated(False) popup.setEditTriggers(QTreeWidget.NoEditTriggers) popup.setSelectionBehavior(QTreeWidget.SelectRows) popup.setFrameStyle(QFrame.Box | QFrame.Plain) popup.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) popup.header().hide() popup.installEventFilter(self) popup.itemClicked.connect(self.done) self.timer = QTimer(self) timer = self.timer timer.setSingleShot(True) # TODO: make interval optional timer.setInterval(500) timer.timeout.connect(self.suggest) editor.textEdited.connect(timer.start) self.engine = Engine(iciba.Engine()) self.engine.query_finished.connect(self.handle_query_finished) def eventFilter(self, o, e): if not o is self.popup: return False if e.type() == QEvent.MouseButtonPress: self.popup.hide() self.editor.setFocus() return True if e.type() == QEvent.KeyPress: consumed = False key = e.key() if key in (Qt.Key_Enter, Qt.Key_Return): self.done() consumed = True elif key in (Qt.Key_Escape, ): self.editor.setFocus() self.popup.hide() consumed = True elif key in ( Qt.Key_Up, Qt.Key_Down, Qt.Key_Home, Qt.Key_End, Qt.Key_PageUp, Qt.Key_PageDown ): pass else: self.editor.setFocus() self.editor.event(e) self.popup.hide() return consumed return False def complete(self, choices): if not choices: return self.popup.setUpdatesEnabled(False) self.popup.clear() for i in range(len(choices)): item = QTreeWidgetItem(self.popup) item.setText(0, choices[i]) self.popup.setCurrentItem(self.popup.topLevelItem(0)) self.popup.resizeColumnToContents(0) self.popup.resizeColumnToContents(1) self.popup.adjustSize() self.popup.setUpdatesEnabled(True) h = self.popup.sizeHintForRow(0) * min(7, len(choices)) + 3 self.popup.resize(self.editor.width(), h) self.popup.move(self.editor.mapToGlobal(QPoint(0, self.editor.height()))) self.popup.setFocus() self.popup.show() @pyqtSlot() def done(self): self.timer.stop() self.popup.hide() self.editor.setFocus() item = self.popup.currentItem() if item: self.editor.setText(item.text(0)) QMetaObject.invokeMethod(self.editor, "returnPressed") @pyqtSlot() def suggest(self): key = self.editor.text() self.engine.query(key) @pyqtSlot() def stop(self): self.timer.stop() @pyqtSlot(object) def handle_query_finished(self, result): self.complete(result)