def __init__(self, parent=None): super(FeatureFormWidget, self).__init__(parent) self.setupUi(self) utils.install_touch_scroll(self.scrollArea) toolbar = QToolBar() size = QSize(48, 48) toolbar.setIconSize(size) style = Qt.ToolButtonTextUnderIcon toolbar.setToolButtonStyle(style) self.actionDelete = toolbar.addAction(QIcon(":/icons/delete"), "Delete") self.actionDelete.triggered.connect(self.delete_feature) label = '<b style="color:red">*</b> Required fields' self.missingfieldsLabel = QLabel(label) self.missingfieldsLabel.hide() self.missingfieldaction = toolbar.addWidget(self.missingfieldsLabel) titlespacer = QWidget() titlespacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) toolbar.addWidget(titlespacer) self.titlellabel = QLabel(label) self.titlellabel.setProperty("headerlabel", True) self.titlelabelaction = toolbar.addWidget(self.titlellabel) spacer = QWidget() spacer2 = QWidget() spacer2.setMinimumWidth(40) spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) spacer2.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) toolbar.addWidget(spacer) self.actionCancel = toolbar.addAction(QIcon(":/icons/cancel"), "Cancel") toolbar.addWidget(spacer2) self.actionSave = toolbar.addAction(QIcon(":/icons/save"), "Save") self.actionSave.triggered.connect(self.save_feature) self.layout().setContentsMargins(0, 3, 0, 3) self.layout().insertWidget(0, toolbar) self.actiontoolbar = QToolBar() self.actiontoolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.actiontoolbar.addWidget(spacer) self.layout().insertWidget(1, self.actiontoolbar) self.featureform = None self.values = {} self.config = {} self.feature = None
class PythonConsoleWidget(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) self.setWindowTitle(QCoreApplication.translate("PythonConsole", "Python Console")) self.settings = QgsSettings() 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() icon_size = iface.iconSize(dockedToolbar=True) if iface else QSize(16, 16) 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.svg")) 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.svg")) 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.svg")) 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.svg")) 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("mActionEditCut.svg")) 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("mActionEditCopy.svg")) 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("mActionEditPaste.svg")) 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.svg")) 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.svg")) 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.svg")) 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.svg")) 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.svg")) 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.svg")) 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.svg")) 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.svg")) self.optionsButton.setMenuRole(QAction.PreferencesRole) self.optionsButton.setIconVisibleInMenu(True) self.optionsButton.setToolTip(optionsBt) self.optionsButton.setText(optionsBt) # 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/mIconRunConsole.svg")) 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.svg")) 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(icon_size) self.toolBar.setMovable(False) self.toolBar.setFloatable(False) self.toolBar.addAction(self.clearButton) 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(icon_size) 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) 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.toolBarFindText = QToolBar() self.toolBarFindText.setIconSize(icon_size) self.findNextButton = QAction(self) self.findNextButton.setEnabled(False) toolTipfindNext = QCoreApplication.translate("PythonConsole", "Find Next") self.findNextButton.setToolTip(toolTipfindNext) self.findNextButton.setIcon(QgsApplication.getThemeIcon("console/iconSearchNextEditorConsole.svg")) self.findPrevButton = QAction(self) self.findPrevButton.setEnabled(False) toolTipfindPrev = QCoreApplication.translate("PythonConsole", "Find Previous") self.findPrevButton.setToolTip(toolTipfindPrev) self.findPrevButton.setIcon(QgsApplication.getThemeIcon("console/iconSearchPrevEditorConsole.svg")) 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.toolBarFindText.addWidget(self.lineEditFind) self.toolBarFindText.addAction(self.findPrevButton) self.toolBarFindText.addAction(self.findNextButton) self.toolBarFindText.addWidget(self.caseSensitive) self.toolBarFindText.addWidget(self.wholeWord) self.toolBarFindText.addWidget(self.wrapAround) self.layoutFind.addWidget(self.toolBarFindText, 0, 1, 1, 1) # ------------ Add first Tab in Editor ------------------------------- # self.tabEditorWidget.newTabEditor(tabName='first', filename=None) # ------------ Signal ------------------------------- self.findTextButton.triggered.connect(self._toggleFind) 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.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.listClassMethod.itemClicked.connect(self.onClickGoToLine) self.lineEditFind.returnPressed.connect(self._findNext) self.findNextButton.triggered.connect(self._findNext) self.findPrevButton.triggered.connect(self._findPrev) self.lineEditFind.textChanged.connect(self._textFindChanged) self.findScut = QShortcut(QKeySequence.Find, self.widgetEditor) self.findScut.setContext(Qt.WidgetWithChildrenShortcut) self.findScut.activated.connect(self._openFind) self.findNextScut = QShortcut(QKeySequence.FindNext, self.widgetEditor) self.findNextScut.setContext(Qt.WidgetWithChildrenShortcut) self.findNextScut.activated.connect(self._findNext) self.findPreviousScut = QShortcut(QKeySequence.FindPrevious, self.widgetEditor) self.findPreviousScut.setContext(Qt.WidgetWithChildrenShortcut) self.findPreviousScut.activated.connect(self._findPrev) # Escape on editor hides the find bar self.findScut = QShortcut(Qt.Key_Escape, self.widgetEditor) self.findScut.setContext(Qt.WidgetWithChildrenShortcut) self.findScut.activated.connect(self._closeFind) def _toggleFind(self): self.tabEditorWidget.currentWidget().newEditor.toggleFindWidget() def _openFind(self): self.tabEditorWidget.currentWidget().newEditor.openFindWidget() def _closeFind(self): self.tabEditorWidget.currentWidget().newEditor.closeFindWidget() 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) self.tabEditorWidget.currentWidget().newEditor.findText(True, showMessage=False, findFirst=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 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 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, selected_filter = 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.homePath()) pathFileName = os.path.join(folder, fileName) fileNone = True else: pathFileName = tabWidget.path fileNone = False saveAsFileTr = QCoreApplication.translate("PythonConsole", "Save File As") filename, filter = 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): QgsHelp.openHelp("plugins/python_console.html") def openSettings(self): if optionsDialog(self).exec_(): self.shell.refreshSettingsShell() self.shellOut.refreshSettingsOutput() self.tabEditorWidget.refreshSettingsEditor() def callWidgetMessageBar(self, text): self.shellOut.widgetMessageBar(iface, text) def callWidgetMessageBarEditor(self, text, level, timed): self.tabEditorWidget.widgetMessageBar(iface, text, level, timed) def updateTabListScript(self, script, action=None): if action == 'remove': self.tabListScript.remove(script) elif action == 'append': if not self.tabListScript: self.tabListScript = [] if script not in self.tabListScript: self.tabListScript.append(script) else: self.tabListScript = [] self.settings.setValue("pythonConsole/tabScripts", self.tabListScript) def saveSettingsConsole(self): self.settings.setValue("pythonConsole/splitterConsole", self.splitter.saveState()) self.settings.setValue("pythonConsole/splitterObj", self.splitterObj.saveState()) self.settings.setValue("pythonConsole/splitterEditor", self.splitterEditor.saveState()) self.shell.writeHistoryFile(True) def restoreSettingsConsole(self): storedTabScripts = self.settings.value("pythonConsole/tabScripts", []) self.tabListScript = storedTabScripts self.splitter.restoreState(self.settings.value("pythonConsole/splitterConsole", QByteArray())) self.splitterEditor.restoreState(self.settings.value("pythonConsole/splitterEditor", QByteArray())) self.splitterObj.restoreState(self.settings.value("pythonConsole/splitterObj", QByteArray()))
class PythonConsoleWidget(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) self.setWindowTitle( QCoreApplication.translate("PythonConsole", "Python Console")) self.settings = QgsSettings() 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() icon_size = iface.iconSize( dockedToolbar=True) if iface else QSize(16, 16) 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("mActionScriptOpen.svg")) 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.svg")) 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("mActionFileSave.svg")) 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("mActionFileSaveAs.svg")) 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("mActionEditCut.svg")) 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("mActionEditCopy.svg")) 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("mActionEditPaste.svg")) 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("mActionStart.svg")) 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.svg")) 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.svg")) 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.svg")) 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.svg")) 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.svg")) 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.svg")) 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.svg")) self.optionsButton.setMenuRole(QAction.PreferencesRole) self.optionsButton.setIconVisibleInMenu(True) self.optionsButton.setToolTip(optionsBt) self.optionsButton.setText(optionsBt) # 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/mIconRunConsole.svg")) self.runButton.setMenuRole(QAction.PreferencesRole) self.runButton.setIconVisibleInMenu(True) self.runButton.setToolTip(runBt) self.runButton.setText(runBt) # Help button self.helpConsoleAction = QAction(self) self.helpConsoleAction.setEnabled(True) self.helpConsoleAction.setText( QCoreApplication.translate("PythonConsole", "Python Console Help")) self.helpAPIAction = QAction(self) self.helpAPIAction.setEnabled(True) self.helpAPIAction.setText( QCoreApplication.translate("PythonConsole", "PyQGIS API Documentation")) self.helpCookbookAction = QAction(self) self.helpCookbookAction.setEnabled(True) self.helpCookbookAction.setText( QCoreApplication.translate("PythonConsole", "PyQGIS Cookbook")) self.helpMenu = QMenu(self) self.helpMenu.addAction(self.helpConsoleAction) self.helpMenu.addAction(self.helpAPIAction) self.helpMenu.addAction(self.helpCookbookAction) helpBt = QCoreApplication.translate("PythonConsole", "Help…") self.helpButton = QToolButton(self) self.helpButton.setPopupMode(QToolButton.InstantPopup) self.helpButton.setEnabled(True) self.helpButton.setIcon( QgsApplication.getThemeIcon("console/iconHelpConsole.svg")) self.helpButton.setToolTip(helpBt) self.helpButton.setMenu(self.helpMenu) 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(icon_size) self.toolBar.setMovable(False) self.toolBar.setFloatable(False) self.toolBar.addAction(self.clearButton) self.toolBar.addAction(self.runButton) self.toolBar.addSeparator() self.toolBar.addAction(self.showEditorButton) self.toolBar.addSeparator() self.toolBar.addAction(self.optionsButton) self.toolBar.addWidget(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(icon_size) 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.cutEditorButton) self.toolBarEditor.addAction(self.copyEditorButton) self.toolBarEditor.addAction(self.pasteEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.findTextButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.commentEditorButton) self.toolBarEditor.addAction(self.uncommentEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.objectListButton) 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.toolBarFindText = QToolBar() self.toolBarFindText.setIconSize(icon_size) self.findNextButton = QAction(self) self.findNextButton.setEnabled(False) toolTipfindNext = QCoreApplication.translate("PythonConsole", "Find Next") self.findNextButton.setToolTip(toolTipfindNext) self.findNextButton.setIcon( QgsApplication.getThemeIcon( "console/iconSearchNextEditorConsole.svg")) self.findPrevButton = QAction(self) self.findPrevButton.setEnabled(False) toolTipfindPrev = QCoreApplication.translate("PythonConsole", "Find Previous") self.findPrevButton.setToolTip(toolTipfindPrev) self.findPrevButton.setIcon( QgsApplication.getThemeIcon( "console/iconSearchPrevEditorConsole.svg")) 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.toolBarFindText.addWidget(self.lineEditFind) self.toolBarFindText.addAction(self.findPrevButton) self.toolBarFindText.addAction(self.findNextButton) self.toolBarFindText.addWidget(self.caseSensitive) self.toolBarFindText.addWidget(self.wholeWord) self.toolBarFindText.addWidget(self.wrapAround) self.layoutFind.addWidget(self.toolBarFindText, 0, 1, 1, 1) # ------------ Add first Tab in Editor ------------------------------- # self.tabEditorWidget.newTabEditor(tabName='first', filename=None) # ------------ Signal ------------------------------- self.findTextButton.triggered.connect(self._toggleFind) 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.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.helpConsoleAction.triggered.connect(self.openHelpConsole) self.helpAPIAction.triggered.connect(self.openHelpAPI) self.helpCookbookAction.triggered.connect(self.openHelpCookbook) self.listClassMethod.itemClicked.connect(self.onClickGoToLine) self.lineEditFind.returnPressed.connect(self._findNext) self.findNextButton.triggered.connect(self._findNext) self.findPrevButton.triggered.connect(self._findPrev) self.lineEditFind.textChanged.connect(self._textFindChanged) self.findScut = QShortcut(QKeySequence.Find, self.widgetEditor) self.findScut.setContext(Qt.WidgetWithChildrenShortcut) self.findScut.activated.connect(self._openFind) self.findNextScut = QShortcut(QKeySequence.FindNext, self.widgetEditor) self.findNextScut.setContext(Qt.WidgetWithChildrenShortcut) self.findNextScut.activated.connect(self._findNext) self.findPreviousScut = QShortcut(QKeySequence.FindPrevious, self.widgetEditor) self.findPreviousScut.setContext(Qt.WidgetWithChildrenShortcut) self.findPreviousScut.activated.connect(self._findPrev) # Escape on editor hides the find bar self.findScut = QShortcut(Qt.Key_Escape, self.widgetEditor) self.findScut.setContext(Qt.WidgetWithChildrenShortcut) self.findScut.activated.connect(self._closeFind) def _toggleFind(self): self.tabEditorWidget.currentWidget().newEditor.toggleFindWidget() def _openFind(self): self.tabEditorWidget.currentWidget().newEditor.openFindWidget() def _closeFind(self): self.tabEditorWidget.currentWidget().newEditor.closeFindWidget() 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) self.tabEditorWidget.currentWidget().newEditor.findText( True, showMessage=False, findFirst=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 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 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, selected_filter = 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.homePath()) pathFileName = os.path.join(folder, fileName) fileNone = True else: pathFileName = tabWidget.path fileNone = False saveAsFileTr = QCoreApplication.translate("PythonConsole", "Save File As") filename, filter = 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 openHelpConsole(self): QgsHelp.openHelp("plugins/python_console.html") def openHelpAPI(self): m = re.search(r'^([0-9]+)\.([0-9]+)\.', Qgis.QGIS_VERSION) if m: QDesktopServices.openUrl( QUrl('https://qgis.org/pyqgis/{}.{}/'.format( m.group(1), m.group(2)))) def openHelpCookbook(self): m = re.search(r'^([0-9]+)\.([0-9]+)\.', Qgis.QGIS_VERSION) if m: QDesktopServices.openUrl( QUrl( 'https://docs.qgis.org/{}.{}/en/docs/pyqgis_developer_cookbook/index.html' .format(m.group(1), m.group(2)))) 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 Plugin(QObject): def __init__(self, iface): QObject.__init__(self) self.__iface = iface self.__shortcuts = [] self.__current_section = QComboBox() self.__current_section.setMinimumWidth(150) self.__current_graph = QComboBox() self.__current_graph.setMinimumWidth(150) self.__toolbar = None self.__menu = None self.__log_strati = None def initGui(self): for keyseq, slot in ( (Qt.CTRL + Qt.ALT + Qt.Key_K, self.__create_group), # (Qt.CTRL + Qt.ALT + Qt.Key_S, self.__select_next_group), (Qt.CTRL + Qt.ALT + Qt.Key_N, self.__next_section), (Qt.CTRL + Qt.ALT + Qt.Key_B, self.__previous_section), (Qt.CTRL + Qt.ALT + Qt.Key_J, self.__add_section_from_selection), ): short = QShortcut(QKeySequence(keyseq), self.__iface.mainWindow()) short.setContext(Qt.ApplicationShortcut) short.activated.connect(slot) self.__shortcuts.append(short) self.__menu = QMenu("Albion") self.__menu.aboutToShow.connect(self.__create_menu_entries) self.__iface.mainWindow().menuBar().addMenu(self.__menu) self.__toolbar = QToolBar("Albion") self.__iface.addToolBar(self.__toolbar) #self.__toolbar.addAction( # icon("log_strati.svg"), "stratigraphic log" #).triggered.connect(self.__log_strati_clicked) self.__toolbar.addWidget(self.__current_graph) self.__current_graph.currentIndexChanged[str].connect( self.__current_graph_changed ) self.__toolbar.addWidget(self.__current_section) self.__current_section.currentIndexChanged[str].connect( self.__current_section_changed ) self.__toolbar.addAction( icon("previous_line_big.svg"), "previous section (Ctrl+Alt+b)" ).triggered.connect(self.__previous_section) self.__toolbar.addAction( icon("previous_line.svg"), "previous sub section" ).triggered.connect(self.__previous_subsection) self.__toolbar.addAction( icon("next_line.svg"), "next sub section" ).triggered.connect(self.__next_subsection) self.__toolbar.addAction( icon("next_line_big.svg"), "next section (Ctrl+Alt+n)" ).triggered.connect(self.__next_section) self.__toolbar.addAction( icon("line_from_selected.svg"), "create temporary section" ).triggered.connect(self.__section_from_selection) self.__viewer3d = QDockWidget("3D") self.__viewer3d.setWidget(Viewer3d()) self.__iface.addDockWidget(Qt.LeftDockWidgetArea, self.__viewer3d) self.__iface.mainWindow().tabifyDockWidget( self.__iface.mainWindow().findChild(QDockWidget, "Layers"), self.__viewer3d ) self.__viewer3d_ctrl = QToolBar("3D controls") self.__viewer3d_ctrl.addWidget(ViewerControls(self.__viewer3d.widget())) self.__iface.addToolBar(self.__viewer3d_ctrl) QgsProject.instance().readProject.connect(self.__qgis__project__loaded) self.__qgis__project__loaded() # case of reload def unload(self): for s in self.__shortcuts: s.setParent(None) self.__toolbar and self.__toolbar.setParent(None) self.__menu and self.__menu.setParent(None) self.__viewer3d and self.__viewer3d.setParent(None) self.__viewer3d_ctrl and self.__viewer3d_ctrl.setParent(None) def __add_menu_entry(self, name, callback, enabled=True, help_str=""): act = self.__menu.addAction(name) if callback is not None: act.triggered.connect(callback) act.setEnabled(enabled) act.setToolTip(help_str) else: act.setEnabled(False) act.setToolTip("NOT INMPLEMENTED " + help_str) return act def __create_menu_entries(self): self.__menu.clear() self.__add_menu_entry("New &Project", self.__new_project) self.__add_menu_entry("Import Project", self.__import_project) self.__add_menu_entry("Export Project", self.__export_project, self.project is not None) self.__add_menu_entry("Upgrade Project", self.__upgrade_project) self.__menu.addSeparator() self.__add_menu_entry( "&Import directory", self.__import_data, self.project is not None, "Import data from directory" ) self.__add_menu_entry( "&Import holes", None, #self.__import_holes, self.project is not None and False, "Import hole data from directory" ) self.__add_menu_entry( "Export holes", self.__export_holes, self.project is not None and self.project.has_hole, "Export hole trace in .vtk or .dxf format", ) self.__add_menu_entry( "Import layer", self.__import_layer, self.project is not None, "Import data from selected layer." ) self.__add_menu_entry( "Export layer", self.__export_layer, self.project is not None ) self.__add_menu_entry( "Compute &Mineralization", self.__compute_mineralization, self.project is not None and self.project.has_radiometry, "", ) self.__menu.addSeparator() self.__menu.addSeparator() self.__add_menu_entry( "Create cells", self.__create_cells, self.project is not None and self.project.has_hole, "Create Delaunay triangulation of collar layer.", ) self.__add_menu_entry( "Create subsections", self.__create_sections, self.project is not None and self.project.has_group_cell, "Once cell groups have been defined, create section lines.", ) self.__add_menu_entry( "Refresh selected layers sections", self.__refresh_selected_layers_sections, self.project is not None, "" ) self.__menu.addSeparator() self.__add_menu_entry( "New &Graph", self.__new_graph, self.project is not None, "Create a new graph", ) self.__add_menu_entry( "Delete Graph", self.__delete_graph, self.project is not None and self.project.has_graph ) self.__add_menu_entry( "Add selection to graph nodes", self.__add_selection_to_graph_node, self.project is not None and self.project.has_graph ) self.__add_menu_entry( "Accept graph possible edges", self.__accept_possible_edge, self.project is not None and self.project.has_graph ) self.__add_menu_entry( "Create terminations", self.__create_terminations, self.project is not None and bool(self.__current_graph.currentText()), "Create terminations associated with current graph.", ) self.__menu.addSeparator() self.__add_menu_entry( "Create volumes", self.__create_volumes, self.project is not None and bool(self.__current_graph.currentText()), "Create volumes associated with current graph.", ) self.__add_menu_entry( "Export Volume", self.__export_volume, self.project is not None and bool(self.__current_graph.currentText()), "Export volume of current graph in .obj or .dxf format", ) self.__add_menu_entry( "Export Elementary Volume", self.__export_elementary_volume, self.project is not None and bool(self.__current_graph.currentText()), "Export an elementary volume of current graph in .obj or .dxf format", ) self.__add_menu_entry( "Export Sections", self.__export_sections, self.project is not None and bool(self.__current_graph.currentText()) and self.project.has_section and self.project.has_volume, "Export triangulated section in .obj or .dxf format", ) self.__add_menu_entry( "Export rasters from formation", self.__export_raster_formation, self.project is not None and self.project.has_cell, "Export rasters (DEM, aspect, slope, ruggedness index) from formation", ) self.__add_menu_entry( "Export rasters from collar", self.__export_raster_collar, self.project is not None and self.project.has_cell, "Export rasters (DEM, aspect, slope, ruggedness index) from collar", ) self.__menu.addSeparator() self.__menu.addAction("Help").triggered.connect(self.open_help) def __current_graph_changed(self, graph_id): if self.project is None: return self.__viewer3d.widget().set_graph(graph_id) def __getattr__(self, name): if name == "project": project_name = QgsProject.instance().readEntry( "albion", "project_name", "" )[0] return Project(project_name) if project_name else None else: raise AttributeError(name) def __create_terminations(self): self.project.create_terminations(self.__current_graph.currentText()) self.__viewer3d.widget().refresh_data() self.__refresh_layers("section") def __create_volumes(self): self.project.create_volumes(self.__current_graph.currentText()) self.__viewer3d.widget().refresh_data() def __next_section(self): self.project.next_section(self.__current_section.currentText()) self.__refresh_layers("section") self.__viewer3d.widget().scene.update("section") self.__viewer3d.widget().scene.update("volume_section") self.__viewer3d.widget().update() def __previous_section(self): self.project.previous_section(self.__current_section.currentText()) self.__refresh_layers("section") self.__viewer3d.widget().scene.update("section") self.__viewer3d.widget().scene.update("volume_section") self.__viewer3d.widget().update() def __next_subsection(self): self.project.next_subsection(self.__current_section.currentText()) print("refresh") self.__refresh_layers("section") print("section") self.__viewer3d.widget().scene.update("section") print("volume section") self.__viewer3d.widget().scene.update("volume_section") print("3D update") self.__viewer3d.widget().update() print("done done") def __previous_subsection(self): self.project.previous_subsection(self.__current_section.currentText()) self.__refresh_layers("section") self.__viewer3d.widget().scene.update("section") self.__viewer3d.widget().scene.update("volume_section") self.__viewer3d.widget().update() def __refresh_layers(self, name=None, updateExtent=False): for layer in self.__iface.mapCanvas().layers(): if name is None or layer.name().find(name) != -1: layer.triggerRepaint() def __layer(self, name): lay = None for layer in self.__iface.mapCanvas().layers(): if name is None or layer.name() == name: lay = layer return lay def __current_section_changed(self, section_id): layers = QgsProject.instance().mapLayersByName(u"group_cell") if len(layers): layers[0].setSubsetString("section_id='{}'".format(section_id)) self.__refresh_layers("section") # def __select_next_group(self): # if ( # self.__iface.activeLayer() # and self.__iface.activeLayer().name() == u"cell" # ): # self.__iface.activeLayer().removeSelection() # self.__iface.activeLayer().selectByExpression( # "id in ({})".format(",".join(project.next_group_ids())) # ) # def __create_group(self): if ( self.__iface.activeLayer() and self.__iface.activeLayer().name() == u"cell" ): if self.__iface.activeLayer().selectedFeatureCount(): section = self.__current_section.currentText() self.project.create_group( section, [f["id"] for f in self.__iface.activeLayer().selectedFeatures()], ) self.__iface.activeLayer().removeSelection() self.__refresh_layers("group_cell") def __qgis__project__loaded(self): if self.project is None: return self.__current_graph.clear() self.__current_section.clear() self.__current_section.addItems(self.project.sections()) self.__current_graph.addItems(self.project.graphs()) layers = QgsProject.instance().mapLayersByName("section.anchor") if len(layers): layers[0].editingStopped.connect(self.__update_section_list) self.__viewer3d.widget().resetScene(self.project) # We make sure that corresponding extents are valid when the project # is loaded cell = QgsProject.instance().mapLayersByName("cell") if len(cell): cell[0].updateExtents() section_geom = QgsProject.instance().mapLayersByName("section.geom") if section_geom: section_geom[0].updateExtents() def __update_section_list(self): self.__current_section.clear() self.__current_section.addItems(self.project.sections()) def __upgrade_project(self): project_name, ok = QInputDialog.getText( self.__iface.mainWindow(), "Database name", "Database name:", QLineEdit.Normal, "", ) if not ok: return project = Project(project_name) project.update() QgsProject.instance().writeEntry("albion", "project_name", project.name) QgsProject.instance().writeEntry("albion", "srid", project.srid) self.__qgis__project__loaded() def __new_project(self): fil, __ = QFileDialog.getSaveFileName( None, u"New project name (no space, plain ascii)", QgsProject.instance().readEntry("albion", "last_dir", "")[0], "QGIS poject file (*.qgs)", ) if not fil: return fil = fil if len(fil) > 4 and fil[-4:] == ".qgs" else fil + ".qgs" fil = fil.replace(" ", "_") if len(fil) != len(fil.encode()): self.__iface.messageBar().pushError( "Albion:", "project name may only contain asci character (no accent)" ) return srid, ok = QInputDialog.getText( self.__iface.mainWindow(), "Project SRID", "Project SRID EPSG:", QLineEdit.Normal, "32632", ) if not ok: return srid = int(srid) project_name = str(os.path.split(fil)[1][:-4]) if Project.exists(project_name): if ( QMessageBox.Yes != QMessageBox( QMessageBox.Information, "Delete existing DB", "Database {} exits, do you want to delete it ?".format( project_name ), QMessageBox.Yes | QMessageBox.No, ).exec_() ): self.__iface.messageBar().pushInfo("Albion:", "keeping existing database...") else: Project.delete(project_name) self.__iface.messageBar().pushInfo("Albion:", "creating project...") Project.create(project_name, srid) else: self.__iface.messageBar().pushInfo("Albion:", "creating project...") Project.create(project_name, srid) if os.path.exists(fil): os.remove(fil) # load template open(fil, "w").write( open(resource("template_project.qgs")) .read() .replace("template_project", project_name) .replace("32632", str(srid)) ) self.__iface.newProject() QgsProject.instance().setFileName(fil) QgsProject.instance().read() QgsProject.instance().writeEntry("albion", "project_name", project_name) QgsProject.instance().writeEntry("albion", "srid", srid) QgsProject.instance().write() self.__qgis__project__loaded() def __import_data(self): assert(self.project) dir_ = QFileDialog.getExistingDirectory( None, u"Data directory", QgsProject.instance().readEntry("albion", "last_dir", "")[0], QFileDialog.ShowDirsOnly | QFileDialog.DontUseNativeDialog ) if not dir_: return QgsProject.instance().writeEntry("albion", "last_dir", dir_), progressMessageBar = self.__iface.messageBar().createMessage( "Loading {}...".format(dir_) ) progress = QProgressBar() progress.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) progressMessageBar.layout().addWidget(progress) self.__iface.messageBar().pushWidget(progressMessageBar) self.project.import_data(dir_, ProgressBar(progress)) #self.project.triangulate() self.project.create_section_view_0_90(4) self.__iface.messageBar().clearWidgets() collar = QgsProject.instance().mapLayersByName("collar") if len(collar): collar[0].reload() collar[0].updateExtents() self.__iface.setActiveLayer(collar[0]) QApplication.instance().processEvents() while self.__iface.mapCanvas().isDrawing(): QApplication.instance().processEvents() self.__iface.zoomToActiveLayer() self.__iface.actionSaveProject().trigger() self.__viewer3d.widget().resetScene(self.project) self.__current_section.clear() self.__current_section.addItems(self.project.sections()) def __import_layer(self): assert(self.project) if self.__iface.activeLayer(): from_idx = None to_idx = None hole_id_idx= None other_idx = [] definitions = [] fields = [] for idx, f in enumerate(self.__iface.activeLayer().fields()): if f.name().lower() == 'from' or f.name().lower() == 'from_': from_idx = idx elif f.name().lower() == 'to' or f.name().lower() == 'to_': to_idx = idx elif f.name().lower() == 'hole_id' or f.name().lower() == 'holeid': hole_id_idx = idx else: other_idx.append(idx) name = f.name().lower().replace(' ', '_') fields.append(name) type_ = 'varchar' if f.typeName() == 'double': type_ = 'double precision' elif f.typeName() == 'integer': type_ = 'integer' definitions.append(name + ' ' + type_) table = { 'NAME': self.__iface.activeLayer().name().lower().replace(' ', '_'), 'FIELDS_DEFINITION': ', '.join(definitions), 'FIELDS': ', '.join(fields), 'SRID': self.project.srid } if from_idx is None or to_idx is None or hole_id_idx is None: self.__iface.messageBar().pushCritical( "Albion", "imported layer must have 'to', 'from' and 'hole_id' fields") return values = [] for f in self.__iface.activeLayer().getFeatures(): values.append((f[hole_id_idx], f[from_idx], f[to_idx]) + tuple((f[i] for i in other_idx))) self.project.add_table(table, values) def __new_graph(self): graph, ok = QInputDialog.getText( self.__iface.mainWindow(), "Graph", "Graph name:", QLineEdit.Normal, "test_graph", ) if not ok: return parent, ok = QInputDialog.getText( self.__iface.mainWindow(), "Parent Graph", "Parent Graph name:", QLineEdit.Normal, "", ) if not ok: return self.project.new_graph(graph, parent) self.__current_graph.addItem(graph) self.__current_graph.setCurrentIndex(self.__current_graph.findText(graph)) def __delete_graph(self): graph, ok = QInputDialog.getText( self.__iface.mainWindow(), "Graph", "Graph name:", QLineEdit.Normal, self.__current_graph.currentText(), ) if not ok: return self.__current_graph.removeItem(self.__current_graph.findText(graph)) self.project.delete_graph(graph) def __add_selection_to_graph_node(self): assert(self.project) #TODO ADD DIALOG TO REMIND USER THE CURRENT GRAPH if ( self.__iface.activeLayer() and self.__iface.activeLayer().selectedFeatures() ): selection = self.__iface.activeLayer().selectedFeatures() graph = self.__current_graph.currentText() if ( QMessageBox.Yes != QMessageBox( QMessageBox.Information, "Adding selected edges", "Do you want to add {} selected edges to {} ?".format( len(selection), graph ), QMessageBox.Yes | QMessageBox.No, ).exec_() ): return self.project.add_to_graph_node(graph, selection) self.__refresh_layers() def __accept_possible_edge(self): assert(self.project) self.project.accept_possible_edge(self.__current_graph.currentText()) def __create_cells(self): assert(self.project) createAlbionRaster = True if self.project.has_cell: createAlbionRaster = False if ( QMessageBox.Yes != QMessageBox( QMessageBox.Information, "Creating cells", "Do you want to replace project cells (your graphs will become invalid) ?", QMessageBox.Yes | QMessageBox.No, ).exec_() ): return self.project.triangulate(createAlbionRaster) self.__refresh_layers() def __create_sections(self): assert(self.project) self.project.create_sections() def __refresh_selected_layers_sections(self): assert(self.project) for l in self.__iface.layerTreeView().selectedLayers(): uri = QgsDataSourceUri(l.dataProvider().dataSourceUri()) table = uri.table() if table.endswith('_section'): table = table[:-8] self.project.refresh_section_geom(table) self.__refresh_layers(table+'_section') def __compute_mineralization(self): MineralizationDialog(self.project).exec_() def __export_volume(self): assert(self.project) fil, __ = QFileDialog.getSaveFileName( None, u"Export volume for current graph", QgsProject.instance().readEntry("albion", "last_dir", "")[0], "File formats (*.dxf *.obj)", ) if not fil: return QgsProject.instance().writeEntry("albion", "last_dir", os.path.dirname(fil)) if fil[-4:] == ".obj": self.project.export_obj(self.__current_graph.currentText(), fil) elif fil[-4:] == ".dxf": self.project.export_dxf(self.__current_graph.currentText(), fil) else: self.__iface.messageBar().pushWarning( "Albion", "unsupported extension for volume export" ) def __export_elementary_volume(self): assert(self.project) layer = self.__layer("cell") if not layer: self.__iface.messageBar().pushWarning( "Albion", "cell layer must be selected" ) return graph = self.__current_graph.currentText() export_widget = ExportElementaryVolume(layer, self.project, graph) export_widget.show() export_widget.exec_() def __export_sections(self): assert(self.project) fil, __ = QFileDialog.getSaveFileName( None, u"Export named sections for current graph", QgsProject.instance().readEntry("albion", "last_dir", "")[0], "File formats (*.dxf *.obj)", ) if not fil: return QgsProject.instance().writeEntry("albion", "last_dir", os.path.dirname(fil)) if fil[-4:] == ".obj": self.project.export_sections_obj(self.__current_graph.currentText(), fil) elif fil[-4:] == ".dxf": self.project.export_sections_dxf(self.__current_graph.currentText(), fil) else: self.__iface.messageBar().pushWarning( "Albion", "unsupported extension for section export" ) def __export_holes(self): assert(self.project) fil, __ = QFileDialog.getSaveFileName( None, u"Export holes", QgsProject.instance().readEntry("albion", "last_dir", "")[0], "File formats (*.dxf *.vtk)", ) if not fil: return QgsProject.instance().writeEntry("albion", "last_dir", os.path.dirname(fil)) if fil[-4:] == ".vtk": self.project.export_holes_vtk(fil) elif fil[-4:] == ".dxf": self.project.export_holes_dxf(fil) else: self.__iface.messageBar().pushWarning("Albion", "unsupported extension for hole export") def __export_layer(self): assert(self.project) table = None for l in self.__iface.layerTreeView().selectedLayers(): uri = QgsDataSourceUri(l.dataProvider().dataSourceUri()) table = uri.table() if table.endswith('_section'): table = table[:-8] break if table is None: self.__iface.messageBar().pushWarning("Albion", "you must select a layer") return fil, __ = QFileDialog.getSaveFileName( None, u"Export layer", QgsProject.instance().readEntry("albion", "last_dir", "")[0], "File formats (*.dxf *.vtk)", ) if not fil: return QgsProject.instance().writeEntry("albion", "last_dir", os.path.dirname(fil)) if fil.endswith('.vtk'): self.project.export_layer_vtk(table, fil) elif fil.endswith('.dxf'): self.project.export_layer_dxf(table, fil) else: self.__iface.messageBar().pushWarning("Albion", "unsupported extension for hole export") def __import_project(self): fil, __ = QFileDialog.getOpenFileName( None, u"Import project from file", QgsProject.instance().readEntry("albion", "last_dir", "")[0], "File formats (*.zip)", ) if not fil: return QgsProject.instance().writeEntry("albion", "last_dir", os.path.dirname(fil)), if fil[-4:] != ".zip": self.__iface.messageBar().pushWarning( "Albion", "unsupported extension for import" ) project_name = os.path.split(fil)[1][:-4] dir_ = tempfile.mkdtemp() with zipfile.ZipFile(fil, "r") as z: z.extractall(dir_) dump = find_in_dir(dir_, ".dump") prj = find_in_dir(dir_, ".qgs") self.__iface.messageBar().pushInfo( "Albion", "loading {} from {}".format(project_name, dump) ) dbname = os.path.splitext(os.path.basename(dump))[0] if Project.exists(dbname): if ( QMessageBox.Yes != QMessageBox( QMessageBox.Information, "Delete existing DB", "Database {} exits, to you want to delete it ?".format( dbname ), QMessageBox.Yes | QMessageBox.No, ).exec_() ): return Project.delete(dbname) project = Project.import_(dbname, dump) QgsProject.instance().read(prj) def __export_project(self): if self.project is None: return fil, __ = QFileDialog.getSaveFileName( None, u"Export project", QgsProject.instance().readEntry("albion", "last_dir", "")[0], "Data files(*.zip)", ) if not fil: return QgsProject.instance().writeEntry("albion", "last_dir", os.path.dirname(fil)), if os.path.exists(fil): os.remove(fil) with zipfile.ZipFile(fil, "w") as project: dump = tempfile.mkstemp()[1] self.project.export(dump) project.write(dump, self.project.name + ".dump") project.write( QgsProject.instance().fileName(), os.path.split(QgsProject.instance().fileName())[1], ) def __export_raster_formation(self): ret = ExportRasterFormationDialog(self.project).exec_() def __export_raster_collar(self): ret = ExportRasterCollarDialog(self.project).exec_() #def __log_strati_clicked(self): # # @todo switch behavior when in section view -> ortho # self.__click_tool = QgsMapToolEmitPoint(self.__iface.mapCanvas()) # self.__iface.mapCanvas().setMapTool(self.__click_tool) # self.__click_tool.canvasClicked.connect(self.__map_log_clicked) #def __map_log_clicked(self, point, button): # self.__click_tool.setParent(None) # self.__click_tool = None # if self.project is None: # self.__log_strati and self.__log_strati.setParent(None) # self.__log_strati = None # return # if self.__log_strati is None: # self.__log_strati = QDockWidget("Stratigraphic Log") # self.__log_strati.setWidget(BoreHoleWindow(self.project)) # self.__iface.addDockWidget(Qt.LeftDockWidgetArea, self.__log_strati) # self.__iface.mainWindow().tabifyDockWidget( # self.__iface.mainWindow().findChild(QDockWidget, "Layers"), # self.__log_strati, # ) # res = self.project.closest_hole_id(point.x(), point.y()) # if res: # self.__log_strati.widget().scene.set_current_id(res) # self.__log_strati.show() # self.__log_strati.raise_() def __line_from_selection(self): if ( self.__iface.activeLayer() and self.__iface.activeLayer().name() == u"collar" and self.__iface.activeLayer().selectedFeatures() ): collar = self.__iface.activeLayer() selection = collar.selectedFeatures() if len(selection) < 2: return def align(l): assert len(l) >= 2 res = numpy.array(l[:2]) for p in l[2:]: u, v = res[0] - res[1], p - res[1] if numpy.dot(u, v) < 0: res[1] = p elif numpy.dot(u, u) < numpy.dot(v, v): res[0] = p # align with ref direction sqrt2 = math.sqrt(2.0) / 2 l = l[numpy.argsort(numpy.dot(l - res[0], res[1] - res[0]))] d = numpy.array(l[-1] - l[0]) dr = numpy.array([(0, 1), (sqrt2, sqrt2), (1, 0), (sqrt2, -sqrt2)]) i = numpy.argmax(numpy.abs(dr.dot(d))) return l if (dr.dot(d))[i] > 0 else l[::-1] line = LineString( align(numpy.array([f.geometry().asPoint() for f in selection])) ) collar.removeSelection() return line else: return None def __add_section_from_selection(self): assert(self.project) line = self.__line_from_selection() if line: self.project.add_named_section(self.__current_section.currentText(), line) self.__refresh_layers("named_section") def __section_from_selection(self): assert(self.project) line = self.__line_from_selection() if line: self.project.set_section_geom(self.__current_section.currentText(), line) self.__refresh_layers("section") self.__viewer3d.widget().scene.update("section") self.__viewer3d.widget().scene.update("volume_section") self.__viewer3d.widget().update() def open_help(self): QDesktopServices.openUrl( QUrl.fromLocalFile( os.path.join( os.path.dirname(__file__), "doc", "build", "html", "index.html" ) ) )
class FeatureFormWidget(Ui_Form, QWidget): # Raise the cancel event, takes a reason and a level canceled = pyqtSignal(str, int) featuresaved = pyqtSignal() featuredeleted = pyqtSignal() def __init__(self, parent=None): super(FeatureFormWidget, self).__init__(parent) self.setupUi(self) utils.install_touch_scroll(self.scrollArea) toolbar = QToolBar() size = QSize(48, 48) toolbar.setIconSize(size) style = Qt.ToolButtonTextUnderIcon toolbar.setToolButtonStyle(style) self.actionDelete = toolbar.addAction(QIcon(":/icons/delete"), "Delete") self.actionDelete.triggered.connect(self.delete_feature) label = '<b style="color:red">*</b> Required fields' self.missingfieldsLabel = QLabel(label) self.missingfieldsLabel.hide() self.missingfieldaction = toolbar.addWidget(self.missingfieldsLabel) titlespacer = QWidget() titlespacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) toolbar.addWidget(titlespacer) self.titlellabel = QLabel(label) self.titlellabel.setProperty("headerlabel", True) self.titlelabelaction = toolbar.addWidget(self.titlellabel) spacer = QWidget() spacer2 = QWidget() spacer2.setMinimumWidth(40) spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) spacer2.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) toolbar.addWidget(spacer) self.actionCancel = toolbar.addAction(QIcon(":/icons/cancel"), "Cancel") toolbar.addWidget(spacer2) self.actionSave = toolbar.addAction(QIcon(":/icons/save"), "Save") self.actionSave.triggered.connect(self.save_feature) self.layout().setContentsMargins(0, 3, 0, 3) self.layout().insertWidget(0, toolbar) self.actiontoolbar = QToolBar() self.actiontoolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.actiontoolbar.addWidget(spacer) self.layout().insertWidget(1, self.actiontoolbar) self.featureform = None self.values = {} self.config = {} self.feature = None def set_featureform(self, featureform): """ Note: There can only be one feature form. If you need to show another one make a new FeatureFormWidget """ self.featureform = featureform self.titlellabel.setText(self.featureform.windowTitle()) self.featureform.formvalidation.connect(self._update_validation) self.featureform.helprequest.connect( functools.partial(RoamEvents.helprequest.emit, self)) self.featureform.showlargewidget.connect(RoamEvents.show_widget.emit) self.featureform.enablesave.connect(self.actionSave.setEnabled) self.featureform.enablesave.connect(self.actionSave.setVisible) self.featureform.rejected.connect(self.canceled.emit) self.featureform.accepted.connect(self.featuresaved) actions = self.featureform.form_actions() if actions: for action in actions: self.actiontoolbar.addAction(action) else: self.actiontoolbar.hide() self.featureform.setContentsMargins(0, 0, 0, 0) self.featureformarea.layout().addWidget(self.featureform) def delete_feature(self): try: msg = self.featureform.deletemessage except AttributeError: msg = 'Do you really want to delete this feature?' box = DeleteFeatureDialog(msg) if not box.exec_(): return try: self.featureform.delete() except featureform.DeleteFeatureException as ex: RoamEvents.raisemessage(*ex.error) self.featureform.featuredeleted(self.feature) self.featuredeleted.emit() def feature_saved(self): self.featuresaved.emit() RoamEvents.featuresaved.emit() def save_feature(self): try: self.featureform.save() except featureform.MissingValuesException as ex: RoamEvents.raisemessage(*ex.error) return except featureform.FeatureSaveException as ex: RoamEvents.raisemessage(*ex.error) self.feature_saved() def set_config(self, config): self.config = config editmode = config['editmode'] allowsave = config.get('allowsave', True) self.feature = config.get('feature', None) tools = config.get('tools', []) candelete = True if tools: candelete = "delete" in tools self.featureform.feature = self.feature self.featureform.editingmode = editmode self.actionDelete.setVisible(editmode and candelete) self.actionSave.setEnabled(allowsave) def _update_validation(self, passed): # Show the error if there is missing fields self.missingfieldaction.setVisible(not passed) def bind_values(self, values): self.values = values self.featureform.bindvalues(values) def after_load(self): self.featureform.loaded() def before_load(self): self.featureform.load(self.config['feature'], self.config['layers'], self.values)
class MainApp(QDockWidget, QMainWindow, Ui_MainApp): # signals goBack = pyqtSignal() searchOpsubByName = pyqtSignal(str) enableSearch = pyqtSignal(bool) refreshLegend = pyqtSignal(QgsMapLayer) ogrDatasourceLoaded = pyqtSignal(bool) class VfkLayer(object): Par = 0 Bud = 1 def __init__(self, iface): QDockWidget.__init__(self, iface.mainWindow()) self.setupUi(self) self.iface = iface # variables self.__mLastVfkFile = [] self.__mOgrDataSource = None self.__mDataSourceName = '' self.__fileName = [] self.__mLoadedLayers = {} self.__mDefaultPalette = self.vfkFileLineEdit.palette() # new lineEdits variables self.lineEditsCount = 1 self.__browseButtons = {} self.__vfkLineEdits = {} # data will be load from source according to checked radiobox self.__source_for_data = 'file' # apply changes into main database self.__databases = {} # self.pb_applyChanges.setEnabled(False) self.changes_instance = ApplyChanges() # Connect ui with functions self.__createToolbarsAndConnect() # check GDAL version self.__gdal_version = int(gdal.VersionInfo()) if self.__gdal_version < 2020000: self.actionZpracujZmeny.setEnabled(False) self.pb_nextFile.setEnabled(False) self.pb_nextFile.setToolTip( u'Není možné načíst více souborů, verze GDAL je nižší než 2.2.0.' ) self.actionZpracujZmeny.setToolTip( u'Zpracování změn není povoleno, verze GDAL je nižší než 2.2.0.' ) self.groupBox.setEnabled(False) # settings self.loadVfkButton.setDisabled(True) self.searchFormMainControls = SearchFormController.MainControls() self.searchFormMainControls.formCombobox = self.searchCombo self.searchFormMainControls.searchForms = self.searchForms self.searchFormMainControls.searchButton = self.searchButton self.searchForms = SearchFormController.SearchForms() self.searchForms.vlastnici = self.vlastniciSearchForm self.searchForms.parcely = self.parcelySearchForm self.searchForms.budovy = self.budovySearchForm self.searchForms.jednotky = self.jednotkySearchForm # search form controller self.__mSearchController = SearchFormController( self.searchFormMainControls, self.searchForms, self) self.__mSearchController.actionTriggered.connect( self.vfkBrowser.processAction) self.enableSearch.connect(self.searchButton.setEnabled) self.vfkBrowser.showParcely.connect(self.showParInMap) self.vfkBrowser.showBudovy.connect(self.showBudInMap) # connect lineEdits and returnPressed action self.vfkFileLineEdit.returnPressed.connect(self.loadVfkButton_clicked) self.vlastniciSearchForm.ui.jmenoLineEdit.returnPressed.connect( self.__mSearchController.search) self.vlastniciSearchForm.ui.rcIcoLineEdit.returnPressed.connect( self.__mSearchController.search) self.vlastniciSearchForm.ui.lvVlastniciLineEdit.returnPressed.connect( self.__mSearchController.search) self.parcelySearchForm.ui.parCisloLineEdit.returnPressed.connect( self.__mSearchController.search) self.parcelySearchForm.ui.lvParcelyLineEdit.returnPressed.connect( self.__mSearchController.search) self.budovySearchForm.ui.cisloDomovniLineEdit.returnPressed.connect( self.__mSearchController.search) self.budovySearchForm.ui.naParceleLineEdit.returnPressed.connect( self.__mSearchController.search) self.budovySearchForm.ui.lvBudovyLineEdit.returnPressed.connect( self.__mSearchController.search) self.jednotkySearchForm.ui.mCisloJednotkyLineEdit.returnPressed.connect( self.__mSearchController.search) self.jednotkySearchForm.ui.mCisloDomovniLineEdit.returnPressed.connect( self.__mSearchController.search) self.jednotkySearchForm.ui.mNaParceleLineEdit.returnPressed.connect( self.__mSearchController.search) self.jednotkySearchForm.ui.mLvJednotkyLineEdit.returnPressed.connect( self.__mSearchController.search) self.vfkBrowser.showHelpPage() # settings self.settings = QtCore.QSettings() def browseButton_clicked(self, browseButton_id=1): """ :param browseButton_id: ID of clicked browse button. :return: """ sender = '{}-lastUsedDir'.format(self.sender().objectName()) lastUsedDir = self.settings.value(sender, '') if self.__source_for_data == 'file': ext = '*.vfk' if self.__gdal_version >= 2020000: ext += ' *.db' loaded_file, __ = QFileDialog.getOpenFileName( self, u'Načti soubor VFK', lastUsedDir, u'Soubory podporované ovladačem VFK GDAL ({})'.format(ext)) if not loaded_file: return self.__fileName.append(loaded_file) if browseButton_id == 1: self.vfkFileLineEdit.setText(self.__fileName[0]) else: self.__vfkLineEdits['vfkL1ineEdit_{}'.format( len(self.__vfkLineEdits))].setText( self.__fileName[browseButton_id - 1]) self.settings.setValue(sender, os.path.dirname(loaded_file)) elif self.__source_for_data == 'directory': loaded_file = QFileDialog.getExistingDirectory( self, u"Vyberte adresář s daty VFK", lastUsedDir) if not loaded_file: return self.__fileName = [] self.__fileName.append(loaded_file) self.vfkFileLineEdit.setText(self.__fileName[0]) self.settings.setValue(sender, loaded_file) else: iface.messageBar().pushWarning(u'ERROR', u'Not valid data source') self.loadVfkButton.setEnabled(True) def browserGoBack(self): self.vfkBrowser.goBack() def browserGoForward(self): self.vfkBrowser.goForth() def selectParInMap(self): self.showInMap(self.vfkBrowser.currentParIds(), "PAR") def selectBudInMap(self): self.showInMap(self.vfkBrowser.currentBudIds(), "BUD") def latexExport(self): fileName, __ = QFileDialog.getSaveFileName( self, u"Jméno exportovaného souboru", ".tex", "LaTeX (*.tex)") if fileName: export_succesfull = self.vfkBrowser.exportDocument( self.vfkBrowser.currentUrl(), fileName, self.vfkBrowser.ExportFormat.Latex) if export_succesfull: self.succesfullExport("LaTeX") def htmlExport(self): fileName, __ = QFileDialog.getSaveFileName( self, u"Jméno exportovaného souboru", ".html", "HTML (*.html)") if fileName: export_succesfull = self.vfkBrowser.exportDocument( self.vfkBrowser.currentUrl(), fileName, self.vfkBrowser.ExportFormat.Html) if export_succesfull: self.succesfullExport("HTML") def setSelectionChangedConnected(self, connected): """ :type connected: bool :return: """ for layer in self.__mLoadedLayers: id = self.__mLoadedLayers[layer] vectorLayer = QgsProject.instance().mapLayer(id) if connected: vectorLayer.selectionChanged.connect( self.showInfoAboutSelection) else: vectorLayer.selectionChanged.disconnect( self.showInfoAboutSelection) def showInMap(self, ids, layerName): """ :type ids: list :type layerName: str :return: """ if layerName in self.__mLoadedLayers: id = self.__mLoadedLayers[layerName] vectorLayer = QgsProject.instance().mapLayer(id) searchString = "ID IN ({})".format(", ".join(ids)) error = '' fIds = self.__search(vectorLayer, searchString, error) if error: iface.messageBar().pushWarning( u'ERROR', u'In showInMap: {}'.format(error)) return else: vectorLayer.setSelectedFeatures(fIds) def __search(self, layer, searchString, error): """ :type layer: QgsVectorLayer :type searchString: str :type error: str :return: """ # parse search string and build parsed tree search = QgsExpression(searchString) rect = QgsRectangle() fIds = [] if search.hasParserError(): error += "Parsing error:" + search.parserErrorString() return fIds if not search.prepare(layer.fields()): error + "Evaluation error:" + search.evalErrorString() layer.select(rect, False) fit = QgsFeatureIterator(layer.getFeatures()) f = QgsFeature() while fit.nextFeature(f): if search.evaluate(f): fIds.append(f.id()) # check if there were errors during evaluating if search.hasEvalError(): iface.messageBar().pushWarning( u'ERROR', u'Evaluate error: {}'.format(error)) break return fIds def loadVfkButton_clicked(self): """ After click method starts loading all inserted files """ # check the source of data if self.__source_for_data == 'directory': dir_path = self.__fileName[0] self.__fileName = self.__findVFKFilesInDirectory(dir_path) # check if first file is amendment amendment_file = self.__checkIfAmendmentFile(self.__fileName[0]) # prepare name for database if amendment_file: new_database_name = '{}_zmeny.db'.format( os.path.basename(self.__fileName[0]).split('.')[0]) else: new_database_name = '{}_stav.db'.format( os.path.basename(self.__fileName[0]).split('.')[0]) gdal.SetConfigOption( 'OGR_VFK_DB_NAME', str( os.path.join(os.path.dirname(self.__fileName[0]), new_database_name))) self.__mDataSourceName = self.__fileName[0] QgsApplication.processEvents() self.importThread = OpenThread(self.__fileName) self.importThread.working.connect(self.runLoadingLayer) if not self.importThread.isRunning(): self.importThread.start() def runLoadingLayer(self, fileName): """ :return: """ if fileName not in self.__mLastVfkFile: self.labelLoading.setText( u'Načítám data do SQLite databáze (může nějaký čas trvat...)') try: self.loadVfkFile(fileName) except VFKError as e: QMessageBox.critical(self, u'Chyba', u'{}'.format(e), QMessageBox.Ok) self.enableSearch.emit(False) return self.__mLastVfkFile.append(fileName) self.importThread.nextLayer = False if fileName == self.__fileName[-1]: self.loadingLayersFinished() def loadingLayersFinished(self): """ :return: """ try: self.__openDatabase(gdal.GetConfigOption('OGR_VFK_DB_NAME')) except VFKError as e: QMessageBox.critical(self, u'Chyba', u'{}'.format(e), QMessageBox.Ok) self.enableSearch.emit(False) return self.vfkBrowser.setConnectionName(self.property("connectionName")) self.__mSearchController.setConnectionName( self.property("connectionName")) self.enableSearch.emit(True) self.__mLoadedLayers.clear() if self.parCheckBox.isChecked(): self.__loadVfkLayer('PAR') else: self.__unLoadVfkLayer('PAR') if self.budCheckBox.isChecked(): self.__loadVfkLayer('BUD') else: self.__unLoadVfkLayer('BUD') self.labelLoading.setText(u'Načítání souborů VFK bylo dokončeno.') def vfkFileLineEdit_textChanged(self, arg1): """ :type arg1: str :return: """ info = QFileInfo(arg1) if info.isFile(): self.loadVfkButton.setEnabled(True) self.vfkFileLineEdit.setPalette(self.__mDefaultPalette) else: self.loadVfkButton.setEnabled(False) pal = QPalette(self.vfkFileLineEdit.palette()) pal.setColor(QPalette.text(), Qt.red) self.vfkFileLineEdit.setPalette(pal) def __loadVfkLayer(self, vfkLayerName): """ :type vfkLayerName: str :return: """ # QgsMessageLog.logMessage(u"(VFK) Loading vfk layer {}".format(vfkLayerName)) if vfkLayerName in self.__mLoadedLayers: # QgsMessageLog.logMessage( # "(VFK) Vfk layer {} is already loaded".format(vfkLayerName) # ) return composedURI = self.__mDataSourceName + "|layername=" + vfkLayerName layer = QgsVectorLayer(composedURI, vfkLayerName, "ogr") if not layer.isValid(): iface.messageBar().pushWarning(u'ERROR', u"Layer failed to load!") self.__mLoadedLayers[vfkLayerName] = layer.id() try: self.__setSymbology(layer) except VFKWarning as e: QMessageBox.information(self, 'Load Style', e, QMessageBox.Ok) QgsProject.instance().addMapLayer(layer) def __unLoadVfkLayer(self, vfkLayerName): """ :type vfkLayerName: str :return: """ # QgsMessageLog.logMessage("(VFK) Unloading vfk layer {}".format(vfkLayerName)) if vfkLayerName not in self.__mLoadedLayers: # QgsMessageLog.logMessage( # "(VFK) Vfk layer {} is already unloaded".format(vfkLayerName) # ) return QgsProject.instance().removeMapLayer( self.__mLoadedLayers[vfkLayerName]) del self.__mLoadedLayers[vfkLayerName] def __setSymbology(self, layer): """ :type layer: QgsVectorLayer :return: """ name = layer.name() symbologyFile = '' if name == 'PAR': symbologyFile = ':/parStyle.qml' elif name == 'BUD': symbologyFile = ':/budStyle.qml' errorMsg, resultFlag = layer.loadNamedStyle(symbologyFile) if not resultFlag: raise VFKWarning(u'Load style: {}'.format(errorMsg)) layer.triggerRepaint() self.refreshLegend.emit(layer) def __openDatabase(self, dbPath): """ :type dbPath: str :return: """ # QgsMessageLog.logMessage("(VFK) Open DB: {}".format(dbPath)) if not QSqlDatabase.isDriverAvailable('QSQLITE'): raise VFKError(u'Databázový ovladač QSQLITE není dostupný.') connectionName = QUuid.createUuid().toString() db = QSqlDatabase.addDatabase("QSQLITE", connectionName) db.setDatabaseName(dbPath) if not db.open(): raise VFKError(u'Nepodařilo se otevřít databázi. ') self.setProperty("connectionName", connectionName) def loadVfkFile(self, fileName): """ :type fileName: str :return: """ label_text = fileName.split('/') label_text = '...' + label_text[-2] + '/' + label_text[-1] # overwrite database if fileName == self.__fileName[0]: if self.overwriteCheckBox.isChecked(): # QgsMessageLog.logMessage(u'(VFK) Database will be overwritten') gdal.SetConfigOption('OGR_VFK_DB_OVERWRITE', 'YES') if self.__mOgrDataSource: self.__mOgrDataSource.Destroy() self.__mOgrDataSource = None QgsApplication.registerOgrDrivers() self.progressBar.setRange(0, 1) self.progressBar.setValue(0) QgsApplication.processEvents() self.labelLoading.setText( u'Načítám soubor {} (může nějaký čas trvat...)'.format(label_text)) QgsApplication.processEvents() self.__mOgrDataSource = ogr.Open( fileName, 0) # 0 - datasource is open in read-only mode if not self.__mOgrDataSource: raise VFKError( u"Nelze otevřít VFK soubor '{}' jako platný OGR datasource.". format(fileName)) layerCount = self.__mOgrDataSource.GetLayerCount() layers_names = [] for i in range(layerCount): layers_names.append( self.__mOgrDataSource.GetLayer(i).GetLayerDefn().GetName()) if ('PAR' not in layers_names or 'BUD' not in layers_names) and len( self.__vfkLineEdits) == 1: self.__dataWithoutParBud() self.labelLoading.setText( u'Data nemohla být načtena. Vstupní soubor neobsahuje bloky PAR a BUD.' ) QgsApplication.processEvents() return # load all layers self.progressBar.setRange(0, layerCount - 1) for i in range(layerCount): self.progressBar.setValue(i) theLayerName = self.__mOgrDataSource.GetLayer( i).GetLayerDefn().GetName() self.labelLoading.setText(u"VFK data {}/{}: {}".format( i + 1, layerCount, theLayerName)) QgsApplication.processEvents() self.__mOgrDataSource.GetLayer(i).GetFeatureCount(True) time.sleep(0.02) self.labelLoading.setText( u'Soubor {} úspěšně načten.'.format(label_text)) gdal.SetConfigOption('OGR_VFK_DB_OVERWRITE', 'NO') self.__mOgrDataSource.Destroy() self.__mOgrDataSource = None def __selectedIds(self, layer): """ :type layer: QgsVectorLayer :return: """ ids = [] flist = layer.selectedFeatures() for it in flist: f = QgsFeature(it) ids.append(str(f.attribute("ID"))) return ids def showInfoAboutSelection(self): layers = ["PAR", "BUD"] layerIds = {} for layer in layers: if layer in self.__mLoadedLayers: id = str(self.__mLoadedLayers[layer]) vectorLayer = QgsProject.instance().mapLayer(id) layerIds[layer] = self.__selectedIds(vectorLayer) self.vfkBrowser.showInfoAboutSelection(layerIds["PAR"], layerIds["BUD"]) def showParInMap(self, ids): """ :type ids: list :return: """ if self.actionShowInfoaboutSelection.isChecked(): self.setSelectionChangedConnected(False) self.showInMap(ids, "PAR") self.setSelectionChangedConnected(True) else: self.showInMap(ids, "PAR") def showBudInMap(self, ids): """ :type ids: list :return: """ if self.actionShowInfoaboutSelection.isChecked(): self.setSelectionChangedConnected(False) self.showInMap(ids, "BUD") self.setSelectionChangedConnected(True) else: self.showInMap(ids, "BUD") def showOnCuzk(self): x = self.vfkBrowser.currentDefinitionPoint().first.split(".")[0] y = self.vfkBrowser.currentDefinitionPoint().second.split(".")[0] url = "http://nahlizenidokn.cuzk.cz/MapaIdentifikace.aspx?&x=-{}&y=-{}".format( y, x) QDesktopServices.openUrl(QUrl(url, QUrl.TolerantMode)) def switchToImport(self): self.actionImport.trigger() def switchToSearch(self, searchType): """ :type searchType: int """ self.actionVyhledavani.trigger() self.searchCombo.setCurrentIndex(searchType) self.searchFormMainControls.searchForms.setCurrentIndex(searchType) def switchToChanges(self): """ """ self.actionZpracujZmeny.trigger() def succesfullExport(self, export_format): """ :type export_format: str :return: """ QMessageBox.information( self, u'Export', u"Export do formátu {} proběhl úspěšně.".format(export_format), QMessageBox.Ok) def __dataWithoutParBud(self): """ :type export_format: str :return: """ QMessageBox.warning( self, u'Upozornění', u"Zvolený VFK soubor neobsahuje vrstvy s geometrií (PAR, BUD), proto nemohou " u"být pomocí VFK Pluginu načtena. Data je možné načíst v QGIS pomocí volby " u"'Načíst vektorovou vrstvu.'", QMessageBox.Ok) def __addRowToGridLayout(self): if len(self.__vfkLineEdits) >= 5: self.__maximumLineEditsReached() return # update label self.label.setText('VFK soubory:') # new layout horizontalLayout = QtWidgets.QHBoxLayout() # create new objects self.__browseButtons['browseButton_{}'.format( len(self.__vfkLineEdits) + 1)] = QtWidgets.QPushButton(u"Procházet") self.__vfkLineEdits['vfkLineEdit_{}'.format( len(self.__vfkLineEdits) + 1)] = QtWidgets.QLineEdit() horizontalLayout.addWidget(self.__vfkLineEdits['vfkLineEdit_{}'.format( len(self.__vfkLineEdits))]) horizontalLayout.addWidget( self.__browseButtons['browseButton_{}'.format( len(self.__vfkLineEdits))]) # number of lines in gridLayout rows_count = self.gridLayout_12.rowCount( ) # count of rows in gridLayout # export objects from gridLayout item_label = self.gridLayout_12.itemAtPosition(rows_count - 3, 0) item_par = self.gridLayout_12.itemAtPosition(rows_count - 3, 1) item_bud = self.gridLayout_12.itemAtPosition(rows_count - 2, 1) item_settings = self.gridLayout_12.itemAtPosition(rows_count - 1, 0) item_rewrite_db = self.gridLayout_12.itemAtPosition(rows_count - 1, 1) # remove objects from gridLayout self.gridLayout_12.removeItem( self.gridLayout_12.itemAtPosition(rows_count - 3, 0)) self.gridLayout_12.removeItem( self.gridLayout_12.itemAtPosition(rows_count - 3, 1)) self.gridLayout_12.removeItem( self.gridLayout_12.itemAtPosition(rows_count - 2, 1)) self.gridLayout_12.removeItem( self.gridLayout_12.itemAtPosition(rows_count - 1, 0)) self.gridLayout_12.removeItem( self.gridLayout_12.itemAtPosition(rows_count - 1, 1)) # re-build gridLayout self.gridLayout_12.addLayout(horizontalLayout, rows_count - 3, 1) self.gridLayout_12.addItem(item_label, rows_count - 2, 0) self.gridLayout_12.addItem(item_par, rows_count - 2, 1) self.gridLayout_12.addItem(item_bud, rows_count - 1, 1) self.gridLayout_12.addItem(item_settings, rows_count, 0) self.gridLayout_12.addItem(item_rewrite_db, rows_count, 1) self.__browseButtons['browseButton_{}'.format(len(self.__vfkLineEdits))].clicked.\ connect(lambda: self.browseButton_clicked( int('{}'.format(len(self.__vfkLineEdits))))) def __maximumLineEditsReached(self): QMessageBox.information( self, u'Upozornění', u"Byl dosažen maximální počet ({}) VFK souboru pro zpracování." u"\nNačítání dalších souborů není povoleno!".format( self.lineEditsCount), QMessageBox.Ok) def browseDb_clicked(self, database_type): """ Method run dialog for select database in widget with changes. According to pushButton name will fill in relevant lineEdit. :type database_type: str """ title = u'Vyber databázi' settings = QSettings() lastUsedDir = str( settings.value('/UI/' + "lastVectorFileFilter" + "Dir", ".")) if database_type == 'mainDb': self.__databases[database_type] = QFileDialog.getOpenFileName( self, title, lastUsedDir, u'Datábaze (*.db)') if not self.__databases[database_type]: return self.le_mainDb.setText(str(self.__databases[database_type])) elif database_type == 'amendmentDb': self.__databases[database_type] = QFileDialog.getOpenFileName( self, title, lastUsedDir, u'Datábaze (*.db)') if not self.__databases[database_type]: return self.le_amendmentDb.setText(str(self.__databases[database_type])) elif database_type == 'exportDb': title = u'Zadej jméno výstupní databáze' self.__databases[database_type] = QFileDialog.getSaveFileName( self, u"Jméno výstupní databáze", ".db", u"Databáze (*.db)") if not self.__databases[database_type]: return self.le_exportDb.setText(str(self.__databases[database_type])) if len(self.__databases) == 3: self.pb_applyChanges.setEnabled(True) def applyChanges(self): """ Method :return: """ self.changes_instance.run(self.__databases['mainDb'], self.__databases['amendmentDb'], self.__databases['exportDb']) def __updateProgressBarChanges(self, iteration, table_name): """ :type iteration: int :type table_name: str """ self.progressBar_changes.setValue(iteration) self.l_status.setText( u'Aplikuji změny na tabulku {}...'.format(table_name)) QgsApplication.processEvents() def __setRangeProgressBarChanges(self, max_range): """ :type max_range: int """ self.progressBar_changes.setRange(0, max_range) self.progressBar_changes.setValue(0) def __changesApplied(self): """ """ time.sleep(1) self.l_status.setText(u'Změny byly úspěšně aplikovány.') QgsApplication.processEvents() def __changesPreprocessingDatabase(self): """ """ self.l_status.setText(u'Připravuji výstupní databázi...') QgsApplication.processEvents() def __checkIfAmendmentFile(self, file_name): """ :param file_name: Name of the input file :type file_name: str :return: bool """ if file_name.endswith(".vfk"): with open(file_name, 'rb') as f: for line in f: line_splited = str(line).split(';') if line_splited[0] == '&HZMENY': if line_splited[1] == '1': return True else: return False else: # fix_print_with_import print('database') # TODO: dopsat kontrolu, zda se jedna o stavovou, nebo zmenovou databazi def radioButtonValue(self): """ Check which radio button is checked """ self.vfkFileLineEdit.setText('') self.__fileName = [] self.loadVfkButton.setEnabled(False) if self.rb_file.isChecked(): self.__source_for_data = 'file' self.pb_nextFile.show() self.label.setText('VFK soubor:') elif self.rb_directory.isChecked(): self.__source_for_data = 'directory' self.pb_nextFile.hide() self.label.setText(u'Adresář:') # delete if len(self.__browseButtons) > 1: for i, button in enumerate(self.__browseButtons): if i > 0: self.__browseButtons[button].hide() if len(self.__vfkLineEdits) > 1: for i, le in enumerate(self.__vfkLineEdits): if i > 0: self.__vfkLineEdits[le].hide() def __findVFKFilesInDirectory(self, dir_path): """ Finds all files with extension '.vfk' in given directory including subdirectories :param dir_path: Path to directory. :type dir_path: str :return: List of VFK files """ file_paths = [] for root, dirs, files in os.walk(dir_path): for file in files: if file.endswith(".vfk"): file_paths.append(os.path.join(root, file)) return file_paths def __createToolbarsAndConnect(self): actionGroup = QActionGroup(self) actionGroup.addAction(self.actionImport) actionGroup.addAction(self.actionVyhledavani) actionGroup.addAction(self.actionZpracujZmeny) # QSignalMapper self.signalMapper = QtCore.QSignalMapper(self) self.actionImport.triggered.connect(self.signalMapper.map) self.actionVyhledavani.triggered.connect(self.signalMapper.map) self.actionZpracujZmeny.triggered.connect(self.signalMapper.map) # setMapping on each button to the QStackedWidget index we'd like to # switch to self.signalMapper.setMapping(self.actionImport, 0) self.signalMapper.setMapping(self.actionVyhledavani, 2) self.signalMapper.setMapping(self.actionZpracujZmeny, 1) # connect mapper to stackedWidget self.signalMapper.mapped.connect(self.stackedWidget.setCurrentIndex) self.vfkBrowser.switchToPanelImport.connect(self.switchToImport) self.vfkBrowser.switchToPanelSearch.connect(self.switchToSearch) self.vfkBrowser.switchToPanelChanges.connect(self.switchToChanges) # Browser toolbar # --------------- self.__mBrowserToolbar = QToolBar(self) self.actionBack.triggered.connect(self.vfkBrowser.goBack) self.actionForward.triggered.connect(self.vfkBrowser.goForth) self.actionSelectBudInMap.triggered.connect(self.selectBudInMap) self.actionSelectParInMap.triggered.connect(self.selectParInMap) self.actionCuzkPage.triggered.connect(self.showOnCuzk) self.actionExportLatex.triggered.connect(self.latexExport) self.actionExportHtml.triggered.connect(self.htmlExport) self.actionShowInfoaboutSelection.toggled.connect( self.setSelectionChangedConnected) self.actionShowHelpPage.triggered.connect(self.vfkBrowser.showHelpPage) self.loadVfkButton.clicked.connect(self.loadVfkButton_clicked) self.__browseButtons['browseButton_1'] = self.browseButton self.__browseButtons['browseButton_1'].clicked.connect( lambda: self.browseButton_clicked( int('{}'.format(len(self.__vfkLineEdits))))) self.__vfkLineEdits['vfkLineEdit_1'] = self.vfkFileLineEdit bt = QToolButton(self.__mBrowserToolbar) bt.setPopupMode(QToolButton.InstantPopup) bt.setText("Export ") menu = QMenu(bt) menu.addAction(self.actionExportLatex) menu.addAction(self.actionExportHtml) bt.setMenu(menu) # add actions to toolbar icons self.__mBrowserToolbar.addAction(self.actionImport) self.__mBrowserToolbar.addAction(self.actionVyhledavani) self.__mBrowserToolbar.addAction(self.actionZpracujZmeny) self.__mBrowserToolbar.addSeparator() self.__mBrowserToolbar.addAction(self.actionBack) self.__mBrowserToolbar.addAction(self.actionForward) self.__mBrowserToolbar.addAction(self.actionSelectParInMap) self.__mBrowserToolbar.addAction(self.actionSelectBudInMap) self.__mBrowserToolbar.addAction(self.actionCuzkPage) self.__mBrowserToolbar.addSeparator() self.__mBrowserToolbar.addAction(self.actionShowInfoaboutSelection) self.__mBrowserToolbar.addSeparator() self.__mBrowserToolbar.addWidget(bt) self.__mBrowserToolbar.addSeparator() self.__mBrowserToolbar.addAction(self.actionShowHelpPage) self.rightWidgetLayout.insertWidget(0, self.__mBrowserToolbar) # connect signals from vfkbrowser when changing history self.vfkBrowser.currentParIdsChanged.connect( self.actionSelectParInMap.setEnabled) self.vfkBrowser.currentBudIdsChanged.connect( self.actionSelectBudInMap.setEnabled) self.vfkBrowser.historyBefore.connect(self.actionBack.setEnabled) self.vfkBrowser.historyAfter.connect(self.actionForward.setEnabled) self.vfkBrowser.definitionPointAvailable.connect( self.actionCuzkPage.setEnabled) # add toolTips self.pb_nextFile.setToolTip(u'Přidej další soubor VFK') self.parCheckBox.setToolTip(u'Načti vrstvu parcel') self.budCheckBox.setToolTip(u'Načti vrstvu budov') # add new VFK file self.pb_nextFile.clicked.connect(self.__addRowToGridLayout) # widget apply changes self.pb_mainDb.clicked.connect(lambda: self.browseDb_clicked('mainDb')) self.pb_amendmentDb.clicked.connect( lambda: self.browseDb_clicked('amendmentDb')) self.pb_exportDb.clicked.connect( lambda: self.browseDb_clicked('exportDb')) self.pb_applyChanges.clicked.connect(self.applyChanges) self.pb_applyChanges.setEnabled(False) self.changes_instance.maxRangeProgressBar.connect( self.__setRangeProgressBarChanges) self.changes_instance.updateStatus.connect( self.__updateProgressBarChanges) self.changes_instance.finishedStatus.connect(self.__changesApplied) self.changes_instance.preprocessingDatabase.connect( self.__changesPreprocessingDatabase) # connect radio boxes self.rb_file.clicked.connect(self.radioButtonValue) self.rb_directory.clicked.connect(self.radioButtonValue)
class _CameraWidget(QWidget): imagecaptured = pyqtSignal(QPixmap) cancel = pyqtSignal() def __init__(self, parent=None): super(_CameraWidget, self).__init__(parent) self.setLayout(QGridLayout()) self.toolbar = QToolBar() spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.toolbar.setIconSize(QSize(48, 48)) self.toolbar.addWidget(spacer) self.swapaction = self.toolbar.addAction(QIcon(":/widgets/cameraswap"), "Swap Camera") self.swapaction.triggered.connect(self.swapcamera) self.current_camera_index = 0 self.camera = None self.viewfinder = QCameraViewfinder() self.viewfinder.mousePressEvent = self.capture self.viewfinder.setAspectRatioMode(Qt.KeepAspectRatioByExpanding) self.update_camera_buttons() self.capturebutton = QPushButton("Capture", self) self.capturebutton.pressed.connect(self.capture) self.actionCancel = self.toolbar.addAction(QIcon(":/icons/cancel"), "Cancel") self.actionCancel.triggered.connect(self._cancel) self.layout().setContentsMargins(0, 0, 0, 0) self.layout().addWidget(self.toolbar) self.layout().addWidget(self.viewfinder) self.layout().addWidget(self.capturebutton) self.viewfinder.show() def __del__(self): if self.camera: self.camera.unload() def _cancel(self): if self.camera: self.camera.unload() self.cancel.emit() @property def list_of_cameras(self): return QCameraInfo.availableCameras() def update_camera_buttons(self): if len(self.list_of_cameras) <= 1: self.swapaction.setVisible(False) def capture(self, *args): self.camera.searchAndLock() self.camera_capture.capture() self.camera.unlock() def swapcamera(self): cameras = QCameraInfo.availableCameras() if self.current_camera_index + 1 == len(cameras): self.current_camera_index = 0 else: self.current_camera_index += 1 self.start(self.current_camera_index) @property def camera_res(self): width, height = tuple(roam.config.settings['camera_res'].split(',')) return width, height def imageCaptured(self, frameid, image): # TODO Doing a pixmap convert here is a waste but downstream needs a qpixmap for now # refactor later if self.camera: self.camera.unload() self.imagecaptured.emit(QPixmap.fromImage(image)) def start(self, dev=1): if self.camera: self.camera.unload() cameras = QCameraInfo.availableCameras() self.camera = QCamera(cameras[dev]) self.camera.setViewfinder(self.viewfinder) self.camera.setCaptureMode(QCamera.CaptureStillImage) self.camera.start() self.camera_capture = QCameraImageCapture(self.camera) self.camera_capture.setCaptureDestination( QCameraImageCapture.CaptureToBuffer) self.camera_capture.imageCaptured.connect(self.imageCaptured)
def __init__(self, iface): locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join(os.path.dirname(__file__), 'i18n', 'annotationManager_{}.qm'.format(locale)) self.translator = None if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) if qVersion() > '4.3.3': QCoreApplication.installTranslator(self.translator) self.iface = iface self.iface.projectRead.connect(self.projectOpen) self.dock = QDockWidget(self.tr('Annotations')) self.manager = QWidget() toolbar = QToolBar() self.annotationList = QListWidget() self.annotationList.setSelectionMode( QAbstractItemView.ExtendedSelection) self.annotationList.itemSelectionChanged.connect(self.selectAnnotation) self.annotationList.itemChanged.connect(self.checkItem) action_refresh = QAction( QIcon(':/plugins/annotationManager/resources/mActionDraw.png'), self.tr('Refresh the annotations list'), self.manager) action_refresh.triggered.connect(self.refreshAnnotations) action_remove = QAction( QIcon( ':/plugins/annotationManager/resources/mActionRemoveAnnotation.png' ), self.tr('Remove the selected annotation'), self.manager) action_remove.triggered.connect(self.removeAnnotation) viewMenu = QMenu() action_showAll = QAction( QIcon(':/plugins/annotationManager/resources/mActionShowAll.png'), self.tr('Show all annotations'), self.manager) action_showAll.triggered.connect(self.showAll) action_hideAll = QAction( QIcon(':/plugins/annotationManager/resources/mActionHideAll.png'), self.tr('Hide all annotations'), self.manager) action_hideAll.triggered.connect(self.hideAll) action_showAllSelected = QAction( QIcon(':/plugins/annotationManager/resources/mActionShowAll.png'), self.tr('Show all selected annotations'), self.manager) action_showAllSelected.triggered.connect(self.showAllSelected) action_hideAllSelected = QAction( QIcon(':/plugins/annotationManager/resources/mActionHideAll.png'), self.tr('Hide all selected annotations'), self.manager) action_hideAllSelected.triggered.connect(self.hideAllSelected) viewMenu.addAction(action_showAll) viewMenu.addAction(action_hideAll) viewMenu.addAction(action_showAllSelected) viewMenu.addAction(action_hideAllSelected) viewButton = QToolButton() viewButton.setIcon( QIcon(':/plugins/annotationManager/resources/mActionShowAll.png')) viewButton.setPopupMode(2) viewButton.setMenu(viewMenu) toolbar.addAction(action_refresh) toolbar.addAction(action_remove) toolbar.addWidget(viewButton) toolbar.setIconSize(QSize(16, 16)) p1_vertical = QVBoxLayout() p1_vertical.setContentsMargins(0, 0, 0, 0) p1_vertical.addWidget(toolbar) p1_vertical.addWidget(self.annotationList) self.manager.setLayout(p1_vertical) self.dock.setWidget(self.manager) self.dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.dock) self.rb = QgsRubberBand(self.iface.mapCanvas(), QgsWkbTypes.PolygonGeometry) self.project = QgsProject.instance() self.annotationManager = self.project.annotationManager() self.annotationManager.annotationAdded.connect(self.refreshAnnotations) self.annotationManager.annotationRemoved.connect( self.refreshAnnotations)
class AequilibraEMenu: def __init__(self, iface): self.translator = None self.iface = iface self.project = None # type: Project self.link_layer = None # type: QgsVectorLayer self.node_layer = None # type: QgsVectorLayer self.dock = QDockWidget(self.trlt('AequilibraE')) self.manager = QWidget() # The self.toolbar will hold everything self.toolbar = QToolBar() self.toolbar.setOrientation(2) # # ######################################################################## # # ####################### PROJECT SUB-MENU ############################ projectMenu = QMenu() self.open_project_action = QAction(self.trlt('Open Project'), self.manager) self.open_project_action.triggered.connect(self.run_load_project) projectMenu.addAction(self.open_project_action) self.project_from_osm_action = QAction( self.trlt('Create project from OSM'), self.manager) self.project_from_osm_action.triggered.connect( self.run_project_from_osm) projectMenu.addAction(self.project_from_osm_action) self.create_transponet_action = QAction( self.trlt('Create Project from layers'), self.manager) self.create_transponet_action.triggered.connect( self.run_create_transponet) projectMenu.addAction(self.create_transponet_action) projectButton = QToolButton() projectButton.setText(self.trlt('Project')) projectButton.setPopupMode(2) projectButton.setMenu(projectMenu) self.toolbar.addWidget(projectButton) # # ######################################################################## # # ################# NETWORK MANIPULATION SUB-MENU ####################### netMenu = QMenu() self.action_netPrep = QAction(self.trlt('Network Preparation'), self.manager) self.action_netPrep.triggered.connect(self.run_net_prep) netMenu.addAction(self.action_netPrep) self.add_connectors_action = QAction( self.trlt('Add centroid connectors'), self.manager) self.add_connectors_action.triggered.connect(self.run_add_connectors) netMenu.addAction(self.add_connectors_action) netbutton = QToolButton() netbutton.setText(self.trlt('Network Manipulation')) netbutton.setMenu(netMenu) netbutton.setPopupMode(2) self.toolbar.addWidget(netbutton) # # ######################################################################## # # #################### DATA UTILITIES SUB-MENU ######################### dataMenu = QMenu() self.display_custom_formats_action = QAction( self.trlt('Display AequilibraE formats'), self.manager) self.display_custom_formats_action.triggered.connect( self.run_display_aequilibrae_formats) dataMenu.addAction(self.display_custom_formats_action) self.load_matrix_action = QAction(self.trlt('Import matrices'), self.manager) self.load_matrix_action.triggered.connect(self.run_load_matrices) dataMenu.addAction(self.load_matrix_action) self.load_database_action = QAction(self.trlt('Import dataset'), self.manager) self.load_database_action.triggered.connect(self.run_load_database) dataMenu.addAction(self.load_database_action) databutton = QToolButton() databutton.setText(self.trlt('Data')) databutton.setPopupMode(2) databutton.setMenu(dataMenu) self.toolbar.addWidget(databutton) # # # ######################################################################## # # # ################## TRIP DISTRIBUTION SUB-MENU ######################## distributionButton = QToolButton() distributionButton.setText(self.trlt('Trip Distribution')) distributionButton.clicked.connect(self.run_distribution_models) self.toolbar.addWidget(distributionButton) # # ######################################################################## # # ################### PATH COMPUTATION SUB-MENU ####################### pathMenu = QMenu() self.shortest_path_action = QAction(self.trlt('Shortest path'), self.manager) self.shortest_path_action.triggered.connect(self.run_shortest_path) pathMenu.addAction(self.shortest_path_action) self.dist_matrix_action = QAction(self.trlt('Impedance matrix'), self.manager) self.dist_matrix_action.triggered.connect(self.run_dist_matrix) pathMenu.addAction(self.dist_matrix_action) self.traffic_assignment_action = QAction( self.trlt('Traffic Assignment'), self.manager) self.traffic_assignment_action.triggered.connect( self.run_traffic_assig) pathMenu.addAction(self.traffic_assignment_action) pathButton = QToolButton() pathButton.setText(self.trlt('Paths and assignment')) pathButton.setPopupMode(2) pathButton.setMenu(pathMenu) self.toolbar.addWidget(pathButton) # # ######################################################################## # # ####################### ROUTING SUB-MENU ########################### if has_ortools: routingMenu = QMenu() self.tsp_action = QAction(self.trlt('Travelling Salesman Problem'), self.manager) self.tsp_action.triggered.connect(self.run_tsp) routingMenu.addAction(self.tsp_action) routingButton = QToolButton() routingButton.setText(self.trlt('Routing')) routingButton.setPopupMode(2) routingButton.setMenu(routingMenu) self.toolbar.addWidget(routingButton) # # ######################################################################## # # ####################### TRANSIT SUB-MENU ########################### transitMenu = QMenu() self.gtfs_import_action = QAction( self.trlt('Convert GTFS to SpatiaLite'), self.manager) self.gtfs_import_action.triggered.connect(self.run_import_gtfs) transitMenu.addAction(self.gtfs_import_action) transitButton = QToolButton() transitButton.setText(self.trlt('Public Transport')) transitButton.setPopupMode(2) transitButton.setMenu(transitMenu) self.toolbar.addWidget(transitButton) # ######################################################################## # ################# GIS TOOLS SUB-MENU ######################### gisMenu = QMenu() self.simple_tag_action = QAction(self.trlt('Simple tag'), self.manager) self.simple_tag_action.triggered.connect(self.run_simple_tag) gisMenu.addAction(self.simple_tag_action) self.lcd_action = QAction(self.trlt('Lowest common denominator'), self.manager) self.lcd_action.triggered.connect(self.run_lcd) gisMenu.addAction(self.lcd_action) self.dlines_action = QAction(self.trlt('Desire Lines'), self.manager) self.dlines_action.triggered.connect(self.run_dlines) gisMenu.addAction(self.dlines_action) self.bandwidth_action = QAction(self.trlt('Stacked Bandwidth'), self.manager) self.bandwidth_action.triggered.connect(self.run_bandwidth) gisMenu.addAction(self.bandwidth_action) self.scenario_comparison_action = QAction( self.trlt('Scenario Comparison'), self.manager) self.scenario_comparison_action.triggered.connect( self.run_scenario_comparison) gisMenu.addAction(self.scenario_comparison_action) gisButton = QToolButton() gisButton.setText(self.trlt('GIS')) gisButton.setPopupMode(2) gisButton.setMenu(gisMenu) self.toolbar.addWidget(gisButton) # ######################################################################## # ################# LOOSE STUFF ######################### parametersButton = QToolButton() parametersButton.setText(self.trlt('Parameters')) parametersButton.clicked.connect(self.run_change_parameters) self.toolbar.addWidget(parametersButton) aboutButton = QToolButton() aboutButton.setText(self.trlt('About')) aboutButton.clicked.connect(self.run_about) self.toolbar.addWidget(aboutButton) logButton = QToolButton() logButton.setText(self.trlt('logfile')) logButton.clicked.connect(self.run_log) self.toolbar.addWidget(logButton) helpButton = QToolButton() helpButton.setText(self.trlt('Help')) helpButton.clicked.connect(self.run_help) self.toolbar.addWidget(helpButton) if no_binary: binariesButton = QToolButton() binariesButton.setText(self.trlt('Download binaries')) binariesButton.clicked.connect(self.run_binary_download) self.toolbar.addWidget(binariesButton) if not extra_packages: xtrapkgButton = QToolButton() xtrapkgButton.setText(self.trlt('Install extra packages')) xtrapkgButton.clicked.connect(self.install_extra_packages) self.toolbar.addWidget(xtrapkgButton) # ######################################################################## # ################# PROJECT MANAGER ######################### self.showing = QCheckBox() self.showing.setText('Show project info') self.showing.setChecked(True) self.toolbar.addWidget(self.showing) self.showing.toggled.connect(self.hide_info_pannel) self.projectManager = QTabWidget() self.toolbar.addWidget(self.projectManager) # # # ######################################################################## self.tabContents = [] self.toolbar.setIconSize(QSize(16, 16)) p1_vertical = QVBoxLayout() p1_vertical.setContentsMargins(0, 0, 0, 0) p1_vertical.addWidget(self.toolbar) self.manager.setLayout(p1_vertical) self.dock.setWidget(self.manager) self.dock.setAllowedAreas(Qt.LeftDockWidgetArea | Qt.RightDockWidgetArea) self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.dock) def run_help(self): url = 'http://aequilibrae.com/qgis' if sys.platform == 'darwin': # in case of OS X subprocess.Popen(['open', url]) else: webbrowser.open_new_tab(url) def run_log(self): dlg2 = LogDialog(self.iface) dlg2.show() dlg2.exec_() def unload(self): del self.dock def trlt(self, message): # In the near future, we will use this function to automatically translate the AequilibraE menu # To any language we can get people to translate it to # return QCoreApplication.translate('AequilibraE', message) return message def initGui(self): pass def removes_temporary_files(self): # pass # Removes all the temporary files from previous uses p = tempfile.gettempdir() + "/aequilibrae_*" for f in glob.glob(p): try: os.unlink(f) except: pass def hide_info_pannel(self): if len(self.tabContents) > 0: if self.showing.isChecked(): for v in self.tabContents: self.projectManager.addTab(v[0], v[1]) else: tab_count = 1 for i in range(tab_count): self.projectManager.removeTab(i) def run_load_project(self): formats = ["AequilibraE Project(*.sqlite)"] path, dtype = GetOutputFileName( QtWidgets.QDialog(), "AequilibraE Project", formats, ".sqlite", standard_path(), ) # Cleans the project descriptor tab_count = 1 for i in range(tab_count): self.projectManager.removeTab(i) if dtype is not None: self.contents = [] self.showing.setVisible(True) self.project = Project() self.project.load(path) self.project.conn = qgis.utils.spatialite_connect(path) self.project.network.conn = self.project.conn uri = QgsDataSourceUri() uri.setDatabase(path) uri.setDataSource('', 'links', 'geometry') self.link_layer = QgsVectorLayer(uri.uri(), 'links', 'spatialite') QgsProject.instance().addMapLayer(self.link_layer) uri.setDataSource('', 'nodes', 'geometry') self.node_layer = QgsVectorLayer(uri.uri(), 'nodes', 'spatialite') QgsProject.instance().addMapLayer(self.node_layer) descr = QWidget() descrlayout = QVBoxLayout() # We create a tab with the main description of the project p1 = QLabel('Project: {}'.format(path)) p2 = QLabel('Modes: {}'.format(', '.join( self.project.network.modes()))) p3 = QLabel('Total Links: {:,}'.format( self.project.network.count_links())) p4 = QLabel('Total Nodes: {:,}'.format( self.project.network.count_nodes())) for p in [p1, p2, p3, p4]: descrlayout.addWidget(p) descr.setLayout(descrlayout) self.tabContents = [(descr, "Project")] self.projectManager.addTab(descr, "Project") def run_change_parameters(self): dlg2 = ParameterDialog(self.iface) dlg2.show() dlg2.exec_() def run_about(self): dlg2 = AboutDialog(self.iface) dlg2.show() dlg2.exec_() def run_load_matrices(self): dlg2 = LoadMatrixDialog(self.iface, sparse=True, multiple=True, single_use=False) dlg2.show() dlg2.exec_() def run_load_database(self): dlg2 = LoadDatasetDialog(self.iface, single_use=False) dlg2.show() dlg2.exec_() def run_display_aequilibrae_formats(self): dlg2 = DisplayAequilibraEFormatsDialog(self.iface) dlg2.show() dlg2.exec_() def install_extra_packages(self): dlg2 = DownloadExtraPackages(self.iface) dlg2.show() dlg2.exec_() def run_binary_download(self): dlg2 = BinaryDownloaderDialog(self.iface) dlg2.show() dlg2.exec_() # run method that calls the network preparation section of the code def run_net_prep(self): dlg2 = NetworkPreparationDialog(self.iface) dlg2.show() dlg2.exec_() # If we wanted modal, we would eliminate the dlg2.show() # run method that calls the network preparation section of the code def run_create_transponet(self): if no_binary: self.message_binary() else: dlg2 = CreatesTranspoNetDialog(self.iface) dlg2.show() dlg2.exec_() # If we wanted modal, we would eliminate the dlg2.show() def run_add_connectors(self): dlg2 = AddConnectorsDialog(self.iface, self.project) dlg2.show() dlg2.exec_() def run_distribution_models(self): dlg2 = DistributionModelsDialog(self.iface) dlg2.show() dlg2.exec_() def run_shortest_path(self): if no_binary: self.message_binary() else: if self.project is None: self.show_message_no_project() else: dlg2 = ShortestPathDialog(self.iface, self.project, self.link_layer, self.node_layer) dlg2.show() dlg2.exec_() def run_dist_matrix(self): if no_binary: self.message_binary() else: if self.project is None: self.show_message_no_project() else: dlg2 = ImpedanceMatrixDialog(self.iface, self.project, self.link_layer) dlg2.show() dlg2.exec_() def run_traffic_assig(self): if no_binary: self.message_binary() else: if self.project is None: self.show_message_no_project() else: dlg2 = TrafficAssignmentDialog(self.iface, self.project, self.link_layer) dlg2.show() dlg2.exec_() def run_tsp(self): if self.project is None: self.show_message_no_project() else: dlg2 = TSPDialog(self.iface, self.project, self.link_layer, self.node_layer) dlg2.show() dlg2.exec_() def run_import_gtfs(self): dlg2 = GtfsImportDialog(self.iface) dlg2.show() dlg2.exec_() def run_project_from_osm(self): dlg2 = ProjectFromOSMDialog(self.iface) dlg2.show() dlg2.exec_() def run_simple_tag(self): dlg2 = SimpleTagDialog(self.iface) dlg2.show() dlg2.exec_() def run_lcd(self): dlg2 = LeastCommonDenominatorDialog(self.iface) dlg2.show() dlg2.exec_() def run_dlines(self): if no_binary: self.message_binary() else: dlg2 = DesireLinesDialog(self.iface) dlg2.show() dlg2.exec_() def run_bandwidth(self): dlg2 = CreateBandwidthsDialog(self.iface) dlg2.show() dlg2.exec_() def run_scenario_comparison(self): dlg2 = CompareScenariosDialog(self.iface) dlg2.show() dlg2.exec_() def message_binary(self): qgis.utils.iface.messageBar().pushMessage( "Binary Error: ", "Please download it from the repository using the downloader from the menu", level=3) def show_message_no_project(self): self.iface.messageBar().pushMessage("Error", "You need to load a project first", level=3, duration=10)
class VertexComparePlugin(QObject): """QGIS Plugin Implementation.""" def __init__(self, iface: QgisInterface): """Constructor. :param iface: An interface instance that will be passed to this class which provides the hook by which you can manipulate the QGIS application at run time. :type iface: QgsInterface """ super().__init__() # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QgsApplication.locale() locale_path = os.path.join(self.plugin_dir, 'i18n', '{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) QCoreApplication.installTranslator(self.translator) self.toolbar = None self.layer_combo = None self.actions = [] self.dock = None self.vertex_highlighter = VertexHighlighterManager() self.selection_handler = SelectionHandler(self) self.show_vertices_action = None self.show_topology_action = None self.show_dock_action = None @staticmethod def tr(message): """Get the translation for a string using Qt translation API. We implement this ourselves since we do not inherit QObject. :param message: String for translation. :type message: str, QString :returns: Translated version of message. :rtype: QString """ # noinspection PyTypeChecker,PyArgumentList,PyCallByClass return QCoreApplication.translate('VertexCompare', message) def initProcessing(self): """Create the Processing provider""" def initGui(self): """Creates application GUI widgets""" self.initProcessing() self.dock = VertexDockWidget(self.iface.mapCanvas()) self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dock) self.dock.setUserVisible(False) self.toolbar = QToolBar(self.tr('Vertex Compare Toolbar')) self.toolbar.setObjectName('vertexCompareToolbar') self.iface.addToolBar(self.toolbar) self.layer_combo = QgsMapLayerComboBox() self.layer_combo.setAllowEmptyLayer(True, self.tr('Disabled')) self.layer_combo.setFilters(QgsMapLayerProxyModel.PolygonLayer | QgsMapLayerProxyModel.LineLayer) self.layer_combo.setMinimumWidth( QFontMetrics(self.layer_combo.font()).width('x') * 40) self.layer_combo.setCurrentIndex(0) self.layer_combo.layerChanged.connect(self._set_layer) self.toolbar.addWidget(self.layer_combo) self.show_vertices_action = QAction(self.tr("Show Vertex Numbers"), self) self.show_vertices_action.setIcon( GuiUtils.get_icon('show_vertex_numbers.svg')) self.show_vertices_action.setCheckable(True) self.show_vertices_action.setEnabled(False) self.actions.append(self.show_vertices_action) self.toolbar.addAction(self.show_vertices_action) self.show_vertices_action.toggled.connect( self.vertex_highlighter.set_visible) self.show_topology_action = QAction(self.tr("Compare Vertices"), self) self.show_topology_action.setIcon(GuiUtils.get_icon('topology.svg')) self.show_topology_action.setCheckable(True) self.actions.append(self.show_topology_action) self.toolbar.addAction(self.show_topology_action) self.show_topology_action.toggled.connect( self.vertex_highlighter.set_topological) self.show_dock_action = QAction(self.tr('Show Vertices'), parent=self.toolbar) self.show_dock_action.setIcon(GuiUtils.get_icon('vertex_table.svg')) self.toolbar.addAction(self.show_dock_action) self.actions.append(self.show_dock_action) self.dock.setToggleVisibilityAction(self.show_dock_action) self.selection_handler.selection_changed.connect( self._selection_changed) self.dock.label_filter_changed.connect(self.vertex_highlighter.redraw) self.dock.vertex_symbol_changed.connect(self.vertex_highlighter.redraw) self.dock.vertex_text_format_changed.connect( self.vertex_highlighter.redraw) self.dock.selected_vertex_changed.connect( self.vertex_highlighter.set_selected_vertex) def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" for a in self.actions: a.deleteLater() self.actions = [] if self.toolbar is not None: self.toolbar.deleteLater() self.toolbar = None if self.dock is not None: self.dock.deleteLater() self.dock = None def _set_layer(self, layer: Optional[QgsVectorLayer]): """ Triggered when the selected layer is changed """ self.selection_handler.set_layer(layer) self.vertex_highlighter.set_layer(layer) self.show_vertices_action.setEnabled(layer is not None) if not self.show_vertices_action.isEnabled(): self.show_vertices_action.setChecked(False) else: self.show_vertices_action.setChecked(True) self.dock.set_selection( layer, layer.selectedFeatureIds() if layer is not None else []) def _selection_changed(self, layer: Optional[QgsVectorLayer], selection: List[int]): """ Triggered when the watched layer's selection is changed """ self.dock.set_selection(layer, selection)