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 OWPySparkScript(SharedSparkContext, widget.OWWidget): priority = 3 name = "PySpark Script" description = "Write a PySpark script and run it on input" icon = "../icons/PythonScript.svg" inputs = [("in_object", object, "setObject")] outputs = [("out_object", object, widget.Dynamic)] libraryListSource = \ Setting([Script("Hello world", "print('Hello world')\n")]) currentScriptIndex = Setting(0) splitterState = Setting(None) auto_execute = Setting(False) def __init__(self): super().__init__() self.in_data = None self.in_distance = None self.in_learner = None self.in_classifier = None self.in_object = None self.auto_execute = False for s in self.libraryListSource: s.flags = 0 self._cachedDocuments = { } self.infoBox = gui.widgetBox(self.controlArea, 'Info') gui.label( self.infoBox, self, "<p>Execute python script.</p><p>Input variables:<ul><li> " + \ "<li>".join(t.name for t in self.inputs) + \ "</ul></p><p>Output variables:<ul><li>" + \ "<li>".join(t.name for t in self.outputs) + \ "</ul></p>" ) self.libraryList = itemmodels.PyListModel( [], self, flags = Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable) self.libraryList.wrap(self.libraryListSource) self.controlBox = gui.widgetBox(self.controlArea, 'Library') self.controlBox.layout().setSpacing(1) self.libraryView = QListView( editTriggers = QListView.DoubleClicked | QListView.EditKeyPressed, sizePolicy = QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Preferred) ) self.libraryView.setItemDelegate(ScriptItemDelegate(self)) self.libraryView.setModel(self.libraryList) self.libraryView.selectionModel().selectionChanged.connect( self.onSelectedScriptChanged ) self.controlBox.layout().addWidget(self.libraryView) w = itemmodels.ModelActionsWidget() self.addNewScriptAction = action = QAction("+", self) action.setToolTip("Add a new script to the library") action.triggered.connect(self.onAddScript) w.addAction(action) action = QAction(unicodedata.lookup("MINUS SIGN"), self) action.setToolTip("Remove script from library") action.triggered.connect(self.onRemoveScript) w.addAction(action) action = QAction("Update", self) action.setToolTip("Save changes in the editor to library") action.setShortcut(QKeySequence(QKeySequence.Save)) action.triggered.connect(self.commitChangesToLibrary) w.addAction(action) action = QAction("More", self, toolTip = "More actions") new_from_file = QAction("Import a script from a file", self) save_to_file = QAction("Save selected script to a file", self) save_to_file.setShortcut(QKeySequence(QKeySequence.SaveAs)) new_from_file.triggered.connect(self.onAddScriptFromFile) save_to_file.triggered.connect(self.saveScript) menu = QMenu(w) menu.addAction(new_from_file) menu.addAction(save_to_file) action.setMenu(menu) button = w.addAction(action) button.setPopupMode(QToolButton.InstantPopup) w.layout().setSpacing(1) self.controlBox.layout().addWidget(w) gui.auto_commit(self.controlArea, self, "auto_execute", "Execute") self.splitCanvas = QSplitter(Qt.Vertical, self.mainArea) self.mainArea.layout().addWidget(self.splitCanvas) self.defaultFont = defaultFont = \ "Monaco" if sys.platform == "darwin" else "Courier" self.textBox = gui.widgetBox(self, 'Python script') self.splitCanvas.addWidget(self.textBox) self.text = PythonScriptEditor(self) self.textBox.layout().addWidget(self.text) self.textBox.setAlignment(Qt.AlignVCenter) self.text.setTabStopWidth(4) self.text.modificationChanged[bool].connect(self.onModificationChanged) self.saveAction = action = QAction("&Save", self.text) action.setToolTip("Save script to file") action.setShortcut(QKeySequence(QKeySequence.Save)) action.setShortcutContext(Qt.WidgetWithChildrenShortcut) action.triggered.connect(self.saveScript) self.consoleBox = gui.widgetBox(self, 'Console') self.splitCanvas.addWidget(self.consoleBox) self.__dict__['sc'] = self._sc self.__dict__['hc'] = self._hc self.console = PySparkConsole(self.__dict__, self, sc = self.sc) self.consoleBox.layout().addWidget(self.console) self.console.document().setDefaultFont(QFont(defaultFont)) self.consoleBox.setAlignment(Qt.AlignBottom) self.console.setTabStopWidth(4) select_row(self.libraryView, self.currentScriptIndex) self.splitCanvas.setSizes([2, 1]) if self.splitterState is not None: self.splitCanvas.restoreState(QByteArray(self.splitterState)) self.splitCanvas.splitterMoved[int, int].connect(self.onSpliterMoved) self.controlArea.layout().addStretch(1) self.resize(800, 600) def setExampleTable(self, et): self.in_data = et def setDistanceMatrix(self, dm): self.in_distance = dm def setLearner(self, learner): self.in_learner = learner def setClassifier(self, classifier): self.in_classifier = classifier def setObject(self, obj): self.in_object = obj def handleNewSignals(self): self.unconditional_commit() def selectedScriptIndex(self): rows = self.libraryView.selectionModel().selectedRows() if rows: return [i.row() for i in rows][0] else: return None def setSelectedScript(self, index): select_row(self.libraryView, index) def onAddScript(self, *args): self.libraryList.append(Script("New script", "", 0)) self.setSelectedScript(len(self.libraryList) - 1) def onAddScriptFromFile(self, *args): filename = QFileDialog.getOpenFileName( self, 'Open Python Script', os.path.expanduser("~/"), 'Python files (*.py)\nAll files(*.*)' ) filename = str(filename) if filename: name = os.path.basename(filename) contents = open(filename, "rb").read().decode("utf-8", errors = "ignore") self.libraryList.append(Script(name, contents, 0, filename)) self.setSelectedScript(len(self.libraryList) - 1) def onRemoveScript(self, *args): index = self.selectedScriptIndex() if index is not None: del self.libraryList[index] select_row(self.libraryView, max(index - 1, 0)) def onSaveScriptToFile(self, *args): index = self.selectedScriptIndex() if index is not None: self.saveScript() def onSelectedScriptChanged(self, selected, deselected): index = [i.row() for i in selected.indexes()] if index: current = index[0] if current >= len(self.libraryList): self.addNewScriptAction.trigger() return self.text.setDocument(self.documentForScript(current)) self.currentScriptIndex = current def documentForScript(self, script = 0): if type(script) != Script: script = self.libraryList[script] if script not in self._cachedDocuments: doc = QtGui.QTextDocument(self) doc.setDocumentLayout(QtGui.QPlainTextDocumentLayout(doc)) doc.setPlainText(script.script) doc.setDefaultFont(QFont(self.defaultFont)) doc.highlighter = PythonSyntaxHighlighter(doc) doc.modificationChanged[bool].connect(self.onModificationChanged) doc.setModified(False) self._cachedDocuments[script] = doc return self._cachedDocuments[script] def commitChangesToLibrary(self, *args): index = self.selectedScriptIndex() if index is not None: self.libraryList[index].script = self.text.toPlainText() self.text.document().setModified(False) self.libraryList.emitDataChanged(index) def onModificationChanged(self, modified): index = self.selectedScriptIndex() if index is not None: self.libraryList[index].flags = Script.Modified if modified else 0 self.libraryList.emitDataChanged(index) def onSpliterMoved(self, pos, ind): self.splitterState = str(self.splitCanvas.saveState()) def updateSelecetdScriptState(self): index = self.selectedScriptIndex() if index is not None: script = self.libraryList[index] self.libraryList[index] = Script(script.name, self.text.toPlainText(), 0) def saveScript(self): index = self.selectedScriptIndex() if index is not None: script = self.libraryList[index] filename = script.filename else: filename = os.path.expanduser("~/") filename = QFileDialog.getSaveFileName( self, 'Save Python Script', filename, 'Python files (*.py)\nAll files(*.*)' ) if filename: fn = "" head, tail = os.path.splitext(filename) if not tail: fn = head + ".py" else: fn = filename f = open(fn, 'w') f.write(self.text.toPlainText()) f.close() def commit(self): self._script = str(self.text.toPlainText()) self.console.write("\nRunning script:\n") self.console.push("exec(_script)") self.console.new_prompt(sys.ps1) for out in self.outputs: signal = out.name self.send(signal, getattr(self, signal, None))
class OWPythonScript(widget.OWWidget): name = "Python Script" description = "Executes a Python script." icon = "icons/PythonScript.svg" priority = 3150 inputs = [ ("in_data", Orange.data.Table, "setExampleTable", widget.Default), # ("in_distance", Orange.misc.SymMatrix, "setDistanceMatrix", # widget.Default), ("in_learner", Orange.classification.Fitter, "setLearner", widget.Default), ("in_classifier", Orange.classification.Model, "setClassifier", widget.Default), ("in_object", object, "setObject") ] outputs = [ ( "out_data", Orange.data.Table, ), # ("out_distance", Orange.misc.SymMatrix, ), ( "out_learner", Orange.classification.Fitter, ), ("out_classifier", Orange.classification.Model, widget.Dynamic), ("out_object", object, widget.Dynamic) ] libraryListSource = \ Setting([Script("Hello world", "print('Hello world')\n")]) currentScriptIndex = Setting(0) splitterState = Setting(None) auto_execute = Setting(False) def __init__(self): super().__init__() self.in_data = None self.in_distance = None self.in_learner = None self.in_classifier = None self.in_object = None self.auto_execute = False for s in self.libraryListSource: s.flags = 0 self._cachedDocuments = {} self.infoBox = gui.widgetBox(self.controlArea, 'Info') gui.label( self.infoBox, self, "<p>Execute python script.</p><p>Input variables:<ul><li> " + \ "<li>".join(t.name for t in self.inputs) + \ "</ul></p><p>Output variables:<ul><li>" + \ "<li>".join(t.name for t in self.outputs) + \ "</ul></p>" ) self.libraryList = itemmodels.PyListModel( [], self, flags=Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable) self.libraryList.wrap(self.libraryListSource) self.controlBox = gui.widgetBox(self.controlArea, 'Library') self.controlBox.layout().setSpacing(1) self.libraryView = QListView( editTriggers=QListView.DoubleClicked | QListView.EditKeyPressed, sizePolicy=QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Preferred)) self.libraryView.setItemDelegate(ScriptItemDelegate(self)) self.libraryView.setModel(self.libraryList) self.libraryView.selectionModel().selectionChanged.connect( self.onSelectedScriptChanged) self.controlBox.layout().addWidget(self.libraryView) w = itemmodels.ModelActionsWidget() self.addNewScriptAction = action = QAction("+", self) action.setToolTip("Add a new script to the library") action.triggered.connect(self.onAddScript) w.addAction(action) action = QAction(unicodedata.lookup("MINUS SIGN"), self) action.setToolTip("Remove script from library") action.triggered.connect(self.onRemoveScript) w.addAction(action) action = QAction("Update", self) action.setToolTip("Save changes in the editor to library") action.setShortcut(QKeySequence(QKeySequence.Save)) action.triggered.connect(self.commitChangesToLibrary) w.addAction(action) action = QAction("More", self, toolTip="More actions") new_from_file = QAction("Import a script from a file", self) save_to_file = QAction("Save selected script to a file", self) save_to_file.setShortcut(QKeySequence(QKeySequence.SaveAs)) new_from_file.triggered.connect(self.onAddScriptFromFile) save_to_file.triggered.connect(self.saveScript) menu = QMenu(w) menu.addAction(new_from_file) menu.addAction(save_to_file) action.setMenu(menu) button = w.addAction(action) button.setPopupMode(QToolButton.InstantPopup) w.layout().setSpacing(1) self.controlBox.layout().addWidget(w) self.runBox = gui.widgetBox(self.controlArea, 'Run') gui.button(self.runBox, self, "Execute", callback=self.execute) gui.checkBox(self.runBox, self, "auto_execute", "Auto execute", tooltip="Run the script automatically whenever " + "the inputs to the widget change.") self.splitCanvas = QSplitter(Qt.Vertical, self.mainArea) self.mainArea.layout().addWidget(self.splitCanvas) self.defaultFont = defaultFont = \ "Monaco" if sys.platform == "darwin" else "Courier" self.textBox = gui.widgetBox(self, 'Python script') self.splitCanvas.addWidget(self.textBox) self.text = PythonScriptEditor(self) self.textBox.layout().addWidget(self.text) self.textBox.setAlignment(Qt.AlignVCenter) self.text.setTabStopWidth(4) self.text.modificationChanged[bool].connect(self.onModificationChanged) self.saveAction = action = QAction("&Save", self.text) action.setToolTip("Save script to file") action.setShortcut(QKeySequence(QKeySequence.Save)) action.setShortcutContext(Qt.WidgetWithChildrenShortcut) action.triggered.connect(self.saveScript) self.consoleBox = gui.widgetBox(self, 'Console') self.splitCanvas.addWidget(self.consoleBox) self.console = PythonConsole(self.__dict__, self) self.consoleBox.layout().addWidget(self.console) self.console.document().setDefaultFont(QFont(defaultFont)) self.consoleBox.setAlignment(Qt.AlignBottom) self.console.setTabStopWidth(4) select_row(self.libraryView, self.currentScriptIndex) self.splitCanvas.setSizes([2, 1]) if self.splitterState is not None: self.splitCanvas.restoreState(QByteArray(self.splitterState)) self.splitCanvas.splitterMoved[int, int].connect(self.onSpliterMoved) self.controlArea.layout().addStretch(1) self.resize(800, 600) def setExampleTable(self, et): self.in_data = et def setDistanceMatrix(self, dm): self.in_distance = dm def setLearner(self, learner): self.in_learner = learner def setClassifier(self, classifier): self.in_classifier = classifier def setObject(self, obj): self.in_object = obj def handleNewSignals(self): if self.auto_execute: self.execute() def selectedScriptIndex(self): rows = self.libraryView.selectionModel().selectedRows() if rows: return [i.row() for i in rows][0] else: return None def setSelectedScript(self, index): select_row(self.libraryView, index) def onAddScript(self, *args): self.libraryList.append(Script("New script", "", 0)) self.setSelectedScript(len(self.libraryList) - 1) def onAddScriptFromFile(self, *args): filename = QFileDialog.getOpenFileName( self, 'Open Python Script', os.path.expanduser("~/"), 'Python files (*.py)\nAll files(*.*)') filename = str(filename) if filename: name = os.path.basename(filename) contents = open(filename, "rb").read().decode("utf-8", errors="ignore") self.libraryList.append(Script(name, contents, 0, filename)) self.setSelectedScript(len(self.libraryList) - 1) def onRemoveScript(self, *args): index = self.selectedScriptIndex() if index is not None: del self.libraryList[index] select_row(self.libraryView, max(index - 1, 0)) def onSaveScriptToFile(self, *args): index = self.selectedScriptIndex() if index is not None: self.saveScript() def onSelectedScriptChanged(self, selected, deselected): index = [i.row() for i in selected.indexes()] if index: current = index[0] if current >= len(self.libraryList): self.addNewScriptAction.trigger() return self.text.setDocument(self.documentForScript(current)) self.currentScriptIndex = current def documentForScript(self, script=0): if type(script) != Script: script = self.libraryList[script] if script not in self._cachedDocuments: doc = QtGui.QTextDocument(self) doc.setDocumentLayout(QtGui.QPlainTextDocumentLayout(doc)) doc.setPlainText(script.script) doc.setDefaultFont(QFont(self.defaultFont)) doc.highlighter = PythonSyntaxHighlighter(doc) doc.modificationChanged[bool].connect(self.onModificationChanged) doc.setModified(False) self._cachedDocuments[script] = doc return self._cachedDocuments[script] def commitChangesToLibrary(self, *args): index = self.selectedScriptIndex() if index is not None: self.libraryList[index].script = self.text.toPlainText() self.text.document().setModified(False) self.libraryList.emitDataChanged(index) def onModificationChanged(self, modified): index = self.selectedScriptIndex() if index is not None: self.libraryList[index].flags = Script.Modified if modified else 0 self.libraryList.emitDataChanged(index) def onSpliterMoved(self, pos, ind): self.splitterState = str(self.splitCanvas.saveState()) def updateSelecetdScriptState(self): index = self.selectedScriptIndex() if index is not None: script = self.libraryList[index] self.libraryList[index] = Script(script.name, self.text.toPlainText(), 0) def saveScript(self): index = self.selectedScriptIndex() if index is not None: script = self.libraryList[index] filename = script.filename else: filename = os.path.expanduser("~/") filename = QFileDialog.getSaveFileName( self, 'Save Python Script', filename, 'Python files (*.py)\nAll files(*.*)') if filename: fn = "" head, tail = os.path.splitext(filename) if not tail: fn = head + ".py" else: fn = filename f = open(fn, 'w') f.write(self.text.toPlainText()) f.close() def execute(self): self._script = str(self.text.toPlainText()) self.console.write("\nRunning script:\n") self.console.push("exec(_script)") self.console.new_prompt(sys.ps1) for out in self.outputs: signal = out.name self.send(signal, getattr(self, signal, None))
class NPhotoMainWindow(QMainWindow): rootAlbum = None currentPage = 0 def __init__(self, parent=None): super(NPhotoMainWindow, self).__init__(parent) self.image = None self.status = self.statusBar() self.status.setSizeGripEnabled(False) fileMenu = self.menuBar().addMenu("&File") fileEditAction = createAction(self, "&Edit", self.doEdit, "Ctrl-E", "fileedit", "Edit photo details") fileDeleteAction = createAction(self, "&Delete", self.doDelete, "Ctrl-D", "filedelete", "Delete selected file(s)") fileImportAction = createAction(self, "&Import", self.doImport, "Ctrl-I", "fileimport", "Import photos into your library") fileRescanLibraryAction = createAction(self, "&Rescan", self.doRescan, "Ctrl-R", "filerescan", "Rescan library folder and update sidecar files, and thumbnails") fileBackupAction = createAction(self, "&Backup", self.doBackup, "Ctrl-B", "filebkup", "Backup your library") fileSettingsAction = createAction(self, "&Settings", self.doSettings, "Ctrl-S", "filesettings", "Settings") fileQuitAction = createAction(self, "&Quit", self.close, "Ctrl+Q", "filequit", "Close the application") helpMenu = self.menuBar().addMenu("&Help") helpAboutAction = createAction(self, "&About", self.doAbout, None, "helpabout", "About nPhoto") addActions(fileMenu, (fileEditAction, fileDeleteAction, None, fileImportAction, fileRescanLibraryAction, fileBackupAction, fileSettingsAction, None, fileQuitAction)) addActions(helpMenu, (helpAboutAction,)) size = getSettingQVar("MainWindow/Size", QSize(600,500)).toSize() self.resize(size) position = getSettingQVar("MainWindow/Position", QPoint(0,0)).toPoint() self.move(position) self.restoreState(getSettingQVar("MainWindow/State").toByteArray()) self.setWindowTitle("nPhoto") self.controlFrame = QFrame() self.controlLayout = QBoxLayout(QBoxLayout.TopToBottom) #TODO Make this a combo box that populates the tree by date or by folder self.viewByCombo = QLabel("PLACEHOLDER") self.tree = QTreeWidget() self.tree.setColumnCount(1) self.tree.setHeaderLabels(["Album"]) self.tree.setItemsExpandable(True) self.connect(self.tree, SIGNAL("itemSelectionChanged()"), self.treeSelection) self.controlLayout.addWidget(self.viewByCombo) self.controlLayout.addWidget(self.tree) self.controlFrame.setLayout(self.controlLayout) self.browserFrame = QFrame() self.browserGrid = QGridLayout() self.imageLabels = [] for row in range(0,BROWSER_GRID_HEIGHT): self.imageLabels.append([]) for col in range(0,BROWSER_GRID_WIDTH): self.imageLabels[row].append(QLabel()) self.imageLabels[row][col].setBackgroundRole(QPalette.Base) self.imageLabels[row][col].setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) self.imageLabels[row][col].setScaledContents = True self.imageLabels[row][col].setAlignment(Qt.AlignCenter) self.imageLabels[row][col].setStyleSheet("border:2px solid #000") dbl = functools.partial(self.imgDoubleClick, row, col) click = functools.partial(self.imgMouseRelease, row, col) self.imageLabels[row][col].mouseDoubleClickEvent = dbl self.imageLabels[row][col].mouseReleaseEvent = click self.browserGrid.addWidget(self.imageLabels[row][col],row,col) self.prevPage = QPushButton("Prev") self.pageInfoLabel = QLabel("Page 0 of 0") self.pageInfoLabel.setAlignment(Qt.AlignCenter) self.nextPage = QPushButton("Next") self.prevPage.clicked.connect(self.goPreviousPage) self.nextPage.clicked.connect(self.goNextPage) self.browserGrid.addWidget(self.prevPage, row+1, 0) self.browserGrid.addWidget(self.pageInfoLabel, row+1, 1) self.browserGrid.addWidget(self.nextPage, row+1, 2) self.browserFrame.setLayout(self.browserGrid) self.mainSplitter = QSplitter(Qt.Horizontal) self.mainSplitter.addWidget(self.controlFrame) self.mainSplitter.addWidget(self.browserFrame) self.mainSplitter.setStretchFactor(1,4) self.setCentralWidget(self.mainSplitter) self.mainSplitter.restoreState(getSettingQVar("MainWindow/Splitter").toByteArray()) if getSettingStr("Paths/Library") not in (None, ''): QTimer.singleShot(0, self.loadLibrary) else: self.status.showMessage("No Library Path in settings", 10000) def getPhotoByBrowserLocation(self, row, col): idx = ((self.currentPage - 1) * BROWSER_THUMBS_PER_PAGE) + (row * BROWSER_GRID_WIDTH) + col if idx < len(self.currentAlbum.photos): return self.currentAlbum.photos[idx] else: return None def imgDoubleClick(self, row, col, event): if event.button() == Qt.LeftButton: if event.modifiers() & Qt.ControlModifier or event.modifiers() & Qt.AltModifier \ or event.modifiers() & Qt.ShiftModifier: pass else: curr = self.getPhotoByBrowserLocation(row,col) if curr: self.currentSelection = [curr,] self.highlightSelected() self.doEdit() def imgMouseRelease(self, row, col, event): if event.button() == Qt.LeftButton: if event.modifiers() & Qt.ControlModifier or event.modifiers() & Qt.AltModifier \ or event.modifiers() & Qt.ShiftModifier: pass else: curr = self.getPhotoByBrowserLocation(row,col) if curr: if not hasattr(self, "currentSelection"): self.currentSelection = [] if curr in self.currentSelection: self.currentSelection.remove(curr) else: self.currentSelection.append(curr) self.highlightSelected() def highlightSelected(self): if hasattr(self, "currentSelection"): for x in range(0, BROWSER_GRID_HEIGHT): for y in range(0, BROWSER_GRID_WIDTH): ph = self.getPhotoByBrowserLocation(x,y) if ph: if ph in self.currentSelection: self.imageLabels[x][y].setStyleSheet("border:2px solid #FFF") else: self.imageLabels[x][y].setStyleSheet("border:2px solid #000") def regenAlbumThumbnails(self, album): for al in album.albums: self.regenAlbumThumbnails(al) for ph in album.photos: createThumbnail(ph.path, True) def doRescan(self): #TODO Rebuild sidecar files! self.regenAlbumThumbnails(self.rootAlbum) self.reloadLibrary() def treeSelection(self): curr = self.tree.currentItem() path = curr.data(0,0).toString() tmp = curr while tmp.parent() is not None: tmp = tmp.parent() path = tmp.data(0,0).toString() + "." + path album = self.getAlbum(path) if hasattr(self, 'currentAlbum'): if self.currentAlbum != album: self.currentAlbum = album else: self.currentAlbum = album self.changeAlbums() def changeAlbums(self): if len(self.currentAlbum.photos) == 0: self.currentPage = 0 else: self.currentPage = 1 for row in range(0, BROWSER_GRID_HEIGHT): for col in range(0, BROWSER_GRID_WIDTH): if len(self.currentAlbum.photos)<= (row*BROWSER_GRID_WIDTH + col): self.imageLabels[row][col].setPixmap(QPixmap()) else: self.imageLabels[row][col].setPixmap(loadQPixMap(self.image, self.currentAlbum.photos[ (BROWSER_THUMBS_PER_PAGE * (self.currentPage - 1)) + row*BROWSER_GRID_WIDTH+col] .path, self.imageLabels[0][0].width(), self.imageLabels[0][0].height(), True)) self.imageLabels[row][col].adjustSize() self.updatePageInfo() def loadPageThumbs(self): for row in range(0, BROWSER_GRID_HEIGHT): for col in range(0, BROWSER_GRID_WIDTH): if len(self.currentAlbum.photos)<= ( (BROWSER_THUMBS_PER_PAGE * (self.currentPage - 1)) + row*BROWSER_GRID_WIDTH + col): self.imageLabels[row][col].setPixmap(QPixmap()) else: self.imageLabels[row][col].setPixmap(loadQPixMap(self.image, self.currentAlbum.photos[ (BROWSER_THUMBS_PER_PAGE * (self.currentPage - 1)) + row*BROWSER_GRID_WIDTH+col] .path, self.imageLabels[0][0].width(), self.imageLabels[0][0].height(), True)) self.imageLabels[row][col].adjustSize() def goPreviousPage(self): if self.currentPage > 1: self.currentPage -= 1 self.loadPageThumbs() self.updatePageInfo() def goNextPage(self): if self.currentPage < self.getMaxPage(): self.currentPage += 1 self.loadPageThumbs() self.updatePageInfo() def getMaxPage(self): totalPages = len(self.currentAlbum.photos) / BROWSER_THUMBS_PER_PAGE if (len(self.currentAlbum.photos) % BROWSER_THUMBS_PER_PAGE) != 0: totalPages += 1 return totalPages def updatePageInfo(self): if self.currentPage == 0: self.pageInfoLabel.setText("Page 0 of 0") else: self.pageInfoLabel.setText("Page %d of %d" % (self.currentPage, self.getMaxPage())) def getAlbum(self, path): nodes = path.split(".") if nodes[0] != 'Library': print "WTF?!?!?!" else: album = self.rootAlbum for albumName in nodes[1:]: album = album.albums[unicode(albumName)] return album def doBackup(self): libDir = getSettingStr("Paths/Library") bkupPaths = getSettingStr("Paths/Backup") if libDir in (None, ''): QMessageBox.warning(self, "Backup Failed", "You need to specify a library directory in your settings") return if not os.path.exists(libDir) or os.path.isfile(libDir): QMessageBox.warning(self, "Backup Failed", "The library directory in your settings either doesn't exist, or its not a directory") return if bkupPaths in (None, ''): QMessageBox.warning(self, "Backup Failed", "You need to specify at least one backup directory in your settings") return dt = datetime.date.today() bkupDirName = str(dt.year) + str(dt.month) + str(dt.day) for path in bkupPaths.split(","): if not os.path.exists(path.strip()) or os.path.isfile(path.strip()): QMessageBox.warning(self, "Backup Failed", "The backup directory <%s> in your settings either doesn't exist, or its not a directory" % (path)) return if os.path.exists(path.strip() + os.sep + bkupDirName): QMessageBox.warning(self, "Backup Failed", "There is already a backup for today in a backup directory <%s>" % (path.strip())) return for path in bkupPaths.split(","): shutil.copytree(libDir, path.strip() + os.sep + bkupDirName) QMessageBox.information(self, "Backup", "Backup completed!") def doDelete(self): if hasattr(self, "currentSelection"): if len(self.currentSelection) > 0: msg = "Are you sure you want to delete the selected image?" if len(self.currentSelection) > 1: msg = "Are you sure you want to delete the %s selected images?" % len(self.currentSelection) if QMessageBox.warning(self, "Delete Image(s)", msg, QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes: for ph in self.currentSelection: msg = ph.delete() if msg not in (None, ''): QMessageBox.warning(self, "Error while deleting", msg) break self.reloadLibrary() def reloadLibrary(self): self.currentSelection = [] self.highlightSelected() currPage = self.currentPage self.loadLibrary() if currPage > self.getMaxPage(): #Assumes you can't delete more than one page worth of photos at a time currPage = self.getMaxPage() self.currentPage = currPage self.loadPageThumbs() self.updatePageInfo() def doEdit(self): if hasattr(self, "currentSelection"): if len(self.currentSelection) == 1: ph = self.currentSelection[0] comment = ph.comment keywords = (" ".join(ph.keywords)).strip() dialog = EditPhotoDialog(self, ph.path, comment, keywords) if dialog.exec_(): ph.comment = unicode(dialog.commentEdit.text()).strip() ph.keywords = unicode(dialog.keywordEdit.text()).strip().split(" ") ph.save(ph.path) def doSettings(self): libPath = getSettingStr("Paths/Library", "") backupPaths = getSettingStr("Paths/Backup", "") fileExt = getSettingStr("FileExtensions", "jpg, CR2") fileExtOther = getSettingStr("FileExtensionsOther", "mov, avi") dialog = SettingsDialog(self, libPath, backupPaths, fileExt, fileExtOther) if dialog.exec_(): saveSetting("Paths/Library", dialog.libPathEdit.text()) saveSetting("Paths/Backup", dialog.backupPathsEdit.text()) saveSetting("FileExtensions", dialog.fileExtensionEdit.text()) saveSetting("FileExtensionsOther", dialog.fileExtensionOtherEdit.text()) self.status.showMessage("Settings updated", 5000) def buildTree(self, parentNode, parentAlbum): for name in parentAlbum.albums: childNode = QTreeWidgetItem(parentNode, [name]) childAlbum = parentAlbum.albums[name] if childAlbum.albums != None and len(childAlbum.albums) > 0: self.buildTree(childNode, childAlbum) def loadLibrary(self): self.status.showMessage("Loading Photo Library") self.rootAlbum = self.loadAlbum(getSettingStr("Paths/Library"), "Library") if self.rootAlbum == None: self.rootAlbum = Album(name="Library") self.refreshTree() self.status.showMessage("Library successfully loaded", 5000) def refreshTree(self): self.tree.clear() node = QTreeWidgetItem(self.tree, ["Library"]) self.buildTree(node, self.rootAlbum) self.tree.setCurrentItem(node) def loadAlbum(self, path, title = None): album = Album() if title not in (None, ''): album.name = title else: album.name = path[path.rfind(os.sep)+1:] album.albums = {} album.photos = [] album.path = path files = os.listdir(path) files.sort() tmpPhotos = [] for fl in files: if not os.path.isfile(path + os.sep + fl): album.albums[fl] = self.loadAlbum(path + os.sep + fl) else: if self.isImageFile(path + os.sep + fl): ph = None if os.path.exists(path + os.sep + fl + ".sidecar"): ph = Photo.load(path + os.sep + fl + ".sidecar") else: ph = Photo() ph.comment = "" ph.keywords = {} ph.srcPath = None ph.path = path + os.sep + fl exif = loadExif(path + os.sep + fl, EXIF_TAGS) ph.setExif(exif) ph.save(path + os.sep + fl) ph.path = path + os.sep + fl tmpPhotos.append(ph) album.photos = sorted(tmpPhotos, key = lambda photo: photo.date) return album def doImport(self): libPath = getSettingStr("Paths/Library") fileExt = getSettingStr("FileExtensions") if libPath in (None, ''): QMessageBox.warning(self, "Import Failed", "You need to specify a library directory in your settings") return if not os.path.exists(libPath) or os.path.isfile(libPath): QMessageBox.warning(self, "Import Failed", "The library directory in your settings either doesn't exist, or its not a directory") return if not fileExt or fileExt in (None, ''): QMessageBox.warning(self, "Import Failed", "You need to specify file extensions to manage in your settings") return lastImport = getSettingStr("Paths/LastImport") importFrom = QFileDialog.getExistingDirectory(self, "Choose a Path to Import From", lastImport) if importFrom in (None, ''): return if not os.path.exists(importFrom) or os.path.isfile(importFrom): QMessageBox.warning(self, "Import Failed", "The import directory either doesn't exist, or is not a directory") return if importFrom == libPath: QMessageBox.warning(self, "Import Failed", "Your import directory and library directory can not be the same") return imd = ImportMetadataDialog(self) if imd.exec_(): album = imd.albumEdit.text() comments = imd.commentsEdit.text() keywords = imd.keywordsEdit.text() if album and album not in (None, ''): albumpath = album + os.sep else: album = None albumpath = "" if not keywords or keywords in (None, ''): keywords = "" if not comments or comments in (None, ''): comments = "" paths = self.buildFileList(importFrom) numTotal = len(paths) nonDupes = self.removeDuplicates(paths, importFrom, albumpath) numDuplicates = numTotal - len(nonDupes) if QMessageBox.question(self, "Import", "Out of %d files found, %d look to be duplicates. Continue with import?" % (numTotal, numDuplicates), QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes: saveSetting("Paths/LastImport", importFrom) for path in nonDupes: dest = self.buildLibPath(importFrom, path, albumpath) copyFileIncludingDirectories(path, dest) # TODO Handle copy failure exceptions! if not os.path.exists(dest): QMessageBox.warming(self, "Import Failed", "The file <%s> was not imported properly, aborting import" % (path)) return if self.isImageFile(path): exif = loadExif(unicode(path), EXIF_TAGS) ph = Photo() ph.path = dest ph.srcPath = path ph.comment = comments ph.keywords = keywords ph.setExif(exif) ph.save(dest) #Create Thumbnail createThumbnail(unicode(ph.path)) QMessageBox.information(self, "Import", "Import completed") self.loadLibrary() def buildLibPath(self, importFrom, path, albumpath): relPath = path[len(importFrom):] libPath = getSettingStr("Paths/Library") + os.sep + albumpath + relPath return libPath def isImageFile(self, filepath): extensionList = unicode(getSettingStr("FileExtensions")).split(",") for extension in extensionList: if unicode(filepath).upper().endswith(unicode(extension).upper()): return True return False def isOtherManagedFile(self, filepath): #TODO Implement list of other files to import into lib folders and to backup extensionList = unicode(getSettingStr("FileExtensionsOther")).split(",") for extension in extensionList: if unicode(filepath).upper().endswith(unicode(extension).upper()): return True return False def removeDuplicates(self, paths, importFrom, albumpath): nonDupes = [] for path in paths: libPath = self.buildLibPath(importFrom, path, albumpath) if not os.path.exists(libPath): nonDupes.append(path) return nonDupes def buildFileList(self, importFrom): #TODO Can probably be done with Glob or whatever it is? paths = [] for f in os.listdir(importFrom): fullpath = importFrom + os.sep + f if not os.path.isfile(fullpath): paths.extend(self.buildFileList(fullpath)) else: if self.isImageFile(fullpath): paths.append(fullpath) elif self.isOtherManagedFile(fullpath): paths.append(fullpath) return paths def closeEvent(self, event): saveSetting("MainWindow/Size", self.size()) saveSetting("MainWindow/Position", self.pos()) saveSetting("MainWindow/State", self.saveState()) saveSetting("MainWindow/Splitter", self.mainSplitter.saveState()) def doAbout(self): QMessageBox.about(self, "About nPhoto", "<p>nPhoto allows simple reviewing, commenting, and keywording of images, useful for running" " on a netbook while travelling, to then import into programs such as Lightroom" " on return from your holiday</p>")
class OWPySparkScript(SharedSparkContext, widget.OWWidget): priority = 3 name = "PySpark Script" description = "Write a PySpark script and run it on input" icon = "../icons/PythonScript.svg" inputs = [("in_object", object, "setObject")] outputs = [("out_object", object, widget.Dynamic)] in_object = None out_object = None auto_execute = Setting(False) libraryListSource = \ Setting([Script("Hello world", "print('Hello world')\n")]) currentScriptIndex = Setting(0) splitterState = Setting(None) auto_execute = Setting(False) _script = Setting("") def __init__(self): super().__init__() self.spark_logo = """ ____ __ / __/__ ___ _____/ /__ _\ \/ _ \/ _ `/ __/ '_/ /__ / .__/\_,_/_/ /_/\_\ version {version} /_/ """.format(version=self.sc.version) for s in self.libraryListSource: s.flags = 0 self._cachedDocuments = {} self.infoBox = gui.widgetBox(self.controlArea, 'Info') gui.label( self.infoBox, self, "<p>Execute python script.</p><p>Input variables:<ul><li> " + \ "<li>".join(t.name for t in self.inputs) + \ "</ul></p><p>Output variables:<ul><li>" + \ "<li>".join(t.name for t in self.outputs) + \ "</ul></p>" ) self.libraryList = itemmodels.PyListModel( [], self, flags=Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable) self.libraryList.wrap(self.libraryListSource) self.controlBox = gui.widgetBox(self.controlArea, 'Library') self.controlBox.layout().setSpacing(1) self.libraryView = QListView( editTriggers=QListView.DoubleClicked | QListView.EditKeyPressed, sizePolicy=QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Preferred)) self.libraryView.setItemDelegate(ScriptItemDelegate(self)) self.libraryView.setModel(self.libraryList) self.libraryView.selectionModel().selectionChanged.connect( self.onSelectedScriptChanged) self.controlBox.layout().addWidget(self.libraryView) w = itemmodels.ModelActionsWidget() self.addNewScriptAction = action = QAction("+", self) action.setToolTip("Add a new script to the library") action.triggered.connect(self.onAddScript) w.addAction(action) action = QAction(unicodedata.lookup("MINUS SIGN"), self) action.setToolTip("Remove script from library") action.triggered.connect(self.onRemoveScript) w.addAction(action) action = QAction("Update", self) action.setToolTip("Save changes in the editor to library") action.setShortcut(QKeySequence(QKeySequence.Save)) action.triggered.connect(self.commitChangesToLibrary) w.addAction(action) action = QAction("More", self, toolTip="More actions") new_from_file = QAction("Import a script from a file", self) save_to_file = QAction("Save selected script to a file", self) save_to_file.setShortcut(QKeySequence(QKeySequence.SaveAs)) new_from_file.triggered.connect(self.onAddScriptFromFile) save_to_file.triggered.connect(self.saveScript) menu = QMenu(w) menu.addAction(new_from_file) menu.addAction(save_to_file) action.setMenu(menu) button = w.addAction(action) button.setPopupMode(QToolButton.InstantPopup) w.layout().setSpacing(1) self.controlBox.layout().addWidget(w) gui.auto_commit(self.controlArea, self, "auto_execute", "Execute") self.splitCanvas = QSplitter(Qt.Vertical, self.mainArea) self.mainArea.layout().addWidget(self.splitCanvas) self.defaultFont = defaultFont = "Monaco" if sys.platform == "darwin" else "Courier" self.textBox = gui.widgetBox(self, 'Python script') self.splitCanvas.addWidget(self.textBox) self.text = PythonScriptEditor(self) self.textBox.layout().addWidget(self.text) self.textBox.setAlignment(Qt.AlignVCenter) self.text.setTabStopWidth(4) self.text.modificationChanged[bool].connect(self.onModificationChanged) self.saveAction = action = QAction("&Save", self.text) action.setToolTip("Save script to file") action.setShortcut(QKeySequence(QKeySequence.Save)) action.setShortcutContext(Qt.WidgetWithChildrenShortcut) action.triggered.connect(self.saveScript) self.consoleBox = gui.widgetBox(self, 'Console') self.splitCanvas.addWidget(self.consoleBox) # self.console = PySparkConsole(self.__dict__, self, sc = self.sc) self.console = EmbedIPython(sc=self._sc, hc=self._hc, in_object=self.in_object, out_object=self.out_object) # self.console.kernel.shell.run_cell('%pylab qt') self.console.kernel.shell.run_cell( "print('{sparklogo}')".format(sparklogo=self.spark_logo)) self.consoleBox.layout().addWidget(self.console) self.consoleBox.setAlignment(Qt.AlignBottom) select_row(self.libraryView, self.currentScriptIndex) self.splitCanvas.setSizes([2, 1]) if self.splitterState is not None: self.splitCanvas.restoreState(QByteArray(self.splitterState)) self.splitCanvas.splitterMoved[int, int].connect(self.onSpliterMoved) self.controlArea.layout().addStretch(1) self.resize(800, 600) def setObject(self, obj): self.in_object = obj def handleNewSignals(self): self.unconditional_commit() def selectedScriptIndex(self): rows = self.libraryView.selectionModel().selectedRows() if rows: return [i.row() for i in rows][0] else: return None def setSelectedScript(self, index): select_row(self.libraryView, index) def onAddScript(self, *args): self.libraryList.append(Script("New script", "", 0)) self.setSelectedScript(len(self.libraryList) - 1) def onAddScriptFromFile(self, *args): filename = QFileDialog.getOpenFileName( self, 'Open Python Script', os.path.expanduser("~/"), 'Python files (*.py)\nAll files(*.*)') filename = str(filename) if filename: name = os.path.basename(filename) contents = open(filename, "rb").read().decode("utf-8", errors="ignore") self.libraryList.append(Script(name, contents, 0, filename)) self.setSelectedScript(len(self.libraryList) - 1) def onRemoveScript(self, *args): index = self.selectedScriptIndex() if index is not None: del self.libraryList[index] select_row(self.libraryView, max(index - 1, 0)) def onSaveScriptToFile(self, *args): index = self.selectedScriptIndex() if index is not None: self.saveScript() def onSelectedScriptChanged(self, selected, deselected): index = [i.row() for i in selected.indexes()] if index: current = index[0] if current >= len(self.libraryList): self.addNewScriptAction.trigger() return self.text.setDocument(self.documentForScript(current)) self.currentScriptIndex = current def documentForScript(self, script=0): if type(script) != Script: script = self.libraryList[script] if script not in self._cachedDocuments: doc = QtGui.QTextDocument(self) doc.setDocumentLayout(QtGui.QPlainTextDocumentLayout(doc)) doc.setPlainText(script.script) doc.setDefaultFont(QFont(self.defaultFont)) doc.highlighter = PythonSyntaxHighlighter(doc) doc.modificationChanged[bool].connect(self.onModificationChanged) doc.setModified(False) self._cachedDocuments[script] = doc return self._cachedDocuments[script] def commitChangesToLibrary(self, *args): index = self.selectedScriptIndex() if index is not None: self.libraryList[index].script = self.text.toPlainText() self.text.document().setModified(False) self.libraryList.emitDataChanged(index) def onModificationChanged(self, modified): index = self.selectedScriptIndex() if index is not None: self.libraryList[index].flags = Script.Modified if modified else 0 self.libraryList.emitDataChanged(index) def onSpliterMoved(self, pos, ind): self.splitterState = str(self.splitCanvas.saveState()) def updateSelecetdScriptState(self): index = self.selectedScriptIndex() if index is not None: script = self.libraryList[index] self.libraryList[index] = Script(script.name, self.text.toPlainText(), 0) def saveScript(self): index = self.selectedScriptIndex() if index is not None: script = self.libraryList[index] filename = script.filename else: filename = os.path.expanduser("~/") filename = QFileDialog.getSaveFileName( self, 'Save Python Script', filename, 'Python files (*.py)\nAll files(*.*)') if filename: fn = "" head, tail = os.path.splitext(filename) if not tail: fn = head + ".py" else: fn = filename f = open(fn, 'w') f.write(self.text.toPlainText()) f.close() def commit(self): self._script = str(self.text.toPlainText()) self.console.execute(self._script) self.send("out_object", self.out_object)
class OWPythonScript(OWWidget): settingsList = [ "codeFile", "libraryListSource", "currentScriptIndex", "splitterState", "auto_execute" ] def __init__(self, parent=None, signalManager=None): OWWidget.__init__(self, parent, signalManager, 'Python Script') self.inputs = [ ("in_data", Orange.data.Table, self.setExampleTable, Default), ("in_distance", Orange.misc.SymMatrix, self.setDistanceMatrix, Default), ("in_learner", Orange.core.Learner, self.setLearner, Default), ("in_classifier", Orange.core.Classifier, self.setClassifier, Default), ("in_object", object, self.setObject) ] self.outputs = [("out_data", Orange.data.Table), ("out_distance", Orange.misc.SymMatrix), ("out_learner", Orange.core.Learner), ("out_classifier", Orange.core.Classifier, Dynamic), ("out_object", object, Dynamic)] self.in_data = None self.in_distance = None self.in_learner = None self.in_classifier = None self.in_object = None self.auto_execute = False self.codeFile = '' self.libraryListSource = [ Script("Hello world", "print 'Hello world'\n") ] self.currentScriptIndex = 0 self.splitterState = None self.loadSettings() for s in self.libraryListSource: s.flags = 0 self._cachedDocuments = {} self.infoBox = OWGUI.widgetBox(self.controlArea, 'Info') OWGUI.label( self.infoBox, self, "<p>Execute python script.</p><p>Input variables:<ul><li> " + \ "<li>".join(t[0] for t in self.inputs) + \ "</ul></p><p>Output variables:<ul><li>" + \ "<li>".join(t[0] for t in self.outputs) + \ "</ul></p>" ) self.libraryList = PyListModel([], self, flags=Qt.ItemIsSelectable | \ Qt.ItemIsEnabled | Qt.ItemIsEditable) self.libraryList.wrap(self.libraryListSource) self.controlBox = OWGUI.widgetBox(self.controlArea, 'Library') self.controlBox.layout().setSpacing(1) self.libraryView = QListView() self.libraryView.setEditTriggers(QListView.DoubleClicked | \ QListView.EditKeyPressed) self.libraryView.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Preferred) self.libraryView.setItemDelegate(ScriptItemDelegate(self)) self.libraryView.setModel(self.libraryList) self.connect( self.libraryView.selectionModel(), SIGNAL("selectionChanged(QItemSelection, QItemSelection)"), self.onSelectedScriptChanged) self.controlBox.layout().addWidget(self.libraryView) w = ModelActionsWidget() self.addNewScriptAction = action = QAction("+", self) action.setToolTip("Add a new script to the library") self.connect(action, SIGNAL("triggered()"), self.onAddScript) w.addAction(action) self.removeAction = action = QAction("-", self) action.setToolTip("Remove script from library") self.connect(action, SIGNAL("triggered()"), self.onRemoveScript) w.addAction(action) action = QAction("Update", self) action.setToolTip("Save changes in the editor to library") action.setShortcut(QKeySequence(QKeySequence.Save)) self.connect(action, SIGNAL("triggered()"), self.commitChangesToLibrary) w.addAction(action) action = QAction("More", self) action.pyqtConfigure(toolTip="More actions") new_from_file = QAction("Import a script from a file", self) save_to_file = QAction("Save selected script to a file", self) save_to_file.setShortcut(QKeySequence(QKeySequence.SaveAs)) self.connect(new_from_file, SIGNAL("triggered()"), self.onAddScriptFromFile) self.connect(save_to_file, SIGNAL("triggered()"), self.saveScript) menu = QMenu(w) menu.addAction(new_from_file) menu.addAction(save_to_file) action.setMenu(menu) button = w.addAction(action) button.setPopupMode(QToolButton.InstantPopup) w.layout().setSpacing(1) self.controlBox.layout().addWidget(w) self.runBox = OWGUI.widgetBox(self.controlArea, 'Run') OWGUI.button(self.runBox, self, "Execute", callback=self.execute) OWGUI.checkBox(self.runBox, self, "auto_execute", "Auto execute", tooltip=("Run the script automatically whenever " "the inputs to the widget change.")) self.splitCanvas = QSplitter(Qt.Vertical, self.mainArea) self.mainArea.layout().addWidget(self.splitCanvas) self.defaultFont = defaultFont = \ "Monaco" if sys.platform == "darwin" else "Courier" self.textBox = OWGUI.widgetBox(self, 'Python script') self.splitCanvas.addWidget(self.textBox) self.text = PythonScriptEditor(self) self.textBox.layout().addWidget(self.text) self.textBox.setAlignment(Qt.AlignVCenter) self.text.setTabStopWidth(4) self.connect(self.text, SIGNAL("modificationChanged(bool)"), self.onModificationChanged) self.saveAction = action = QAction("&Save", self.text) action.setToolTip("Save script to file") action.setShortcut(QKeySequence(QKeySequence.Save)) action.setShortcutContext(Qt.WidgetWithChildrenShortcut) self.connect(action, SIGNAL("triggered()"), self.saveScript) self.consoleBox = OWGUI.widgetBox(self, 'Console') self.splitCanvas.addWidget(self.consoleBox) self.console = PythonConsole(self.__dict__, self) self.consoleBox.layout().addWidget(self.console) self.console.document().setDefaultFont(QFont(defaultFont)) self.consoleBox.setAlignment(Qt.AlignBottom) self.console.setTabStopWidth(4) self.openScript(self.codeFile) try: self.libraryView.selectionModel().select( self.libraryList.index(self.currentScriptIndex), QItemSelectionModel.ClearAndSelect) except Exception: pass self.splitCanvas.setSizes([2, 1]) if self.splitterState is not None: self.splitCanvas.restoreState(QByteArray(self.splitterState)) self.connect(self.splitCanvas, SIGNAL("splitterMoved(int, int)"), self.onSpliterMoved) self.controlArea.layout().addStretch(1) self.resize(800, 600) def setExampleTable(self, et): self.in_data = et def setDistanceMatrix(self, dm): self.in_distance = dm def setLearner(self, learner): self.in_learner = learner def setClassifier(self, classifier): self.in_classifier = classifier def setObject(self, obj): self.in_object = obj def handleNewSignals(self): if self.auto_execute: self.execute() def selectedScriptIndex(self): rows = self.libraryView.selectionModel().selectedRows() if rows: return [i.row() for i in rows][0] else: return None def setSelectedScript(self, index): selection = self.libraryView.selectionModel() selection.select(self.libraryList.index(index), QItemSelectionModel.ClearAndSelect) def onAddScript(self, *args): self.libraryList.append(Script("New script", "", 0)) self.setSelectedScript(len(self.libraryList) - 1) def onAddScriptFromFile(self, *args): filename = QFileDialog.getOpenFileName( self, 'Open Python Script', self.codeFile, 'Python files (*.py)\nAll files(*.*)') filename = unicode(filename) if filename: name = os.path.basename(filename) self.libraryList.append( Script(name, open(filename, "rb").read(), 0, filename)) self.setSelectedScript(len(self.libraryList) - 1) def onRemoveScript(self, *args): index = self.selectedScriptIndex() if index is not None: del self.libraryList[index] self.libraryView.selectionModel().select( self.libraryList.index(max(index - 1, 0)), QItemSelectionModel.ClearAndSelect) def onSaveScriptToFile(self, *args): index = self.selectedScriptIndex() if index is not None: self.saveScript() def onSelectedScriptChanged(self, selected, deselected): index = [i.row() for i in selected.indexes()] if index: current = index[0] if current >= len(self.libraryList): self.addNewScriptAction.trigger() return self.text.setDocument(self.documentForScript(current)) self.currentScriptIndex = current def documentForScript(self, script=0): if type(script) != Script: script = self.libraryList[script] if script not in self._cachedDocuments: doc = QTextDocument(self) doc.setDocumentLayout(QPlainTextDocumentLayout(doc)) doc.setPlainText(script.script) doc.setDefaultFont(QFont(self.defaultFont)) doc.highlighter = PythonSyntaxHighlighter(doc) self.connect(doc, SIGNAL("modificationChanged(bool)"), self.onModificationChanged) doc.setModified(False) self._cachedDocuments[script] = doc return self._cachedDocuments[script] def commitChangesToLibrary(self, *args): index = self.selectedScriptIndex() if index is not None: self.libraryList[index].script = self.text.toPlainText() self.text.document().setModified(False) self.libraryList.emitDataChanged(index) def onModificationChanged(self, modified): index = self.selectedScriptIndex() if index is not None: self.libraryList[index].flags = Script.Modified if modified else 0 self.libraryList.emitDataChanged(index) def onSpliterMoved(self, pos, ind): self.splitterState = str(self.splitCanvas.saveState()) def updateSelecetdScriptState(self): index = self.selectedScriptIndex() if index is not None: script = self.libraryList[index] self.libraryList[index] = Script(script.name, self.text.toPlainText(), 0) def openScript(self, filename=None): if filename == None: filename = QFileDialog.getOpenFileName( self, 'Open Python Script', self.codeFile, 'Python files (*.py)\nAll files(*.*)') filename = unicode(filename) self.codeFile = filename else: self.codeFile = filename if self.codeFile == "": return self.error(0) try: f = open(self.codeFile, 'r') except (IOError, OSError), ex: self.text.setPlainText("") return self.text.setPlainText(f.read()) f.close()
class OWPythonScript(OWWidget): settingsList = ["libraryListSource", "currentScriptIndex", "splitterState", "auto_execute"] def __init__(self, parent=None, signalManager=None): OWWidget.__init__(self, parent, signalManager, 'Python Script') self.inputs = [("in_data", Orange.data.Table, self.setExampleTable, Default), ("in_distance", Orange.misc.SymMatrix, self.setDistanceMatrix, Default), ("in_learner", Orange.core.Learner, self.setLearner, Default), ("in_classifier", Orange.core.Classifier, self.setClassifier, Default), ("in_object", object, self.setObject)] self.outputs = [("out_data", Orange.data.Table), ("out_distance", Orange.misc.SymMatrix), ("out_learner", Orange.core.Learner), ("out_classifier", Orange.core.Classifier, Dynamic), ("out_object", object, Dynamic)] self.in_data = None self.in_distance = None self.in_learner = None self.in_classifier = None self.in_object = None self.auto_execute = False self.libraryListSource = [Script("Hello world", "print 'Hello world'\n")] self.currentScriptIndex = 0 self.splitterState = None self.loadSettings() for s in self.libraryListSource: s.flags = 0 self._cachedDocuments = {} self.infoBox = OWGUI.widgetBox(self.controlArea, 'Info') OWGUI.label( self.infoBox, self, "<p>Execute python script.</p><p>Input variables:<ul><li> " + "<li>".join(t[0] for t in self.inputs) + "</ul></p><p>Output variables:<ul><li>" + "<li>".join(t[0] for t in self.outputs) + "</ul></p>" ) self.libraryList = PyListModel( [], self, flags=Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable ) self.libraryList.wrap(self.libraryListSource) self.controlBox = OWGUI.widgetBox(self.controlArea, 'Library') self.controlBox.layout().setSpacing(1) self.libraryView = QListView( editTriggers=QListView.DoubleClicked | QListView.EditKeyPressed, sizePolicy=QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Preferred) ) self.libraryView.setItemDelegate(ScriptItemDelegate(self)) self.libraryView.setModel(self.libraryList) self.libraryView.selectionModel().selectionChanged.connect( self.onSelectedScriptChanged ) self.controlBox.layout().addWidget(self.libraryView) w = ModelActionsWidget() self.addNewScriptAction = action = QAction("+", self) action.setToolTip("Add a new script to the library") action.triggered.connect(self.onAddScript) w.addAction(action) action = QAction(unicodedata.lookup("MINUS SIGN"), self) action.setToolTip("Remove script from library") action.triggered.connect(self.onRemoveScript) w.addAction(action) action = QAction("Update", self) action.setToolTip("Save changes in the editor to library") action.setShortcut(QKeySequence(QKeySequence.Save)) action.triggered.connect(self.commitChangesToLibrary) w.addAction(action) action = QAction("More", self, toolTip="More actions") new_from_file = QAction("Import a script from a file", self) save_to_file = QAction("Save selected script to a file", self) save_to_file.setShortcut(QKeySequence(QKeySequence.SaveAs)) new_from_file.triggered.connect(self.onAddScriptFromFile) save_to_file.triggered.connect(self.saveScript) menu = QMenu(w) menu.addAction(new_from_file) menu.addAction(save_to_file) action.setMenu(menu) button = w.addAction(action) button.setPopupMode(QToolButton.InstantPopup) w.layout().setSpacing(1) self.controlBox.layout().addWidget(w) self.runBox = OWGUI.widgetBox(self.controlArea, 'Run') OWGUI.button(self.runBox, self, "Execute", callback=self.execute) OWGUI.checkBox(self.runBox, self, "auto_execute", "Auto execute", tooltip=("Run the script automatically whenever " "the inputs to the widget change.")) self.splitter = QSplitter(Qt.Vertical, self.mainArea) self.mainArea.layout().addWidget(self.splitter) self.defaultFont = defaultFont = \ "Monaco" if sys.platform == "darwin" else "Courier" self.textBox = OWGUI.widgetBox(self, 'Python script') self.splitter.addWidget(self.textBox) self.text = PythonScriptEditor(self) self.textBox.layout().addWidget(self.text) self.textBox.setAlignment(Qt.AlignVCenter) self.text.setTabStopWidth(4) self.text.modificationChanged[bool].connect(self.onModificationChanged) self.consoleBox = OWGUI.widgetBox(self, 'Console') self.splitter.addWidget(self.consoleBox) self.console = PythonConsole(self.__dict__, self) self.consoleBox.layout().addWidget(self.console) self.console.document().setDefaultFont(QFont(defaultFont)) self.consoleBox.setAlignment(Qt.AlignBottom) self.console.setTabStopWidth(4) select_row(self.libraryView, self.currentScriptIndex) self.splitter.setSizes([2, 1]) if self.splitterState is not None: self.splitter.restoreState(QByteArray(self.splitterState)) self.splitter.splitterMoved[int, int].connect(self.onSpliterMoved) self.controlArea.layout().addStretch(1) self.resize(800, 600) def setExampleTable(self, et): self.in_data = et def setDistanceMatrix(self, dm): self.in_distance = dm def setLearner(self, learner): self.in_learner = learner def setClassifier(self, classifier): self.in_classifier = classifier def setObject(self, obj): self.in_object = obj def handleNewSignals(self): if self.auto_execute: self.execute() def selectedScriptIndex(self): rows = self.libraryView.selectionModel().selectedRows() if rows: return [i.row() for i in rows][0] else: return None def setSelectedScript(self, index): select_row(self.libraryView, index) def onAddScript(self, *args): self.libraryList.append(Script("New script", "", 0)) self.setSelectedScript(len(self.libraryList) - 1) def onAddScriptFromFile(self, *args): filename = QFileDialog.getOpenFileName( self, 'Open Python Script', os.path.expanduser("~/"), 'Python files (*.py)\nAll files(*.*)' ) filename = unicode(filename) if filename: name = os.path.basename(filename) self.libraryList.append(Script(name, open(filename, "rb").read(), 0, filename)) self.setSelectedScript(len(self.libraryList) - 1) def onRemoveScript(self, *args): index = self.selectedScriptIndex() if index is not None: del self.libraryList[index] select_row(self.libraryView, max(index - 1, 0)) def onSelectedScriptChanged(self, selected, deselected): index = [i.row() for i in selected.indexes()] if index: current = index[0] self.text.setDocument(self.documentForScript(current)) self.currentScriptIndex = current def documentForScript(self, script=0): if type(script) != Script: script = self.libraryList[script] if script not in self._cachedDocuments: doc = QTextDocument(self) doc.setDocumentLayout(QPlainTextDocumentLayout(doc)) doc.setPlainText(script.script) doc.setDefaultFont(QFont(self.defaultFont)) doc.highlighter = PythonSyntaxHighlighter(doc) doc.modificationChanged[bool].connect(self.onModificationChanged) doc.setModified(False) self._cachedDocuments[script] = doc return self._cachedDocuments[script] def commitChangesToLibrary(self, *args): index = self.selectedScriptIndex() if index is not None: self.libraryList[index].script = unicode(self.text.toPlainText()) self.text.document().setModified(False) self.libraryList.emitDataChanged(index) def onModificationChanged(self, modified): index = self.selectedScriptIndex() if index is not None: self.libraryList[index].flags = Script.Modified if modified else 0 self.libraryList.emitDataChanged(index) def onSpliterMoved(self, pos, ind): self.splitterState = str(self.splitter.saveState()) def saveScript(self): index = self.selectedScriptIndex() filename = os.path.expanduser("~/") if index is not None: script = self.libraryList[index] filename = script.sourceFileName or filename filename = QFileDialog.getSaveFileName( self, 'Save Python Script', filename, 'Python files (*.py)\nAll files(*.*)' ) self.codeFile = unicode(filename) if self.codeFile: fn = "" head, tail = os.path.splitext(self.codeFile) if not tail: fn = head + ".py" else: fn = self.codeFile f = open(fn, 'w') f.write(self.text.toPlainText()) f.close() def execute(self): self._script = str(self.text.toPlainText()) self.console.write("\nRunning script:\n") self.console.push("exec(_script)") self.console.new_prompt(sys.ps1) for out in self.outputs: signal = out[0] self.send(signal, getattr(self, signal, None))
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 Script...") 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", "Options...") 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...") self.lineEditFind.setPlaceholderText(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 WWorkspace(QWidget): """ Workspace widget """ WORKSPACE = 0 UpdateWindowTitle = pyqtSignal(str) RecentFile = pyqtSignal(dict) BusyCursor = pyqtSignal() ArrowCursor = pyqtSignal() def __init__(self, parent=None): """ Constructs WWorkspace widget Signals emited: * updateWindowTitle @param parent: @type parent: """ QWidget.__init__(self, parent) self.parent = parent self.type = self.WORKSPACE self.name = self.tr('Workspace') # create each part WRepositories.initialize(parent=self) WDocumentViewer.initialize(parent=self, iRepo=WRepositories.instance(), lRepo=WRepositories.LocalRepository, rRepo=WRepositories.RemoteRepository) WDocumentProperties.initialize(parent=self, iRepo=WRepositories.instance(), lRepo=WRepositories.LocalRepository, rRepo=WRepositories.RemoteRepository) WHelper.initialize(parent=self) # splitter state self.splitterState = None self.splitterHelperState = None # create widget self.createWidgets() self.createActions() self.creationConnections() def createWidgets(self): """ QtWidgets creation _________ _______________________ _________ / \__________ | | / \__ | | Q | | Q | | | WRepositories | S | | S | | | | p | | p | | |_____________________| l | | l | | _____QSplitter i | WDocumentViewer | i | WHelper | / \__________ t | | t | | | | t | | t | | | WDocumentProperties | e | | e | | | | r | | r | | |_____________________| |_______________________| |_____________| """ self.wCursorPosition = WCursorPosition(self) self.parent.addWidgetToStatusBar(self.wCursorPosition) WDocumentProperties.instance().setDisabled(True) layout = QHBoxLayout(self) # properties | viewer | helper self.vSplitter = QSplitter(self) if not QtHelper.str2bool( Settings.instance().readValue(key='View/tab-left')): self.hSplitter = QSplitter(self) self.hSplitter.setOrientation(Qt.Vertical) self.hSplitter.addWidget(WRepositories.instance()) self.hSplitter.addWidget(WDocumentProperties.instance()) self.hSplitter.setContentsMargins(0, 0, 0, 0) self.vSplitter.addWidget(self.hSplitter) else: WRepositories.instance().hideWidgetsHeader() WDocumentProperties.instance().hideWidgetsHeader() self.leftTab = QTabWidget(self) self.leftTab.addTab(WRepositories.instance(), QIcon(":/folders.png"), self.tr("Repositories")) self.leftTab.addTab(WDocumentProperties.instance(), QIcon(":/controls.png"), self.tr("Test Properties")) self.vSplitter.addWidget(self.leftTab) self.vSplitter.addWidget(WDocumentViewer.instance()) self.vSplitter.setStretchFactor(1, 1) layout.addWidget(self.vSplitter) self.hSplitter2 = QSplitter(self) self.hSplitter2.setOrientation(Qt.Vertical) self.vSplitter.addWidget(self.hSplitter2) self.hSplitter2.addWidget(WHelper.instance()) self.setLayout(layout) def creationConnections(self): """ QtSignals connection: * WRepositories <=> WDocumentViewer.newTab * WDocumentViewer <=> cursorPositionChanged * WDocumentViewer <=> focusChanged """ WRepositories.instance().local().OpenFile.connect( WDocumentViewer.instance().newTab) WDocumentViewer.instance().CursorPositionChanged.connect( self.cursorPositionChanged) WDocumentViewer.instance().TotalLinesChanged.connect( self.totalLinesChanged) WDocumentViewer.instance().FocusChanged.connect(self.focusChanged) WDocumentViewer.instance().BusyCursor.connect(self.emitBusy) WDocumentViewer.instance().ArrowCursor.connect(self.emitIdle) WDocumentViewer.instance().CurrentDocumentChanged.connect( self.currentDocumentChanged) WDocumentViewer.instance().DocumentOpened.connect(self.documentOpened) WDocumentViewer.instance().UpdateWindowTitle.connect( self.updateWindowTitle) WDocumentViewer.instance().DocumentViewerEmpty.connect( self.documentViewerEmpty) # from testplan when the test selection changed in the tree WDocumentViewer.instance().PropertiesChanged.connect( self.propertiesChanged) if WRepositories.instance().localConfigured != "Undefined": if RCI.instance().isAuthenticated(): WDocumentViewer.instance().RefreshLocalRepository.connect( WRepositories.instance().localRepository.refreshAll) WDocumentProperties.instance().RefreshLocalRepository.connect( WRepositories.instance().localRepository.refreshAll) WDocumentViewer.instance().RecentFile.connect(self.recentFileUpdated) WHelper.instance().ShowAssistant.connect(self.onEnterAssistant) WHelper.instance().HideAssistant.connect(self.onLeaveAssistant) # new in v16 WDocumentViewer.instance().ShowPropertiesTab.connect( self.onShowPropertiesTab) def onShowPropertiesTab(self): """ On show properties tabulation """ if QtHelper.str2bool( Settings.instance().readValue(key='View/tab-left')): self.leftTab.setCurrentIndex(TAB_PROPERTIES) def onEnterAssistant(self): """ On mouse enter in the online helper """ pass def onLeaveAssistant(self): """ On mouse leave in the online helper """ pass def createActions(self): """ Create qt actions """ self.hideDeveloperModeAction = QtHelper.createAction( self, self.tr("Developer"), self.hideDeveloperMode, checkable=True, icon=QIcon(":/window-fit.png"), shortcut=Settings.instance().readValue( key='KeyboardShorcuts/developer'), tip=self.tr('Fit the document viewer to maximize the editor area')) WDocumentViewer.instance().addActionToolbar( action=self.hideDeveloperModeAction) def emitBusy(self): """ Emit busy """ self.BusyCursor.emit() def emitIdle(self): """ Emit idle """ self.ArrowCursor.emit() def hideDeveloperMode(self): """ Hide developer mode """ if not self.hideDeveloperModeAction.isChecked(): Settings.instance().setValue(key='View/developer', value='False') self.deactiveDeveloperView() else: Settings.instance().setValue(key='View/developer', value='True') self.activeDeveloperView() def activeDeveloperView(self): """ Activate developer view """ self.splitterState = self.vSplitter.saveState() self.vSplitter.setSizes([0, self.vSplitter.sizes()[1], 0]) def deactiveDeveloperView(self): """ Deactive developer view """ if self.splitterState is not None: self.vSplitter.restoreState(self.splitterState) def mainSplitterMoved(self, index, pos): """ Memorize the new position of the splitter """ Settings.instance().setValue(key='View/helper-pos', value=self.vSplitter.sizes()[2]) def hideHelper(self): """ Hide assistant """ self.splitterHelperState = self.vSplitter.saveState() self.vSplitter.setSizes( [self.vSplitter.sizes()[0], self.vSplitter.sizes()[1], 0]) def showHelper(self): """ Show assistant """ if self.splitterHelperState is not None: self.vSplitter.restoreState(self.splitterHelperState) def documentViewerEmpty(self): """ Called to deactivate the WDocumentProperties widget Hide the WCursorPosition widget in the status bar """ WDocumentProperties.instance().clear() WDocumentProperties.instance().setDisabled(True) self.hideStatusBar() WDocumentViewer.instance().findWidget.hide() def currentDocumentChanged(self, wdocument): """ Called when the current document is changed @param wdocument: @type wdocument: """ # hide cursor position widget on disconnection or on the welcome page if isinstance(wdocument, WDocumentViewer.WelcomePage): self.hideStatusBar() if not RCI.instance().isAuthenticated(): WDocumentProperties.instance().setDisabled(True) return # test properties uneeded for test config, test adapter and library adapters # and welcome page if isinstance(wdocument, WDocumentViewer.WelcomePage): WDocumentProperties.instance().setDisabled(True) WDocumentProperties.instance().clear() elif isinstance(wdocument, TestConfig.WTestConfig) or isinstance(wdocument, TestAdapter.WTestAdapter) \ or isinstance(wdocument, TestTxt.WTestTxt) or isinstance(wdocument, TestLibrary.WTestLibrary) \ or isinstance(wdocument, TestPng.WTestPng) : WDocumentProperties.instance().setDisabled(True) WDocumentProperties.instance().clear() else: WDocumentProperties.instance().setDocument(wdoc=wdocument) WDocumentProperties.instance().setDisabled(False) WDocumentProperties.instance().addDescriptions(wdoc=wdocument) WDocumentProperties.instance().addParameters(wdoc=wdocument) if not isinstance(wdocument, TestData.WTestData): WDocumentProperties.instance().addParametersOutput( wdoc=wdocument) WDocumentProperties.instance().addProbes(wdoc=wdocument) WDocumentProperties.instance().addAgents(wdoc=wdocument) WDocumentViewer.instance().updateActions(wdocument=wdocument) if isinstance(wdocument, TestData.WTestData): WDocumentProperties.instance().disableOutputParameters() WDocumentProperties.instance().disableAgents() WDocumentProperties.instance().disableProbes() else: WDocumentProperties.instance().enableOutputParameters() WDocumentProperties.instance().enableProbes() WDocumentProperties.instance().enableAgents() if not isinstance(wdocument, TestAbstract.WTestAbstract): WDocumentProperties.instance().disableSteps() WDocumentProperties.instance().disableAdapters() WDocumentProperties.instance().disableLibraries() else: WDocumentProperties.instance().addSteps(wdoc=wdocument) WDocumentProperties.instance().enableSteps() WDocumentProperties.instance().addAdapters(wdoc=wdocument) WDocumentProperties.instance().enableAdapters() WDocumentProperties.instance().addLibraries(wdoc=wdocument) WDocumentProperties.instance().enableLibraries() if isinstance(wdocument, TestUnit.WTestUnit) or isinstance( wdocument, TestSuite.WTestSuite): WDocumentProperties.instance().enableMarkUnused() else: WDocumentProperties.instance().disableMarkUnused() # disable/enable status bar if isinstance(wdocument, TestConfig.WTestConfig) \ or isinstance(wdocument, TestPlan.WTestPlan) \ or isinstance(wdocument, TestPng.WTestPng) \ or isinstance(wdocument, TestAbstract.WTestAbstract) \ or isinstance(wdocument, WDocumentViewer.WelcomePage) : self.hideStatusBar() else: self.showStatusBar() self.wCursorPosition.setNumberLines(nb=wdocument.editor().lines()) def propertiesChanged(self, properties, isRoot, testId): """ Called when document propertis changed @param properties: @param properties: dict @param isRoot: @type isRoot: """ if isRoot: WDocumentProperties.instance().addDescriptions(wdoc=properties) WDocumentProperties.instance().addParameters(wdoc=properties) WDocumentProperties.instance().addParametersOutput(wdoc=properties) WDocumentProperties.instance().addAgents(wdoc=properties) WDocumentProperties.instance().addProbes(wdoc=properties) WDocumentProperties.instance().probes.setEnabled(True) else: WDocumentProperties.instance().addParameters(wdoc=properties) WDocumentProperties.instance().addAgents(wdoc=properties) WDocumentProperties.instance().addParametersOutput(wdoc=properties) WDocumentProperties.instance().probes.clear() WDocumentProperties.instance().probes.setEnabled(False) # new in v19 WDocumentProperties.instance().updateCache(properties, isRoot, testId) def documentOpened(self, wdocument): """ Called when a document is opened @param wdocument: @type wdocument: """ WDocumentProperties.instance().setEnabled(True) self.currentDocumentChanged(wdocument=wdocument) def updateWindowTitle(self, windowTitle): """ Emit the signal "updateWindowTitle" to update the title of the application @param windowTitle: new window title @type windowTitle: string """ self.UpdateWindowTitle.emit(windowTitle) def recentFileUpdated(self, fileDescription): """ Emit the signal "recentFile" to update the title of the application @param windowTitle: file descr with the complete path and type @type windowTitle: string """ self.RecentFile.emit(fileDescription) def focusChanged(self, wdocument): """ Called when the focus of the WDocumentViewer is changed @param wdocument: @type wdocument: """ WDocumentViewer.instance().updateActions(wdocument=wdocument) self.wCursorPosition.setNumberLines(nb=wdocument.editor().lines()) def totalLinesChanged(self, nb): """ This function is automaticaly called when the cursor changed in both editors and enables to update the cursor's position in the widget WCursorPosition @param ln: line index @type ln: Integer @param col: column index @type col: Integer """ self.wCursorPosition.setNumberLines(nb=nb) def cursorPositionChanged(self, ln, col): """ This function is automaticaly called when the cursor changed in both editors and enables to update the cursor's position in the widget WCursorPosition @param ln: line index @type ln: Integer @param col: column index @type col: Integer """ self.wCursorPosition.cursorPositionChanged(ln, col) def showStatusBar(self): """ Show WCursorPosition widget """ self.wCursorPosition.show() def hideStatusBar(self): """ Hide WCursorPosition widget """ self.wCursorPosition.hide()
class MainWindow(QMainWindow): """ Initialization """ def __init__(self, rulesModel, logoFnam, *args): QMainWindow.__init__(self, *args) self.rulesModel = rulesModel self.rulesModel.dataChanged.connect(self._statusRefresh) self.cancelled = True # for to handle win close box the same as Cancel button self.mainHSplit = QSplitter(self) # data | buttons self.mainHSplit.setChildrenCollapsible(False) self.setCentralWidget(self.mainHSplit) self.mainVSplit = QSplitter(Qt.Vertical) self.mainVSplit.setChildrenCollapsible(False) self.mainHSplit.addWidget(self.mainVSplit) self._drawRules() self.mainVSplit.addWidget(self.rulesView) self.condActSplit = QSplitter() self.condActSplit.setChildrenCollapsible(False) self._drawCondAct() self.mainVSplit.addWidget(self.condActSplit) # let rules view resize vertically two times faster than cond/action view self.rulesView.setSizeIncrement(self.rulesView.sizeIncrement().width(), 2 * self.condView.sizeIncrement().height()) self._drawButtons(logoFnam) self.setStatusBar(QStatusBar()) self.condView.horizontalHeader().setCascadingSectionResizes(True) self.rulesView.selectRow(0) def _drawRules(self): self.rulesView = QTableView() self.rulesView.setModel(self.rulesModel) self.rulesView.setEditTriggers(QAbstractItemView.AllEditTriggers) self.rulesView.setSelectionBehavior(QAbstractItemView.SelectRows) self.rulesView.setSelectionMode(QAbstractItemView.SingleSelection) self.rulesView.horizontalHeader().setStretchLastSection(True) self.rulesView.resizeColumnsToContents() #self.rulesView.verticalHeader().setMovable(True) # row remapping - see QHeaderView.logicalIndex() #self.rulesView.verticalHeader().setCascadingSectionResizes(True) # takes space from next row self.rulesView.selectionModel().currentRowChanged.connect(self._ruleRowChanged) self.rulesView.verticalHeader().sectionResized[int,int,int].connect(self._ruleRowHeightChanged) def _drawCondAct(self): if getattr(self, 'condGB', None): m_settings.setValue('spl_condAct', self.condActSplit.saveState()) self.condGB.deleteLater() # or .destroy() del self.condGB self.actionGB.deleteLater() del self.actionGB row = self._ruleCurrRow() rcount = self.rulesModel.rowCount() self.condGB = QGroupBox(self.tr('Conditions')) self.condView = QTableView() conds = self.rulesModel.ruleConditions(row) if row in range(rcount) \ else [] self.condModel = ConditionsModel(conds, self.rulesModel) self.condModel.dataChanged.connect(self._codeFragChanged) self.condView.setModel(self.condModel) self.condTypeDelegate = ComboBoxDelegate(Condition._types._typeCaptions) self.condView.setItemDelegateForColumn(0, self.condTypeDelegate) self.condView.setEditTriggers(QAbstractItemView.AllEditTriggers) self.condView.setSelectionBehavior(QAbstractItemView.SelectRows) self.condView.setSelectionMode(QAbstractItemView.SingleSelection) self.condView.horizontalHeader().setStretchLastSection(True) self.condView.resizeColumnsToContents() self.condView.selectionModel().currentRowChanged.connect(self._statusRefresh) vbox = QVBoxLayout() vbox.addWidget(self.condView) self.condGB.setLayout(vbox) self.condActSplit.addWidget(self.condGB) self.actionGB = QGroupBox(self.tr('Actions')) self.actionView = QTableView() # parent = self.actionGB) actions = self.rulesModel.ruleActions(row) if row in range(rcount) \ else [] self.actionModel = ActionsModel(actions, self.rulesModel) self.actionModel.dataChanged.connect(self._codeFragChanged) self.actionView.setModel(self.actionModel) self.actionTypeDelegate = ComboBoxDelegate(Action._types._typeCaptions) self.actionView.setItemDelegateForColumn(0, self.actionTypeDelegate) self.actionView.setEditTriggers(QAbstractItemView.AllEditTriggers) self.actionView.setSelectionBehavior(QAbstractItemView.SelectRows) self.actionView.setSelectionMode(QAbstractItemView.SingleSelection) self.actionView.horizontalHeader().setStretchLastSection(True) self.actionView.resizeColumnsToContents() self.actionView.selectionModel().currentRowChanged.connect(self._statusRefresh) vbox = QVBoxLayout() vbox.addWidget(self.actionView) self.actionGB.setLayout(vbox) self.condActSplit.addWidget(self.actionGB) self.condActSplit.restoreState(m_settings.value('spl_condAct').toByteArray()) def _drawButton(self, vbox, caption, slot, ena = False): but = QPushButton(self.tr(caption)) but.setEnabled(ena) but.clicked.connect(getattr(self, slot)) vbox.addWidget(but) # add to VBoxLayout return but def _drawButtons(self, logoFnam): gbox = QGroupBox() spol = QSizePolicy() spol.horizontalPolicy = QSizePolicy.Maximum gbox.setSizePolicy(spol) vbox = QVBoxLayout() if os.path.isfile(logoFnam): img = QPixmap(logoFnam) #.scaled(64, 64) lblLogo = QLabel() lblLogo.setPixmap(img) lblLogo.setAlignment(Qt.AlignTop | Qt.AlignRight) vbox.addWidget(lblLogo) #vbox.addSpacing(3) self.butSave = self._drawButton(vbox, "M&odify", 'closeSave') font = QFont() font.setBold(True) self.butSave.setFont(font) self.butCancel = self._drawButton(vbox, "Cancel", 'closeCancel', True) vbox.addSpacing(36) self.butAddRule = self._drawButton(vbox, "Add Rule", 'addRule', True) self.butCopyRule = self._drawButton(vbox, "Copy Rule", 'copyRule') self.butDelRule = self._drawButton(vbox, "Delete Rule", 'delRule') self.butMoveRuleUp = self._drawButton(vbox, "Move Rule Up", 'moveRuleUp') self.butMoveRuleDn = self._drawButton(vbox, "Move Rule Down", 'moveRuleDown') vbox.addSpacing(24) self.butAddCond = self._drawButton(vbox, "Add Condition", 'addCond') self.butDelCond = self._drawButton(vbox, "Delete Condition", 'delCond') vbox.addSpacing(15) self.butAddAction = self._drawButton(vbox, "Add Action", 'addAction') self.butDelAction = self._drawButton(vbox, "Delete Action", 'delAction') gbox.setLayout(vbox) self.mainHSplit.addWidget(gbox) """ Internal Bindings Signal Receivers """ # main win close events # .. (cancel closing with event.ignore(); QMainWindow calls event.accept()) @pyqtSlot(QCloseEvent) def closeEvent(self, event): self._saveAppState() # save rules if not empty and user clicked Modified/Save button if self.rulesModel.rowCount() > 0 and not self.cancelled: text = self.rulesModel.getRawRules().validate() if text: self.cancelled = True QMessageBox.information(self, APP_TITLE, self.tr("Validation failed because of:<p><p>") + text) event.ignore() return # RETURN - cancel app closing ###### self.rulesModel.saveScript() # accept window closing QMainWindow.closeEvent(self, event) # quit application m_app.quit() @pyqtSlot() def _statusRefresh(self): # dis/enable buttons, display view selections ruleRow = self._ruleCurrRow() condRow = self._condCurrRow() actionRow = self._actionCurrRow() self.butSave.setEnabled(self.rulesModel.isModified()) ruleCnt = self.rulesModel.rowCount() self.butCopyRule.setEnabled(ruleRow >= 0) self.butDelRule.setEnabled(ruleRow >= 0) self.butMoveRuleUp.setEnabled(ruleRow > 0) self.butMoveRuleDn.setEnabled(ruleRow >= 0 and ruleRow + 1 < ruleCnt) self.butAddCond.setEnabled(ruleRow >= 0) self.butDelCond.setEnabled(condRow >= 0) self.butAddAction.setEnabled(ruleRow >= 0) self.butDelAction.setEnabled(actionRow >= 0) # display currently selected list rows in the status bar - if empty if ruleRow >= 0 and False: # replace False with ~self.statusBar().isEmpty()?!?!? text = str(self.tr("Selected Rule: {ruleI}"))\ .format(ruleI = ruleRow + 1) if condRow >= 0: text += " " \ + str(self.tr("Selected Condition: {typeI}"))\ .format(typeI = condRow + 1) if actionRow >= 0: text += " " \ + str(self.tr("Selected Action: {typeI}"))\ .format(typeI = actionRow + 1) self.statusBar().showMessage(text, 3000) @pyqtSlot(int,int,int) def _ruleRowHeightChanged(self, section, oldsize, newsize): hdr = self.rulesView.verticalHeader() for row in range(hdr.count()): if row != section: hdr.resizeSection(row, newsize) @pyqtSlot() def _ruleRowChanged(self): self._drawCondAct() self._statusRefresh() @pyqtSlot() def _codeFragChanged(self): # refresh the rules list columns Conditions and Actions row = self._ruleCurrRow() leftColIndex = self.rulesModel.index(row, 2, QModelIndex()) rightColIndex = self.rulesModel.index(row, 3, QModelIndex()) self.rulesView.dataChanged(leftColIndex, rightColIndex) self._statusRefresh() """ User Action Signal Receivers """ @pyqtSlot() def closeSave(self): self.cancelled = False self.close() @pyqtSlot() def closeCancel(self): self.cancelled = True self.close() @pyqtSlot() def addRule(self): row = self._ruleCurrRow() self.rulesModel.insertRow(row) self.rulesView.selectRow(row) self._statusRefresh() @pyqtSlot() def copyRule(self): row = self._ruleCurrRow() self.rulesModel.setSourceRowForNextAdd(row) self.rulesModel.insertRow(row) self.rulesView.selectRow(row) self._statusRefresh() @pyqtSlot() def delRule(self): self.rulesModel.removeRow(self._ruleCurrRow()) self._statusRefresh() @pyqtSlot() def moveRuleUp(self): row = self._ruleCurrRow() self.rulesModel.moveRule(row, -1) self._statusRefresh() @pyqtSlot() def moveRuleDown(self): row = self._ruleCurrRow() self.rulesModel.moveRule(row) self._statusRefresh() @pyqtSlot() def addCond(self): cnt = self.condModel.rowCount() self.condModel.insertRow(cnt) self.condView.selectRow(cnt) self._statusRefresh() @pyqtSlot() def delCond(self): self.condModel.removeRow(self._condCurrRow()) self._statusRefresh() @pyqtSlot() def addAction(self): cnt = self.actionModel.rowCount() self.actionModel.insertRow(cnt) self.actionView.selectRow(cnt) self._statusRefresh() @pyqtSlot() def delAction(self): self.actionModel.removeRow(self._actionCurrRow()) self._statusRefresh() """ Helping Methods """ def _ruleCurrRow(self): #idxs = self.rulesView.selectedIndexes() #return idxs[0].row() if idxs else -1 return self.rulesView.currentIndex().row() def _condCurrRow(self): return self.condView.currentIndex().row() def _actionCurrRow(self): return self.actionView.currentIndex().row() # main win save/restore def _saveAppState(self): m_app.processEvents() # save win geometry and splitter positions _UI_SAVE(self, 'win_geometry') _UI_SAVE(self.mainHSplit, 'spl_mainH') _UI_SAVE(self.mainVSplit, 'spl_mainV') _UI_SAVE(self.condActSplit, 'spl_condAct') #_UI_SAVE(self.condView.horizontalHeader(), 'tvh_condHdr') def _restoreAppState(self): try: # will fail on first app startup after installation # restore last win position, -size and 3 splitter positions _UI_RESTORE(self, 'win_geometry') _UI_RESTORE(self.mainHSplit, 'spl_mainH') _UI_RESTORE(self.mainVSplit, 'spl_mainV') _UI_RESTORE(self.condActSplit, 'spl_condAct') #_UI_RESTORE(self.condView.horizontalHeader(), 'tvh_condHdr') except: # first start screenWidth = QApplication.desktop().width() screenHeight = QApplication.desktop().height() self.setGeometry(screenWidth / 9, screenHeight / 12, screenWidth / 1.26, screenHeight / 1.56)