class ButtonLineEdit(QLineEdit): buttonClicked = pyqtSignal() def __init__(self, parent=None): super(ButtonLineEdit, self).__init__(parent) self.setPlaceholderText("Search") self.btnSearch = QToolButton(self) self.btnSearch.setIcon(QIcon(os.path.join(pluginPath, "icons", "search.svg"))) self.btnSearch.setStyleSheet("QToolButton { padding: 0px; }") self.btnSearch.setCursor(Qt.ArrowCursor) self.btnSearch.clicked.connect(self.buttonClicked.emit) frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) buttonSize = self.btnSearch.sizeHint() self.setStyleSheet("QLineEdit {{padding-right: {}px; }}".format(buttonSize.width() + frameWidth + 1)) self.setMinimumSize(max(self.minimumSizeHint().width(), buttonSize.width() + frameWidth * 2 + 2), max(self.minimumSizeHint().height(), buttonSize.height() + frameWidth * 2 + 2)) def resizeEvent(self, event): buttonSize = self.btnSearch.sizeHint() frameWidth = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) self.btnSearch.move(self.rect().right() - frameWidth - buttonSize.width(), (self.rect().bottom() - buttonSize.height() + 1) / 2) super(ButtonLineEdit, self).resizeEvent(event)
def setupUi(self, PostNAS_SearchDialogBase): PostNAS_SearchDialogBase.setObjectName(_fromUtf8("PostNAS_SearchDialogBase")) PostNAS_SearchDialogBase.resize(501, 337) self.gridLayout = QGridLayout(PostNAS_SearchDialogBase) self.gridLayout.setObjectName(_fromUtf8("gridLayout")) self.treeWidget = QTreeWidget(PostNAS_SearchDialogBase) self.treeWidget.setSelectionMode(QAbstractItemView.ExtendedSelection) self.treeWidget.setHeaderHidden(True) self.treeWidget.setObjectName(_fromUtf8("treeWidget")) self.treeWidget.headerItem().setText(0, _fromUtf8("1")) self.gridLayout.addWidget(self.treeWidget, 1, 0, 1, 3) self.lineEdit = QLineEdit(PostNAS_SearchDialogBase) self.lineEdit.setObjectName(_fromUtf8("lineEdit")) self.gridLayout.addWidget(self.lineEdit, 0, 0, 1, 3) self.showButton = QToolButton(PostNAS_SearchDialogBase) self.showButton.setEnabled(False) icon = QtGui.QIcon() icon.addPixmap(QPixmap(_fromUtf8(":/plugins/PostNAS_Search/search_16x16.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.showButton.setIcon(icon) self.showButton.setObjectName(_fromUtf8("showButton")) self.gridLayout.addWidget(self.showButton, 2, 2, 1, 1) self.resetButton = QToolButton(PostNAS_SearchDialogBase) self.resetButton.setEnabled(False) icon1 = QIcon() icon1.addPixmap(QtGui.QPixmap(_fromUtf8(":/plugins/PostNAS_Search/marker-delete.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.resetButton.setIcon(icon1) self.resetButton.setObjectName(_fromUtf8("resetButton")) self.gridLayout.addWidget(self.resetButton, 2, 1, 1, 1) self.retranslateUi(PostNAS_SearchDialogBase) QtCore.QMetaObject.connectSlotsByName(PostNAS_SearchDialogBase)
def createWidget(self): if self.dialogType == DIALOG_STANDARD: widget = QWidget() layout = QHBoxLayout() layout.setMargin(0) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(2) self.combo = QgsMapLayerComboBox() layout.addWidget(self.combo) btn = QToolButton() btn.setText('...') btn.setToolTip(self.tr("Select file")) btn.clicked.connect(self.selectFile) layout.addWidget(btn) widget.setLayout(layout) if self.param.optional: self.combo.setAllowEmptyLayer(True) self.combo.setFilters(QgsMapLayerProxyModel.VectorLayer) self.combo.setExcludedProviders(['grass']) self.combo.currentIndexChanged.connect(lambda: self.widgetValueHasChanged.emit(self)) self.combo.currentTextChanged.connect(lambda: self.widgetValueHasChanged.emit(self)) return widget elif self.dialogType == DIALOG_BATCH: return BatchInputSelectionPanel(self.param, self.row, self.col, self.dialog) else: self.combo = QComboBox() layers = self.dialog.getAvailableValuesOfType(ParameterRaster, OutputRaster) self.combo.setEditable(True) tables = self.dialog.getAvailableValuesOfType(ParameterTable, OutputTable) layers = self.dialog.getAvailableValuesOfType(ParameterVector, OutputVector) if self.param.optional: self.combo.addItem(self.NOT_SELECTED, None) for table in tables: self.combo.addItem(self.dialog.resolveValueDescription(table), table) for layer in layers: self.combo.addItem(self.dialog.resolveValueDescription(layer), layer) widget = QWidget() layout = QHBoxLayout() layout.setMargin(0) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(2) layout.addWidget(self.combo) btn = QToolButton() btn.setText('...') btn.setToolTip(self.tr("Select file")) btn.clicked.connect(self.selectFile) layout.addWidget(btn) widget.setLayout(layout) return widget
def initGui(self): hlayout = QHBoxLayout() layout = QVBoxLayout() self.searchBox = QLineEdit() self.searchBox.returnPressed.connect(self.search) self.searchBox.setPlaceholderText("[Enter search string and press enter to search for maps]") hlayout.addWidget(self.searchBox) self.button = QToolButton() self.button.setText("Search") self.button.clicked.connect(self.search) self.button.adjustSize() self.searchBox.setFixedHeight(self.button.height()) hlayout.addWidget(self.button) layout.addLayout(hlayout) w = QFrame() self.browser = QWebView() w.setStyleSheet("QFrame{border:1px solid rgb(0, 0, 0);}") innerlayout = QHBoxLayout() innerlayout.setSpacing(0) innerlayout.setMargin(0) innerlayout.addWidget(self.browser) w.setLayout(innerlayout) layout.addWidget(w) self.setLayout(layout) self.browser.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks) self.browser.settings().setUserStyleSheetUrl(QUrl("file://" + resourceFile("search.css").replace("\\", "/"))) self.browser.linkClicked.connect(self.linkClicked) self.resize(600, 500) self.setWindowTitle("Search stories")
class FileDirectorySelector(QWidget): def __init__(self, parent=None, selectFile=False): QWidget.__init__(self, parent) # create gui self.btnSelect = QToolButton() self.btnSelect.setText('…') self.lineEdit = QLineEdit() self.hbl = QHBoxLayout() self.hbl.setMargin(0) self.hbl.setSpacing(0) self.hbl.addWidget(self.lineEdit) self.hbl.addWidget(self.btnSelect) self.setLayout(self.hbl) self.canFocusOut = False self.selectFile = selectFile self.setFocusPolicy(Qt.StrongFocus) self.btnSelect.clicked.connect(self.select) def select(self): lastDir = '' if not self.selectFile: selectedPath = QFileDialog.getExistingDirectory(None, self.tr('Select directory'), lastDir, QFileDialog.ShowDirsOnly) else: selectedPath, selected_filter = QFileDialog.getOpenFileName(None, self.tr('Select file'), lastDir, self.tr('All files (*.*)') ) if not selectedPath: return self.lineEdit.setText(selectedPath) self.canFocusOut = True def text(self): return self.lineEdit.text() def setText(self, value): self.lineEdit.setText(value)
class MultipleDirectorySelector(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) # create gui self.btnSelect = QToolButton() self.btnSelect.setText('…') self.lineEdit = QLineEdit() self.hbl = QHBoxLayout() self.hbl.setMargin(0) self.hbl.setSpacing(0) self.hbl.addWidget(self.lineEdit) self.hbl.addWidget(self.btnSelect) self.setLayout(self.hbl) self.canFocusOut = False self.setFocusPolicy(Qt.StrongFocus) self.btnSelect.clicked.connect(self.select) def select(self): text = self.lineEdit.text() if text != '': items = text.split(';') else: items = [] dlg = DirectorySelectorDialog(None, items) if dlg.exec_(): text = dlg.value() self.lineEdit.setText(text) self.canFocusOut = True def text(self): return self.lineEdit.text() def setText(self, value): self.lineEdit.setText(value)
def createWidget(self): if self.dialogType == DIALOG_MODELER: self.combo = QComboBox() widget = QWidget() layout = QHBoxLayout() layout.setMargin(0) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(1) layout.addWidget(self.combo) btn = QToolButton() btn.setIcon(QgsApplication.getThemeIcon("mActionSetProjection.svg")) btn.setToolTip(self.tr("Select CRS")) btn.clicked.connect(self.selectProjection) layout.addWidget(btn) widget.setLayout(layout) self.combo.setEditable(True) crss = self.dialog.getAvailableValuesOfType(ParameterCrs) for crs in crss: self.combo.addItem(self.dialog.resolveValueDescription(crs), crs) raster = self.dialog.getAvailableValuesOfType(ParameterRaster, OutputRaster) vector = self.dialog.getAvailableValuesOfType(ParameterVector, OutputVector) for r in raster: self.combo.addItem("Crs of layer " + self.dialog.resolveValueDescription(r), r) for v in vector: self.combo.addItem("Crs of layer " + self.dialog.resolveValueDescription(v), v) if not self.param.default: self.combo.setEditText(self.param.default) return widget else: widget = QgsProjectionSelectionWidget() if self.param.optional: widget.setOptionVisible(QgsProjectionSelectionWidget.CrsNotSet, True) if self.param.default: crs = QgsCoordinateReferenceSystem(self.param.default) widget.setCrs(crs) return widget
def __init__(self, parent, tree, providerName, param): QTreeWidgetItem.__init__(self, parent) self.providereName = providerName self.param = param self.tree = tree self.setText(0, param.description) self.paramName = settingName(providerName, param.name) if isinstance(param.defaultValue, bool): self.value = QSettings().value(self.paramName, defaultValue=param.defaultValue, type=bool) if self.value: self.setCheckState(1, Qt.Checked) else: self.setCheckState(1, Qt.Unchecked) elif isinstance(param.defaultValue, list): self.combo = QComboBox() for element in param.defaultValue: self.combo.addItem(element) self.tree.setItemWidget(self, 1, self.combo) self.value = QSettings().value(self.paramName, defaultValue=param.defaultValue[0]) idx = self.combo.findText(self.value) self.combo.setCurrentIndex(idx) elif param.description == "Password": self.passwordField = QLineEdit() self.passwordField.setEchoMode(QLineEdit.Password); #self.passwordField.setStyleSheet("QLineEdit { border: none }"); self.value = QSettings().value(self.paramName, defaultValue=param.defaultValue) self.passwordField.setText(str(self.value)) self.tree.setItemWidget(self, 1, self.passwordField) elif param.action is not None: layout = QHBoxLayout() layout.setMargin(0) layout.setSpacing(0) self.textbox = QLineEdit() self.value = QSettings().value(self.paramName, defaultValue=param.defaultValue) self.textbox.setText(str(self.value)) layout.addWidget(self.textbox) self.button = QToolButton() self.button.setText(param.actionText) self.button.clicked.connect(param.action) layout.addWidget(self.button) self.widget = QWidget() self.widget.setLayout(layout) self.tree.setItemWidget(self, 1, self.widget) else: self.textbox = QLineEdit() #self.textbox.setStyleSheet("QLineEdit { border: none }"); self.tree.setItemWidget(self, 1, self.textbox) self.value = QSettings().value(self.paramName, defaultValue=param.defaultValue) self.textbox.setText(str(self.value))
def initGui(self): readTrackedLayers() QgsMapLayerRegistry.instance().layerWasAdded.connect(trackLayer) QgsMapLayerRegistry.instance().layerRemoved.connect(layerRemoved) icon = QIcon(os.path.dirname(__file__) + "/ui/resources/geogig.png") self.explorerAction = navigatorInstance.toggleViewAction() self.explorerAction.setIcon(icon) self.explorerAction.setText("GeoGig Navigator") icon = QIcon(os.path.dirname(__file__) + "/ui/resources/identify.png") self.toolAction = QAction(icon, "GeoGig Feature Info Tool", self.iface.mainWindow()) self.toolAction.setCheckable(True) self.toolAction.triggered.connect(self.setTool) self.menu = QMenu(self.iface.mainWindow()) self.menu.setTitle("GeoGig") self.menu.addAction(self.explorerAction) self.menu.addAction(self.toolAction) bar = self.iface.layerToolBar() self.toolButton = QToolButton() self.toolButton.setMenu(self.menu) self.toolButton.setPopupMode(QToolButton.MenuButtonPopup) self.toolButton.setDefaultAction(self.explorerAction) bar.addWidget(self.toolButton) self.iface.addPluginToMenu("&GeoGig", self.explorerAction) self.iface.addPluginToMenu("&GeoGig", self.toolAction) addSettingsMenu("GeoGig") addHelpMenu("GeoGig") addAboutMenu("GeoGig") self.mapTool = MapToolGeoGigInfo(self.iface.mapCanvas()) #This crashes QGIS, so we comment it out until finding a solution #self.mapTool.setAction(self.toolAction) self.iface.addDockWidget(Qt.RightDockWidgetArea, navigatorInstance) try: from lessons import addLessonsFolder, addGroup folder = os.path.join(os.path.dirname(__file__), "_lessons") addLessonsFolder(folder, "geogig") group_description = os.path.join(folder, "group.md") addGroup("GeoGig lessons", group_description) except Exception as e: pass
def __init__(self, repo, ref = None): super(RefPanel, self).__init__(None) self.repo = repo self.ref = ref self.horizontalLayout = QHBoxLayout(self) self.horizontalLayout.setSpacing(2) self.horizontalLayout.setMargin(0) self.text = QLineEdit() self.text.setEnabled(False) if ref is not None: self.text.setText(ref.humantext()) self.text.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.horizontalLayout.addWidget(self.text) self.pushButton = QToolButton() self.pushButton.setText("...") self.pushButton.clicked.connect(self.showSelectionDialog) self.pushButton.setEnabled(self.repo is not None) self.horizontalLayout.addWidget(self.pushButton) self.setLayout(self.horizontalLayout)
def __init__(self, parent=None): QWidget.__init__(self, parent) # create gui self.btnSelect = QToolButton() self.btnSelect.setText('…') self.lineEdit = QLineEdit() self.hbl = QHBoxLayout() self.hbl.setMargin(0) self.hbl.setSpacing(0) self.hbl.addWidget(self.lineEdit) self.hbl.addWidget(self.btnSelect) self.setLayout(self.hbl) self.canFocusOut = False self.setFocusPolicy(Qt.StrongFocus) self.btnSelect.clicked.connect(self.select)
class RefPanel(QWidget): refChanged = pyqtSignal() def __init__(self, repo, ref = None): super(RefPanel, self).__init__(None) self.repo = repo self.ref = ref self.horizontalLayout = QHBoxLayout(self) self.horizontalLayout.setSpacing(2) self.horizontalLayout.setMargin(0) self.text = QLineEdit() self.text.setEnabled(False) if ref is not None: self.text.setText(ref.humantext()) self.text.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.horizontalLayout.addWidget(self.text) self.pushButton = QToolButton() self.pushButton.setText("...") self.pushButton.clicked.connect(self.showSelectionDialog) self.pushButton.setEnabled(self.repo is not None) self.horizontalLayout.addWidget(self.pushButton) self.setLayout(self.horizontalLayout) def showSelectionDialog(self): from geogig.gui.dialogs.historyviewer import HistoryViewerDialog dialog = HistoryViewerDialog(self.repo) dialog.exec_() ref = dialog.ref if ref: commit = Commit.fromref(self.repo, ref) self.setRef(commit) def setRepo(self, repo): self.repo = repo self.pushButton.setEnabled(True) self.setRef(Commitish(repo, repo.HEAD)) def setRef(self, ref): self.ref = ref self.text.setText(ref.humantext()) self.refChanged.emit() def getRef(self): return self.ref
def __init__(self, geoservice, image_ba, parent=None, extent_renderer=None): QWidget.__init__(self, parent) self.extent_renderer = extent_renderer self.layout = QHBoxLayout(self) self.layout.setContentsMargins(5, 10, 5, 10) self.setLayout(self.layout) self.service_icon = QLabel(self) self.service_icon.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.service_icon.resize(24, 24) qimg = QImage.fromData(image_ba) pixmap = QPixmap.fromImage(qimg) self.service_icon.setPixmap(pixmap) self.layout.addWidget(self.service_icon) self.service_desc_layout = QGridLayout(self) self.service_desc_layout.setSpacing(0) self.layout.addLayout(self.service_desc_layout) self.service_name = QLabel(self) self.service_name.setTextFormat(Qt.RichText) self.service_name.setWordWrap(True) self.service_name.setText(u" <strong> {} </strong>".format(geoservice.get('name', u""))) self.service_desc_layout.addWidget(self.service_name, 0, 0, 1, 3) self.service_type = QLabel(self) self.service_type.setTextFormat(Qt.RichText) self.service_type.setWordWrap(True) self.service_type.setText(geoservice.get('type', u"").upper() + " ") self.service_desc_layout.addWidget(self.service_type, 1, 0) self.service_deteils = QLabel(self) self.service_deteils.setTextFormat(Qt.RichText) self.service_deteils.setWordWrap(True) self.service_deteils.setOpenExternalLinks(True) self.service_deteils.setText(u"<a href=\"{0}\">{1}</a>, ".format( Client().geoservice_info_url(geoservice.get('id', u"")), self.tr('details') )) self.service_desc_layout.addWidget(self.service_deteils, 1, 1) self.service_report = QLabel(self) self.service_report.setTextFormat(Qt.RichText) self.service_report.setWordWrap(True) self.service_report.setOpenExternalLinks(True) self.service_report.setText(u"<a href=\"{0}\">{1}</a><div/>".format( Client().geoservice_report_url(geoservice.get('id', u"")), self.tr('report a problem') )) self.service_desc_layout.addWidget(self.service_report, 1, 2) self.service_desc_layout.setColumnStretch(2, 1) self.status_label = QLabel(self) self.status_label.setTextFormat(Qt.RichText) self.status_label.setText(u'\u2022') status = geoservice.get('cumulative_status', u'') if status == 'works': self.status_label.setStyleSheet("color: green; font-size: 30px") if status == 'failed': self.status_label.setStyleSheet("color: red; font-size: 30px") if status == 'problematic': self.status_label.setStyleSheet("color: yellow; font-size: 30px") self.layout.addWidget(self.status_label) self.addButton = QToolButton() self.addButton.setText(self.tr("Add")) self.addButton.clicked.connect(self.addToMap) self.layout.addWidget(self.addButton) self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum) self.geoservice = geoservice self.image_ba = image_ba
class GeoGigPlugin(object): def __init__(self, iface): self.iface = iface config.iface = iface readSettings() config.initConfigParams() layers = list(QgsMapLayerRegistry.instance().mapLayers().values()) for layer in layers: trackLayer(layer) try: from qgistester.tests import addTestModule from geogig.tests import testplugin addTestModule(testplugin, "GeoGig Light") except Exception as e: pass QSettings().setValue("/qgis/walForSqlite3", False) def unload(self): navigatorInstance.setVisible(False) try: QgsMapLayerRegistry.instance().layerWasAdded.disconnect(trackLayer) QgsMapLayerRegistry.instance().layerRemoved.disconnect(layerRemoved) except: pass self.menu.deleteLater() self.toolButton.deleteLater() self.iface.removePluginMenu("&GeoGig", self.explorerAction) self.iface.removePluginMenu("&GeoGig", self.toolAction) layers = list(QgsMapLayerRegistry.instance().mapLayers().values()) for layer in layers: removeLayerActions(layer) removeNonexistentTrackedLayers() removeTempFolder() try: from qgistester.tests import removeTestModule from geogig.tests import testplugin removeTestModule(testplugin, "GeoGig Light") except Exception as e: pass try: from lessons import removeLessonsFolder removeLessonsFolder(folder, "geogig") except: pass removeHelpMenu("GeoGig") removeAboutMenu("GeoGig") removeSettingsMenu("GeoGig") def initGui(self): readTrackedLayers() QgsMapLayerRegistry.instance().layerWasAdded.connect(trackLayer) QgsMapLayerRegistry.instance().layerRemoved.connect(layerRemoved) icon = QIcon(os.path.dirname(__file__) + "/ui/resources/geogig.png") self.explorerAction = navigatorInstance.toggleViewAction() self.explorerAction.setIcon(icon) self.explorerAction.setText("GeoGig Navigator") icon = QIcon(os.path.dirname(__file__) + "/ui/resources/identify.png") self.toolAction = QAction(icon, "GeoGig Feature Info Tool", self.iface.mainWindow()) self.toolAction.setCheckable(True) self.toolAction.triggered.connect(self.setTool) self.menu = QMenu(self.iface.mainWindow()) self.menu.setTitle("GeoGig") self.menu.addAction(self.explorerAction) self.menu.addAction(self.toolAction) bar = self.iface.layerToolBar() self.toolButton = QToolButton() self.toolButton.setMenu(self.menu) self.toolButton.setPopupMode(QToolButton.MenuButtonPopup) self.toolButton.setDefaultAction(self.explorerAction) bar.addWidget(self.toolButton) self.iface.addPluginToMenu("&GeoGig", self.explorerAction) self.iface.addPluginToMenu("&GeoGig", self.toolAction) addSettingsMenu("GeoGig") addHelpMenu("GeoGig") addAboutMenu("GeoGig") self.mapTool = MapToolGeoGigInfo(self.iface.mapCanvas()) #This crashes QGIS, so we comment it out until finding a solution #self.mapTool.setAction(self.toolAction) self.iface.addDockWidget(Qt.RightDockWidgetArea, navigatorInstance) try: from lessons import addLessonsFolder, addGroup folder = os.path.join(os.path.dirname(__file__), "_lessons") addLessonsFolder(folder, "geogig") group_description = os.path.join(folder, "group.md") addGroup("GeoGig lessons", group_description) except Exception as e: pass def setWarning(self, msg): QMessageBox.warning(None, 'Could not complete GeoGig command', msg, QMessageBox.Ok) def setTool(self): self.toolAction.setChecked(True) self.iface.mapCanvas().setMapTool(self.mapTool)
def __init__(self, parent=None): super(MapWidget, self).__init__(parent) self.setupUi(self) self.snapping = True icon = roam_style.iconsize() self.projecttoolbar.setIconSize(QSize(icon, icon)) self.defaultextent = None self.current_form = None self.last_form = None self.layerbuttons = [] self.editfeaturestack = [] self.lastgpsposition = None self.project = None self.gps = None self.gpslogging = None self.selectionbands = defaultdict(partial(QgsRubberBand, self.canvas)) self.bridge = QgsLayerTreeMapCanvasBridge( QgsProject.instance().layerTreeRoot(), self.canvas) self.bridge.setAutoSetupOnFirstLayer(False) self.canvas.setCanvasColor(Qt.white) self.canvas.enableAntiAliasing(True) self.snappingutils = SnappingUtils(self.canvas, self) self.canvas.setSnappingUtils(self.snappingutils) threadcount = QThread.idealThreadCount() threadcount = 2 if threadcount > 2 else 1 QgsApplication.setMaxThreads(threadcount) self.canvas.setParallelRenderingEnabled(True) self.canvas.setFrameStyle(QFrame.NoFrame) self.editgroup = QActionGroup(self) self.editgroup.setExclusive(True) self.editgroup.addAction(self.actionPan) self.editgroup.addAction(self.actionZoom_In) self.editgroup.addAction(self.actionZoom_Out) self.editgroup.addAction(self.actionInfo) self.actionGPS = GPSAction(self.canvas, self) self.projecttoolbar.addAction(self.actionGPS) if roam.config.settings.get('north_arrow', False): self.northarrow = NorthArrow(":/icons/north", self.canvas) self.northarrow.setPos(10, 10) self.canvas.scene().addItem(self.northarrow) smallmode = roam.config.settings.get("smallmode", False) self.projecttoolbar.setSmallMode(smallmode) self.projecttoolbar.setContextMenuPolicy(Qt.CustomContextMenu) gpsspacewidget = QWidget() gpsspacewidget.setMinimumWidth(30) gpsspacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.topspaceraction = self.projecttoolbar.insertWidget( self.actionGPS, gpsspacewidget) self.dataentryselection = QAction(self.projecttoolbar) self.dataentryaction = self.projecttoolbar.insertAction( self.topspaceraction, self.dataentryselection) self.dataentryselection.triggered.connect(self.select_data_entry) self.gpsMarker = GPSMarker(self.canvas) self.gpsMarker.hide() self.currentfeatureband = CurrentSelection(self.canvas) self.currentfeatureband.setIconSize(30) self.currentfeatureband.setWidth(10) self.currentfeatureband.setColor(QColor(88, 64, 173, 50)) self.currentfeatureband.setOutlineColour(QColor(88, 64, 173)) self.gpsband = QgsRubberBand(self.canvas) self.gpsband.setColor(QColor(165, 111, 212, 75)) self.gpsband.setWidth(5) RoamEvents.refresh_map.connect(self.refresh_map) RoamEvents.editgeometry.connect(self.queue_feature_for_edit) RoamEvents.selectioncleared.connect(self.clear_selection) RoamEvents.selectionchanged.connect(self.highlight_selection) RoamEvents.openfeatureform.connect(self.feature_form_loaded) RoamEvents.sync_complete.connect(self.refresh_map) RoamEvents.snappingChanged.connect(self.snapping_changed) self.snappingbutton = QToolButton() self.snappingbutton.setText("Snapping: On") self.snappingbutton.setAutoRaise(True) self.snappingbutton.pressed.connect(self.toggle_snapping) spacer = QWidget() spacer2 = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) spacer2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.scalewidget = QgsScaleComboBox() self.scalebutton = QToolButton() self.scalebutton.setAutoRaise(True) self.scalebutton.setMaximumHeight(self.statusbar.height()) self.scalebutton.pressed.connect(self.selectscale) self.scalebutton.setText("Scale") self.scalelist = BigList(parent=self.canvas, centeronparent=True, showsave=False) self.scalelist.hide() self.scalelist.setlabel("Map Scale") self.scalelist.setmodel(self.scalewidget.model()) self.scalelist.closewidget.connect(self.scalelist.close) self.scalelist.itemselected.connect(self.update_scale_from_item) self.scalelist.itemselected.connect(self.scalelist.close) self.positionlabel = QLabel('') self.gpslabel = QLabel("GPS: Not active") self.gpslabelposition = QLabel("") self.gpslabelaveraging = QLabel('') # averaging self.statusbar.addWidget(self.snappingbutton) self.statusbar.addWidget(spacer2) self.statusbar.addWidget(self.gpslabel) self.statusbar.addWidget(self.gpslabelposition) self.statusbar.addWidget(self.gpslabelaveraging) # averaging self.statusbar.addPermanentWidget(self.scalebutton) self.canvas.extentsChanged.connect(self.update_status_label) self.canvas.scaleChanged.connect(self.update_status_label) self.connectButtons() scalebar_enabled = roam.config.settings.get('scale_bar', False) self.scalebar_enabled = False if scalebar_enabled: roam.utils.warning( "Unsupported feature: Scale bar support not ported to QGIS 3 API yet." ) RoamEvents.raisemessage( "Unsupported feature", "Scale bar support not ported to QGIS 3 API yet", level=RoamEvents.CRITICAL) self.scalebar_enabled = False
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() sizes = self.splitter.sizes() self.splitter.setSizes(sizes) # ----------------Restore Settings------------------------------------ self.restoreSettingsConsole() # ------------------Toolbar Editor------------------------------------- # Action for Open File openFileBt = QCoreApplication.translate("PythonConsole", "Open Script...") self.openFileButton = QAction(self) self.openFileButton.setCheckable(False) self.openFileButton.setEnabled(True) self.openFileButton.setIcon(QgsApplication.getThemeIcon("console/iconOpenConsole.png")) self.openFileButton.setMenuRole(QAction.PreferencesRole) self.openFileButton.setIconVisibleInMenu(True) self.openFileButton.setToolTip(openFileBt) self.openFileButton.setText(openFileBt) openExtEditorBt = QCoreApplication.translate("PythonConsole", "Open in External Editor") self.openInEditorButton = QAction(self) self.openInEditorButton.setCheckable(False) self.openInEditorButton.setEnabled(True) self.openInEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconShowEditorConsole.png")) self.openInEditorButton.setMenuRole(QAction.PreferencesRole) self.openInEditorButton.setIconVisibleInMenu(True) self.openInEditorButton.setToolTip(openExtEditorBt) self.openInEditorButton.setText(openExtEditorBt) # Action for Save File saveFileBt = QCoreApplication.translate("PythonConsole", "Save") self.saveFileButton = QAction(self) self.saveFileButton.setCheckable(False) self.saveFileButton.setEnabled(False) self.saveFileButton.setIcon(QgsApplication.getThemeIcon("console/iconSaveConsole.png")) self.saveFileButton.setMenuRole(QAction.PreferencesRole) self.saveFileButton.setIconVisibleInMenu(True) self.saveFileButton.setToolTip(saveFileBt) self.saveFileButton.setText(saveFileBt) # Action for Save File As saveAsFileBt = QCoreApplication.translate("PythonConsole", "Save As...") self.saveAsFileButton = QAction(self) self.saveAsFileButton.setCheckable(False) self.saveAsFileButton.setEnabled(True) self.saveAsFileButton.setIcon(QgsApplication.getThemeIcon("console/iconSaveAsConsole.png")) self.saveAsFileButton.setMenuRole(QAction.PreferencesRole) self.saveAsFileButton.setIconVisibleInMenu(True) self.saveAsFileButton.setToolTip(saveAsFileBt) self.saveAsFileButton.setText(saveAsFileBt) # Action Cut cutEditorBt = QCoreApplication.translate("PythonConsole", "Cut") self.cutEditorButton = QAction(self) self.cutEditorButton.setCheckable(False) self.cutEditorButton.setEnabled(True) self.cutEditorButton.setIcon(QgsApplication.getThemeIcon("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.png")) self.runScriptEditorButton.setMenuRole(QAction.PreferencesRole) self.runScriptEditorButton.setIconVisibleInMenu(True) self.runScriptEditorButton.setToolTip(runScriptEditorBt) self.runScriptEditorButton.setText(runScriptEditorBt) # Action Run Script (subprocess) commentEditorBt = QCoreApplication.translate("PythonConsole", "Comment") self.commentEditorButton = QAction(self) self.commentEditorButton.setCheckable(False) self.commentEditorButton.setEnabled(True) self.commentEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconCommentEditorConsole.png")) self.commentEditorButton.setMenuRole(QAction.PreferencesRole) self.commentEditorButton.setIconVisibleInMenu(True) self.commentEditorButton.setToolTip(commentEditorBt) self.commentEditorButton.setText(commentEditorBt) # Action Run Script (subprocess) uncommentEditorBt = QCoreApplication.translate("PythonConsole", "Uncomment") self.uncommentEditorButton = QAction(self) self.uncommentEditorButton.setCheckable(False) self.uncommentEditorButton.setEnabled(True) self.uncommentEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconUncommentEditorConsole.png")) self.uncommentEditorButton.setMenuRole(QAction.PreferencesRole) self.uncommentEditorButton.setIconVisibleInMenu(True) self.uncommentEditorButton.setToolTip(uncommentEditorBt) self.uncommentEditorButton.setText(uncommentEditorBt) # Action for Object browser objList = QCoreApplication.translate("PythonConsole", "Object Inspector...") self.objectListButton = QAction(self) self.objectListButton.setCheckable(True) self.objectListButton.setEnabled(self.settings.value("pythonConsole/enableObjectInsp", False, type=bool)) self.objectListButton.setIcon(QgsApplication.getThemeIcon("console/iconClassBrowserConsole.png")) self.objectListButton.setMenuRole(QAction.PreferencesRole) self.objectListButton.setIconVisibleInMenu(True) self.objectListButton.setToolTip(objList) self.objectListButton.setText(objList) # Action for Find text findText = QCoreApplication.translate("PythonConsole", "Find Text") self.findTextButton = QAction(self) self.findTextButton.setCheckable(True) self.findTextButton.setEnabled(True) self.findTextButton.setIcon(QgsApplication.getThemeIcon("console/iconSearchEditorConsole.png")) self.findTextButton.setMenuRole(QAction.PreferencesRole) self.findTextButton.setIconVisibleInMenu(True) self.findTextButton.setToolTip(findText) self.findTextButton.setText(findText) # ----------------Toolbar Console------------------------------------- # Action Show Editor showEditor = QCoreApplication.translate("PythonConsole", "Show Editor") self.showEditorButton = QAction(self) self.showEditorButton.setEnabled(True) self.showEditorButton.setCheckable(True) self.showEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconShowEditorConsole.png")) self.showEditorButton.setMenuRole(QAction.PreferencesRole) self.showEditorButton.setIconVisibleInMenu(True) self.showEditorButton.setToolTip(showEditor) self.showEditorButton.setText(showEditor) # Action for Clear button clearBt = QCoreApplication.translate("PythonConsole", "Clear Console") self.clearButton = QAction(self) self.clearButton.setCheckable(False) self.clearButton.setEnabled(True) self.clearButton.setIcon(QgsApplication.getThemeIcon("console/iconClearConsole.png")) self.clearButton.setMenuRole(QAction.PreferencesRole) self.clearButton.setIconVisibleInMenu(True) self.clearButton.setToolTip(clearBt) self.clearButton.setText(clearBt) # Action for settings optionsBt = QCoreApplication.translate("PythonConsole", "Options...") self.optionsButton = QAction(self) self.optionsButton.setCheckable(False) self.optionsButton.setEnabled(True) self.optionsButton.setIcon(QgsApplication.getThemeIcon("console/iconSettingsConsole.png")) self.optionsButton.setMenuRole(QAction.PreferencesRole) self.optionsButton.setIconVisibleInMenu(True) self.optionsButton.setToolTip(optionsBt) self.optionsButton.setText(optionsBt) # Action menu for class actionClassBt = QCoreApplication.translate("PythonConsole", "Import Class") self.actionClass = QAction(self) self.actionClass.setCheckable(False) self.actionClass.setEnabled(True) self.actionClass.setIcon(QgsApplication.getThemeIcon("console/iconClassConsole.png")) self.actionClass.setMenuRole(QAction.PreferencesRole) self.actionClass.setIconVisibleInMenu(True) self.actionClass.setToolTip(actionClassBt) self.actionClass.setText(actionClassBt) # Action for Run script runBt = QCoreApplication.translate("PythonConsole", "Run Command") self.runButton = QAction(self) self.runButton.setCheckable(False) self.runButton.setEnabled(True) self.runButton.setIcon(QgsApplication.getThemeIcon("console/iconRunConsole.png")) self.runButton.setMenuRole(QAction.PreferencesRole) self.runButton.setIconVisibleInMenu(True) self.runButton.setToolTip(runBt) self.runButton.setText(runBt) # Help action helpBt = QCoreApplication.translate("PythonConsole", "Help...") self.helpButton = QAction(self) self.helpButton.setCheckable(False) self.helpButton.setEnabled(True) self.helpButton.setIcon(QgsApplication.getThemeIcon("console/iconHelpConsole.png")) self.helpButton.setMenuRole(QAction.PreferencesRole) self.helpButton.setIconVisibleInMenu(True) self.helpButton.setToolTip(helpBt) self.helpButton.setText(helpBt) self.toolBar = QToolBar() self.toolBar.setEnabled(True) self.toolBar.setFocusPolicy(Qt.NoFocus) self.toolBar.setContextMenuPolicy(Qt.DefaultContextMenu) self.toolBar.setLayoutDirection(Qt.LeftToRight) self.toolBar.setIconSize(QSize(16, 16)) self.toolBar.setMovable(False) self.toolBar.setFloatable(False) self.toolBar.addAction(self.clearButton) self.toolBar.addAction(self.actionClass) self.toolBar.addAction(self.runButton) self.toolBar.addSeparator() self.toolBar.addAction(self.showEditorButton) self.toolBar.addSeparator() self.toolBar.addAction(self.optionsButton) self.toolBar.addAction(self.helpButton) self.toolBarEditor = QToolBar() self.toolBarEditor.setEnabled(False) self.toolBarEditor.setFocusPolicy(Qt.NoFocus) self.toolBarEditor.setContextMenuPolicy(Qt.DefaultContextMenu) self.toolBarEditor.setLayoutDirection(Qt.LeftToRight) self.toolBarEditor.setIconSize(QSize(16, 16)) self.toolBarEditor.setMovable(False) self.toolBarEditor.setFloatable(False) self.toolBarEditor.addAction(self.openFileButton) self.toolBarEditor.addAction(self.openInEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.saveFileButton) self.toolBarEditor.addAction(self.saveAsFileButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.runScriptEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.findTextButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.cutEditorButton) self.toolBarEditor.addAction(self.copyEditorButton) self.toolBarEditor.addAction(self.pasteEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.commentEditorButton) self.toolBarEditor.addAction(self.uncommentEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.objectListButton) # Menu Import Class default_command = { (QCoreApplication.translate("PythonConsole", "Import Processing Class"), QgsApplication.getThemeIcon("console/iconProcessingConsole.png")): ["import processing"], (QCoreApplication.translate("PythonConsole", "Import PyQt.QtCore Class"), QgsApplication.getThemeIcon("console/iconQtCoreConsole.png")): ["from qgis.PyQt.QtCore import *"], (QCoreApplication.translate("PythonConsole", "Import PyQt.QtGui Class"), QgsApplication.getThemeIcon("console/iconQtGuiConsole.png")): ["from qgis.PyQt.QtGui import *", "from qgis.PyQt.QtWidgets import *"] } self.classMenu = QMenu() for (title, icon), commands in list(default_command.items()): action = self.classMenu.addAction(icon, title) action.triggered.connect(partial(self.shell.commandConsole, commands)) cM = self.toolBar.widgetForAction(self.actionClass) cM.setMenu(self.classMenu) cM.setPopupMode(QToolButton.InstantPopup) self.widgetButton = QWidget() sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.widgetButton.sizePolicy().hasHeightForWidth()) self.widgetButton.setSizePolicy(sizePolicy) self.widgetButtonEditor = QWidget(self.widgetEditor) sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.widgetButtonEditor.sizePolicy().hasHeightForWidth()) self.widgetButtonEditor.setSizePolicy(sizePolicy) sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.shellOut.sizePolicy().hasHeightForWidth()) self.shellOut.setSizePolicy(sizePolicy) self.shellOut.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.shell.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) # ------------ Layout ------------------------------- self.mainLayout = QGridLayout(self) self.mainLayout.setMargin(0) self.mainLayout.setSpacing(0) self.mainLayout.addWidget(self.widgetButton, 0, 0, 1, 1) self.mainLayout.addWidget(self.splitterEditor, 0, 1, 1, 1) self.shellOutWidget.layout().insertWidget(0, self.toolBar) self.layoutEditor = QGridLayout(self.widgetEditor) self.layoutEditor.setMargin(0) self.layoutEditor.setSpacing(0) self.layoutEditor.addWidget(self.toolBarEditor, 0, 1, 1, 1) self.layoutEditor.addWidget(self.widgetButtonEditor, 1, 0, 2, 1) self.layoutEditor.addWidget(self.tabEditorWidget, 1, 1, 1, 1) self.layoutEditor.addWidget(self.widgetFind, 2, 1, 1, 1) # Layout for the find widget self.layoutFind = QGridLayout(self.widgetFind) self.layoutFind.setContentsMargins(0, 0, 0, 0) self.lineEditFind = QgsFilterLineEdit() placeHolderTxt = QCoreApplication.translate("PythonConsole", "Enter text to find...") self.lineEditFind.setPlaceholderText(placeHolderTxt) self.findNextButton = QToolButton() self.findNextButton.setEnabled(False) toolTipfindNext = QCoreApplication.translate("PythonConsole", "Find Next") self.findNextButton.setToolTip(toolTipfindNext) self.findNextButton.setIcon(QgsApplication.getThemeIcon("console/iconSearchNextEditorConsole.png")) self.findNextButton.setIconSize(QSize(24, 24)) self.findNextButton.setAutoRaise(True) self.findPrevButton = QToolButton() self.findPrevButton.setEnabled(False) toolTipfindPrev = QCoreApplication.translate("PythonConsole", "Find Previous") self.findPrevButton.setToolTip(toolTipfindPrev) self.findPrevButton.setIcon(QgsApplication.getThemeIcon("console/iconSearchPrevEditorConsole.png")) self.findPrevButton.setIconSize(QSize(24, 24)) self.findPrevButton.setAutoRaise(True) self.caseSensitive = QCheckBox() caseSensTr = QCoreApplication.translate("PythonConsole", "Case Sensitive") self.caseSensitive.setText(caseSensTr) self.wholeWord = QCheckBox() wholeWordTr = QCoreApplication.translate("PythonConsole", "Whole Word") self.wholeWord.setText(wholeWordTr) self.wrapAround = QCheckBox() self.wrapAround.setChecked(True) wrapAroundTr = QCoreApplication.translate("PythonConsole", "Wrap Around") self.wrapAround.setText(wrapAroundTr) self.layoutFind.addWidget(self.lineEditFind, 0, 1, 1, 1) self.layoutFind.addWidget(self.findPrevButton, 0, 2, 1, 1) self.layoutFind.addWidget(self.findNextButton, 0, 3, 1, 1) self.layoutFind.addWidget(self.caseSensitive, 0, 4, 1, 1) self.layoutFind.addWidget(self.wholeWord, 0, 5, 1, 1) self.layoutFind.addWidget(self.wrapAround, 0, 6, 1, 1) # ------------ Add first Tab in Editor ------------------------------- # self.tabEditorWidget.newTabEditor(tabName='first', filename=None) # ------------ Signal ------------------------------- self.findTextButton.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.clicked.connect(self._findNext) self.findPrevButton.clicked.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 createWidget(self): if self.dialogType == DIALOG_STANDARD: widget = QWidget() layout = QHBoxLayout() layout.setMargin(0) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(2) self.combo = QgsMapLayerComboBox() layout.addWidget(self.combo) btn = QToolButton() btn.setText('...') btn.setToolTip(self.tr("Select file")) btn.clicked.connect(self.selectFile) layout.addWidget(btn) widget.setLayout(layout) if self.param.optional: self.combo.setAllowEmptyLayer(True) if ProcessingConfig.getSetting(ProcessingConfig.SHOW_CRS_DEF): self.combo.setShowCrs(True) self.combo.setFilters(QgsMapLayerProxyModel.RasterLayer) self.combo.setExcludedProviders(['grass']) self.combo.currentIndexChanged.connect( lambda: self.widgetValueHasChanged.emit(self)) self.combo.currentTextChanged.connect( lambda: self.widgetValueHasChanged.emit(self)) return widget elif self.dialogType == DIALOG_BATCH: return BatchInputSelectionPanel(self.param, self.row, self.col, self.dialog) else: self.combo = QComboBox() layers = self.dialog.getAvailableValuesOfType( ParameterRaster, OutputRaster) self.combo.setEditable(True) for layer in layers: self.combo.addItem(self.dialog.resolveValueDescription(layer), layer) if self.param.optional: self.combo.setEditText("") widget = QWidget() layout = QHBoxLayout() layout.setMargin(0) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(2) layout.addWidget(self.combo) btn = QToolButton() btn.setText('...') btn.setToolTip(self.tr("Select file")) btn.clicked.connect(self.selectFile) layout.addWidget(btn) widget.setLayout(layout) return widget
def __init__(self, alg): super(AlgorithmDialogBase, self).__init__(iface.mainWindow() if iface else None) self.setupUi(self) # don't collapse parameters panel self.splitter.setCollapsible(0, False) # add collapse button to splitter splitterHandle = self.splitter.handle(1) handleLayout = QVBoxLayout() handleLayout.setContentsMargins(0, 0, 0, 0) self.btnCollapse = QToolButton(splitterHandle) self.btnCollapse.setAutoRaise(True) self.btnCollapse.setFixedSize(12, 12) self.btnCollapse.setCursor(Qt.ArrowCursor) handleLayout.addWidget(self.btnCollapse) handleLayout.addStretch() splitterHandle.setLayout(handleLayout) self.settings = QgsSettings() self.splitter.restoreState(self.settings.value("/Processing/dialogBaseSplitter", QByteArray())) self.restoreGeometry(self.settings.value("/Processing/dialogBase", QByteArray())) self.splitterState = self.splitter.saveState() self.splitterChanged(0, 0) self.executed = False self.mainWidget = None self.alg = alg self.setWindowTitle(self.alg.displayName()) self.buttonBox.rejected.connect(self.reject) self.buttonBox.accepted.connect(self.accept) # Rename OK button to Run self.btnRun = self.buttonBox.button(QDialogButtonBox.Ok) self.btnRun.setText(self.tr('Run')) self.buttonCancel.setEnabled(False) self.btnClose = self.buttonBox.button(QDialogButtonBox.Close) self.buttonBox.helpRequested.connect(self.openHelp) self.btnCollapse.clicked.connect(self.toggleCollapsed) self.splitter.splitterMoved.connect(self.splitterChanged) # desktop = QDesktopWidget() # if desktop.physicalDpiX() > 96: # self.txtHelp.setZoomFactor(desktop.physicalDpiX() / 96) algHelp = self.formatHelp(self.alg) if algHelp is None: self.textShortHelp.hide() else: self.textShortHelp.document().setDefaultStyleSheet('''.summary { margin-left: 10px; margin-right: 10px; } h2 { color: #555555; padding-bottom: 15px; } a { text-decoration: none; color: #3498db; font-weight: bold; } p { color: #666666; } b { color: #333333; } dl dd { margin-bottom: 5px; }''') self.textShortHelp.setHtml(algHelp) def linkClicked(url): webbrowser.open(url.toString()) self.textShortHelp.anchorClicked.connect(linkClicked) self.showDebug = ProcessingConfig.getSetting( ProcessingConfig.SHOW_DEBUG_IN_DIALOG)
def append_menu_buttons(self): """ Append menus and buttons to appropriate toolbar :return: """ # add to QGIS menu if PluginSettings.move_to_layers_menu(): self.iface.addLayerMenu().addMenu(self.menu) else: # need workaround for WebMenu _temp_act = QAction('temp', self.iface.mainWindow()) self.iface.addPluginToWebMenu("_tmp", _temp_act) self.iface.webMenu().addMenu(self.menu) self.iface.removePluginWebMenu("_tmp", _temp_act) # add to QGIS toolbar toolbutton = QToolButton() toolbutton.setPopupMode(QToolButton.InstantPopup) toolbutton.setMenu(self.menu) toolbutton.setIcon(self.menu.icon()) toolbutton.setText(self.menu.title()) toolbutton.setToolTip(self.menu.title()) # self.tb_action = toolbutton.defaultAction() # print "self.tb_action: ", self.tb_action if PluginSettings.move_to_layers_menu(): self.tb_action = self.iface.layerToolBar().addWidget(toolbutton) self.iface.layerToolBar().addAction(self.qms_search_action) else: self.tb_action = self.iface.webToolBar().addWidget(toolbutton) self.iface.webToolBar().addAction(self.qms_search_action)
class ForeignKeyLineEdit(QLineEdit): """ Line edit that enables the browsing of related entities defined through foreign key constraint. """ def __init__(self, column, parent=None, pixmap=None, host=None): """ Class constructor. :param column: Column object containing foreign key information. :type column: BaseColumn :param parent: Parent widget for the control. :type parent: QWidget :param pixmap: Pixmap to use for the line edit button. :type pixmap: QPixmap """ QLineEdit.__init__(self, parent) self.column = column self._entity = self.column.entity self.entity_dialog = host # Configure load button self.btn_load = QToolButton(parent) self.btn_load.setCursor(Qt.PointingHandCursor) self.btn_load.setFocusPolicy(Qt.NoFocus) px = GuiUtils.get_icon_pixmap('select_record.png') if not pixmap is None: px = pixmap self.btn_load.setIcon(QIcon(px)) self.btn_load.setIconSize(px.size()) self.btn_load.setStyleSheet('background: transparent; padding: 0px; ' 'border: none;') self.btn_load.clicked.connect(self.on_load_foreign_key_browser) clear_px = GuiUtils.get_icon_pixmap('clear.png') self.btn_clear = QToolButton(parent) self.btn_clear.setCursor(Qt.PointingHandCursor) self.btn_clear.setFocusPolicy(Qt.NoFocus) self.btn_clear.setIcon(QIcon(clear_px)) self.btn_clear.setIconSize(clear_px.size()) self.btn_clear.setStyleSheet('background: transparent; padding: 0px; ' 'border: none;') self.btn_clear.clicked.connect(self.clear_line_edit) frame_width = self.set_button_minimum_size(self.btn_load) self.set_button_minimum_size(self.btn_clear) # Ensure that text does not overlay button padding = self.btn_load.sizeHint().width() + frame_width + 1 self.setStyleSheet('padding-right: ' + str(padding * 2) + 'px;') # Set layout self.button_layout = QHBoxLayout(self) self.button_layout.addWidget(self.btn_clear, 0, Qt.AlignRight) self.button_layout.addWidget(self.btn_load, 0, Qt.AlignRight) self.button_layout.setSpacing(0) self.button_layout.setMargin(5) self.btn_clear.setVisible(False) # Readonly as text is loaded from the related entity self.setReadOnly(True) # Current model object self._current_item = None def set_button_minimum_size(self, button): """ Sets the minimum button size. :param button: The button to be set. :type button: QToolButton :return: Returns the frame width of the button :rtype: Integer """ frame_width = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) msz = self.minimumSizeHint() self.setMinimumSize( max( msz.width(), button.sizeHint().height() + frame_width * 2 + 2 ), max( msz.height(), button.sizeHint().height() + frame_width * 2 + 2 ) ) return frame_width @property def current_item(self): return self._current_item @current_item.setter def current_item(self, value): # Update display every time the current item is changed. self._current_item = value self.format_display() @property def entity(self): """ :return: Returns the entity object corresponding to this widget. :rtype: Entity """ return self._entity def clear_line_edit(self): """ Clears the text in the line edit. """ self.clear() self.hide_clear_button() def hide_clear_button(self): """ Hides the clear button. """ self.btn_clear.setVisible(False) self.button_layout.setStretch(0, 0) def show_clear_button(self): """ Shows the clear button if a text exists. """ if len(self.text()) > 0: self.btn_clear.setVisible(True) self.button_layout.setStretch(0, 5) def on_load_foreign_key_browser(self): """ Slot raised to load browser for selecting foreign key entities. To be implemented by subclasses. """ raise NotImplementedError def format_display(self): """ Extract object values to show in the line edit based on the specified display columns. """ raise NotImplementedError def parent_entity_model(self): """ :return: Returns the database model corresponding to the parent table of the relation defined by this column. Please note that the database model will not contain relationship configurations in its attributes. :rtype: object """ entity = self.column.entity_relation.parent return entity_model(entity, entity_only=True) def load_current_item_from_id(self, id): """ Loads the current item from the id corresponding to the primary key. :param id: Primary key of the referenced entity. :type id: int """ QApplication.processEvents() model = self.parent_entity_model() if model is None: return model_obj = model() res = model_obj.queryObject().filter(model.id == id).first() if not res is None: self.current_item = res
def initWidgets(self): # If there are advanced parameters — show corresponding groupbox for param in self.alg.parameterDefinitions(): if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced: self.grpAdvanced.show() break # Create widgets and put them in layouts for param in self.alg.parameterDefinitions(): if param.flags() & QgsProcessingParameterDefinition.FlagHidden: continue if param.isDestination(): continue else: desc = param.description() if isinstance(param, QgsProcessingParameterExtent): desc += self.tr(' (xmin, xmax, ymin, ymax)') if isinstance(param, QgsProcessingParameterPoint): desc += self.tr(' (x, y)') if param.flags( ) & QgsProcessingParameterDefinition.FlagOptional: desc += self.tr(' [optional]') wrapper = WidgetWrapperFactory.create_wrapper( param, self.parent) self.wrappers[param.name()] = wrapper widget = wrapper.widget if widget is not None: if isinstance(param, QgsProcessingParameterFeatureSource): layout = QHBoxLayout() layout.setSpacing(6) layout.setMargin(0) layout.addWidget(widget) button = QToolButton() icon = QIcon( os.path.join(pluginPath, 'images', 'iterate.png')) button.setIcon(icon) button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) button.setToolTip( self. tr('Iterate over this layer, creating a separate output for every feature in the layer' )) button.setCheckable(True) layout.addWidget(button) layout.setAlignment(button, Qt.AlignTop) self.iterateButtons[param.name()] = button button.toggled.connect(self.buttonToggled) widget = QWidget() widget.setLayout(layout) widget.setToolTip(param.toolTip()) if isinstance(widget, QCheckBox): # checkbox widget - so description is embedded in widget rather than a separate # label widget.setText(desc) else: label = QLabel(desc) # label.setToolTip(tooltip) self.labels[param.name()] = label if param.flags( ) & QgsProcessingParameterDefinition.FlagAdvanced: self.layoutAdvanced.addWidget(label) else: self.layoutMain.insertWidget( self.layoutMain.count() - 2, label) if param.flags( ) & QgsProcessingParameterDefinition.FlagAdvanced: self.layoutAdvanced.addWidget(widget) else: self.layoutMain.insertWidget( self.layoutMain.count() - 2, widget) for output in self.alg.destinationParameterDefinitions(): if output.flags() & QgsProcessingParameterDefinition.FlagHidden: continue label = QLabel(output.description()) widget = DestinationSelectionPanel(output, self.alg) self.layoutMain.insertWidget(self.layoutMain.count() - 1, label) self.layoutMain.insertWidget(self.layoutMain.count() - 1, widget) if isinstance(output, (QgsProcessingParameterRasterDestination, QgsProcessingParameterFeatureSink, QgsProcessingParameterVectorDestination)): check = QCheckBox() check.setText( self.tr('Open output file after running algorithm')) check.setChecked(True) self.layoutMain.insertWidget(self.layoutMain.count() - 1, check) self.checkBoxes[output.name()] = check widget.setToolTip(param.toolTip()) self.outputWidgets[output.name()] = widget for wrapper in list(self.wrappers.values()): wrapper.postInitialize(list(self.wrappers.values()))
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)
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(str.encode(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 WaysCalc: """QGIS Plugin Implementation.""" def __init__(self, iface): """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 """ # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join( self.plugin_dir, 'i18n', 'WaysCalc_{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) QCoreApplication.installTranslator(self.translator) # Declare instance attributes self.actions = [] self.menu = self.tr(u'&WaysCalc') # TODO: We are going to let the user set this up in a future iteration # self.toolbar = self.iface.addToolBar(u'WaysCalc') # self.toolbar.setObjectName(u'WaysCalc') #print "** INITIALIZING WaysCalc" self.pluginIsActive = False self.dockwidget_inters_ways = None self.dockwidget_inters_allways = None # self.settings = None self.IW = None #IntersectionWays self.IAW = None #IntersectionAllWays # noinspection PyMethodMayBeStatic def tr(self, 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('WaysCalc', message) def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" # выпадающая кнопка для пересекающихся маршрутов self.toolButton = QToolButton() self.toolButton.setMenu(QMenu()) # setPopupMode: DelayedPopup, MenuButtonPopup, InstantPopup self.toolButton.setPopupMode(QToolButton.InstantPopup) self.toolButton.setAutoRaise(True) self.toolButton_action = self.iface.addToolBarWidget(self.toolButton) self.action_intersection = QAction( QIcon(":/plugins/_Ways_calc/icon.png"), u'Поиск пересечений для линейного объекта', self.iface.mainWindow()) self.action_initLayerWays = QAction( u"Выбор слоя для поиска пересечений", self.iface.mainWindow()) self.action_allintersection = QAction( QIcon(":/plugins/_Ways_calc/icon.png"), u'Поиск пересечений всех линейных объектов', self.iface.mainWindow()) self.iface.addPluginToMenu(u"WaysCalc", self.action_intersection) self.iface.addPluginToMenu(u"WaysCalc", self.action_initLayerWays) self.iface.addPluginToMenu(u"WaysCalc", self.action_allintersection) # self.iface.addToolBarIcon(self.action_intersection) m = self.toolButton.menu() m.addAction(self.action_intersection) m.addAction(self.action_initLayerWays) m.addSeparator() m.addAction(self.action_allintersection) self.toolButton.setDefaultAction(self.action_intersection) self.action_intersection.triggered.connect(self.run_intersection) # пересекающиеся маршруты self.action_allintersection.triggered.connect(self.run_allintersection) # пересекающиеся все маршруты self.action_initLayerWays.triggered.connect(self.run_initLayerWays) # выбор слоя сравнения self.pointEmitterIntersection = QgsMapToolEmitPoint(self.iface.mapCanvas()) self.pointEmitterIntersection.setAction(self.action_intersection) self.pointEmitterIntersection.canvasClicked.connect(self.pointEmitterIntersectioncanvasClicked) self.iface.mapCanvas().currentLayerChanged.connect(self.onCurrentLayerChanged) #-------------------------------------------------------------------------- def onClosePlugin(self): """Cleanup necessary items here when plugin dockwidget is closed""" # disconnects try: self.dockwidget_inters_ways.closingPlugin.disconnect(self.onClosePlugin) except: pass try: self.dockwidget_inters_allways.closingPlugin.disconnect(self.onClosePlugin) except: pass self.pluginIsActive = False def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" self.iface.removePluginMenu(u"WaysCalc", self.action_intersection) self.iface.removePluginMenu(u"WaysCalc", self.action_allintersection) self.iface.removePluginMenu(u"WaysCalc", self.action_initLayerWays) self.iface.removeToolBarIcon(self.action_intersection) self.iface.removeToolBarIcon(self.action_intersection) self.iface.removeToolBarIcon(self.toolButton_action) self.action_intersection.triggered.disconnect(self.run_intersection) # пересекающиеся маршруты self.action_allintersection.triggered.disconnect(self.run_allintersection) # пересекающиеся все маршруты self.action_initLayerWays.triggered.disconnect(self.run_initLayerWays) # выбор слоя сравнения self.pointEmitterIntersection.canvasClicked.connect(self.pointEmitterIntersectioncanvasClicked) self.iface.mapCanvas().currentLayerChanged.disconnect(self.onCurrentLayerChanged) if self.IW is not None: self.IW.onUnLoadModule() def init_dock_inters_ways(self, dock): """Run method that loads and starts the plugin""" # if not self.pluginIsActive: self.pluginIsActive = True if self.dockwidget_inters_ways == None: self.dockwidget_inters_ways = WaysCalcDockWidget() self.dockwidget_inters_ways.closingPlugin.connect(self.onClosePlugin) self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dockwidget_inters_ways) self.dockwidget_inters_ways.hide() self.dockwidget_inters_ways.setWindowTitle(u'WaysCalc: Поиск пересечений для линейного объекта') def init_dock_inters_allways(self, dock): """Run method that loads and starts the plugin""" # if not self.pluginIsActive: self.pluginIsActive = True if self.dockwidget_inters_allways == None: self.dockwidget_inters_allways = WaysCalcDockWidget() self.dockwidget_inters_allways.closingPlugin.connect(self.onClosePlugin) self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dockwidget_inters_allways) self.dockwidget_inters_allways.hide() self.dockwidget_inters_allways.setWindowTitle(u'WaysCalc: Поиск пересечений всех линейных объектов') def onCurrentLayerChanged(self): self.iface.mapCanvas().unsetMapTool(self.pointEmitterIntersection) #-------------------------------------------------------------------------- # def loadSettings(self): # with open(os.path.join(self.plugin_dir, "settings.json"), "r") as read_file: # self.settings = json.load(read_file) #--------INTERSECTION WAYS------------------------------------------------- def run_initLayerWays(self): if self.IW is None: self.init_IW() self.IW.initLayerWays() def run_intersection(self): self.toolButton.setDefaultAction(self.action_intersection) self.init_dock_inters_ways(self.dockwidget_inters_ways) if self.IW is None: self.init_IW() if self.IW.checkLayers(): self.iface.mapCanvas().setMapTool(self.pointEmitterIntersection) def pointEmitterIntersectioncanvasClicked(self, point, button): self.IW.insersection_take_way(point) def init_IW(self): self.IW = IntersectionWays(self.iface, self.dockwidget_inters_ways) #-------- END INTERSECTION WAYS--------------------------------------------- def init_IAW(self): self.IAW = IntersectionAllWays(self.iface, self.dockwidget_inters_allways) def run_allintersection(self): self.init_dock_inters_allways(self.dockwidget_inters_allways) if self.IAW is None: self.init_IAW() self.IAW.showClickedFeaturesList()
def initGui(self): self.azDigitizerTool = AzDigitizerTool(self.iface) self.lineDigitizerTool = LineDigitizerTool(self.iface) # Initialize the create shape menu items menu = QMenu() # Initialize Create Arc Wedge tool icon = QIcon(self.plugin_dir + '/images/arc.png') self.createArcAction = menu.addAction(icon, tr('Create arc wedge'), self.createArc) self.createArcAction.setObjectName('stCreateArcWedge') icon = QIcon(self.plugin_dir + '/images/donut.png') self.createDonutAction = menu.addAction(icon, tr('Create donut'), self.createDonut) self.createDonutAction.setObjectName('stCreateDonut') icon = QIcon(self.plugin_dir + '/images/ellipse.png') self.createEllipseAction = menu.addAction(icon, tr('Create ellipse'), self.createEllipse) self.createEllipseAction.setObjectName('stCreateEllipse') icon = QIcon(self.plugin_dir + '/images/rose.png') self.createEllipseRoseAction = menu.addAction( icon, tr('Create ellipse rose'), self.createEllipseRose) self.createEllipseRoseAction.setObjectName('stCreateEllipseRose') icon = QIcon(self.plugin_dir + '/images/epicycloid.png') self.createEpicycloidAction = menu.addAction(icon, tr('Create epicycloid'), self.createEpicycloid) self.createEpicycloidAction.setObjectName('stCreateEpicycloid') icon = QIcon(self.plugin_dir + '/images/heart.png') self.createHeartAction = menu.addAction(icon, tr('Create heart'), self.createHeart) self.createHeartAction.setObjectName('stCreateHeart') icon = QIcon(self.plugin_dir + '/images/hypocycloid.png') self.createHypocycloidAction = menu.addAction(icon, tr('Create hypocycloid'), self.createHypocycloid) self.createHypocycloidAction.setObjectName('stCreateHypocycloid') icon = QIcon(self.plugin_dir + '/images/line.png') self.createLOBAction = menu.addAction(icon, tr('Create line of bearing'), self.createLOB) self.createLOBAction.setObjectName('stCreateLineOfBearing') icon = QIcon(self.plugin_dir + '/images/pie.png') self.createPieAction = menu.addAction(icon, tr('Create pie wedge'), self.createPie) self.createPieAction.setObjectName('stCreatePie') icon = QIcon(self.plugin_dir + '/images/polyfoil.png') self.createPolyfoilAction = menu.addAction(icon, tr('Create polyfoil'), self.createPolyfoil) self.createPolyfoilAction.setObjectName('stCreatePolyfoil') icon = QIcon(self.plugin_dir + '/images/polygon.png') self.createPolygonAction = menu.addAction(icon, tr('Create polygon'), self.createPolygon) self.createPolygonAction.setObjectName('stCreatePolygon') icon = QIcon(self.plugin_dir + '/images/star.png') self.createStarAction = menu.addAction(icon, tr('Create star'), self.createStar) self.createStarAction.setObjectName('stCreateStar') # Add the shape creation tools to the menu icon = QIcon(self.plugin_dir + '/images/shapes.png') self.createShapesAction = QAction(icon, tr('Create shapes'), self.iface.mainWindow()) self.createShapesAction.setMenu(menu) self.iface.addPluginToVectorMenu('Shape Tools', self.createShapesAction) # Add the shape creation tools to the toolbar self.createShapeButton = QToolButton() self.createShapeButton.setMenu(menu) self.createShapeButton.setDefaultAction(self.createDonutAction) self.createShapeButton.setPopupMode(QToolButton.MenuButtonPopup) self.createShapeButton.triggered.connect(self.createShapeTriggered) self.createShapeToolbar = self.toolbar.addWidget( self.createShapeButton) # Initialize the XY to Line menu item icon = QIcon(self.plugin_dir + '/images/xyline.png') self.xyLineAction = QAction(icon, tr('XY to line'), self.iface.mainWindow()) self.xyLineAction.setObjectName('stXYtoLine') self.xyLineAction.triggered.connect(self.xyLineTool) self.iface.addPluginToVectorMenu('Shape Tools', self.xyLineAction) self.toolbar.addAction(self.xyLineAction) # Initialize the Geodesic Densifier menu item icon = QIcon(self.plugin_dir + '/images/geodesicDensifier.png') self.geodesicDensifyAction = QAction(icon, tr('Geodesic shape densifier'), self.iface.mainWindow()) self.geodesicDensifyAction.setObjectName('stGeodesicDensifier') self.geodesicDensifyAction.triggered.connect(self.geodesicDensifyTool) self.iface.addPluginToVectorMenu('Shape Tools', self.geodesicDensifyAction) self.toolbar.addAction(self.geodesicDensifyAction) # Initialize the Geodesic decimation menu items menu = QMenu() icon = QIcon(self.plugin_dir + '/images/geodesicLineDecimate.png') self.lineDecimateAction = menu.addAction(icon, tr('Geodesic line decimate'), self.lineDecimateTool) self.lineDecimateAction.setObjectName('stGeodesicLineDecimate') icon = QIcon(self.plugin_dir + '/images/geodesicPointDecimate.png') self.pointDecimateAction = menu.addAction( icon, tr('Geodesic point decimate'), self.pointDecimateTool) self.pointDecimateAction.setObjectName('stGeodesicPointDecimate') # Add the decimation tools to the menu icon = QIcon(self.plugin_dir + '/images/geodesicLineDecimate.png') self.simplifyGeomAction = QAction( icon, tr('Geodesic geometry simplification'), self.iface.mainWindow()) self.simplifyGeomAction.setMenu(menu) self.iface.addPluginToVectorMenu('Shape Tools', self.simplifyGeomAction) # Add the shape creation tools to the toolbar self.simplifyButton = QToolButton() self.simplifyButton.setMenu(menu) self.simplifyButton.setDefaultAction(self.lineDecimateAction) self.simplifyButton.setPopupMode(QToolButton.MenuButtonPopup) self.simplifyButton.triggered.connect(self.simplifyTriggered) self.simplifyToolbar = self.toolbar.addWidget(self.simplifyButton) # Initialize the Geodesic line break menu item icon = QIcon(self.plugin_dir + '/images/idlbreak.png') self.geodesicLineBreakAction = QAction( icon, tr('Geodesic line break at -180,180'), self.iface.mainWindow()) self.geodesicLineBreakAction.setObjectName('stGeodesicLineBreak') self.geodesicLineBreakAction.triggered.connect( self.geodesicLineBreakTool) self.iface.addPluginToVectorMenu('Shape Tools', self.geodesicLineBreakAction) self.toolbar.addAction(self.geodesicLineBreakAction) # Initialize Geodesic Measure Tool self.geodesicMeasureTool = GeodesicMeasureTool(self.iface, self.iface.mainWindow()) icon = QIcon(self.plugin_dir + '/images/measure.png') self.measureAction = QAction(icon, tr('Geodesic measure tool'), self.iface.mainWindow()) self.measureAction.setObjectName('stGeodesicMeasureTool') self.measureAction.triggered.connect(self.measureTool) self.measureAction.setCheckable(True) self.iface.addPluginToVectorMenu('Shape Tools', self.measureAction) self.toolbar.addAction(self.measureAction) # Initialize Geodesic Measurement layer icon = QIcon(self.plugin_dir + '/images/measureLine.png') self.measureLayerAction = QAction(icon, tr('Geodesic measurement layer'), self.iface.mainWindow()) self.measureLayerAction.setObjectName('stGeodesicLineBreak') self.measureLayerAction.triggered.connect(self.measureLayerTool) self.iface.addPluginToVectorMenu('Shape Tools', self.measureLayerAction) self.toolbar.addAction(self.measureLayerAction) menu = QMenu() # Initialize Geodesic transformation tool icon = QIcon(self.plugin_dir + '/images/transformShape.png') self.transformationsAction = menu.addAction( icon, tr('Geodesic transformations'), self.transformTool) self.transformationsAction.setObjectName('stGeodesicTransformations') icon = QIcon(self.plugin_dir + '/images/flip.png') self.flipRotateAction = menu.addAction(icon, tr('Geodesic flip and rotate'), self.flipRotateTool) self.flipRotateAction.setObjectName('stGeodesicFlipRotate') icon = QIcon(self.plugin_dir + '/images/flipHorizontal.png') self.flipHorizontalAction = menu.addAction(icon, tr('Flip horizontal'), self.flipHorizontalTool) self.flipHorizontalAction.setObjectName('stGeodesicFlipHorizontal') self.flipHorizontalAction.setEnabled(False) icon = QIcon(self.plugin_dir + '/images/flipVertical.png') self.flipVerticalAction = menu.addAction(icon, tr('Flip vertical'), self.flipVerticalTool) self.flipVerticalAction.setObjectName('stGeodesicFlipVertical') self.flipVerticalAction.setEnabled(False) icon = QIcon(self.plugin_dir + '/images/rotate180.png') self.rotate180Action = menu.addAction(icon, tr('Rotate 180\xb0'), self.rotate180Tool) self.rotate180Action.setObjectName('stGeodesicRotate180') self.rotate180Action.setEnabled(False) icon = QIcon(self.plugin_dir + '/images/rotatecw.png') self.rotate90CWAction = menu.addAction(icon, tr('Rotate 90\xb0 CW'), self.rotate90CWTool) self.rotate90CWAction.setObjectName('stGeodesicRotate90CW') self.rotate90CWAction.setEnabled(False) icon = QIcon(self.plugin_dir + '/images/rotateccw.png') self.rotate90CCWAction = menu.addAction(icon, tr('Rotate 90\xb0 CCW'), self.rotate90CCWTool) self.rotate90CCWAction.setObjectName('stGeodesicRotate90CCW') self.rotate90CCWAction.setEnabled(False) self.transformsAction = QAction(icon, tr('Geodesic transforms'), self.iface.mainWindow()) self.transformsAction.setMenu(menu) self.iface.addPluginToVectorMenu('Shape Tools', self.transformsAction) self.transformationButton = QToolButton() self.transformationButton.setMenu(menu) self.transformationButton.setDefaultAction(self.transformationsAction) self.transformationButton.setPopupMode(QToolButton.MenuButtonPopup) self.transformationButton.triggered.connect(self.toolButtonTriggered) self.tranformToolbar = self.toolbar.addWidget( self.transformationButton) # Initialize the Azimuth Distance Digitize function icon = QIcon(self.plugin_dir + '/images/dazdigitize.png') self.digitizeAction = QAction(icon, tr('Azimuth distance digitizer'), self.iface.mainWindow()) self.digitizeAction.setObjectName('stAzDistanceDigitizer') self.digitizeAction.triggered.connect(self.setShowAzDigitizerTool) self.digitizeAction.setCheckable(True) self.digitizeAction.setEnabled(False) self.iface.addPluginToVectorMenu(u'Shape Tools', self.digitizeAction) self.toolbar.addAction(self.digitizeAction) # Initialize the multi point azimuth Digitize function icon = QIcon(self.plugin_dir + '/images/linedigitize.png') self.lineDigitizeAction = QAction( icon, tr('Azimuth distance sequence digitizer'), self.iface.mainWindow()) self.lineDigitizeAction.setObjectName('stLineDigitizer') self.lineDigitizeAction.triggered.connect(self.setShowLineDigitizeTool) self.lineDigitizeAction.setCheckable(True) self.lineDigitizeAction.setEnabled(False) self.iface.addPluginToVectorMenu(u'Shape Tools', self.lineDigitizeAction) self.toolbar.addAction(self.lineDigitizeAction) # Settings icon = QIcon(self.plugin_dir + '/images/settings.png') self.settingsAction = QAction(icon, tr('Settings'), self.iface.mainWindow()) self.settingsAction.setObjectName('shapeToolsSettings') self.settingsAction.triggered.connect(self.settings) self.iface.addPluginToVectorMenu('Shape Tools', self.settingsAction) # Help icon = QIcon(self.plugin_dir + '/images/help.png') self.helpAction = QAction(icon, tr('Shape Tools help'), self.iface.mainWindow()) self.helpAction.setObjectName('shapeToolsHelp') self.helpAction.triggered.connect(self.help) self.iface.addPluginToVectorMenu('Shape Tools', self.helpAction) self.iface.currentLayerChanged.connect(self.currentLayerChanged) self.canvas.mapToolSet.connect(self.unsetTool) self.enableTools() # Add the processing provider QgsApplication.processingRegistry().addProvider(self.provider)
class SearchDialog(QDialog): def __init__(self): super(SearchDialog, self).__init__(iface.mainWindow()) self.initGui() self.mapstory = None def initGui(self): hlayout = QHBoxLayout() layout = QVBoxLayout() self.searchBox = QLineEdit() self.searchBox.returnPressed.connect(self.search) self.searchBox.setPlaceholderText("[Enter search string and press enter to search for maps]") hlayout.addWidget(self.searchBox) self.button = QToolButton() self.button.setText("Search") self.button.clicked.connect(self.search) self.button.adjustSize() self.searchBox.setFixedHeight(self.button.height()) hlayout.addWidget(self.button) layout.addLayout(hlayout) w = QFrame() self.browser = QWebView() w.setStyleSheet("QFrame{border:1px solid rgb(0, 0, 0);}") innerlayout = QHBoxLayout() innerlayout.setSpacing(0) innerlayout.setMargin(0) innerlayout.addWidget(self.browser) w.setLayout(innerlayout) layout.addWidget(w) self.setLayout(layout) self.browser.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks) self.browser.settings().setUserStyleSheetUrl(QUrl("file://" + resourceFile("search.css").replace("\\", "/"))) self.browser.linkClicked.connect(self.linkClicked) self.resize(600, 500) self.setWindowTitle("Search stories") def linkClicked(self, url): self.mapstory = url.path() self.close() def search(self): text = self.searchBox.text().strip() if text: try: r = execute(lambda: requests.get("http://mapstory.org/api/base/search", params={"type__in":"map", "limit":50, "q": text})) r.raise_for_status() mapstories = r.json()["objects"] if mapstories: s = "<div><ul>" for mapstory in mapstories: link = "<a href='%s' class='button'>Open</a>" % (mapstory["id"]) s += "<li>%s <h3>%s</h3> %s <br> </li>" % (link, mapstory["title"], mapstory["abstract"]) s += "</ul></div>" else: s = "<h2>No maps matching your search criteria were found.</h2>" self.browser.setHtml(s) except RequestException as e: QMessageBox.warning(self, "Search", u"There has been a problem performing the search:\n" + str(e.args[0]), QMessageBox.Ok)
def initGui(self): """startup""" parent = self.iface.mainWindow() ######## action, button icon = QIcon("%s/%s" % (config.PLUGIN_DIR, "images/xyz.png")) icon_bbox = QIcon("%s/%s" % (config.PLUGIN_DIR, "images/bbox.svg")) self.action_connect = QAction(icon, "New XYZ Hub Connection", parent) self.action_connect.setWhatsThis( QCoreApplication.translate(PLUGIN_NAME, "WhatsThis message")) self.action_connect.setStatusTip( QCoreApplication.translate(PLUGIN_NAME, "status tip message")) self.action_clear_cache = QAction("Clear cache", parent) self.action_upload = QAction("Upload to New XYZ Geospace", parent) self.action_basemap = QAction("Add HERE Map Tile", parent) self.action_magic_sync = QAction("Magic Sync (EXPERIMENTAL)", parent) self.action_manage = QAction("Manage XYZ Geospace (EXPERIMENTAL)", parent) self.action_edit = QAction("Edit/Delete XYZ Geospace (EXPERIMENTAL)", parent) if self.iface.activeLayer() is None: # self.action_upload.setEnabled(False) self.action_edit.setEnabled(False) self.action_magic_sync.setEnabled(False) # self.action_magic_sync.setVisible(False) # disable magic sync ######## CONNECT action, button self.action_connect.triggered.connect(self.open_connection_dialog) self.action_manage.triggered.connect(self.open_manage_dialog) self.action_edit.triggered.connect(self.open_edit_dialog) self.action_upload.triggered.connect(self.open_upload_dialog) self.action_magic_sync.triggered.connect(self.open_magic_sync_dialog) self.action_clear_cache.triggered.connect(self.open_clear_cache_dialog) self.action_basemap.triggered.connect(self.open_basemap_dialog) ######## Add the toolbar + button self.toolbar = self.iface.addToolBar(PLUGIN_NAME) self.toolbar.setObjectName("XYZ Hub Connector") tool_btn = QToolButton(self.toolbar) self.actions = [ self.action_connect, self.action_upload, self.action_basemap, self.action_clear_cache ] # , self.action_magic_sync, self.action_manage, self.action_edit for a in self.actions: tool_btn.addAction(a) self.iface.addPluginToWebMenu(self.web_menu, a) tool_btn.setDefaultAction(self.action_connect) tool_btn.setPopupMode(tool_btn.MenuButtonPopup) self.xyz_widget_action = self.toolbar.addWidget(tool_btn) self.action_help = None self.action_reload = QAction(icon_bbox, "Reload BBox", parent) self.action_reload.triggered.connect(self.layer_reload_bbox) self.action_reload.setVisible(False) # disable self.toolbar.addAction(self.action_reload) progress = QProgressBar() progress.setMinimum(0) progress.setMaximum(0) progress.reset() progress.hide() # progress = self.iface.statusBarIface().children()[2] # will be hidden by qgis self.iface.statusBarIface().addPermanentWidget(progress) self.pb = progress
def __init__(self, column, parent=None, pixmap=None, host=None): """ Class constructor. :param column: Column object containing foreign key information. :type column: BaseColumn :param parent: Parent widget for the control. :type parent: QWidget :param pixmap: Pixmap to use for the line edit button. :type pixmap: QPixmap """ QLineEdit.__init__(self, parent) self.column = column self._entity = self.column.entity self.entity_dialog = host # Configure load button self.btn_load = QToolButton(parent) self.btn_load.setCursor(Qt.PointingHandCursor) self.btn_load.setFocusPolicy(Qt.NoFocus) px = GuiUtils.get_icon_pixmap('select_record.png') if not pixmap is None: px = pixmap self.btn_load.setIcon(QIcon(px)) self.btn_load.setIconSize(px.size()) self.btn_load.setStyleSheet('background: transparent; padding: 0px; ' 'border: none;') self.btn_load.clicked.connect(self.on_load_foreign_key_browser) clear_px = GuiUtils.get_icon_pixmap('clear.png') self.btn_clear = QToolButton(parent) self.btn_clear.setCursor(Qt.PointingHandCursor) self.btn_clear.setFocusPolicy(Qt.NoFocus) self.btn_clear.setIcon(QIcon(clear_px)) self.btn_clear.setIconSize(clear_px.size()) self.btn_clear.setStyleSheet('background: transparent; padding: 0px; ' 'border: none;') self.btn_clear.clicked.connect(self.clear_line_edit) frame_width = self.set_button_minimum_size(self.btn_load) self.set_button_minimum_size(self.btn_clear) # Ensure that text does not overlay button padding = self.btn_load.sizeHint().width() + frame_width + 1 self.setStyleSheet('padding-right: ' + str(padding * 2) + 'px;') # Set layout self.button_layout = QHBoxLayout(self) self.button_layout.addWidget(self.btn_clear, 0, Qt.AlignRight) self.button_layout.addWidget(self.btn_load, 0, Qt.AlignRight) self.button_layout.setSpacing(0) self.button_layout.setMargin(5) self.btn_clear.setVisible(False) # Readonly as text is loaded from the related entity self.setReadOnly(True) # Current model object self._current_item = None
class AeroGen: """QGIS Plugin Implementation.""" def __init__(self, iface): """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 """ # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join(self.plugin_dir, 'i18n', 'AeroGen_{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) if qVersion() > '4.3.3': QCoreApplication.installTranslator(self.translator) # Declare instance attributes self.actions = [] self.menu = self.tr('&AeroGen') # add plugin icon into plugin toolbar self.toolButton = QToolButton() #print "** INITIALIZING AeroGen" self.pluginIsActive = False self.dockwidget = None # noinspection PyMethodMayBeStatic def tr(self, 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('AeroGen', message) def add_action(self, icon_path, text, callback, enabled_flag=True, add_to_menu=True, add_to_toolbar=True, status_tip=None, whats_this=None, parent=None): """Add a toolbar icon to the toolbar. :param icon_path: Path to the icon for this action. Can be a resource path (e.g. ':/plugins/foo/bar.png') or a normal file system path. :type icon_path: str :param text: Text that should be shown in menu items for this action. :type text: str :param callback: Function to be called when the action is triggered. :type callback: function :param enabled_flag: A flag indicating if the action should be enabled by default. Defaults to True. :type enabled_flag: bool :param add_to_menu: Flag indicating whether the action should also be added to the menu. Defaults to True. :type add_to_menu: bool :param add_to_toolbar: Flag indicating whether the action should also be added to the toolbar. Defaults to True. :type add_to_toolbar: bool :param status_tip: Optional text to show in a popup when mouse pointer hovers over the action. :type status_tip: str :param parent: Parent widget for the new action. Defaults None. :type parent: QWidget :param whats_this: Optional text to show in the status bar when the mouse pointer hovers over the action. :returns: The action that was created. Note that the action is also added to self.actions list. :rtype: QAction """ icon = QIcon(icon_path) action = QAction(icon, text, parent) action.triggered.connect(callback) action.setEnabled(enabled_flag) if status_tip is not None: action.setStatusTip(status_tip) if whats_this is not None: action.setWhatsThis(whats_this) if add_to_toolbar: self.toolButton.setDefaultAction(action) self.iface.addToolBarWidget(self.toolButton) if add_to_menu: self.iface.addPluginToMenu(self.menu, action) self.actions.append(action) return action def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" icon_path = ':/plugins/AeroGen/icon.png' self.add_action(icon_path, text=self.tr('AeroGen'), callback=self.run, parent=self.iface.mainWindow()) #-------------------------------------------------------------------------- def onClosePlugin(self): """Cleanup necessary items here when plugin dockwidget is closed""" #print "** CLOSING AeroGen" # disconnects self.dockwidget.closingPlugin.disconnect(self.onClosePlugin) # remove this statement if dockwidget is to remain # for reuse if plugin is reopened # Commented next statement since it causes QGIS crashe # when closing the docked window: # self.dockwidget = None self.pluginIsActive = False def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" #print "** UNLOAD AeroGen" for action in self.actions: self.iface.removePluginMenu(self.tr('&AeroGen'), action) self.iface.removeToolBarIcon(action) #-------------------------------------------------------------------------- def run(self): """Run method that loads and starts the plugin""" if not self.pluginIsActive: self.pluginIsActive = True #print "** STARTING AeroGen" # dockwidget may not exist if: # first run of plugin # removed on close (see self.onClosePlugin method) if self.dockwidget == None: # Create the dockwidget (after translation) and keep reference self.dockwidget = AeroGenDockWidget() # connect to provide cleanup on closing of dockwidget self.dockwidget.closingPlugin.connect(self.onClosePlugin) # show the dockwidget # TODO: fix to allow choice of dock location self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.dockwidget) self.dockwidget.show()
class ExpressionLineEdit(QLineEdit): def __init__(self, column, host=None, parent=None): # Use a different pixmap self._current_profile = current_profile() QLineEdit.__init__(self, parent) self.column = column self._entity = self.column.entity self.layer = self.create_layer() self.host = host # Configure load button self.btn_load = QToolButton(parent) self.btn_load.setCursor(Qt.PointingHandCursor) self.btn_load.setFocusPolicy(Qt.NoFocus) px = GuiUtils.get_icon_pixmap('expression.png') self.btn_load.setIcon(QIcon(px)) self.btn_load.setIconSize(px.size()) self.btn_load.setStyleSheet('background: transparent; padding: 0px; ' 'border: none;') frame_width = self.set_button_minimum_size(self.btn_load) # Ensure that text does not overlay button padding = self.btn_load.sizeHint().width() + frame_width + 1 self.setStyleSheet('padding-right: ' + str(padding * 2) + 'px;') # Set layout self.button_layout = QHBoxLayout(self) self.button_layout.addWidget(self.btn_load, 0, Qt.AlignRight) self.button_layout.setSpacing(0) self.button_layout.setMargin(5) # Readonly as text generated automatically self.setReadOnly(True) # Current model object self._current_item = None def create_layer(self): srid = None column = '' if self.entity.has_geometry_column(): geom_cols = [col.name for col in self.entity.columns.values() if col.TYPE_INFO == 'GEOMETRY'] column = geom_cols[0] geom_col_obj = self.entity.columns[column] if geom_col_obj.srid >= 100000: srid = geom_col_obj.srid layer = vector_layer(self.entity.name, geom_column=column, proj_wkt=srid) return layer def get_feature_value(self, model=None): self.layer.startEditing() feature = None request = QgsFeatureRequest() if model is None: model = self.host.model() request.setFilterFid(model.id) feature_itr = self.layer.getFeatures(request) for feat in feature_itr: feature = feat break exp = QgsExpression(self.column.expression) if exp.hasParserError(): raise Exception(exp.parserErrorString()) exp.prepare(self.layer.fields()) if feature is not None: value = exp.evaluate(feature) return value else: return None def set_button_minimum_size(self, button): """ Sets the minimum button size. :param button: The button to be set. :type button: QToolButton :return: Returns the frame width of the button :rtype: Integer """ frame_width = self.style().pixelMetric(QStyle.PM_DefaultFrameWidth) msz = self.minimumSizeHint() self.setMinimumSize( max( msz.width(), button.sizeHint().height() + frame_width * 2 + 2 ), max( msz.height(), button.sizeHint().height() + frame_width * 2 + 2 ) ) return frame_width @property def entity(self): """ :return: Returns the entity object corresponding to this widget. :rtype: Entity """ return self._entity def clear_line_edit(self): """ Clears the text in the line edit. """ self.clear() def on_expression_triggered(self, model=None): """ Slot raised to load browser for selecting foreign key entities. To be implemented by subclasses. """ self.format_display(self.get_feature_value(model)) return self.get_feature_value() def format_display(self, value): """ Extract object values to show in the line edit based on the specified display columns. """ if value is not None: self.setText(str(value))
class ModelerDialog(BASE, WIDGET): ALG_ITEM = 'ALG_ITEM' PROVIDER_ITEM = 'PROVIDER_ITEM' GROUP_ITEM = 'GROUP_ITEM' NAME_ROLE = Qt.UserRole TAG_ROLE = Qt.UserRole + 1 TYPE_ROLE = Qt.UserRole + 2 CANVAS_SIZE = 4000 update_model = pyqtSignal() def __init__(self, model=None): super().__init__(None) self.setAttribute(Qt.WA_DeleteOnClose) self.setupUi(self) self._variables_scope = None # LOTS of bug reports when we include the dock creation in the UI file # see e.g. #16428, #19068 # So just roll it all by hand......! self.propertiesDock = QgsDockWidget(self) self.propertiesDock.setFeatures( QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable) self.propertiesDock.setObjectName("propertiesDock") propertiesDockContents = QWidget() self.verticalDockLayout_1 = QVBoxLayout(propertiesDockContents) self.verticalDockLayout_1.setContentsMargins(0, 0, 0, 0) self.verticalDockLayout_1.setSpacing(0) self.scrollArea_1 = QgsScrollArea(propertiesDockContents) sizePolicy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.scrollArea_1.sizePolicy().hasHeightForWidth()) self.scrollArea_1.setSizePolicy(sizePolicy) self.scrollArea_1.setFocusPolicy(Qt.WheelFocus) self.scrollArea_1.setFrameShape(QFrame.NoFrame) self.scrollArea_1.setFrameShadow(QFrame.Plain) self.scrollArea_1.setWidgetResizable(True) self.scrollAreaWidgetContents_1 = QWidget() self.gridLayout = QGridLayout(self.scrollAreaWidgetContents_1) self.gridLayout.setContentsMargins(6, 6, 6, 6) self.gridLayout.setSpacing(4) self.label_1 = QLabel(self.scrollAreaWidgetContents_1) self.gridLayout.addWidget(self.label_1, 0, 0, 1, 1) self.textName = QLineEdit(self.scrollAreaWidgetContents_1) self.gridLayout.addWidget(self.textName, 0, 1, 1, 1) self.label_2 = QLabel(self.scrollAreaWidgetContents_1) self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1) self.textGroup = QLineEdit(self.scrollAreaWidgetContents_1) self.gridLayout.addWidget(self.textGroup, 1, 1, 1, 1) self.label_1.setText(self.tr("Name")) self.textName.setToolTip(self.tr("Enter model name here")) self.label_2.setText(self.tr("Group")) self.textGroup.setToolTip(self.tr("Enter group name here")) self.scrollArea_1.setWidget(self.scrollAreaWidgetContents_1) self.verticalDockLayout_1.addWidget(self.scrollArea_1) self.propertiesDock.setWidget(propertiesDockContents) self.propertiesDock.setWindowTitle(self.tr("Model Properties")) self.inputsDock = QgsDockWidget(self) self.inputsDock.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable) self.inputsDock.setObjectName("inputsDock") self.inputsDockContents = QWidget() self.verticalLayout_3 = QVBoxLayout(self.inputsDockContents) self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) self.scrollArea_2 = QgsScrollArea(self.inputsDockContents) sizePolicy.setHeightForWidth(self.scrollArea_2.sizePolicy().hasHeightForWidth()) self.scrollArea_2.setSizePolicy(sizePolicy) self.scrollArea_2.setFocusPolicy(Qt.WheelFocus) self.scrollArea_2.setFrameShape(QFrame.NoFrame) self.scrollArea_2.setFrameShadow(QFrame.Plain) self.scrollArea_2.setWidgetResizable(True) self.scrollAreaWidgetContents_2 = QWidget() self.verticalLayout = QVBoxLayout(self.scrollAreaWidgetContents_2) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setSpacing(0) self.inputsTree = QTreeWidget(self.scrollAreaWidgetContents_2) self.inputsTree.setAlternatingRowColors(True) self.inputsTree.header().setVisible(False) self.verticalLayout.addWidget(self.inputsTree) self.scrollArea_2.setWidget(self.scrollAreaWidgetContents_2) self.verticalLayout_3.addWidget(self.scrollArea_2) self.inputsDock.setWidget(self.inputsDockContents) self.addDockWidget(Qt.DockWidgetArea(1), self.inputsDock) self.inputsDock.setWindowTitle(self.tr("Inputs")) self.algorithmsDock = QgsDockWidget(self) self.algorithmsDock.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable) self.algorithmsDock.setObjectName("algorithmsDock") self.algorithmsDockContents = QWidget() self.verticalLayout_4 = QVBoxLayout(self.algorithmsDockContents) self.verticalLayout_4.setContentsMargins(0, 0, 0, 0) self.scrollArea_3 = QgsScrollArea(self.algorithmsDockContents) sizePolicy.setHeightForWidth(self.scrollArea_3.sizePolicy().hasHeightForWidth()) self.scrollArea_3.setSizePolicy(sizePolicy) self.scrollArea_3.setFocusPolicy(Qt.WheelFocus) self.scrollArea_3.setFrameShape(QFrame.NoFrame) self.scrollArea_3.setFrameShadow(QFrame.Plain) self.scrollArea_3.setWidgetResizable(True) self.scrollAreaWidgetContents_3 = QWidget() self.verticalLayout_2 = QVBoxLayout(self.scrollAreaWidgetContents_3) self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) self.verticalLayout_2.setSpacing(4) self.searchBox = QgsFilterLineEdit(self.scrollAreaWidgetContents_3) self.verticalLayout_2.addWidget(self.searchBox) self.algorithmTree = QgsProcessingToolboxTreeView(None, QgsApplication.processingRegistry()) self.algorithmTree.setAlternatingRowColors(True) self.algorithmTree.header().setVisible(False) self.verticalLayout_2.addWidget(self.algorithmTree) self.scrollArea_3.setWidget(self.scrollAreaWidgetContents_3) self.verticalLayout_4.addWidget(self.scrollArea_3) self.algorithmsDock.setWidget(self.algorithmsDockContents) self.addDockWidget(Qt.DockWidgetArea(1), self.algorithmsDock) self.algorithmsDock.setWindowTitle(self.tr("Algorithms")) self.searchBox.setToolTip(self.tr("Enter algorithm name to filter list")) self.searchBox.setShowSearchIcon(True) self.variables_dock = QgsDockWidget(self) self.variables_dock.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable) self.variables_dock.setObjectName("variablesDock") self.variables_dock_contents = QWidget() vl_v = QVBoxLayout() vl_v.setContentsMargins(0, 0, 0, 0) self.variables_editor = QgsVariableEditorWidget() vl_v.addWidget(self.variables_editor) self.variables_dock_contents.setLayout(vl_v) self.variables_dock.setWidget(self.variables_dock_contents) self.addDockWidget(Qt.DockWidgetArea(1), self.variables_dock) self.variables_dock.setWindowTitle(self.tr("Variables")) self.addDockWidget(Qt.DockWidgetArea(1), self.propertiesDock) self.tabifyDockWidget(self.propertiesDock, self.variables_dock) self.variables_editor.scopeChanged.connect(self.variables_changed) self.bar = QgsMessageBar() self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed) self.centralWidget().layout().insertWidget(0, self.bar) try: self.setDockOptions(self.dockOptions() | QMainWindow.GroupedDragging) except: pass if iface is not None: self.mToolbar.setIconSize(iface.iconSize()) self.setStyleSheet(iface.mainWindow().styleSheet()) self.toolbutton_export_to_script = QToolButton() self.toolbutton_export_to_script.setPopupMode(QToolButton.InstantPopup) self.export_to_script_algorithm_action = QAction(QCoreApplication.translate('ModelerDialog', 'Export as Script Algorithm…')) self.toolbutton_export_to_script.addActions([self.export_to_script_algorithm_action]) self.mToolbar.insertWidget(self.mActionExportImage, self.toolbutton_export_to_script) self.export_to_script_algorithm_action.triggered.connect(self.export_as_script_algorithm) self.mActionOpen.setIcon( QgsApplication.getThemeIcon('/mActionFileOpen.svg')) self.mActionSave.setIcon( QgsApplication.getThemeIcon('/mActionFileSave.svg')) self.mActionSaveAs.setIcon( QgsApplication.getThemeIcon('/mActionFileSaveAs.svg')) self.mActionSaveInProject.setIcon( QgsApplication.getThemeIcon('/mAddToProject.svg')) self.mActionZoomActual.setIcon( QgsApplication.getThemeIcon('/mActionZoomActual.svg')) self.mActionZoomIn.setIcon( QgsApplication.getThemeIcon('/mActionZoomIn.svg')) self.mActionZoomOut.setIcon( QgsApplication.getThemeIcon('/mActionZoomOut.svg')) self.mActionExportImage.setIcon( QgsApplication.getThemeIcon('/mActionSaveMapAsImage.svg')) self.mActionZoomToItems.setIcon( QgsApplication.getThemeIcon('/mActionZoomFullExtent.svg')) self.mActionExportPdf.setIcon( QgsApplication.getThemeIcon('/mActionSaveAsPDF.svg')) self.mActionExportSvg.setIcon( QgsApplication.getThemeIcon('/mActionSaveAsSVG.svg')) self.toolbutton_export_to_script.setIcon( QgsApplication.getThemeIcon('/mActionSaveAsPython.svg')) self.mActionEditHelp.setIcon( QgsApplication.getThemeIcon('/mActionEditHelpContent.svg')) self.mActionRun.setIcon( QgsApplication.getThemeIcon('/mActionStart.svg')) self.addDockWidget(Qt.LeftDockWidgetArea, self.propertiesDock) self.addDockWidget(Qt.LeftDockWidgetArea, self.inputsDock) self.addDockWidget(Qt.LeftDockWidgetArea, self.algorithmsDock) self.tabifyDockWidget(self.inputsDock, self.algorithmsDock) self.inputsDock.raise_() self.setWindowFlags(Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint | Qt.WindowCloseButtonHint) settings = QgsSettings() self.restoreState(settings.value("/Processing/stateModeler", QByteArray())) self.restoreGeometry(settings.value("/Processing/geometryModeler", QByteArray())) self.scene = ModelerScene(self, dialog=self) self.scene.setSceneRect(QRectF(0, 0, self.CANVAS_SIZE, self.CANVAS_SIZE)) self.view.setScene(self.scene) self.view.setAcceptDrops(True) self.view.ensureVisible(0, 0, 10, 10) self.view.scale(QgsApplication.desktop().logicalDpiX() / 96, QgsApplication.desktop().logicalDpiX() / 96) def _dragEnterEvent(event): if event.mimeData().hasText() or event.mimeData().hasFormat('application/x-vnd.qgis.qgis.algorithmid'): event.acceptProposedAction() else: event.ignore() def _dropEvent(event): def alg_dropped(algorithm_id, pos): alg = QgsApplication.processingRegistry().createAlgorithmById(algorithm_id) if alg is not None: self._addAlgorithm(alg, pos) else: assert False, algorithm_id def input_dropped(id, pos): if id in [param.id() for param in QgsApplication.instance().processingRegistry().parameterTypes()]: self.addInputOfType(itemId, pos) if event.mimeData().hasFormat('application/x-vnd.qgis.qgis.algorithmid'): data = event.mimeData().data('application/x-vnd.qgis.qgis.algorithmid') stream = QDataStream(data, QIODevice.ReadOnly) algorithm_id = stream.readQString() QTimer.singleShot(0, lambda id=algorithm_id, pos=self.view.mapToScene(event.pos()): alg_dropped(id, pos)) event.accept() elif event.mimeData().hasText(): itemId = event.mimeData().text() QTimer.singleShot(0, lambda id=itemId, pos=self.view.mapToScene(event.pos()): input_dropped(id, pos)) event.accept() else: event.ignore() def _dragMoveEvent(event): if event.mimeData().hasText() or event.mimeData().hasFormat('application/x-vnd.qgis.qgis.algorithmid'): event.accept() else: event.ignore() def _wheelEvent(event): self.view.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) settings = QgsSettings() factor = settings.value('/qgis/zoom_favor', 2.0) # "Normal" mouse has an angle delta of 120, precision mouses provide data # faster, in smaller steps factor = 1.0 + (factor - 1.0) / 120.0 * abs(event.angleDelta().y()) if (event.modifiers() == Qt.ControlModifier): factor = 1.0 + (factor - 1.0) / 20.0 if event.angleDelta().y() < 0: factor = 1 / factor self.view.scale(factor, factor) def _enterEvent(e): QGraphicsView.enterEvent(self.view, e) self.view.viewport().setCursor(Qt.ArrowCursor) def _mouseReleaseEvent(e): QGraphicsView.mouseReleaseEvent(self.view, e) self.view.viewport().setCursor(Qt.ArrowCursor) def _mousePressEvent(e): if e.button() == Qt.MidButton: self.previousMousePos = e.pos() else: QGraphicsView.mousePressEvent(self.view, e) def _mouseMoveEvent(e): if e.buttons() == Qt.MidButton: offset = self.previousMousePos - e.pos() self.previousMousePos = e.pos() self.view.verticalScrollBar().setValue(self.view.verticalScrollBar().value() + offset.y()) self.view.horizontalScrollBar().setValue(self.view.horizontalScrollBar().value() + offset.x()) else: QGraphicsView.mouseMoveEvent(self.view, e) self.view.setDragMode(QGraphicsView.ScrollHandDrag) self.view.dragEnterEvent = _dragEnterEvent self.view.dropEvent = _dropEvent self.view.dragMoveEvent = _dragMoveEvent self.view.wheelEvent = _wheelEvent self.view.enterEvent = _enterEvent self.view.mousePressEvent = _mousePressEvent self.view.mouseMoveEvent = _mouseMoveEvent def _mimeDataInput(items): mimeData = QMimeData() text = items[0].data(0, Qt.UserRole) mimeData.setText(text) return mimeData self.inputsTree.mimeData = _mimeDataInput self.inputsTree.setDragDropMode(QTreeWidget.DragOnly) self.inputsTree.setDropIndicatorShown(True) self.algorithms_model = ModelerToolboxModel(self, QgsApplication.processingRegistry()) self.algorithmTree.setToolboxProxyModel(self.algorithms_model) self.algorithmTree.setDragDropMode(QTreeWidget.DragOnly) self.algorithmTree.setDropIndicatorShown(True) filters = QgsProcessingToolboxProxyModel.Filters(QgsProcessingToolboxProxyModel.FilterModeler) if ProcessingConfig.getSetting(ProcessingConfig.SHOW_ALGORITHMS_KNOWN_ISSUES): filters |= QgsProcessingToolboxProxyModel.FilterShowKnownIssues self.algorithmTree.setFilters(filters) if hasattr(self.searchBox, 'setPlaceholderText'): self.searchBox.setPlaceholderText(QCoreApplication.translate('ModelerDialog', 'Search…')) if hasattr(self.textName, 'setPlaceholderText'): self.textName.setPlaceholderText(self.tr('Enter model name here')) if hasattr(self.textGroup, 'setPlaceholderText'): self.textGroup.setPlaceholderText(self.tr('Enter group name here')) # Connect signals and slots self.inputsTree.doubleClicked.connect(self.addInput) self.searchBox.textChanged.connect(self.algorithmTree.setFilterString) self.algorithmTree.doubleClicked.connect(self.addAlgorithm) # Ctrl+= should also trigger a zoom in action ctrlEquals = QShortcut(QKeySequence("Ctrl+="), self) ctrlEquals.activated.connect(self.zoomIn) self.mActionOpen.triggered.connect(self.openModel) self.mActionSave.triggered.connect(self.save) self.mActionSaveAs.triggered.connect(self.saveAs) self.mActionSaveInProject.triggered.connect(self.saveInProject) self.mActionZoomIn.triggered.connect(self.zoomIn) self.mActionZoomOut.triggered.connect(self.zoomOut) self.mActionZoomActual.triggered.connect(self.zoomActual) self.mActionZoomToItems.triggered.connect(self.zoomToItems) self.mActionExportImage.triggered.connect(self.exportAsImage) self.mActionExportPdf.triggered.connect(self.exportAsPdf) self.mActionExportSvg.triggered.connect(self.exportAsSvg) #self.mActionExportPython.triggered.connect(self.exportAsPython) self.mActionEditHelp.triggered.connect(self.editHelp) self.mActionRun.triggered.connect(self.runModel) if model is not None: self.model = model.create() self.model.setSourceFilePath(model.sourceFilePath()) self.textGroup.setText(self.model.group()) self.textName.setText(self.model.displayName()) self.repaintModel() else: self.model = QgsProcessingModelAlgorithm() self.model.setProvider(QgsApplication.processingRegistry().providerById('model')) self.update_variables_gui() self.fillInputsTree() self.view.centerOn(0, 0) self.help = None self.hasChanged = False def closeEvent(self, evt): settings = QgsSettings() settings.setValue("/Processing/stateModeler", self.saveState()) settings.setValue("/Processing/geometryModeler", self.saveGeometry()) if self.hasChanged: ret = QMessageBox.question( self, self.tr('Save Model?'), self.tr('There are unsaved changes in this model. Do you want to keep those?'), QMessageBox.Save | QMessageBox.Cancel | QMessageBox.Discard, QMessageBox.Cancel) if ret == QMessageBox.Save: self.saveModel(False) evt.accept() elif ret == QMessageBox.Discard: evt.accept() else: evt.ignore() else: evt.accept() def editHelp(self): alg = self.model dlg = HelpEditionDialog(alg) dlg.exec_() if dlg.descriptions: self.model.setHelpContent(dlg.descriptions) self.hasChanged = True def update_variables_gui(self): variables_scope = QgsExpressionContextScope(self.tr('Model Variables')) for k, v in self.model.variables().items(): variables_scope.setVariable(k, v) variables_context = QgsExpressionContext() variables_context.appendScope(variables_scope) self.variables_editor.setContext(variables_context) self.variables_editor.setEditableScopeIndex(0) def variables_changed(self): self.model.setVariables(self.variables_editor.variablesInActiveScope()) def runModel(self): if len(self.model.childAlgorithms()) == 0: self.bar.pushMessage("", self.tr("Model doesn't contain any algorithm and/or parameter and can't be executed"), level=Qgis.Warning, duration=5) return dlg = AlgorithmDialog(self.model.create(), parent=iface.mainWindow()) dlg.exec_() def save(self): self.saveModel(False) def saveAs(self): self.saveModel(True) def saveInProject(self): if not self.can_save(): return self.model.setName(str(self.textName.text())) self.model.setGroup(str(self.textGroup.text())) self.model.setSourceFilePath(None) project_provider = QgsApplication.processingRegistry().providerById(PROJECT_PROVIDER_ID) project_provider.add_model(self.model) self.update_model.emit() self.bar.pushMessage("", self.tr("Model was saved inside current project"), level=Qgis.Success, duration=5) self.hasChanged = False QgsProject.instance().setDirty(True) def zoomIn(self): self.view.setTransformationAnchor(QGraphicsView.NoAnchor) point = self.view.mapToScene(QPoint(self.view.viewport().width() / 2, self.view.viewport().height() / 2)) settings = QgsSettings() factor = settings.value('/qgis/zoom_favor', 2.0) self.view.scale(factor, factor) self.view.centerOn(point) self.repaintModel() def zoomOut(self): self.view.setTransformationAnchor(QGraphicsView.NoAnchor) point = self.view.mapToScene(QPoint(self.view.viewport().width() / 2, self.view.viewport().height() / 2)) settings = QgsSettings() factor = settings.value('/qgis/zoom_favor', 2.0) factor = 1 / factor self.view.scale(factor, factor) self.view.centerOn(point) self.repaintModel() def zoomActual(self): point = self.view.mapToScene(QPoint(self.view.viewport().width() / 2, self.view.viewport().height() / 2)) self.view.resetTransform() self.view.scale(QgsApplication.desktop().logicalDpiX() / 96, QgsApplication.desktop().logicalDpiX() / 96) self.view.centerOn(point) def zoomToItems(self): totalRect = self.scene.itemsBoundingRect() totalRect.adjust(-10, -10, 10, 10) self.view.fitInView(totalRect, Qt.KeepAspectRatio) def exportAsImage(self): self.repaintModel(controls=False) filename, fileFilter = QFileDialog.getSaveFileName(self, self.tr('Save Model As Image'), '', self.tr('PNG files (*.png *.PNG)')) if not filename: return if not filename.lower().endswith('.png'): filename += '.png' totalRect = self.scene.itemsBoundingRect() totalRect.adjust(-10, -10, 10, 10) imgRect = QRectF(0, 0, totalRect.width(), totalRect.height()) img = QImage(totalRect.width(), totalRect.height(), QImage.Format_ARGB32_Premultiplied) img.fill(Qt.white) painter = QPainter() painter.setRenderHint(QPainter.Antialiasing) painter.begin(img) self.scene.render(painter, imgRect, totalRect) painter.end() img.save(filename) self.bar.pushMessage("", self.tr("Successfully exported model as image to <a href=\"{}\">{}</a>").format(QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5) self.repaintModel(controls=True) def exportAsPdf(self): self.repaintModel(controls=False) filename, fileFilter = QFileDialog.getSaveFileName(self, self.tr('Save Model As PDF'), '', self.tr('PDF files (*.pdf *.PDF)')) if not filename: return if not filename.lower().endswith('.pdf'): filename += '.pdf' totalRect = self.scene.itemsBoundingRect() totalRect.adjust(-10, -10, 10, 10) printerRect = QRectF(0, 0, totalRect.width(), totalRect.height()) printer = QPrinter() printer.setOutputFormat(QPrinter.PdfFormat) printer.setOutputFileName(filename) printer.setPaperSize(QSizeF(printerRect.width(), printerRect.height()), QPrinter.DevicePixel) printer.setFullPage(True) painter = QPainter(printer) self.scene.render(painter, printerRect, totalRect) painter.end() self.bar.pushMessage("", self.tr("Successfully exported model as PDF to <a href=\"{}\">{}</a>").format(QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5) self.repaintModel(controls=True) def exportAsSvg(self): self.repaintModel(controls=False) filename, fileFilter = QFileDialog.getSaveFileName(self, self.tr('Save Model As SVG'), '', self.tr('SVG files (*.svg *.SVG)')) if not filename: return if not filename.lower().endswith('.svg'): filename += '.svg' totalRect = self.scene.itemsBoundingRect() totalRect.adjust(-10, -10, 10, 10) svgRect = QRectF(0, 0, totalRect.width(), totalRect.height()) svg = QSvgGenerator() svg.setFileName(filename) svg.setSize(QSize(totalRect.width(), totalRect.height())) svg.setViewBox(svgRect) svg.setTitle(self.model.displayName()) painter = QPainter(svg) self.scene.render(painter, svgRect, totalRect) painter.end() self.bar.pushMessage("", self.tr("Successfully exported model as SVG to <a href=\"{}\">{}</a>").format(QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5) self.repaintModel(controls=True) def exportAsPython(self): filename, filter = QFileDialog.getSaveFileName(self, self.tr('Save Model As Python Script'), '', self.tr('Processing scripts (*.py *.PY)')) if not filename: return if not filename.lower().endswith('.py'): filename += '.py' text = self.model.asPythonCode() with codecs.open(filename, 'w', encoding='utf-8') as fout: fout.write(text) self.bar.pushMessage("", self.tr("Successfully exported model as python script to <a href=\"{}\">{}</a>").format(QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5) def can_save(self): """ Tests whether a model can be saved, or if it is not yet valid :return: bool """ if str(self.textName.text()).strip() == '': self.bar.pushWarning( "", self.tr('Please a enter model name before saving') ) return False return True def saveModel(self, saveAs): if not self.can_save(): return self.model.setName(str(self.textName.text())) self.model.setGroup(str(self.textGroup.text())) if self.model.sourceFilePath() and not saveAs: filename = self.model.sourceFilePath() else: filename, filter = QFileDialog.getSaveFileName(self, self.tr('Save Model'), ModelerUtils.modelsFolders()[0], self.tr('Processing models (*.model3 *.MODEL3)')) if filename: if not filename.endswith('.model3'): filename += '.model3' self.model.setSourceFilePath(filename) if filename: if not self.model.toFile(filename): if saveAs: QMessageBox.warning(self, self.tr('I/O error'), self.tr('Unable to save edits. Reason:\n {0}').format(str(sys.exc_info()[1]))) else: QMessageBox.warning(self, self.tr("Can't save model"), QCoreApplication.translate('QgsPluginInstallerInstallingDialog', ( "This model can't be saved in its original location (probably you do not " "have permission to do it). Please, use the 'Save as…' option.")) ) return self.update_model.emit() if saveAs: self.bar.pushMessage("", self.tr("Model was correctly saved to <a href=\"{}\">{}</a>").format(QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5) else: self.bar.pushMessage("", self.tr("Model was correctly saved"), level=Qgis.Success, duration=5) self.hasChanged = False def openModel(self): filename, selected_filter = QFileDialog.getOpenFileName(self, self.tr('Open Model'), ModelerUtils.modelsFolders()[0], self.tr('Processing models (*.model3 *.MODEL3)')) if filename: self.loadModel(filename) def loadModel(self, filename): alg = QgsProcessingModelAlgorithm() if alg.fromFile(filename): self.model = alg self.model.setProvider(QgsApplication.processingRegistry().providerById('model')) self.textGroup.setText(alg.group()) self.textName.setText(alg.name()) self.repaintModel() self.update_variables_gui() self.view.centerOn(0, 0) self.hasChanged = False else: QgsMessageLog.logMessage(self.tr('Could not load model {0}').format(filename), self.tr('Processing'), Qgis.Critical) QMessageBox.critical(self, self.tr('Open Model'), self.tr('The selected model could not be loaded.\n' 'See the log for more information.')) def repaintModel(self, controls=True): self.scene = ModelerScene(self, dialog=self) self.scene.setSceneRect(QRectF(0, 0, self.CANVAS_SIZE, self.CANVAS_SIZE)) self.scene.paintModel(self.model, controls) self.view.setScene(self.scene) def addInput(self): item = self.inputsTree.currentItem() param = item.data(0, Qt.UserRole) self.addInputOfType(param) def addInputOfType(self, paramType, pos=None): dlg = ModelerParameterDefinitionDialog(self.model, paramType) dlg.exec_() if dlg.param is not None: if pos is None: pos = self.getPositionForParameterItem() if isinstance(pos, QPoint): pos = QPointF(pos) component = QgsProcessingModelParameter(dlg.param.name()) component.setDescription(dlg.param.name()) component.setPosition(pos) self.model.addModelParameter(dlg.param, component) self.repaintModel() # self.view.ensureVisible(self.scene.getLastParameterItem()) self.hasChanged = True def getPositionForParameterItem(self): MARGIN = 20 BOX_WIDTH = 200 BOX_HEIGHT = 80 if len(self.model.parameterComponents()) > 0: maxX = max([i.position().x() for i in list(self.model.parameterComponents().values())]) newX = min(MARGIN + BOX_WIDTH + maxX, self.CANVAS_SIZE - BOX_WIDTH) else: newX = MARGIN + BOX_WIDTH / 2 return QPointF(newX, MARGIN + BOX_HEIGHT / 2) def fillInputsTree(self): icon = QIcon(os.path.join(pluginPath, 'images', 'input.svg')) parametersItem = QTreeWidgetItem() parametersItem.setText(0, self.tr('Parameters')) sortedParams = sorted(QgsApplication.instance().processingRegistry().parameterTypes(), key=lambda pt: pt.name()) for param in sortedParams: if param.flags() & QgsProcessingParameterType.ExposeToModeler: paramItem = QTreeWidgetItem() paramItem.setText(0, param.name()) paramItem.setData(0, Qt.UserRole, param.id()) paramItem.setIcon(0, icon) paramItem.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsDragEnabled) paramItem.setToolTip(0, param.description()) parametersItem.addChild(paramItem) self.inputsTree.addTopLevelItem(parametersItem) parametersItem.setExpanded(True) def addAlgorithm(self): algorithm = self.algorithmTree.selectedAlgorithm() if algorithm is not None: alg = QgsApplication.processingRegistry().createAlgorithmById(algorithm.id()) self._addAlgorithm(alg) def _addAlgorithm(self, alg, pos=None): dlg = ModelerParametersDialog(alg, self.model) if dlg.exec_(): alg = dlg.createAlgorithm() if pos is None: alg.setPosition(self.getPositionForAlgorithmItem()) else: alg.setPosition(pos) from processing.modeler.ModelerGraphicItem import ModelerGraphicItem for i, out in enumerate(alg.modelOutputs()): alg.modelOutput(out).setPosition(alg.position() + QPointF(ModelerGraphicItem.BOX_WIDTH, (i + 1.5) * ModelerGraphicItem.BOX_HEIGHT)) self.model.addChildAlgorithm(alg) self.repaintModel() self.hasChanged = True def getPositionForAlgorithmItem(self): MARGIN = 20 BOX_WIDTH = 200 BOX_HEIGHT = 80 if self.model.childAlgorithms(): maxX = max([alg.position().x() for alg in list(self.model.childAlgorithms().values())]) maxY = max([alg.position().y() for alg in list(self.model.childAlgorithms().values())]) newX = min(MARGIN + BOX_WIDTH + maxX, self.CANVAS_SIZE - BOX_WIDTH) newY = min(MARGIN + BOX_HEIGHT + maxY, self.CANVAS_SIZE - BOX_HEIGHT) else: newX = MARGIN + BOX_WIDTH / 2 newY = MARGIN * 2 + BOX_HEIGHT + BOX_HEIGHT / 2 return QPointF(newX, newY) def export_as_script_algorithm(self): dlg = ScriptEditorDialog(None) dlg.editor.setText('\n'.join(self.model.asPythonCode(QgsProcessing.PythonQgsProcessingAlgorithmSubclass, 4))) dlg.show()
def initGui(self): settings = QgsSettings() icon_paius = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'hfflogo.png')) self.action = QAction(QIcon(icon_paius), "HFF Main Panel", self.iface.mainWindow()) self.action.triggered.connect(self.showHideDockWidget) # dock widget self.dockWidget = HffPluginDialog(self.iface) self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.dockWidget) # TOOLBAR self.toolBar = self.iface.addToolBar("HFF") self.toolBar.setObjectName("HFF") self.toolBar.addAction(self.action) self.dataToolButton = QToolButton(self.toolBar) self.dataToolButton.setPopupMode(QToolButton.MenuButtonPopup) ###### Section dedicated to the basic data entry # add Actions data self.siteToolButton = QToolButton(self.toolBar) self.siteToolButton.setPopupMode(QToolButton.MenuButtonPopup) icon_site = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'iconSite.png')) self.actionSite = QAction(QIcon(icon_site), "Site", self.iface.mainWindow()) self.actionSite.setWhatsThis("Site") self.actionSite.triggered.connect(self.runSite) icon_eamena = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'eamena.jpg')) self.actionEamena = QAction(QIcon(icon_eamena), "Eamena", self.iface.mainWindow()) self.actionEamena.setWhatsThis("Eamena") self.actionEamena.triggered.connect(self.runEamena) icon_eamena_archaeology = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'eamena.jpg')) self.siteToolButton.addActions([self.actionSite, self.actionEamena]) self.siteToolButton.setDefaultAction(self.actionSite) self.toolBar.addWidget(self.siteToolButton) self.toolBar.addSeparator() ###### Section dedicated to the UnderWater data entry # add Actions data icon_UW = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'snorkel.png')) self.actionUW = QAction(QIcon(icon_UW), "Divelog Form", self.iface.mainWindow()) self.actionUW.setWhatsThis("Divelog") self.actionUW.triggered.connect(self.runUW) icon_ANC = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'iconANC.png')) self.actionANC = QAction(QIcon(icon_ANC), "Anchor", self.iface.mainWindow()) self.actionANC.setWhatsThis("Anchor") self.actionANC.triggered.connect(self.runANC) icon_ART = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'radar.png')) self.actionART = QAction(QIcon(icon_ART), "Artefact", self.iface.mainWindow()) self.actionART.setWhatsThis("Artefact") self.actionART.triggered.connect(self.runART) icon_Pottery = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'pottery.png')) self.actionPottery = QAction(QIcon(icon_Pottery), "Pottery", self.iface.mainWindow()) self.actionPottery.setWhatsThis("Pottery") self.actionPottery.triggered.connect(self.runPottery) self.dataToolButton.addActions([ self.actionUW, self.actionART, self.actionANC, self.actionPottery ]) self.dataToolButton.setDefaultAction(self.actionUW) self.toolBar.addWidget(self.dataToolButton) self.toolBar.addSeparator() ###### Section dedicated to the shipwreck # add Actions documentation self.ShipwreckToolButton = QToolButton(self.toolBar) icon_shipwreck = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'Shipwreck.png')) self.actionShipwreck = QAction(QIcon(icon_shipwreck), "Shipwreck", self.iface.mainWindow()) self.actionShipwreck.setWhatsThis("Shipwreck") self.actionShipwreck.triggered.connect(self.runShipwreck) self.ShipwreckToolButton.addActions([self.actionShipwreck]) self.ShipwreckToolButton.setDefaultAction(self.actionShipwreck) self.toolBar.addWidget(self.ShipwreckToolButton) self.toolBar.addSeparator() ###### Section dedicated to the documentation # add Actions documentation self.docToolButton = QToolButton(self.toolBar) self.docToolButton.setPopupMode(QToolButton.MenuButtonPopup) icon_imageViewer = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'photo.png')) self.actionimageViewer = QAction(QIcon(icon_imageViewer), "Media manager", self.iface.mainWindow()) self.actionimageViewer.setWhatsThis("Media manager") self.actionimageViewer.triggered.connect(self.runImageViewer) icon_Directory_export = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'directoryExp.png')) self.actionImages_Directory_export = QAction( QIcon(icon_Directory_export), "Download image", self.iface.mainWindow()) self.actionImages_Directory_export.setWhatsThis("Download image") self.actionImages_Directory_export.triggered.connect( self.runImages_directory_export) icon_excel_exp = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'excel-export.png')) self.actionexcelExp = QAction(QIcon(icon_excel_exp), "Download EXCEL", self.iface.mainWindow()) self.actionexcelExp.setWhatsThis("Download EXCEL") self.actionexcelExp.triggered.connect(self.runPdfexp) self.docToolButton.addActions([ self.actionexcelExp, self.actionimageViewer, self.actionexcelExp, self.actionImages_Directory_export ]) self.docToolButton.setDefaultAction(self.actionimageViewer) #if self.PARAMS_DICT['EXPERIMENTAL'] == 'Si': self.actionImages_Directory_export.setCheckable(True) self.actionexcelExp.setCheckable(True) self.actionimageViewer.setCheckable(True) self.toolBar.addWidget(self.docToolButton) self.toolBar.addSeparator() ###### Section dedicated to the plugin management self.manageToolButton = QToolButton(self.toolBar) self.manageToolButton.setPopupMode(QToolButton.MenuButtonPopup) icon_Con = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'iconConn.png')) self.actionConf = QAction(QIcon(icon_Con), "Config plugin", self.iface.mainWindow()) self.actionConf.setWhatsThis("Config plugin") self.actionConf.triggered.connect(self.runConf) icon_Dbmanagment = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'backup.png')) self.actionDbmanagment = QAction(QIcon(icon_Dbmanagment), "Database manager", self.iface.mainWindow()) self.actionDbmanagment.setWhatsThis("Database manager") self.actionDbmanagment.triggered.connect(self.runDbmanagment) icon_Info = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'iconInfo.png')) self.actionInfo = QAction(QIcon(icon_Info), "Plugin info", self.iface.mainWindow()) self.actionInfo.setWhatsThis("Plugin info") self.actionInfo.triggered.connect(self.runInfo) self.manageToolButton.addActions( [self.actionConf, self.actionDbmanagment, self.actionInfo]) self.manageToolButton.setDefaultAction(self.actionConf) self.toolBar.addWidget(self.manageToolButton) self.toolBar.addSeparator() # menu self.iface.addPluginToMenu("HFF - Survey UW Archaeological GIS Tools", self.actionUW) self.iface.addPluginToMenu("HFF - Survey UW Archaeological GIS Tools", self.actionANC) self.iface.addPluginToMenu("HFF - Survey UW Archaeological GIS Tools", self.actionART) self.iface.addPluginToMenu("HFF - Survey UW Archaeological GIS Tools", self.actionPottery) self.iface.addPluginToMenu("HFF - Survey UW Archaeological GIS Tools", self.actionShipwreck) self.iface.addPluginToMenu( "HFF - Survey Terrestrial Archaeological GIS Tools", self.actionSite) self.iface.addPluginToMenu( "HFF - Survey Terrestrial Archaeological GIS Tools", self.actionEamena) self.iface.addPluginToMenu("HFF - Media manager GIS Tools", self.actionimageViewer) self.iface.addPluginToMenu("HFF - Media manager GIS Tools", self.actionexcelExp) self.iface.addPluginToMenu("HFF - Media manager GIS Tools", self.actionImages_Directory_export) self.iface.addPluginToMenu("HFF - Config GIS Tools", self.actionConf) self.iface.addPluginToMenu("HFF - Config GIS Tools", self.actionDbmanagment) self.iface.addPluginToMenu("HFF - Info GIS Tools", self.actionInfo) # MENU self.menu = QMenu("HFF") self.menu.addActions([self.actionSite, self.actionEamena]) self.menu.addSeparator() self.menu.addActions([self.actionShipwreck]) self.menu.addSeparator() self.menu.addActions([ self.actionUW, self.actionART, self.actionANC, self.actionPottery ]) self.menu.addActions([ self.actionimageViewer, self.actionexcelExp, self.actionImages_Directory_export ]) self.menu.addSeparator() self.menu.addActions( [self.actionConf, self.actionDbmanagment, self.actionInfo]) menuBar = self.iface.mainWindow().menuBar() menuBar.addMenu(self.menu)
class ShapeTools(object): def __init__(self, iface): self.iface = iface self.canvas = iface.mapCanvas() self.settingsDialog = None self.xyLineDialog = None self.geodesicDensifyDialog = None self.azDigitizerTool = None self.lineDigitizerTool = None self.previousLayer = None self.toolbar = self.iface.addToolBar('Shape Tools Toolbar') self.toolbar.setObjectName('ShapeToolsToolbar') self.provider = ShapeToolsProvider() # Initialize the plugin path directory self.plugin_dir = os.path.dirname(__file__) # initialize locale try: locale = QSettings().value("locale/userLocale", "en", type=str)[0:2] except Exception: locale = "en" locale_path = os.path.join(self.plugin_dir, 'i18n', 'shapeTools_{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) QCoreApplication.installTranslator(self.translator) def initGui(self): self.azDigitizerTool = AzDigitizerTool(self.iface) self.lineDigitizerTool = LineDigitizerTool(self.iface) # Initialize the create shape menu items menu = QMenu() # Initialize Create Arc Wedge tool icon = QIcon(self.plugin_dir + '/images/arc.png') self.createArcAction = menu.addAction(icon, tr('Create arc wedge'), self.createArc) self.createArcAction.setObjectName('stCreateArcWedge') icon = QIcon(self.plugin_dir + '/images/donut.png') self.createDonutAction = menu.addAction(icon, tr('Create donut'), self.createDonut) self.createDonutAction.setObjectName('stCreateDonut') icon = QIcon(self.plugin_dir + '/images/ellipse.png') self.createEllipseAction = menu.addAction(icon, tr('Create ellipse'), self.createEllipse) self.createEllipseAction.setObjectName('stCreateEllipse') icon = QIcon(self.plugin_dir + '/images/rose.png') self.createEllipseRoseAction = menu.addAction( icon, tr('Create ellipse rose'), self.createEllipseRose) self.createEllipseRoseAction.setObjectName('stCreateEllipseRose') icon = QIcon(self.plugin_dir + '/images/epicycloid.png') self.createEpicycloidAction = menu.addAction(icon, tr('Create epicycloid'), self.createEpicycloid) self.createEpicycloidAction.setObjectName('stCreateEpicycloid') icon = QIcon(self.plugin_dir + '/images/heart.png') self.createHeartAction = menu.addAction(icon, tr('Create heart'), self.createHeart) self.createHeartAction.setObjectName('stCreateHeart') icon = QIcon(self.plugin_dir + '/images/hypocycloid.png') self.createHypocycloidAction = menu.addAction(icon, tr('Create hypocycloid'), self.createHypocycloid) self.createHypocycloidAction.setObjectName('stCreateHypocycloid') icon = QIcon(self.plugin_dir + '/images/line.png') self.createLOBAction = menu.addAction(icon, tr('Create line of bearing'), self.createLOB) self.createLOBAction.setObjectName('stCreateLineOfBearing') icon = QIcon(self.plugin_dir + '/images/pie.png') self.createPieAction = menu.addAction(icon, tr('Create pie wedge'), self.createPie) self.createPieAction.setObjectName('stCreatePie') icon = QIcon(self.plugin_dir + '/images/polyfoil.png') self.createPolyfoilAction = menu.addAction(icon, tr('Create polyfoil'), self.createPolyfoil) self.createPolyfoilAction.setObjectName('stCreatePolyfoil') icon = QIcon(self.plugin_dir + '/images/polygon.png') self.createPolygonAction = menu.addAction(icon, tr('Create polygon'), self.createPolygon) self.createPolygonAction.setObjectName('stCreatePolygon') icon = QIcon(self.plugin_dir + '/images/star.png') self.createStarAction = menu.addAction(icon, tr('Create star'), self.createStar) self.createStarAction.setObjectName('stCreateStar') # Add the shape creation tools to the menu icon = QIcon(self.plugin_dir + '/images/shapes.png') self.createShapesAction = QAction(icon, tr('Create shapes'), self.iface.mainWindow()) self.createShapesAction.setMenu(menu) self.iface.addPluginToVectorMenu('Shape Tools', self.createShapesAction) # Add the shape creation tools to the toolbar self.createShapeButton = QToolButton() self.createShapeButton.setMenu(menu) self.createShapeButton.setDefaultAction(self.createDonutAction) self.createShapeButton.setPopupMode(QToolButton.MenuButtonPopup) self.createShapeButton.triggered.connect(self.createShapeTriggered) self.createShapeToolbar = self.toolbar.addWidget( self.createShapeButton) # Initialize the XY to Line menu item icon = QIcon(self.plugin_dir + '/images/xyline.png') self.xyLineAction = QAction(icon, tr('XY to line'), self.iface.mainWindow()) self.xyLineAction.setObjectName('stXYtoLine') self.xyLineAction.triggered.connect(self.xyLineTool) self.iface.addPluginToVectorMenu('Shape Tools', self.xyLineAction) self.toolbar.addAction(self.xyLineAction) # Initialize the Geodesic Densifier menu item icon = QIcon(self.plugin_dir + '/images/geodesicDensifier.png') self.geodesicDensifyAction = QAction(icon, tr('Geodesic shape densifier'), self.iface.mainWindow()) self.geodesicDensifyAction.setObjectName('stGeodesicDensifier') self.geodesicDensifyAction.triggered.connect(self.geodesicDensifyTool) self.iface.addPluginToVectorMenu('Shape Tools', self.geodesicDensifyAction) self.toolbar.addAction(self.geodesicDensifyAction) # Initialize the Geodesic decimation menu items menu = QMenu() icon = QIcon(self.plugin_dir + '/images/geodesicLineDecimate.png') self.lineDecimateAction = menu.addAction(icon, tr('Geodesic line decimate'), self.lineDecimateTool) self.lineDecimateAction.setObjectName('stGeodesicLineDecimate') icon = QIcon(self.plugin_dir + '/images/geodesicPointDecimate.png') self.pointDecimateAction = menu.addAction( icon, tr('Geodesic point decimate'), self.pointDecimateTool) self.pointDecimateAction.setObjectName('stGeodesicPointDecimate') # Add the decimation tools to the menu icon = QIcon(self.plugin_dir + '/images/geodesicLineDecimate.png') self.simplifyGeomAction = QAction( icon, tr('Geodesic geometry simplification'), self.iface.mainWindow()) self.simplifyGeomAction.setMenu(menu) self.iface.addPluginToVectorMenu('Shape Tools', self.simplifyGeomAction) # Add the shape creation tools to the toolbar self.simplifyButton = QToolButton() self.simplifyButton.setMenu(menu) self.simplifyButton.setDefaultAction(self.lineDecimateAction) self.simplifyButton.setPopupMode(QToolButton.MenuButtonPopup) self.simplifyButton.triggered.connect(self.simplifyTriggered) self.simplifyToolbar = self.toolbar.addWidget(self.simplifyButton) # Initialize the Geodesic line break menu item icon = QIcon(self.plugin_dir + '/images/idlbreak.png') self.geodesicLineBreakAction = QAction( icon, tr('Geodesic line break at -180,180'), self.iface.mainWindow()) self.geodesicLineBreakAction.setObjectName('stGeodesicLineBreak') self.geodesicLineBreakAction.triggered.connect( self.geodesicLineBreakTool) self.iface.addPluginToVectorMenu('Shape Tools', self.geodesicLineBreakAction) self.toolbar.addAction(self.geodesicLineBreakAction) # Initialize Geodesic Measure Tool self.geodesicMeasureTool = GeodesicMeasureTool(self.iface, self.iface.mainWindow()) icon = QIcon(self.plugin_dir + '/images/measure.png') self.measureAction = QAction(icon, tr('Geodesic measure tool'), self.iface.mainWindow()) self.measureAction.setObjectName('stGeodesicMeasureTool') self.measureAction.triggered.connect(self.measureTool) self.measureAction.setCheckable(True) self.iface.addPluginToVectorMenu('Shape Tools', self.measureAction) self.toolbar.addAction(self.measureAction) # Initialize Geodesic Measurement layer icon = QIcon(self.plugin_dir + '/images/measureLine.png') self.measureLayerAction = QAction(icon, tr('Geodesic measurement layer'), self.iface.mainWindow()) self.measureLayerAction.setObjectName('stGeodesicLineBreak') self.measureLayerAction.triggered.connect(self.measureLayerTool) self.iface.addPluginToVectorMenu('Shape Tools', self.measureLayerAction) self.toolbar.addAction(self.measureLayerAction) menu = QMenu() # Initialize Geodesic transformation tool icon = QIcon(self.plugin_dir + '/images/transformShape.png') self.transformationsAction = menu.addAction( icon, tr('Geodesic transformations'), self.transformTool) self.transformationsAction.setObjectName('stGeodesicTransformations') icon = QIcon(self.plugin_dir + '/images/flip.png') self.flipRotateAction = menu.addAction(icon, tr('Geodesic flip and rotate'), self.flipRotateTool) self.flipRotateAction.setObjectName('stGeodesicFlipRotate') icon = QIcon(self.plugin_dir + '/images/flipHorizontal.png') self.flipHorizontalAction = menu.addAction(icon, tr('Flip horizontal'), self.flipHorizontalTool) self.flipHorizontalAction.setObjectName('stGeodesicFlipHorizontal') self.flipHorizontalAction.setEnabled(False) icon = QIcon(self.plugin_dir + '/images/flipVertical.png') self.flipVerticalAction = menu.addAction(icon, tr('Flip vertical'), self.flipVerticalTool) self.flipVerticalAction.setObjectName('stGeodesicFlipVertical') self.flipVerticalAction.setEnabled(False) icon = QIcon(self.plugin_dir + '/images/rotate180.png') self.rotate180Action = menu.addAction(icon, tr('Rotate 180\xb0'), self.rotate180Tool) self.rotate180Action.setObjectName('stGeodesicRotate180') self.rotate180Action.setEnabled(False) icon = QIcon(self.plugin_dir + '/images/rotatecw.png') self.rotate90CWAction = menu.addAction(icon, tr('Rotate 90\xb0 CW'), self.rotate90CWTool) self.rotate90CWAction.setObjectName('stGeodesicRotate90CW') self.rotate90CWAction.setEnabled(False) icon = QIcon(self.plugin_dir + '/images/rotateccw.png') self.rotate90CCWAction = menu.addAction(icon, tr('Rotate 90\xb0 CCW'), self.rotate90CCWTool) self.rotate90CCWAction.setObjectName('stGeodesicRotate90CCW') self.rotate90CCWAction.setEnabled(False) self.transformsAction = QAction(icon, tr('Geodesic transforms'), self.iface.mainWindow()) self.transformsAction.setMenu(menu) self.iface.addPluginToVectorMenu('Shape Tools', self.transformsAction) self.transformationButton = QToolButton() self.transformationButton.setMenu(menu) self.transformationButton.setDefaultAction(self.transformationsAction) self.transformationButton.setPopupMode(QToolButton.MenuButtonPopup) self.transformationButton.triggered.connect(self.toolButtonTriggered) self.tranformToolbar = self.toolbar.addWidget( self.transformationButton) # Initialize the Azimuth Distance Digitize function icon = QIcon(self.plugin_dir + '/images/dazdigitize.png') self.digitizeAction = QAction(icon, tr('Azimuth distance digitizer'), self.iface.mainWindow()) self.digitizeAction.setObjectName('stAzDistanceDigitizer') self.digitizeAction.triggered.connect(self.setShowAzDigitizerTool) self.digitizeAction.setCheckable(True) self.digitizeAction.setEnabled(False) self.iface.addPluginToVectorMenu(u'Shape Tools', self.digitizeAction) self.toolbar.addAction(self.digitizeAction) # Initialize the multi point azimuth Digitize function icon = QIcon(self.plugin_dir + '/images/linedigitize.png') self.lineDigitizeAction = QAction( icon, tr('Azimuth distance sequence digitizer'), self.iface.mainWindow()) self.lineDigitizeAction.setObjectName('stLineDigitizer') self.lineDigitizeAction.triggered.connect(self.setShowLineDigitizeTool) self.lineDigitizeAction.setCheckable(True) self.lineDigitizeAction.setEnabled(False) self.iface.addPluginToVectorMenu(u'Shape Tools', self.lineDigitizeAction) self.toolbar.addAction(self.lineDigitizeAction) # Settings icon = QIcon(self.plugin_dir + '/images/settings.png') self.settingsAction = QAction(icon, tr('Settings'), self.iface.mainWindow()) self.settingsAction.setObjectName('shapeToolsSettings') self.settingsAction.triggered.connect(self.settings) self.iface.addPluginToVectorMenu('Shape Tools', self.settingsAction) # Help icon = QIcon(self.plugin_dir + '/images/help.png') self.helpAction = QAction(icon, tr('Shape Tools help'), self.iface.mainWindow()) self.helpAction.setObjectName('shapeToolsHelp') self.helpAction.triggered.connect(self.help) self.iface.addPluginToVectorMenu('Shape Tools', self.helpAction) self.iface.currentLayerChanged.connect(self.currentLayerChanged) self.canvas.mapToolSet.connect(self.unsetTool) self.enableTools() # Add the processing provider QgsApplication.processingRegistry().addProvider(self.provider) def unsetTool(self, tool): try: if not isinstance(tool, GeodesicMeasureTool): self.measureAction.setChecked(False) self.geodesicMeasureTool.endInteractiveLine() if not isinstance(tool, AzDigitizerTool): self.digitizeAction.setChecked(False) if not isinstance(tool, LineDigitizerTool): self.lineDigitizeAction.setChecked(False) except Exception: pass def unload(self): self.canvas.unsetMapTool(self.azDigitizerTool) self.canvas.unsetMapTool(self.lineDigitizerTool) # remove from menu self.iface.removePluginVectorMenu('Shape Tools', self.createShapesAction) self.iface.removePluginVectorMenu('Shape Tools', self.xyLineAction) self.iface.removePluginVectorMenu('Shape Tools', self.geodesicDensifyAction) self.iface.removePluginVectorMenu('Shape Tools', self.simplifyGeomAction) self.iface.removePluginVectorMenu('Shape Tools', self.geodesicLineBreakAction) self.iface.removePluginVectorMenu('Shape Tools', self.measureAction) self.iface.removePluginVectorMenu('Shape Tools', self.measureLayerAction) self.iface.removePluginVectorMenu('Shape Tools', self.transformsAction) self.iface.removePluginVectorMenu('Shape Tools', self.digitizeAction) self.iface.removePluginVectorMenu('Shape Tools', self.lineDigitizeAction) self.iface.removePluginVectorMenu('Shape Tools', self.settingsAction) self.iface.removePluginVectorMenu('Shape Tools', self.helpAction) # Remove from toolbar self.iface.removeToolBarIcon(self.createShapeToolbar) self.iface.removeToolBarIcon(self.xyLineAction) self.iface.removeToolBarIcon(self.geodesicDensifyAction) self.iface.removeToolBarIcon(self.simplifyToolbar) self.iface.removeToolBarIcon(self.geodesicLineBreakAction) self.iface.removeToolBarIcon(self.measureAction) self.iface.removeToolBarIcon(self.measureLayerAction) self.iface.removeToolBarIcon(self.transformationsAction) self.iface.removeToolBarIcon(self.digitizeAction) self.iface.removeToolBarIcon(self.lineDigitizeAction) self.iface.removeToolBarIcon(self.tranformToolbar) self.azDigitizerTool = None self.lineDigitizerTool = None # remove the toolbar del self.toolbar QgsApplication.processingRegistry().removeProvider(self.provider) def toolButtonTriggered(self, action): self.transformationButton.setDefaultAction(action) def createShapeTriggered(self, action): self.createShapeButton.setDefaultAction(action) def simplifyTriggered(self, action): self.simplifyButton.setDefaultAction(action) def setShowAzDigitizerTool(self): self.digitizeAction.setChecked(True) self.canvas.setMapTool(self.azDigitizerTool) def setShowLineDigitizeTool(self): self.lineDigitizeAction.setChecked(True) self.canvas.setMapTool(self.lineDigitizerTool) def xyLineTool(self): processing.execAlgorithmDialog('shapetools:xy2line', {}) def geodesicDensifyTool(self): processing.execAlgorithmDialog('shapetools:geodesicdensifier', {}) def pointDecimateTool(self): processing.execAlgorithmDialog('shapetools:geodesicpointdecimate', {}) def lineDecimateTool(self): processing.execAlgorithmDialog('shapetools:geodesiclinedecimate', {}) def geodesicLineBreakTool(self): processing.execAlgorithmDialog('shapetools:linebreak', {}) def measureTool(self): self.measureAction.setChecked(True) self.canvas.setMapTool(self.geodesicMeasureTool) def createArc(sefl): processing.execAlgorithmDialog('shapetools:createarc', {}) def createDonut(sefl): processing.execAlgorithmDialog('shapetools:createdonut', {}) def createEllipse(sefl): processing.execAlgorithmDialog('shapetools:createellipse', {}) def createEllipseRose(sefl): processing.execAlgorithmDialog('shapetools:createrose', {}) def createEpicycloid(sefl): processing.execAlgorithmDialog('shapetools:createepicycloid', {}) def createHeart(sefl): processing.execAlgorithmDialog('shapetools:createheart', {}) def createHypocycloid(sefl): processing.execAlgorithmDialog('shapetools:createhypocycloid', {}) def createLOB(sefl): processing.execAlgorithmDialog('shapetools:createlob', {}) def createPie(sefl): processing.execAlgorithmDialog('shapetools:createpie', {}) def createPolyfoil(sefl): processing.execAlgorithmDialog('shapetools:createpolyfoil', {}) def createPolygon(sefl): processing.execAlgorithmDialog('shapetools:createpolygon', {}) def createStar(sefl): processing.execAlgorithmDialog('shapetools:createstar', {}) def measureLayerTool(self): processing.execAlgorithmDialog('shapetools:measurelayer', {}) def transformTool(self): processing.execAlgorithmDialog('shapetools:geodesictransformations', {}) def flipRotateTool(self): processing.execAlgorithmDialog('shapetools:geodesicflip', {}) def flipHorizontalTool(self): layer = self.iface.activeLayer() flipLayer(self.iface, layer, 0) def flipVerticalTool(self): layer = self.iface.activeLayer() flipLayer(self.iface, layer, 1) def rotate180Tool(self): layer = self.iface.activeLayer() flipLayer(self.iface, layer, 2) def rotate90CWTool(self): layer = self.iface.activeLayer() flipLayer(self.iface, layer, 3) def rotate90CCWTool(self): layer = self.iface.activeLayer() flipLayer(self.iface, layer, 4) def settings(self): if self.settingsDialog is None: self.settingsDialog = SettingsWidget(self.iface, self.iface.mainWindow()) self.settingsDialog.show() def help(self): '''Display a help page''' url = QUrl.fromLocalFile(self.plugin_dir + '/index.html').toString() webbrowser.open(url, new=2) def currentLayerChanged(self): layer = self.iface.activeLayer() if self.previousLayer is not None: try: self.previousLayer.editingStarted.disconnect( self.layerEditingChanged) except Exception: pass try: self.previousLayer.editingStopped.disconnect( self.layerEditingChanged) except Exception: pass self.previousLayer = None if layer is not None: if isinstance(layer, QgsVectorLayer): layer.editingStarted.connect(self.layerEditingChanged) layer.editingStopped.connect(self.layerEditingChanged) self.previousLayer = layer self.enableTools() def layerEditingChanged(self): self.enableTools() def enableTools(self): self.digitizeAction.setEnabled(False) self.lineDigitizeAction.setEnabled(False) self.flipHorizontalAction.setEnabled(False) self.flipVerticalAction.setEnabled(False) self.rotate180Action.setEnabled(False) self.rotate90CWAction.setEnabled(False) self.rotate90CCWAction.setEnabled(False) layer = self.iface.activeLayer() if not layer or not layer.isValid() or ( layer.type() != QgsMapLayer.VectorLayer) or not layer.isEditable(): return wkbtype = layer.wkbType() geomtype = QgsWkbTypes.geometryType(wkbtype) self.lineDigitizeAction.setEnabled(True) if geomtype == QgsWkbTypes.PointGeometry or geomtype == QgsWkbTypes.LineGeometry: self.digitizeAction.setEnabled(True) if geomtype == QgsWkbTypes.LineGeometry or geomtype == QgsWkbTypes.PolygonGeometry: self.flipHorizontalAction.setEnabled(True) self.flipVerticalAction.setEnabled(True) self.rotate180Action.setEnabled(True) self.rotate90CWAction.setEnabled(True) self.rotate90CCWAction.setEnabled(True)
class HffPlugin_s(object): HOME = os.environ['HFF_HOME'] PARAMS_DICT = { 'SERVER': '', 'HOST': '', 'DATABASE': '', 'PASSWORD': '', 'PORT': '', 'USER': '', 'THUMB_PATH': '', 'THUMB_RESIZE': '', 'EXPERIMENTAL': '' } path_rel = os.path.join(os.sep, HOME, 'HFF_DB_folder', 'config.cfg') conf = open(path_rel, "rb+") data = conf.read() text = (b'THUMB_RESIZE') if text in data: pass else: conf.seek(-3, 2) conf.read(1) conf.write(b"','THUMB_RESIZE' : 'insert path for the image resized'}") conf.close() PARAMS_DICT = eval(data) def __init__(self, iface): self.iface = iface userPluginPath = os.path.dirname(__file__) systemPluginPath = QgsApplication.prefixPath() + "/python/plugins/HFF" # overrideLocale = QgsSettings().value("locale/overrideFlag", QVariant) # .toBool() # if not overrideLocale: # localeFullName = QLocale.system().name() # else: # localeFullName = QgsSettings().value("locale/userLocale", QVariant) # .toString() # if QFileInfo(userPluginPath).exists(): # translationPath = userPluginPath + "/i18n/hff_system__plugin_" + localeFullName + ".qm" # else: # translationPath = systemPluginPath + "/i18n/hff_system__plugin_" + localeFullName + ".qm" # self.localePath = translationPath # if QFileInfo(self.localePath).exists(): # self.translator = QTranslator() # self.translator.load(self.localePath) # QCoreApplication.installTranslator(self.translator) def initGui(self): settings = QgsSettings() icon_paius = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'hfflogo.png')) self.action = QAction(QIcon(icon_paius), "HFF Main Panel", self.iface.mainWindow()) self.action.triggered.connect(self.showHideDockWidget) # dock widget self.dockWidget = HffPluginDialog(self.iface) self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.dockWidget) # TOOLBAR self.toolBar = self.iface.addToolBar("HFF") self.toolBar.setObjectName("HFF") self.toolBar.addAction(self.action) self.dataToolButton = QToolButton(self.toolBar) self.dataToolButton.setPopupMode(QToolButton.MenuButtonPopup) ###### Section dedicated to the basic data entry # add Actions data self.siteToolButton = QToolButton(self.toolBar) self.siteToolButton.setPopupMode(QToolButton.MenuButtonPopup) icon_site = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'iconSite.png')) self.actionSite = QAction(QIcon(icon_site), "Site", self.iface.mainWindow()) self.actionSite.setWhatsThis("Site") self.actionSite.triggered.connect(self.runSite) icon_eamena = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'eamena.jpg')) self.actionEamena = QAction(QIcon(icon_eamena), "Eamena", self.iface.mainWindow()) self.actionEamena.setWhatsThis("Eamena") self.actionEamena.triggered.connect(self.runEamena) icon_eamena_archaeology = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'eamena.jpg')) self.siteToolButton.addActions([self.actionSite, self.actionEamena]) self.siteToolButton.setDefaultAction(self.actionSite) self.toolBar.addWidget(self.siteToolButton) self.toolBar.addSeparator() ###### Section dedicated to the UnderWater data entry # add Actions data icon_UW = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'snorkel.png')) self.actionUW = QAction(QIcon(icon_UW), "Divelog Form", self.iface.mainWindow()) self.actionUW.setWhatsThis("Divelog") self.actionUW.triggered.connect(self.runUW) icon_ANC = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'iconANC.png')) self.actionANC = QAction(QIcon(icon_ANC), "Anchor", self.iface.mainWindow()) self.actionANC.setWhatsThis("Anchor") self.actionANC.triggered.connect(self.runANC) icon_ART = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'radar.png')) self.actionART = QAction(QIcon(icon_ART), "Artefact", self.iface.mainWindow()) self.actionART.setWhatsThis("Artefact") self.actionART.triggered.connect(self.runART) icon_Pottery = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'pottery.png')) self.actionPottery = QAction(QIcon(icon_Pottery), "Pottery", self.iface.mainWindow()) self.actionPottery.setWhatsThis("Pottery") self.actionPottery.triggered.connect(self.runPottery) self.dataToolButton.addActions([ self.actionUW, self.actionART, self.actionANC, self.actionPottery ]) self.dataToolButton.setDefaultAction(self.actionUW) self.toolBar.addWidget(self.dataToolButton) self.toolBar.addSeparator() ###### Section dedicated to the shipwreck # add Actions documentation self.ShipwreckToolButton = QToolButton(self.toolBar) icon_shipwreck = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'Shipwreck.png')) self.actionShipwreck = QAction(QIcon(icon_shipwreck), "Shipwreck", self.iface.mainWindow()) self.actionShipwreck.setWhatsThis("Shipwreck") self.actionShipwreck.triggered.connect(self.runShipwreck) self.ShipwreckToolButton.addActions([self.actionShipwreck]) self.ShipwreckToolButton.setDefaultAction(self.actionShipwreck) self.toolBar.addWidget(self.ShipwreckToolButton) self.toolBar.addSeparator() ###### Section dedicated to the documentation # add Actions documentation self.docToolButton = QToolButton(self.toolBar) self.docToolButton.setPopupMode(QToolButton.MenuButtonPopup) icon_imageViewer = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'photo.png')) self.actionimageViewer = QAction(QIcon(icon_imageViewer), "Media manager", self.iface.mainWindow()) self.actionimageViewer.setWhatsThis("Media manager") self.actionimageViewer.triggered.connect(self.runImageViewer) icon_Directory_export = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'directoryExp.png')) self.actionImages_Directory_export = QAction( QIcon(icon_Directory_export), "Download image", self.iface.mainWindow()) self.actionImages_Directory_export.setWhatsThis("Download image") self.actionImages_Directory_export.triggered.connect( self.runImages_directory_export) icon_excel_exp = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'excel-export.png')) self.actionexcelExp = QAction(QIcon(icon_excel_exp), "Download EXCEL", self.iface.mainWindow()) self.actionexcelExp.setWhatsThis("Download EXCEL") self.actionexcelExp.triggered.connect(self.runPdfexp) self.docToolButton.addActions([ self.actionexcelExp, self.actionimageViewer, self.actionexcelExp, self.actionImages_Directory_export ]) self.docToolButton.setDefaultAction(self.actionimageViewer) #if self.PARAMS_DICT['EXPERIMENTAL'] == 'Si': self.actionImages_Directory_export.setCheckable(True) self.actionexcelExp.setCheckable(True) self.actionimageViewer.setCheckable(True) self.toolBar.addWidget(self.docToolButton) self.toolBar.addSeparator() ###### Section dedicated to the plugin management self.manageToolButton = QToolButton(self.toolBar) self.manageToolButton.setPopupMode(QToolButton.MenuButtonPopup) icon_Con = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'iconConn.png')) self.actionConf = QAction(QIcon(icon_Con), "Config plugin", self.iface.mainWindow()) self.actionConf.setWhatsThis("Config plugin") self.actionConf.triggered.connect(self.runConf) icon_Dbmanagment = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'backup.png')) self.actionDbmanagment = QAction(QIcon(icon_Dbmanagment), "Database manager", self.iface.mainWindow()) self.actionDbmanagment.setWhatsThis("Database manager") self.actionDbmanagment.triggered.connect(self.runDbmanagment) icon_Info = '{}{}'.format( filepath, os.path.join(os.sep, 'resources', 'icons', 'iconInfo.png')) self.actionInfo = QAction(QIcon(icon_Info), "Plugin info", self.iface.mainWindow()) self.actionInfo.setWhatsThis("Plugin info") self.actionInfo.triggered.connect(self.runInfo) self.manageToolButton.addActions( [self.actionConf, self.actionDbmanagment, self.actionInfo]) self.manageToolButton.setDefaultAction(self.actionConf) self.toolBar.addWidget(self.manageToolButton) self.toolBar.addSeparator() # menu self.iface.addPluginToMenu("HFF - Survey UW Archaeological GIS Tools", self.actionUW) self.iface.addPluginToMenu("HFF - Survey UW Archaeological GIS Tools", self.actionANC) self.iface.addPluginToMenu("HFF - Survey UW Archaeological GIS Tools", self.actionART) self.iface.addPluginToMenu("HFF - Survey UW Archaeological GIS Tools", self.actionPottery) self.iface.addPluginToMenu("HFF - Survey UW Archaeological GIS Tools", self.actionShipwreck) self.iface.addPluginToMenu( "HFF - Survey Terrestrial Archaeological GIS Tools", self.actionSite) self.iface.addPluginToMenu( "HFF - Survey Terrestrial Archaeological GIS Tools", self.actionEamena) self.iface.addPluginToMenu("HFF - Media manager GIS Tools", self.actionimageViewer) self.iface.addPluginToMenu("HFF - Media manager GIS Tools", self.actionexcelExp) self.iface.addPluginToMenu("HFF - Media manager GIS Tools", self.actionImages_Directory_export) self.iface.addPluginToMenu("HFF - Config GIS Tools", self.actionConf) self.iface.addPluginToMenu("HFF - Config GIS Tools", self.actionDbmanagment) self.iface.addPluginToMenu("HFF - Info GIS Tools", self.actionInfo) # MENU self.menu = QMenu("HFF") self.menu.addActions([self.actionSite, self.actionEamena]) self.menu.addSeparator() self.menu.addActions([self.actionShipwreck]) self.menu.addSeparator() self.menu.addActions([ self.actionUW, self.actionART, self.actionANC, self.actionPottery ]) self.menu.addActions([ self.actionimageViewer, self.actionexcelExp, self.actionImages_Directory_export ]) self.menu.addSeparator() self.menu.addActions( [self.actionConf, self.actionDbmanagment, self.actionInfo]) menuBar = self.iface.mainWindow().menuBar() menuBar.addMenu(self.menu) ## def runSite(self): pluginGui = hff_system__Site(self.iface) pluginGui.show() self.pluginGui = pluginGui # save def runEamena(self): pluginGui = Eamena(self.iface) pluginGui.show() self.pluginGui = pluginGui # save def runUW(self): pluginGui = hff_system__UW(self.iface) pluginGui.show() self.pluginGui = pluginGui # save def runANC(self): pluginGui = hff_system__ANC(self.iface) pluginGui.show() self.pluginGui = pluginGui # save def runART(self): pluginGui = hff_system__ART(self.iface) pluginGui.show() self.pluginGui = pluginGui # save def runPottery(self): pluginGui = hff_system__Pottery(self.iface) pluginGui.show() self.pluginGui = pluginGui # save def runShipwreck(self): pluginGui = hff_system__Shipwreck(self.iface) pluginGui.show() self.pluginGui = pluginGui # save def runConf(self): pluginConfGui = HFF_systemDialog_Config() pluginConfGui.show() self.pluginGui = pluginConfGui # save def runInfo(self): pluginInfoGui = HFF_systemDialog_Info() pluginInfoGui.show() self.pluginGui = pluginInfoGui # save def runImageViewer(self): pluginImageView = Main() pluginImageView.show() self.pluginGui = pluginImageView # save def runImages_directory_export(self): pluginImage_directory_export = hff_system__Images_directory_export() pluginImage_directory_export.show() self.pluginGui = pluginImage_directory_export # save def runDbmanagment(self): pluginDbmanagment = hff_system__dbmanagment(self.iface) pluginDbmanagment.show() self.pluginGui = pluginDbmanagment # save def runPdfexp(self): pluginPdfexp = hff_system__excel_export(self.iface) pluginPdfexp.show() self.pluginGui = pluginPdfexp # save def unload(self): # Remove the plugin self.iface.removePluginMenu("HFF - Survey UW Archaeological GIS Tools", self.actionUW) self.iface.removePluginMenu("HFF - Survey UW Archaeological GIS Tools", self.actionANC) self.iface.removePluginMenu("HFF - Survey UW Archaeological GIS Tools", self.actionART) self.iface.removePluginMenu("HFF - Survey UW Archaeological GIS Tools", self.actionPottery) self.iface.removePluginMenu("HFF - Survey UW Archaeological GIS Tools", self.actionShipwreck) self.iface.removePluginMenu( "HFF - Survey Terrestrial Archaeological GIS Tools", self.actionSite) self.iface.removePluginMenu( "HFF - Survey Terrestrial Archaeological GIS Tools", self.actionEamena) self.iface.removePluginMenu("HFF - Media manager GIS Tools", self.actionimageViewer) self.iface.removePluginMenu("HFF - Media manager GIS Tools", self.actionImages_Directory_export) self.iface.removePluginMenu("HFF - Media manager GIS Tools", self.actionexcelExp) self.iface.removePluginMenu("HFF - Config GIS Tools", self.actionConf) self.iface.removePluginMenu("HFF - Info GIS Tools", self.actionInfo) self.iface.removePluginMenu("HFF - Config GIS Tools", self.actionDbmanagment) self.iface.removeToolBarIcon(self.actionUW) self.iface.removeToolBarIcon(self.actionART) self.iface.removeToolBarIcon(self.actionANC) self.iface.removeToolBarIcon(self.actionPottery) self.iface.removeToolBarIcon(self.actionShipwreck) self.iface.removeToolBarIcon(self.actionSite) self.iface.removeToolBarIcon(self.actionimageViewer) self.iface.removeToolBarIcon(self.actionImages_Directory_export) self.iface.removeToolBarIcon(self.actionexcelExp) self.iface.removeToolBarIcon(self.actionConf) self.iface.removeToolBarIcon(self.actionInfo) self.iface.removeToolBarIcon(self.actionDbmanagment) self.dockWidget.setVisible(False) self.iface.removeDockWidget(self.dockWidget) # remove tool bar del self.toolBar def showHideDockWidget(self): if self.dockWidget.isVisible(): self.dockWidget.hide() else: self.dockWidget.show()
def addLayer(self, index, old=None, addToMap=True): item = index.data(role=Qt.UserRole) if not isinstance(item, LayerItem): return if not self.plugin.setLoading(True): return addedData = [] if isinstance(item, VectorItem): connector = self.getConnector() self.plugin.msgBar = ProgressMessageBar(self.iface, self.tr("Downloading layer '%s'...")%item.name, connector=connector) self.plugin.msgBar.setValue(10) connector.downloadingProgress.connect(self.plugin.updateDownloadProgress) data = connector.diviGetLayerFeatures(item.id) layers = [] if data: permissions = connector.getUserPermission(item.id, 'layer') self.plugin.msgBar.setBoundries(50, 50) #Disable rendering for changing symbology self.iface.mapCanvas().setRenderFlag(False) layers = self.plugin.addLayer(data['features'], item, permissions, addToMap=addToMap) for layer in layers: #Set symbols based on layer geometry type item.setQgisStyle(layer) self.iface.layerTreeView().refreshLayerSymbology(layer.id()) self.iface.mapCanvas().setRenderFlag(True) addedData.extend( layers ) item.items.extend( addedData ) self.plugin.msgBar.setValue(100) aborted = self.plugin.msgBar.aborted self.plugin.msgBar.close() self.plugin.msgBar = None if aborted: # fix_print_with_import print('Aborted') elif not layers: #User can select geometry type in message bar widget = self.iface.messageBar().createMessage( self.tr("Warning"), self.tr(u"Layer '%s' is empty. To open it in QGIS you need to select geometry type.") % item.name ) button = QToolButton(widget) button.setText(self.tr("Add layer as...")) button.setPopupMode(QToolButton.InstantPopup) menu = QMenu(button) def load_layer_as(geom_type): self.plugin.loadLayerType(item = item, geom_type = geom_type) self.iface.messageBar().clearWidgets() menu.addAction(QgsApplication.getThemeIcon('/mIconPointLayer.svg'), self.tr('Points'), lambda: load_layer_as(geom_type='MultiPoint')) menu.addAction(QgsApplication.getThemeIcon('/mIconLineLayer.svg'), self.tr('Linestring'), lambda: load_layer_as(geom_type='MultiLineString')) menu.addAction(QgsApplication.getThemeIcon('/mIconPolygonLayer.svg'), self.tr('Polygons'), lambda: load_layer_as(geom_type='MultiPolygon')) button.setMenu( menu ) widget.layout().addWidget(button) self.iface.messageBar().pushWidget(widget, Qgis.Warning) elif isinstance(item, TableItem): if Qgis.QGIS_VERSION_INT < 21400: self.iface.messageBar().pushMessage('DIVI', self.tr(u'QGIS 2.14 or later is required for loading DIVI tables.'), Qgis.Critical, duration = 3 ) else: self.plugin.msgBar = ProgressMessageBar(self.iface, self.tr("Downloading table '%s'...")%item.name) self.plugin.msgBar.setValue(10) connector = self.getConnector() connector.downloadingProgress.connect(self.plugin.updateDownloadProgress) data = connector.diviGetTableRecords(item.id) if data: permissions = connector.getUserPermission(item.id, 'table') self.plugin.msgBar.setBoundries(50, 50) addedData.append( self.plugin.addTable(data['header'], data['data'], item, permissions, addToMap=addToMap) ) item.items.extend( addedData ) self.plugin.msgBar.setValue(100) self.plugin.msgBar.close() self.plugin.msgBar = None elif isinstance(item, RasterItem): if Qgis.QGIS_VERSION_INT < 21800: self.iface.messageBar().pushMessage('DIVI', self.tr(u'QGIS 2.18 or later is required for loading DIVI rasters.'), Qgis.Critical, duration = 3 ) else: uri = item.getUri(self.token) uri = uri.replace("b'", "").replace("'", "") QgsMessageLog.logMessage( uri, 'DIVI') r = QgsRasterLayer(uri, item.name, 'wms') r.setCustomProperty('DiviId', item.id) if item.extent is not None: #Set extent for raster layer bbox = self.transform2mercator.transformBoundingBox( QgsRectangle( item.extent['st_xmin'], item.extent['st_ymin'], item.extent['st_xmax'], item.extent['st_ymax'] )) r.setExtent( bbox ) addedData.append( r ) item.items.extend( addedData ) if addToMap: QgsProject.instance().addMapLayer(r) elif isinstance(item, WmsItem): uri = item.getUri() QgsMessageLog.logMessage( uri, 'DIVI') r = QgsRasterLayer(uri, item.name, 'wms') r.setCustomProperty('DiviId', item.id) addedData.append( r ) item.items.extend( addedData ) if addToMap: QgsProject.instance().addMapLayer(r) elif isinstance(item, BasemapItem): uri = item.getUri() QgsMessageLog.logMessage( uri, 'DIVI') r = QgsRasterLayer(uri, item.name, 'wms') r.setCustomProperty('DiviId', item.id) addedData.append( r ) item.items.extend( addedData ) if addToMap: QgsProject.instance().addMapLayer(r) else: return index.model().dataChanged.emit(index.parent().parent(), index) self.plugin.setLoading(False) return addedData
def initWidgets(self): # If there are advanced parameters — show corresponding groupbox for param in self.alg.parameterDefinitions(): if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced: self.grpAdvanced.show() break widget_context = QgsProcessingParameterWidgetContext() if iface is not None: widget_context.setMapCanvas(iface.mapCanvas()) if isinstance(self.alg, QgsProcessingModelAlgorithm): widget_context.setModel(self.alg) # Create widgets and put them in layouts for param in self.alg.parameterDefinitions(): if param.flags() & QgsProcessingParameterDefinition.FlagHidden: continue if param.isDestination(): continue else: wrapper = WidgetWrapperFactory.create_wrapper( param, self.parent) wrapper.setWidgetContext(widget_context) wrapper.registerProcessingContextGenerator( self.context_generator) self.wrappers[param.name()] = wrapper # For compatibility with 3.x API, we need to check whether the wrapper is # the deprecated WidgetWrapper class. If not, it's the newer # QgsAbstractProcessingParameterWidgetWrapper class # TODO QGIS 4.0 - remove is_python_wrapper = issubclass(wrapper.__class__, WidgetWrapper) if not is_python_wrapper: widget = wrapper.createWrappedWidget( self.processing_context) else: widget = wrapper.widget if self.in_place and param.name() in ('INPUT', 'OUTPUT'): # don't show the input/output parameter widgets in in-place mode # we still need to CREATE them, because other wrappers may need to interact # with them (e.g. those parameters which need the input layer for field # selections/crs properties/etc) continue if widget is not None: if is_python_wrapper: widget.setToolTip(param.toolTip()) if isinstance(param, QgsProcessingParameterFeatureSource): layout = QHBoxLayout() layout.setSpacing(6) layout.setMargin(0) layout.addWidget(widget) button = QToolButton() icon = QIcon( os.path.join(pluginPath, 'images', 'iterate.png')) button.setIcon(icon) button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) button.setToolTip( self. tr('Iterate over this layer, creating a separate output for every feature in the layer' )) button.setCheckable(True) layout.addWidget(button) layout.setAlignment(button, Qt.AlignTop) self.iterateButtons[param.name()] = button button.toggled.connect(self.buttonToggled) widget = QWidget() widget.setLayout(layout) label = None if not is_python_wrapper: label = wrapper.createWrappedLabel() else: label = wrapper.label if label is not None: if param.flags( ) & QgsProcessingParameterDefinition.FlagAdvanced: self.layoutAdvanced.addWidget(label) else: self.layoutMain.insertWidget( self.layoutMain.count() - 2, label) elif is_python_wrapper: desc = param.description() if isinstance(param, QgsProcessingParameterExtent): desc += self.tr(' (xmin, xmax, ymin, ymax)') if isinstance(param, QgsProcessingParameterPoint): desc += self.tr(' (x, y)') if param.flags( ) & QgsProcessingParameterDefinition.FlagOptional: desc += self.tr(' [optional]') widget.setText(desc) if param.flags( ) & QgsProcessingParameterDefinition.FlagAdvanced: self.layoutAdvanced.addWidget(widget) else: self.layoutMain.insertWidget( self.layoutMain.count() - 2, widget) for output in self.alg.destinationParameterDefinitions(): if output.flags() & QgsProcessingParameterDefinition.FlagHidden: continue if self.in_place and param.name() in ('INPUT', 'OUTPUT'): continue label = QLabel(output.description()) widget = DestinationSelectionPanel(output, self.alg) self.layoutMain.insertWidget(self.layoutMain.count() - 1, label) self.layoutMain.insertWidget(self.layoutMain.count() - 1, widget) if isinstance(output, (QgsProcessingParameterRasterDestination, QgsProcessingParameterFeatureSink, QgsProcessingParameterVectorDestination)): check = QCheckBox() check.setText( QCoreApplication.translate( 'ParametersPanel', 'Open output file after running algorithm')) def skipOutputChanged(checkbox, skipped): checkbox.setEnabled(not skipped) if skipped: checkbox.setChecked(False) check.setChecked(not widget.outputIsSkipped()) check.setEnabled(not widget.outputIsSkipped()) widget.skipOutputChanged.connect( partial(skipOutputChanged, check)) self.layoutMain.insertWidget(self.layoutMain.count() - 1, check) self.checkBoxes[output.name()] = check widget.setToolTip(param.toolTip()) self.outputWidgets[output.name()] = widget for wrapper in list(self.wrappers.values()): wrapper.postInitialize(list(self.wrappers.values()))
class MapWidget(Ui_CanvasWidget, QMainWindow): def __init__(self, parent=None): super(MapWidget, self).__init__(parent) self.setupUi(self) self.snapping = True icon = roam_style.iconsize() self.projecttoolbar.setIconSize(QSize(icon, icon)) self.defaultextent = None self.current_form = None self.last_form = None self.layerbuttons = [] self.editfeaturestack = [] self.lastgpsposition = None self.project = None self.gps = None self.gpslogging = None self.selectionbands = defaultdict(partial(QgsRubberBand, self.canvas)) self.bridge = QgsLayerTreeMapCanvasBridge( QgsProject.instance().layerTreeRoot(), self.canvas) self.bridge.setAutoSetupOnFirstLayer(False) self.canvas.setCanvasColor(Qt.white) self.canvas.enableAntiAliasing(True) self.snappingutils = SnappingUtils(self.canvas, self) self.canvas.setSnappingUtils(self.snappingutils) threadcount = QThread.idealThreadCount() threadcount = 2 if threadcount > 2 else 1 QgsApplication.setMaxThreads(threadcount) self.canvas.setParallelRenderingEnabled(True) self.canvas.setFrameStyle(QFrame.NoFrame) self.editgroup = QActionGroup(self) self.editgroup.setExclusive(True) self.editgroup.addAction(self.actionPan) self.editgroup.addAction(self.actionZoom_In) self.editgroup.addAction(self.actionZoom_Out) self.editgroup.addAction(self.actionInfo) self.actionGPS = GPSAction(self.canvas, self) self.projecttoolbar.addAction(self.actionGPS) if roam.config.settings.get('north_arrow', False): self.northarrow = NorthArrow(":/icons/north", self.canvas) self.northarrow.setPos(10, 10) self.canvas.scene().addItem(self.northarrow) smallmode = roam.config.settings.get("smallmode", False) self.projecttoolbar.setSmallMode(smallmode) self.projecttoolbar.setContextMenuPolicy(Qt.CustomContextMenu) gpsspacewidget = QWidget() gpsspacewidget.setMinimumWidth(30) gpsspacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.topspaceraction = self.projecttoolbar.insertWidget( self.actionGPS, gpsspacewidget) self.dataentryselection = QAction(self.projecttoolbar) self.dataentryaction = self.projecttoolbar.insertAction( self.topspaceraction, self.dataentryselection) self.dataentryselection.triggered.connect(self.select_data_entry) self.gpsMarker = GPSMarker(self.canvas) self.gpsMarker.hide() self.currentfeatureband = CurrentSelection(self.canvas) self.currentfeatureband.setIconSize(30) self.currentfeatureband.setWidth(10) self.currentfeatureband.setColor(QColor(88, 64, 173, 50)) self.currentfeatureband.setOutlineColour(QColor(88, 64, 173)) self.gpsband = QgsRubberBand(self.canvas) self.gpsband.setColor(QColor(165, 111, 212, 75)) self.gpsband.setWidth(5) RoamEvents.refresh_map.connect(self.refresh_map) RoamEvents.editgeometry.connect(self.queue_feature_for_edit) RoamEvents.selectioncleared.connect(self.clear_selection) RoamEvents.selectionchanged.connect(self.highlight_selection) RoamEvents.openfeatureform.connect(self.feature_form_loaded) RoamEvents.sync_complete.connect(self.refresh_map) RoamEvents.snappingChanged.connect(self.snapping_changed) self.snappingbutton = QToolButton() self.snappingbutton.setText("Snapping: On") self.snappingbutton.setAutoRaise(True) self.snappingbutton.pressed.connect(self.toggle_snapping) spacer = QWidget() spacer2 = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) spacer2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.scalewidget = QgsScaleComboBox() self.scalebutton = QToolButton() self.scalebutton.setAutoRaise(True) self.scalebutton.setMaximumHeight(self.statusbar.height()) self.scalebutton.pressed.connect(self.selectscale) self.scalebutton.setText("Scale") self.scalelist = BigList(parent=self.canvas, centeronparent=True, showsave=False) self.scalelist.hide() self.scalelist.setlabel("Map Scale") self.scalelist.setmodel(self.scalewidget.model()) self.scalelist.closewidget.connect(self.scalelist.close) self.scalelist.itemselected.connect(self.update_scale_from_item) self.scalelist.itemselected.connect(self.scalelist.close) self.positionlabel = QLabel('') self.gpslabel = QLabel("GPS: Not active") self.gpslabelposition = QLabel("") self.gpslabelaveraging = QLabel('') # averaging self.statusbar.addWidget(self.snappingbutton) self.statusbar.addWidget(spacer2) self.statusbar.addWidget(self.gpslabel) self.statusbar.addWidget(self.gpslabelposition) self.statusbar.addWidget(self.gpslabelaveraging) # averaging self.statusbar.addPermanentWidget(self.scalebutton) self.canvas.extentsChanged.connect(self.update_status_label) self.canvas.scaleChanged.connect(self.update_status_label) self.connectButtons() scalebar_enabled = roam.config.settings.get('scale_bar', False) self.scalebar_enabled = False if scalebar_enabled: roam.utils.warning( "Unsupported feature: Scale bar support not ported to QGIS 3 API yet." ) RoamEvents.raisemessage( "Unsupported feature", "Scale bar support not ported to QGIS 3 API yet", level=RoamEvents.CRITICAL) self.scalebar_enabled = False # self.scalebar = ScaleBarItem(self.canvas) # self.canvas.scene().addItem(self.scalebar) def clear_plugins(self) -> None: """ Clear all the plugin added toolbars from the map interface. """ toolbars = self.findChildren(QToolBar) for toolbar in toolbars: if toolbar.property("plugin_toolbar"): toolbar.unload() self.removeToolBar(toolbar) toolbar.deleteLater() def add_plugins(self, pluginnames) -> None: """ Add the given plugins to to the mapping interface. Adds the toolbars the plugin exposes as new toolbars for the user. :param pluginnames: The names of the plugins to load. Must already be loaded by the plugin loader """ for name in pluginnames: # Get the plugin try: plugin_mod = plugins.loaded_plugins[name] except KeyError: continue if not hasattr(plugin_mod, 'toolbars'): roam.utils.warning( "No toolbars() function found in {}".format(name)) continue toolbars = plugin_mod.toolbars() self.load_plugin_toolbars(toolbars) def load_plugin_toolbars(self, toolbars): """ Load the plugin toolbars into the mapping interface. :param toolbars: The list of toolbars class objects to load. :return: """ for ToolBarClass in toolbars: toolbar = ToolBarClass(plugins.api, self) self.addToolBar(Qt.BottomToolBarArea, toolbar) toolbar.setProperty("plugin_toolbar", True) def snapping_changed(self, snapping): """ Called when the snapping settings have changed. Updates the label in the status bar. :param snapping: """ self.snapping = snapping if snapping: self.snappingbutton.setText("Snapping: On") else: self.snappingbutton.setText("Snapping: Off") def toggle_snapping(self): """ Toggle snapping on or off. """ self.snapping = not self.snapping try: self.canvas.mapTool().toggle_snapping() except AttributeError: pass RoamEvents.snappingChanged.emit(self.snapping) def selectscale(self): """ Show the select scale widget. :return: """ self.scalelist.show() def update_scale_from_item(self, index): """ Update the canvas scale from the selected scale item. :param index: The index of the selected item. """ scale, _ = self.scalewidget.toDouble(index.data(Qt.DisplayRole)) self.canvas.zoomScale(1.0 / scale) def update_gps_fixed_label(self, fixed, gpsinfo): if not fixed: self.gpslabel.setText("GPS: Acquiring fix") self.gpslabelposition.setText("") self.gpslabelaveraging.setText('') # averaging quality_mappings = { 0: "invalid", 1: "GPS", 2: "DGPS", 3: "PPS", 4: "Real Time Kinematic", 5: "Float RTK", 6: "Estimated", 7: "Manual input mode", 8: "Simulation mode" } def update_gps_label(self, position, gpsinfo): """ Update the GPS label in the status bar with the GPS status. :param position: The current GPS position. :param gpsinfo: The current extra GPS information. """ if not self.gps.connected: return fixtype = self.quality_mappings.get(gpsinfo.quality, "") self.gpslabel.setText( "DOP P:<b>{0:.2f}</b> H:<b>{1:.2f}</b> V:<b>{2:.2f}</b> " "Fix: <b>{3}</b> " "Sats: <b>{4}</b> ".format(gpsinfo.pdop, gpsinfo.hdop, gpsinfo.vdop, fixtype, gpsinfo.satellitesUsed)) places = roam.config.settings.get("gpsplaces", 8) # if averaging, don't show this if not roam.config.settings.get('gps_averaging', True): self.gpslabelposition.setText("X: <b>{x:.{places}f}</b> " "Y: <b>{y:.{places}f}</b> " "Z: <b>{z}m</b> ".format( x=position.x(), y=position.y(), z=position.z(), places=places)) else: self.gpslabelposition.setText('') # --- averaging ------------------------------------------------------- # if turned on if roam.config.settings.get('gps_averaging', True): time = roam.config.settings.get('gps_averaging_start_time', '') # if currently happening if roam.config.settings.get('gps_averaging_in_action', True): time = datetime.now().replace(microsecond=0) - time.replace( microsecond=0) count = roam.config.settings.get('gps_averaging_measurements', int) avglabel = 'AVG: <b>%s / %s</b>' % (time, count) else: avglabel = '' self.gpslabelaveraging.setText(avglabel) # --------------------------------------------------------------------- def gps_disconnected(self): self.gpslabel.setText("GPS: Not Active") self.gpslabelposition.setText("") self.gpslabelaveraging.setText("") self.gpsMarker.hide() def zoom_to_feature(self, feature): """ Zoom to the given feature in the map. :param feature: :return: """ box = feature.geometry().boundingBox() xmin, xmax, ymin, ymax = box.xMinimum(), box.xMaximum(), box.yMinimum( ), box.yMaximum() xmin -= 5 xmax += 5 ymin -= 5 ymax += 5 box = QgsRectangle(xmin, ymin, xmax, ymax) self.canvas.setExtent(box) self.canvas.refresh() def update_status_label(self, *args) -> None: """ Update the status bar labels when the information has changed. """ extent = self.canvas.extent() self.positionlabel.setText("Map Center: {}".format( extent.center().toString())) scale = 1.0 / self.canvas.scale() scale = self.scalewidget.toString(scale) self.scalebutton.setText(scale) def refresh_map(self) -> None: """ Refresh the map """ self.canvas.refresh() def updatescale(self) -> None: """ Update the scale of the map with the current scale from the scale widget :return: """ self.canvas.zoomScale(1.0 / self.scalewidget.scale()) @property def crs(self) -> QgsCoordinateReferenceSystem: """ Get the CRS used that is being used in the canvas :return: The QgsCoordinateReferenceSystem that is used by the canvas """ return self.canvas.mapSettings().destinationCrs() def feature_form_loaded(self, form, feature, *args): """ Called when the feature form is loaded. :param form: The Form object. Holds a reference to the forms layer. :param feature: The current capture feature """ self.currentfeatureband.setToGeometry(feature.geometry(), form.QGISLayer) def highlight_selection(self, results): """ Highlight the selection on the canvas. This updates all selected objects based on the result set. :param results: A dict-of-list of layer-features. """ self.clear_selection() for layer, features in results.items(): band = self.selectionbands[layer] band.setColor(QColor(255, 0, 0)) band.setIconSize(25) band.setWidth(5) band.setBrushStyle(Qt.NoBrush) band.reset(layer.geometryType()) band.setZValue(self.currentfeatureband.zValue() - 1) for feature in features: band.addGeometry(feature.geometry(), layer) self.canvas.update() def highlight_active_selection(self, layer, feature, features): """ Update the current active selected feature. :param layer: The layer of the active feature. :param feature: The active feature. :param features: The other features in the set to show as non active selection. :return: """ self.clear_selection() self.highlight_selection({layer: features}) self.currentfeatureband.setToGeometry(feature.geometry(), layer) self.canvas.update() def clear_selection(self): """ Clear the selection from the canvas. Resets all selection rubber bands. :return: """ # Clear the main selection rubber band self.canvas.scene().update() self.currentfeatureband.reset() # Clear the rest for band in self.selectionbands.values(): band.reset() self.canvas.update() self.editfeaturestack = [] def queue_feature_for_edit(self, form, feature): """ Push a feature on the edit stack so the feature can have the geometry edited. :note: This is a big hack and I don't like it! :param form: The form for the current feature :param feature: The active feature. """ def trigger_default_action(): for action in self.projecttoolbar.actions(): if action.property('dataentry') and action.isdefault: action.trigger() self.canvas.currentLayer().startEditing() self.canvas.mapTool().setEditMode(True, feature.geometry(), feature) break self.editfeaturestack.append((form, feature)) self.save_current_form() self.load_form(form) trigger_default_action() def save_current_form(self): self.last_form = self.current_form def restore_last_form(self): self.load_form(self.last_form) def clear_temp_objects(self): """ Clear all temp objects from the canvas. :return: """ def clear_tool_band(): """ Clear the rubber band of the active tool if it has one """ tool = self.canvas.mapTool() if hasattr(tool, "clearBand"): tool.clearBand() self.currentfeatureband.reset() clear_tool_band() def settings_updated(self, settings): """ Called when the settings have been updated in the Roam config. :param settings: A dict of the settings. """ self.actionGPS.updateGPSPort() gpslogging = settings.get('gpslogging', True) if self.gpslogging: self.gpslogging.logging = gpslogging smallmode = settings.get("smallmode", False) self.projecttoolbar.setSmallMode(smallmode) def set_gps(self, gps, logging): """ Set the GPS for the map widget. Connects GPS signals """ self.gps = gps self.gpslogging = logging self.gps.gpsfixed.connect(self.update_gps_fixed_label) self.gps.gpsposition.connect(self.update_gps_label) self.gps.gpsposition.connect(self.gps_update_canvas) self.gps.firstfix.connect(self.gps_first_fix) self.gps.gpsdisconnected.connect(self.gps_disconnected) self.gpsMarker.setgps(self.gps) self.actionGPS.setgps(gps) def gps_update_canvas(self, position, gpsinfo): """ Updates the map canvas based on the GPS position. By default if the GPS is outside the canvas extent the canvas will move to center on the GPS. Can be turned off in settings. :param postion: The current GPS position. :param gpsinfo: The extra GPS information """ # Recenter map if we go outside of the 95% of the area if self.gpslogging.logging: self.gpsband.addPoint(position) self.gpsband.show() if roam.config.settings.get('gpscenter', True): if not self.lastgpsposition == position: self.lastgpsposition = position.clone() rect = QgsRectangle(QgsPointXY(position), QgsPointXY(position)) extentlimt = QgsRectangle(self.canvas.extent()) extentlimt.scale(0.95) if not extentlimt.contains(QgsPointXY(position)): self.zoom_to_location(position) self.gpsMarker.show() self.gpsMarker.setCenter(position, gpsinfo) def gps_first_fix(self, postion, gpsinfo): """ Called the first time the GPS gets a fix. If set this will zoom to the GPS after the first fix :param postion: The current GPS position. :param gpsinfo: The extra GPS information """ zoomtolocation = roam.config.settings.get('gpszoomonfix', True) if zoomtolocation: self.canvas.zoomScale(1000) self.zoom_to_location(postion) def zoom_to_location(self, position): """ Zoom to ta given position on the map.. """ rect = QgsRectangle(QgsPointXY(position), QgsPointXY(position)) self.canvas.setExtent(rect) self.canvas.refresh() def select_data_entry(self): """ Open the form selection widget to allow the user to pick the active capture form. """ def showformerror(form): pass def actions(): for form in self.project.forms: if not self.form_valid_for_capture(form): continue action = form.createuiaction() valid, failreasons = form.valid if not valid: roam.utils.warning("Form {} failed to load".format( form.label)) roam.utils.warning("Reasons {}".format(failreasons)) action.triggered.connect(partial(showformerror, form)) else: action.triggered.connect(partial(self.load_form, form)) yield action formpicker = PickActionDialog(msg="Select data entry form", wrap=5) formpicker.addactions(actions()) formpicker.exec_() def project_loaded(self, project): """ Called when the project is loaded. Main entry point for a loade project. :param project: The Roam project that has been loaded. """ self.snappingutils.setConfig(QgsProject.instance().snappingConfig()) self.project = project self.actionPan.trigger() firstform = self.first_capture_form() if firstform: self.load_form(firstform) self.dataentryselection.setVisible(True) else: self.dataentryselection.setVisible(False) # Enable the raster layers button only if the project contains a raster layer. layers = roam.api.utils.layers() hasrasters = any(layer.type() == QgsMapLayer.RasterLayer for layer in layers) self.actionRaster.setEnabled(hasrasters) self.defaultextent = self.canvas.extent() roam.utils.info("Extent: {}".format(self.defaultextent.toString())) self.infoTool.selectionlayers = project.selectlayersmapping() self.canvas.refresh() projectscales, _ = QgsProject.instance().readBoolEntry( "Scales", "/useProjectScales") if projectscales: projectscales, _ = QgsProject.instance().readListEntry( "Scales", "/ScalesList") self.scalewidget.updateScales(projectscales) else: scales = [ "1:50000", "1:25000", "1:10000", "1:5000", "1:2500", "1:1000", "1:500", "1:250", "1:200", "1:100" ] scales = roam.config.settings.get('scales', scales) self.scalewidget.updateScales(scales) if self.scalebar_enabled: self.scalebar.update() red = QgsProject.instance().readNumEntry("Gui", "/CanvasColorRedPart", 255)[0] green = QgsProject.instance().readNumEntry("Gui", "/CanvasColorGreenPart", 255)[0] blue = QgsProject.instance().readNumEntry("Gui", "/CanvasColorBluePart", 255)[0] myColor = QColor(red, green, blue) self.canvas.setCanvasColor(myColor) self.actionPan.toggle() self.clear_plugins() self.add_plugins(project.enabled_plugins) def setMapTool(self, tool, *args): """ Set the active map tool in the canvas. :param tool: The QgsMapTool to set. """ if tool == self.canvas.mapTool(): return if hasattr(tool, "setSnapping"): tool.setSnapping(self.snapping) self.canvas.setMapTool(tool) def connectButtons(self): """ Connect the default buttons in the interface. Zoom, pan, etc """ def connectAction(action, tool): action.toggled.connect(partial(self.setMapTool, tool)) def cursor(name): pix = QPixmap(name) pix = pix.scaled(QSize(24, 24)) return QCursor(pix) self.zoomInTool = QgsMapToolZoom(self.canvas, False) self.zoomOutTool = QgsMapToolZoom(self.canvas, True) self.panTool = QgsMapToolPan(self.canvas) self.infoTool = InfoTool(self.canvas) self.infoTool.setAction(self.actionInfo) self.zoomInTool.setAction(self.actionZoom_In) self.zoomOutTool.setAction(self.actionZoom_Out) self.panTool.setAction(self.actionPan) connectAction(self.actionZoom_In, self.zoomInTool) connectAction(self.actionZoom_Out, self.zoomOutTool) connectAction(self.actionPan, self.panTool) connectAction(self.actionInfo, self.infoTool) self.zoomInTool.setCursor(cursor(':/icons/in')) self.zoomOutTool.setCursor(cursor(':/icons/out')) self.infoTool.setCursor(cursor(':/icons/select')) self.actionRaster.triggered.connect(self.toggle_raster_layers) self.actionHome.triggered.connect(self.homeview) def homeview(self): """ Zoom the mapview canvas to the extents the project was opened at i.e. the default extent. """ if self.defaultextent: self.canvas.setExtent(self.defaultextent) self.canvas.refresh() def form_valid_for_capture(self, form): """ Check if the given form is valid for capture. :param form: The form to check. :return: True if valid form for capture """ return form.has_geometry and self.project.layer_can_capture( form.QGISLayer) def first_capture_form(self): """ Return the first valid form for capture. """ for form in self.project.forms: if self.form_valid_for_capture(form): return form def load_form(self, form): """ Load the given form so it's the active one for capture :param form: The form to load """ self.clear_capture_tools() self.dataentryselection.setIcon(QIcon(form.icon)) self.dataentryselection.setText(form.icontext) self.create_capture_buttons(form) self.current_form = form def create_capture_buttons(self, form): """ Create the capture buttons in the toolbar for the given form. :param form: The active form. """ tool = form.getMaptool()(self.canvas, form.settings) for action in tool.actions: # Create the action here. if action.ismaptool: action.toggled.connect(partial(self.setMapTool, tool)) # Set the action as a data entry button so we can remove it later. action.setProperty("dataentry", True) self.editgroup.addAction(action) self.layerbuttons.append(action) self.projecttoolbar.insertAction(self.topspaceraction, action) action.setChecked(action.isdefault) if hasattr(tool, 'geometryComplete'): add = partial(self.add_new_feature, form) tool.geometryComplete.connect(add) else: tool.finished.connect(self.openForm) tool.error.connect(self.show_invalid_geometry_message) def show_invalid_geometry_message(self, message) -> None: """ Shows the message to the user if the there is a invalid geometry capture. :param message: The message to show the user. """ RoamEvents.raisemessage("Invalid geometry capture", message, level=RoamEvents.CRITICAL) if self.canvas.currentLayer() is not None: self.canvas.currentLayer().rollBack() RoamEvents.editgeometry_invalid.emit() def add_new_feature(self, form, geometry: QgsGeometry): """ Add a new new feature to the given layer :param form: The form to use for the new feature. :param geometry: The new geometry to create the feature for. """ # NOTE This function is doing too much, acts as add and also edit. layer = form.QGISLayer if geometry.isMultipart(): geometry.convertToMultiType() # Transform the new geometry back into the map layers geometry if it's needed transform = self.canvas.mapSettings().layerTransform(layer) if transform.isValid(): geometry.transform(transform, QgsCoordinateTransform.ReverseTransform) try: form, feature = self.editfeaturestack.pop() self.editfeaturegeometry(form, feature, newgeometry=geometry) return except IndexError: pass feature = form.new_feature(geometry=geometry) RoamEvents.load_feature_form(form, feature, editmode=False) def editfeaturegeometry(self, form, feature, newgeometry): # TODO Extract into function. layer = form.QGISLayer layer.startEditing() feature.setGeometry(newgeometry) layer.updateFeature(feature) saved = layer.commitChanges() if not saved: map(roam.utils.error, layer.commitErrors()) self.canvas.refresh() self.currentfeatureband.setToGeometry(feature.geometry(), layer) RoamEvents.editgeometry_complete.emit(form, feature) self.canvas.mapTool().setEditMode(False, None, None) self.restore_last_form() def clear_capture_tools(self): """ Clear the capture tools from the toolbar. :return: True if the capture button was active at the time of clearing. """ captureselected = False for action in self.projecttoolbar.actions(): if action.objectName() == "capture" and action.isChecked(): captureselected = True if action.property('dataentry'): self.projecttoolbar.removeAction(action) return captureselected def toggle_raster_layers(self) -> None: """ Toggle all raster layers on or off. """ # Freeze the canvas to save on UI refresh dlg = PickActionDialog(msg="Raster visibility") actions = [ (":/icons/raster_0", "Off", partial(self._set_basemaps_opacity, 0), "photo_off"), (":/icons/raster_25", "25%", partial(self._set_basemaps_opacity, .25), "photo_25"), (":/icons/raster_50", "50%", partial(self._set_basemaps_opacity, .50), "photo_50"), (":/icons/raster_75", "75%", partial(self._set_basemaps_opacity, .75), "photo_75"), (":/icons/raster_100", "100%", partial(self._set_basemaps_opacity, 1), "photo_100"), ] # ":/icons/raster_100"), "100%", self, triggered=partial(self._set_raster_layer_value, 1), # objectName="photo_100") dialog_actions = [] for action in actions: icon = QIcon(action[0]) qaction = QAction(icon, action[1], self, triggered=action[2], objectName=action[3]) dialog_actions.append(qaction) dlg.addactions(dialog_actions) dlg.exec_() def _set_basemaps_opacity(self, value=0) -> None: """ Set the opacity for all basemap raster layers. :param value: The opacity value betwen 0 and 1 """ tree = QgsProject.instance().layerTreeRoot() for node in tree.findLayers(): layer = node.layer() if node.layer().type() == QgsMapLayer.RasterLayer: if value > 0: node.setItemVisibilityChecked(Qt.Checked) renderer = layer.renderer() renderer.setOpacity(value) if value == 0: node.setItemVisibilityChecked(Qt.Unchecked) self.canvas.refresh() def cleanup(self): """ Clean up when the project has changed. :return: """ # TODO Review cleanup # self.bridge.clear() self.gpsband.reset() self.gpsband.hide() self.clear_selection() self.clear_temp_objects() self.clear_capture_tools() for action in self.layerbuttons: self.editgroup.removeAction(action)
class Plugin(): """The QGIS interface implementation for the InaSAFE plugin. This class acts as the 'glue' between QGIS and our custom logic. It creates a toolbar and menu bar entry and launches the InaSAFE user interface if these are activated. """ def __init__(self, iface): """Class constructor. On instantiation, the plugin instance will be assigned a copy of the QGIS iface object which will allow this plugin to access and manipulate the running QGIS instance that spawned it. :param iface:Quantum GIS iface instance. This instance is automatically passed to the plugin by QGIS when it loads the plugin. :type iface: QgisAppInterface """ # Save reference to the QGIS interface self.iface = iface self.dock_widget = None # Actions self.action_add_layers = None self.action_add_osm_layer = None self.action_add_petabencana_layer = None self.action_batch_runner = None self.action_dock = None self.action_extent_selector = None self.action_field_mapping = None self.action_multi_exposure = None self.action_function_centric_wizard = None self.action_import_dialog = None self.action_keywords_wizard = None self.action_minimum_needs = None self.action_minimum_needs_config = None self.action_multi_buffer = None self.action_options = None self.action_run_tests = None self.action_save_scenario = None self.action_shake_converter = None self.action_show_definitions = None self.action_toggle_rubberbands = None self.action_metadata_converter = None self.translator = None self.toolbar = None self.wizard = None self.actions = [] # list of all QActions we create for InaSAFE self.message_bar_item = None # Flag indicating if toolbar should show only common icons or not self.full_toolbar = False # print self.tr('InaSAFE') # For enable/disable the keyword editor icon self.iface.currentLayerChanged.connect(self.layer_changed) developer_mode = setting('developer_mode', False, expected_type=bool) self.hide_developer_buttons = (inasafe_release_status == 'final' and not developer_mode) # noinspection PyMethodMayBeStatic def tr(self, 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('Plugin', message) def add_action(self, action, add_to_toolbar=True, add_to_legend=False): """Add a toolbar icon to the InaSAFE toolbar. :param action: The action that should be added to the toolbar. :type action: QAction :param add_to_toolbar: Flag indicating whether the action should also be added to the InaSAFE toolbar. Defaults to True. :type add_to_toolbar: bool :param add_to_legend: Flag indicating whether the action should also be added to the layer legend menu. Default to False. :type add_to_legend: bool """ # store in the class list of actions for easy plugin unloading self.actions.append(action) self.iface.addPluginToMenu(self.tr('InaSAFE'), action) if add_to_toolbar: self.toolbar.addAction(action) if add_to_legend: # The id is the action name without spaces, tabs ... self.iface.addCustomActionForLayerType(action, self.tr('InaSAFE'), QgsMapLayer.VectorLayer, True) self.iface.addCustomActionForLayerType(action, self.tr('InaSAFE'), QgsMapLayer.RasterLayer, True) def _create_dock_toggle_action(self): """Create action for plugin dockable window (show/hide).""" # pylint: disable=W0201 icon = resources_path('img', 'icons', 'icon.svg') self.action_dock = QAction(QIcon(icon), self.tr('Toggle InaSAFE Dock'), self.iface.mainWindow()) self.action_dock.setObjectName('InaSAFEDockToggle') self.action_dock.setStatusTip(self.tr('Show/hide InaSAFE dock widget')) self.action_dock.setWhatsThis(self.tr('Show/hide InaSAFE dock widget')) self.action_dock.setCheckable(True) self.action_dock.setChecked(True) self.action_dock.triggered.connect(self.toggle_dock_visibility) self.add_action(self.action_dock) # -------------------------------------- # Create action for keywords creation wizard # ------------------------------------- def _create_keywords_wizard_action(self): """Create action for keywords creation wizard.""" icon = resources_path('img', 'icons', 'show-keyword-wizard.svg') self.action_keywords_wizard = QAction( QIcon(icon), self.tr('Keywords Creation Wizard'), self.iface.mainWindow()) self.action_keywords_wizard.setStatusTip( self.tr('Open InaSAFE keywords creation wizard')) self.action_keywords_wizard.setWhatsThis( self.tr('Open InaSAFE keywords creation wizard')) self.action_keywords_wizard.setEnabled(False) self.action_keywords_wizard.triggered.connect( self.show_keywords_wizard) self.add_action(self.action_keywords_wizard, add_to_legend=True) def _create_analysis_wizard_action(self): """Create action for IF-centric wizard.""" icon = resources_path('img', 'icons', 'show-wizard.svg') self.action_function_centric_wizard = QAction( QIcon(icon), self.tr('Impact Function Centric Wizard'), self.iface.mainWindow()) self.action_function_centric_wizard.setStatusTip( self.tr('Open InaSAFE impact function centric wizard')) self.action_function_centric_wizard.setWhatsThis( self.tr('Open InaSAFE impact function centric wizard')) self.action_function_centric_wizard.setEnabled(True) self.action_function_centric_wizard.triggered.connect( self.show_function_centric_wizard) self.add_action(self.action_function_centric_wizard) def _create_options_dialog_action(self): """Create action for options dialog.""" icon = resources_path('img', 'icons', 'configure-inasafe.svg') self.action_options = QAction(QIcon(icon), self.tr('Options'), self.iface.mainWindow()) self.action_options.setStatusTip( self.tr('Open InaSAFE options dialog')) self.action_options.setWhatsThis( self.tr('Open InaSAFE options dialog')) self.action_options.triggered.connect(self.show_options) self.add_action(self.action_options, add_to_toolbar=self.full_toolbar) def _create_minimum_needs_action(self): """Create action for minimum needs dialog.""" icon = resources_path('img', 'icons', 'show-minimum-needs.svg') self.action_minimum_needs = QAction( QIcon(icon), self.tr('Minimum Needs Calculator'), self.iface.mainWindow()) self.action_minimum_needs.setStatusTip( self.tr('Open InaSAFE minimum needs calculator')) self.action_minimum_needs.setWhatsThis( self.tr('Open InaSAFE minimum needs calculator')) self.action_minimum_needs.triggered.connect(self.show_minimum_needs) self.add_action(self.action_minimum_needs, add_to_toolbar=self.full_toolbar) def _create_multi_buffer_action(self): """Create action for multi buffer dialog.""" icon = resources_path('img', 'icons', 'show-multi-buffer.svg') self.action_multi_buffer = QAction(QIcon(icon), self.tr('Multi Buffer'), self.iface.mainWindow()) self.action_multi_buffer.setStatusTip( self.tr('Open InaSAFE multi buffer')) self.action_multi_buffer.setWhatsThis( self.tr('Open InaSAFE multi buffer')) self.action_multi_buffer.triggered.connect(self.show_multi_buffer) self.add_action(self.action_multi_buffer, add_to_toolbar=self.full_toolbar) def _create_minimum_needs_options_action(self): """Create action for global minimum needs dialog.""" icon = resources_path('img', 'icons', 'show-global-minimum-needs.svg') self.action_minimum_needs_config = QAction( QIcon(icon), self.tr('Minimum Needs Configuration'), self.iface.mainWindow()) self.action_minimum_needs_config.setStatusTip( self.tr('Open InaSAFE minimum needs configuration')) self.action_minimum_needs_config.setWhatsThis( self.tr('Open InaSAFE minimum needs configuration')) self.action_minimum_needs_config.triggered.connect( self.show_minimum_needs_configuration) self.add_action(self.action_minimum_needs_config, add_to_toolbar=self.full_toolbar) def _create_shakemap_converter_action(self): """Create action for converter dialog.""" icon = resources_path('img', 'icons', 'show-converter-tool.svg') self.action_shake_converter = QAction(QIcon(icon), self.tr('Shakemap Converter'), self.iface.mainWindow()) self.action_shake_converter.setStatusTip( self.tr('Open InaSAFE Converter')) self.action_shake_converter.setWhatsThis( self.tr('Open InaSAFE Converter')) self.action_shake_converter.triggered.connect( self.show_shakemap_importer) self.add_action(self.action_shake_converter, add_to_toolbar=self.full_toolbar) def _create_batch_runner_action(self): """Create action for batch runner dialog.""" icon = resources_path('img', 'icons', 'show-batch-runner.svg') self.action_batch_runner = QAction(QIcon(icon), self.tr('Batch Runner'), self.iface.mainWindow()) self.action_batch_runner.setStatusTip(self.tr('Open Batch Runner')) self.action_batch_runner.setWhatsThis(self.tr('Open Batch Runner')) self.action_batch_runner.triggered.connect(self.show_batch_runner) self.add_action(self.action_batch_runner, add_to_toolbar=self.full_toolbar) def _create_save_scenario_action(self): """Create action for save scenario dialog.""" icon = resources_path('img', 'icons', 'save-as-scenario.svg') self.action_save_scenario = QAction(QIcon(icon), self.tr('Save Current Scenario'), self.iface.mainWindow()) message = self.tr('Save current scenario to text file') self.action_save_scenario.setStatusTip(message) self.action_save_scenario.setWhatsThis(message) # noinspection PyUnresolvedReferences self.action_save_scenario.triggered.connect(self.save_scenario) self.add_action(self.action_save_scenario, add_to_toolbar=self.full_toolbar) def _create_osm_downloader_action(self): """Create action for import OSM Dialog.""" icon = resources_path('img', 'icons', 'show-osm-download.svg') self.action_import_dialog = QAction( QIcon(icon), self.tr('OpenStreetMap Downloader'), self.iface.mainWindow()) self.action_import_dialog.setStatusTip( self.tr('OpenStreetMap Downloader')) self.action_import_dialog.setWhatsThis( self.tr('OpenStreetMap Downloader')) self.action_import_dialog.triggered.connect(self.show_osm_downloader) self.add_action(self.action_import_dialog, add_to_toolbar=True) def _create_geonode_uploader_action(self): """Create action for Geonode uploader dialog.""" icon = resources_path('img', 'icons', 'geonode.png') label = tr('Geonode Uploader') self.action_geonode = QAction(QIcon(icon), label, self.iface.mainWindow()) self.action_geonode.setStatusTip(label) self.action_geonode.setWhatsThis(label) self.action_geonode.triggered.connect(self.show_geonode_uploader) self.add_action(self.action_geonode, add_to_toolbar=False) def _create_add_osm_layer_action(self): """Create action for import OSM Dialog.""" icon = resources_path('img', 'icons', 'add-osm-tiles-layer.svg') self.action_add_osm_layer = QAction( QIcon(icon), self.tr('Add OpenStreetMap Tile Layer'), self.iface.mainWindow()) self.action_add_osm_layer.setStatusTip( self.tr('Add OpenStreetMap Tile Layer')) self.action_add_osm_layer.setWhatsThis( self.tr('Use this to add an OSM layer to your map. ' 'It needs internet access to function.')) self.action_add_osm_layer.triggered.connect(self.add_osm_layer) self.add_action(self.action_add_osm_layer, add_to_toolbar=True) def _create_show_definitions_action(self): """Create action for showing definitions / help.""" icon = resources_path('img', 'icons', 'show-inasafe-help.svg') self.action_show_definitions = QAction(QIcon(icon), self.tr('InaSAFE Help'), self.iface.mainWindow()) self.action_show_definitions.setStatusTip(self.tr('Show InaSAFE Help')) self.action_show_definitions.setWhatsThis( self. tr('Use this to show a document describing all InaSAFE concepts.')) self.action_show_definitions.triggered.connect(self.show_definitions) self.add_action(self.action_show_definitions, add_to_toolbar=True) def _create_metadata_converter_action(self): """Create action for showing metadata converter dialog.""" icon = resources_path('img', 'icons', 'show-metadata-converter.svg') self.action_metadata_converter = QAction( QIcon(icon), self.tr('InaSAFE Metadata Converter'), self.iface.mainWindow()) self.action_metadata_converter.setStatusTip( self.tr('Convert metadata from version 4.3 to version 3.5.')) self.action_metadata_converter.setWhatsThis( self.tr('Use this tool to convert metadata 4.3 to version 3.5')) self.action_metadata_converter.triggered.connect( self.show_metadata_converter) self.add_action(self.action_metadata_converter, add_to_toolbar=self.full_toolbar) def _create_field_mapping_action(self): """Create action for showing field mapping dialog.""" icon = resources_path('img', 'icons', 'show-mapping-tool.svg') self.action_field_mapping = QAction( QIcon(icon), self.tr('InaSAFE Field Mapping Tool'), self.iface.mainWindow()) self.action_field_mapping.setStatusTip( self.tr('Assign field mapping to layer.')) self.action_field_mapping.setWhatsThis( self.tr('Use this tool to assign field mapping in layer.')) self.action_field_mapping.setEnabled(False) self.action_field_mapping.triggered.connect(self.show_field_mapping) self.add_action(self.action_field_mapping, add_to_toolbar=self.full_toolbar) def _create_multi_exposure_action(self): """Create action for showing the multi exposure tool.""" self.action_multi_exposure = QAction( QIcon(resources_path('img', 'icons', 'show-multi-exposure.svg')), self.tr('InaSAFE Multi Exposure Tool'), self.iface.mainWindow()) self.action_multi_exposure.setStatusTip( self.tr('Open the multi exposure tool.')) self.action_multi_exposure.setWhatsThis( self.tr('Open the multi exposure tool.')) self.action_multi_exposure.setEnabled(True) self.action_multi_exposure.triggered.connect(self.show_multi_exposure) self.add_action(self.action_multi_exposure, add_to_toolbar=self.full_toolbar) def _create_add_petabencana_layer_action(self): """Create action for import OSM Dialog.""" icon = resources_path('img', 'icons', 'add-petabencana-layer.svg') self.action_add_petabencana_layer = QAction( QIcon(icon), self.tr('Add PetaBencana Flood Layer'), self.iface.mainWindow()) self.action_add_petabencana_layer.setStatusTip( self.tr('Add PetaBencana Flood Layer')) self.action_add_petabencana_layer.setWhatsThis( self.tr('Use this to add a PetaBencana layer to your map. ' 'It needs internet access to function.')) self.action_add_petabencana_layer.triggered.connect( self.add_petabencana_layer) self.add_action(self.action_add_petabencana_layer, add_to_toolbar=self.full_toolbar) def _create_rubber_bands_action(self): """Create action for toggling rubber bands.""" icon = resources_path('img', 'icons', 'toggle-rubber-bands.svg') self.action_toggle_rubberbands = QAction( QIcon(icon), self.tr('Toggle Scenario Outlines'), self.iface.mainWindow()) message = self.tr('Toggle rubber bands showing scenario extents.') self.action_toggle_rubberbands.setStatusTip(message) self.action_toggle_rubberbands.setWhatsThis(message) # Set initial state self.action_toggle_rubberbands.setCheckable(True) flag = setting('showRubberBands', False, expected_type=bool) self.action_toggle_rubberbands.setChecked(flag) # noinspection PyUnresolvedReferences self.action_toggle_rubberbands.triggered.connect( self.dock_widget.toggle_rubber_bands) self.add_action(self.action_toggle_rubberbands) def _create_analysis_extent_action(self): """Create action for analysis extent dialog.""" icon = resources_path('img', 'icons', 'set-extents-tool.svg') self.action_extent_selector = QAction(QIcon(icon), self.tr('Set Analysis Area'), self.iface.mainWindow()) self.action_extent_selector.setStatusTip( self.tr('Set the analysis area for InaSAFE')) self.action_extent_selector.setWhatsThis( self.tr('Set the analysis area for InaSAFE')) self.action_extent_selector.triggered.connect( self.show_extent_selector) self.add_action(self.action_extent_selector) def _create_test_layers_action(self): """Create action for adding layers (developer mode, non final only).""" if self.hide_developer_buttons: return icon = resources_path('img', 'icons', 'add-test-layers.svg') self.action_add_layers = QAction(QIcon(icon), self.tr('Add Test Layers'), self.iface.mainWindow()) self.action_add_layers.setStatusTip(self.tr('Add test layers')) self.action_add_layers.setWhatsThis(self.tr('Add test layers')) self.action_add_layers.triggered.connect(self.add_test_layers) self.add_action(self.action_add_layers) def _create_run_test_action(self): """Create action for running tests (developer mode, non final only).""" if self.hide_developer_buttons: return default_package = str(setting('testPackage', 'safe', expected_type=str)) msg = self.tr('Run tests in %s' % default_package) self.test_button = QToolButton() self.test_button.setMenu(QMenu()) self.test_button.setPopupMode(QToolButton.MenuButtonPopup) icon = resources_path('img', 'icons', 'run-tests.svg') self.action_run_tests = QAction(QIcon(icon), msg, self.iface.mainWindow()) self.action_run_tests.setStatusTip(msg) self.action_run_tests.setWhatsThis(msg) self.action_run_tests.triggered.connect(self.run_tests) self.test_button.menu().addAction(self.action_run_tests) self.test_button.setDefaultAction(self.action_run_tests) self.action_select_package = QAction(QIcon(icon), self.tr('Select package'), self.iface.mainWindow()) self.action_select_package.setStatusTip(self.tr('Select Test Package')) self.action_select_package.setWhatsThis(self.tr('Select Test Package')) self.action_select_package.triggered.connect(self.select_test_package) self.test_button.menu().addAction(self.action_select_package) self.toolbar.addWidget(self.test_button) self.add_action(self.action_run_tests, add_to_toolbar=False) self.add_action(self.action_select_package, add_to_toolbar=False) def _create_dock(self): """Create dockwidget and tabify it with the legend.""" # Import dock here as it needs to be imported AFTER i18n is set up from safe.gui.widgets.dock import Dock self.dock_widget = Dock(self.iface) self.dock_widget.setObjectName('InaSAFE-Dock') self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dock_widget) legend_tab = self.iface.mainWindow().findChild(QApplication, 'Legend') if legend_tab: self.iface.mainWindow().tabifyDockWidget(legend_tab, self.dock_widget) self.dock_widget.raise_() # noinspection PyPep8Naming def initGui(self): """Gui initialisation procedure (for QGIS plugin api). .. note:: Don't change the name of this method from initGui! This method is called by QGIS and should be used to set up any graphical user interface elements that should appear in QGIS by default (i.e. before the user performs any explicit action with the plugin). """ self.toolbar = self.iface.addToolBar('InaSAFE') self.toolbar.setObjectName('InaSAFEToolBar') self.dock_widget = None # Now create the actual dock self._create_dock() # And all the menu actions # Configuration Group self._create_dock_toggle_action() self._create_options_dialog_action() self._create_minimum_needs_options_action() self._create_analysis_extent_action() self._create_rubber_bands_action() self._add_spacer_to_menu() self._create_keywords_wizard_action() self._create_analysis_wizard_action() self._add_spacer_to_menu() self._create_field_mapping_action() self._create_multi_exposure_action() self._create_metadata_converter_action() self._create_osm_downloader_action() self._create_add_osm_layer_action() self._create_add_petabencana_layer_action() self._create_geonode_uploader_action() self._create_shakemap_converter_action() self._create_minimum_needs_action() self._create_multi_buffer_action() self._create_test_layers_action() self._create_run_test_action() self._add_spacer_to_menu() self._create_batch_runner_action() self._create_save_scenario_action() self._add_spacer_to_menu() self._create_show_definitions_action() # Hook up a slot for when the dock is hidden using its close button # or view-panels # self.dock_widget.visibilityChanged.connect(self.toggle_inasafe_action) # Also deal with the fact that on start of QGIS dock may already be # hidden. self.action_dock.setChecked(self.dock_widget.isVisible()) self.iface.initializationCompleted.connect( partial(self.show_welcome_message)) def _add_spacer_to_menu(self): """Create a spacer to the menu to separate action groups.""" separator = QAction(self.iface.mainWindow()) separator.setSeparator(True) self.iface.addPluginToMenu(self.tr('InaSAFE'), separator) @staticmethod def clear_modules(): """Unload inasafe functions and try to return QGIS to before InaSAFE. .. todo:: I think this function can be removed. TS. """ # next lets force remove any inasafe related modules modules = [] for module in sys.modules: if 'inasafe' in module: # Check if it is really one of our modules i.e. exists in the # plugin directory tokens = module.split('.') path = '' for myToken in tokens: path += os.path.sep + myToken parent = os.path.abspath( os.path.join(__file__, os.path.pardir, os.path.pardir)) full_path = os.path.join(parent, path + '.py') if os.path.exists(os.path.abspath(full_path)): LOGGER.debug('Removing: %s' % module) modules.append(module) for module in modules: del (sys.modules[module]) for module in sys.modules: if 'inasafe' in module: print(module) # Lets also clean up all the path additions that were made package_path = os.path.abspath( os.path.join(os.path.dirname(__file__), os.path.pardir)) LOGGER.debug('Path to remove: %s' % package_path) # We use a list comprehension to ensure duplicate entries are removed LOGGER.debug(sys.path) sys.path = [y for y in sys.path if package_path not in y] LOGGER.debug(sys.path) def unload(self): """GUI breakdown procedure (for QGIS plugin api). .. note:: Don't change the name of this method from unload! This method is called by QGIS and should be used to *remove* any graphical user interface elements that should appear in QGIS. """ # Remove the plugin menu item and icon if self.wizard: self.wizard.deleteLater() for myAction in self.actions: self.iface.removePluginMenu(self.tr('InaSAFE'), myAction) self.iface.removeToolBarIcon(myAction) self.iface.removeCustomActionForLayerType(myAction) self.iface.mainWindow().removeDockWidget(self.dock_widget) self.iface.mainWindow().removeToolBar(self.toolbar) self.dock_widget.setVisible(False) self.dock_widget.destroy() self.iface.currentLayerChanged.disconnect(self.layer_changed) # Unload QGIS expressions loaded by the plugin. for qgis_expression in list(qgis_expressions().keys()): QgsExpression.unregisterFunction(qgis_expression) def toggle_inasafe_action(self, checked): """Check or un-check the toggle inaSAFE toolbar button. This slot is called when the user hides the inaSAFE panel using its close button or using view->panels. :param checked: True if the dock should be shown, otherwise False. :type checked: bool """ self.action_dock.setChecked(checked) # Run method that performs all the real work def toggle_dock_visibility(self): """Show or hide the dock widget.""" if self.dock_widget.isVisible(): self.dock_widget.setVisible(False) else: self.dock_widget.setVisible(True) self.dock_widget.raise_() def add_test_layers(self): """Add standard test layers.""" from safe.test.utilities import load_standard_layers load_standard_layers() rect = QgsRectangle(106.806, -6.195, 106.837, -6.167) self.iface.mapCanvas().setExtent(rect) def select_test_package(self): """Select the test package.""" default_package = 'safe' user_package = str( setting('testPackage', default_package, expected_type=str)) test_package, _ = QInputDialog.getText( self.iface.mainWindow(), self.tr('Select the python test package'), self.tr('Select the python test package'), QLineEdit.Normal, user_package) if test_package == '': test_package = default_package set_setting('testPackage', test_package) msg = self.tr('Run tests in %s' % test_package) self.action_run_tests.setWhatsThis(msg) self.action_run_tests.setText(msg) def run_tests(self): """Run unit tests in the python console.""" from qgis.PyQt.QtWidgets import QDockWidget main_window = self.iface.mainWindow() action = main_window.findChild(QAction, 'mActionShowPythonDialog') action.trigger() package = str(setting('testPackage', 'safe', expected_type=str)) for child in main_window.findChildren(QDockWidget, 'PythonConsole'): if child.objectName() == 'PythonConsole': child.show() for widget in child.children(): if 'PythonConsoleWidget' in str(widget.__class__): # print "Console widget found" shell = widget.shell shell.runCommand( 'from inasafe.test_suite import test_package') shell.runCommand('test_package(\'%s\')' % package) break def show_extent_selector(self): """Show the extent selector widget for defining analysis extents.""" # import here only so that it is AFTER i18n set up from safe.gui.tools.extent_selector_dialog import ExtentSelectorDialog widget = ExtentSelectorDialog( self.iface, self.iface.mainWindow(), extent=self.dock_widget.extent.user_extent, crs=self.dock_widget.extent.crs) widget.clear_extent.connect( self.dock_widget.extent.clear_user_analysis_extent) widget.extent_defined.connect( self.dock_widget.define_user_analysis_extent) # This ensures that run button state is updated on dialog close widget.extent_selector_closed.connect( self.dock_widget.validate_impact_function) # Needs to be non modal to support hide -> interact with map -> show widget.show() # non modal def show_minimum_needs(self): """Show the minimum needs dialog.""" # import here only so that it is AFTER i18n set up from safe.gui.tools.minimum_needs.needs_calculator_dialog import ( NeedsCalculatorDialog) dialog = NeedsCalculatorDialog(self.iface.mainWindow()) dialog.exec_() def show_minimum_needs_configuration(self): """Show the minimum needs dialog.""" # import here only so that it is AFTER i18n set up from safe.gui.tools.minimum_needs.needs_manager_dialog import ( NeedsManagerDialog) dialog = NeedsManagerDialog(parent=self.iface.mainWindow(), dock=self.dock_widget) dialog.exec_() # modal def show_options(self): """Show the options dialog.""" # import here only so that it is AFTER i18n set up from safe.gui.tools.options_dialog import OptionsDialog dialog = OptionsDialog(iface=self.iface, parent=self.iface.mainWindow()) dialog.show_option_dialog() if dialog.exec_(): # modal self.dock_widget.read_settings() from safe.gui.widgets.message import getting_started_message send_static_message(self.dock_widget, getting_started_message()) # Issue #4734, make sure to update the combobox after update the # InaSAFE option self.dock_widget.get_layers() def show_welcome_message(self): """Show the welcome message.""" # import here only so that it is AFTER i18n set up from safe.gui.tools.options_dialog import OptionsDialog # Do not show by default show_message = False previous_version = StrictVersion(setting('previous_version')) current_version = StrictVersion(inasafe_version) # Set previous_version to the current inasafe_version set_setting('previous_version', inasafe_version) if setting('always_show_welcome_message', expected_type=bool): # Show if it the setting said so show_message = True elif previous_version < current_version: # Always show if the user installed new version show_message = True # Allow to disable welcome message when running automated tests if os.environ.get('INASAFE_DISABLE_WELCOME_MESSAGE', False): show_message = False if show_message: dialog = OptionsDialog(iface=self.iface, parent=self.iface.mainWindow()) dialog.show_welcome_dialog() if dialog.exec_(): # modal self.dock_widget.read_settings() def show_keywords_wizard(self): """Show the keywords creation wizard.""" # import here only so that it is AFTER i18n set up from safe.gui.tools.wizard.wizard_dialog import WizardDialog if self.iface.activeLayer() is None: return # Don't break an existing wizard session if accidentally clicked if self.wizard and self.wizard.isVisible(): return # Prevent spawning multiple copies since the IFCW is non modal if not self.wizard: self.wizard = WizardDialog(self.iface.mainWindow(), self.iface, self.dock_widget) self.wizard.set_keywords_creation_mode() self.wizard.exec_() # modal def show_function_centric_wizard(self): """Show the function centric wizard.""" # import here only so that it is AFTER i18n set up from safe.gui.tools.wizard.wizard_dialog import WizardDialog # Don't break an existing wizard session if accidentally clicked if self.wizard and self.wizard.isVisible(): return # Prevent spawning multiple copies since it is non modal if not self.wizard: self.wizard = WizardDialog(self.iface.mainWindow(), self.iface, self.dock_widget) self.wizard.set_function_centric_mode() # non-modal in order to hide for selecting user extent self.wizard.show() def show_shakemap_importer(self): """Show the converter dialog.""" # import here only so that it is AFTER i18n set up from safe.gui.tools.shake_grid.shakemap_converter_dialog import ( ShakemapConverterDialog) dialog = ShakemapConverterDialog(self.iface.mainWindow(), self.iface, self.dock_widget) dialog.exec_() # modal def show_multi_buffer(self): """Show the multi buffer tool.""" from safe.gui.tools.multi_buffer_dialog import (MultiBufferDialog) dialog = MultiBufferDialog(self.iface.mainWindow(), self.iface, self.dock_widget) dialog.exec_() # modal def show_osm_downloader(self): """Show the OSM buildings downloader dialog.""" from safe.gui.tools.osm_downloader_dialog import OsmDownloaderDialog dialog = OsmDownloaderDialog(self.iface.mainWindow(), self.iface) # otherwise dialog is never deleted dialog.setAttribute(Qt.WA_DeleteOnClose, True) dialog.show() # non modal def show_geonode_uploader(self): """Show the Geonode uploader dialog.""" from safe.gui.tools.geonode_uploader import GeonodeUploaderDialog dialog = GeonodeUploaderDialog(self.iface.mainWindow()) dialog.show() # non modal def add_osm_layer(self): """Add OSM tile layer to the map. This uses a gdal wrapper around the OSM tile service - see the WorldOSM.gdal file for how it is constructed. """ path = resources_path('osm', 'WorldOSM.gdal') layer = QgsRasterLayer(path, self.tr('OpenStreetMap')) project = QgsProject.instance() # Try to add it as the last layer in the list # False flag prevents layer being added to legend project.addMapLayer(layer, False) root = QgsProject.instance().layerTreeRoot() index = len(root.findLayers()) + 1 # LOGGER.info('Inserting layer %s at position %s' % ( # layer.source(), index)) root.insertLayer(index, layer) project.addMapLayer(layer) def show_definitions(self): """Show InaSAFE Definitions (a report showing all key metadata).""" from safe.utilities.help import show_help from safe.gui.tools.help import definitions_help show_help(definitions_help.definitions_help()) def show_field_mapping(self): """Show InaSAFE Field Mapping.""" from safe.gui.tools.field_mapping_dialog import FieldMappingDialog dialog = FieldMappingDialog( parent=self.iface.mainWindow(), iface=self.iface, ) if dialog.exec_(): # modal LOGGER.debug('Show field mapping accepted') self.dock_widget.layer_changed(self.iface.activeLayer()) else: LOGGER.debug('Show field mapping not accepted') def show_metadata_converter(self): """Show InaSAFE Metadata Converter.""" from safe.gui.tools.metadata_converter_dialog import ( MetadataConverterDialog) dialog = MetadataConverterDialog( parent=self.iface.mainWindow(), iface=self.iface, ) dialog.exec_() def show_multi_exposure(self): """Show InaSAFE Multi Exposure.""" from safe.gui.tools.multi_exposure_dialog import MultiExposureDialog dialog = MultiExposureDialog(self.iface.mainWindow(), self.iface) dialog.exec_() # modal def add_petabencana_layer(self): """Add petabencana layer to the map. This uses the PetaBencana API to fetch the latest floods in JK. See https://data.petabencana.id/floods """ from safe.gui.tools.peta_bencana_dialog import PetaBencanaDialog dialog = PetaBencanaDialog(self.iface.mainWindow(), self.iface) dialog.show() # non modal def show_batch_runner(self): """Show the batch runner dialog.""" from safe.gui.tools.batch.batch_dialog import BatchDialog dialog = BatchDialog(parent=self.iface.mainWindow(), iface=self.iface, dock=self.dock_widget) dialog.exec_() # modal def save_scenario(self): """Save current scenario to text file.""" from safe.gui.tools.save_scenario import SaveScenarioDialog dialog = SaveScenarioDialog(iface=self.iface, dock=self.dock_widget) dialog.save_scenario() def layer_changed(self, layer): """Enable or disable keywords editor icon when active layer changes. :param layer: The layer that is now active. :type layer: QgsMapLayer """ if not layer: enable_keyword_wizard = False elif not hasattr(layer, 'providerType'): enable_keyword_wizard = False elif layer.providerType() == 'wms': enable_keyword_wizard = False else: enable_keyword_wizard = True try: if layer: if is_raster_layer(layer): enable_field_mapping_tool = False else: keywords = KeywordIO().read_keywords(layer) keywords_version = keywords.get('keyword_version') if not keywords_version: supported = False else: supported = ( is_keyword_version_supported(keywords_version)) if not supported: enable_field_mapping_tool = False else: layer_purpose = keywords.get('layer_purpose') if not layer_purpose: enable_field_mapping_tool = False else: if layer_purpose == layer_purpose_exposure['key']: layer_subcategory = keywords.get('exposure') elif layer_purpose == layer_purpose_hazard['key']: layer_subcategory = keywords.get('hazard') else: layer_subcategory = None field_groups = get_field_groups( layer_purpose, layer_subcategory) if len(field_groups) == 0: # No field group, disable field mapping tool. enable_field_mapping_tool = False else: enable_field_mapping_tool = True else: enable_field_mapping_tool = False except (KeywordNotFoundError, NoKeywordsFoundError, MetadataReadError): # No keywords, disable field mapping tool. enable_field_mapping_tool = False self.action_keywords_wizard.setEnabled(enable_keyword_wizard) self.action_field_mapping.setEnabled(enable_field_mapping_tool) def shortcut_f7(self): """Executed when user press F7 - will show the shakemap importer.""" self.show_shakemap_importer()
class QmsSearchResultItemWidget(QWidget): def __init__(self, geoservice, image_ba, parent=None, extent_renderer=None): QWidget.__init__(self, parent) self.extent_renderer = extent_renderer self.layout = QHBoxLayout(self) self.layout.setContentsMargins(5, 10, 5, 10) self.setLayout(self.layout) self.service_icon = QLabel(self) self.service_icon.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.service_icon.resize(24, 24) qimg = QImage.fromData(image_ba) pixmap = QPixmap.fromImage(qimg) self.service_icon.setPixmap(pixmap) self.layout.addWidget(self.service_icon) self.service_desc_layout = QGridLayout(self) self.service_desc_layout.setSpacing(0) self.layout.addLayout(self.service_desc_layout) self.service_name = QLabel(self) self.service_name.setTextFormat(Qt.RichText) self.service_name.setWordWrap(True) self.service_name.setText(u" <strong> {} </strong>".format(geoservice.get('name', u""))) self.service_desc_layout.addWidget(self.service_name, 0, 0, 1, 3) self.service_type = QLabel(self) self.service_type.setTextFormat(Qt.RichText) self.service_type.setWordWrap(True) self.service_type.setText(geoservice.get('type', u"").upper() + " ") self.service_desc_layout.addWidget(self.service_type, 1, 0) self.service_deteils = QLabel(self) self.service_deteils.setTextFormat(Qt.RichText) self.service_deteils.setWordWrap(True) self.service_deteils.setOpenExternalLinks(True) self.service_deteils.setText(u"<a href=\"{0}\">{1}</a>, ".format( Client().geoservice_info_url(geoservice.get('id', u"")), self.tr('details') )) self.service_desc_layout.addWidget(self.service_deteils, 1, 1) self.service_report = QLabel(self) self.service_report.setTextFormat(Qt.RichText) self.service_report.setWordWrap(True) self.service_report.setOpenExternalLinks(True) self.service_report.setText(u"<a href=\"{0}\">{1}</a><div/>".format( Client().geoservice_report_url(geoservice.get('id', u"")), self.tr('report a problem') )) self.service_desc_layout.addWidget(self.service_report, 1, 2) self.service_desc_layout.setColumnStretch(2, 1) self.status_label = QLabel(self) self.status_label.setTextFormat(Qt.RichText) self.status_label.setText(u'\u2022') status = geoservice.get('cumulative_status', u'') if status == 'works': self.status_label.setStyleSheet("color: green; font-size: 30px") if status == 'failed': self.status_label.setStyleSheet("color: red; font-size: 30px") if status == 'problematic': self.status_label.setStyleSheet("color: yellow; font-size: 30px") self.layout.addWidget(self.status_label) self.addButton = QToolButton() self.addButton.setText(self.tr("Add")) self.addButton.clicked.connect(self.addToMap) self.layout.addWidget(self.addButton) self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum) self.geoservice = geoservice self.image_ba = image_ba def addToMap(self): try: QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) client = Client() client.set_proxy(*QGISSettings.get_qgis_proxy()) geoservice_info = client.get_geoservice_info(self.geoservice) ds = DataSourceSerializer.read_from_json(geoservice_info) add_layer_to_map(ds) CachedServices().add_service(self.geoservice, self.image_ba) except Exception as ex: plPrint(unicode(ex)) pass finally: QApplication.restoreOverrideCursor() def mouseDoubleClickEvent(self, event): self.addToMap() def enterEvent(self, event): extent = self.geoservice.get('extent', None) if self.extent_renderer and extent: if ';' in extent: extent = extent.split(';')[1] geom = QgsGeometry.fromWkt(extent) self.extent_renderer.show_feature(geom) def leaveEvent(self, event): if self.extent_renderer: self.extent_renderer.clear_feature()
class PositionDisplay(QWidget): ''' Widget to display the mouse position on the canvas in geographic coordinates (lat/lon) The display format can be altered. ''' __FORMATS = ('DD', 'DDM', 'DMDS') exportPosition = pyqtSignal(str) def __init__(self, iface, parent=None): '''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(PositionDisplay, self).__init__(parent) self.setObjectName('positionDisplay') layout = QHBoxLayout() layout.setContentsMargins(0, 0, 3, 0) self.button = QToolButton(self) self.button.setObjectName('toolButtonFormat') self.button.clicked.connect(self.switchCoordinateFormat) self.button.setAutoRaise(True) layout.addWidget(self.button) self.label = QLineEdit('--- ---') self.label.setReadOnly(True) self.label.setAlignment(Qt.AlignHCenter) self.label.setStyleSheet('font-weight: bold;') layout.addWidget(self.label) self.setLayout(layout) s = QSettings() self.format = s.value('PosiView/PositionDisplay/Format', defaultValue=1, type=int) self.button.setText(self.__FORMATS[self.format]) canvas = iface.mapCanvas() crsDest = QgsCoordinateReferenceSystem('EPSG:4326') crsSrc = canvas.mapSettings().destinationCrs() self.xform = QgsCoordinateTransform(crsSrc, crsDest, QgsProject.instance()) canvas.xyCoordinates.connect(self.mouseMoved) canvas.destinationCrsChanged.connect(self.mapCrsHasChanged) self.canvas = canvas try: self.sep = cf.separator() + ' ' except AttributeError: self.sep = ', ' @pyqtSlot(name='on_toolButtonFormat_clicked') def switchCoordinateFormat(self): self.format = (self.format + 1) % 3 self.button.setText(self.tr(self.__FORMATS[self.format])) s = QSettings() s.setValue('PosiView/PositionDisplay/Format', self.format) @pyqtSlot() def mapCrsHasChanged(self): crsSrc = self.canvas.mapSettings().destinationCrs() self.xform.setSourceCrs(crsSrc) @pyqtSlot(QgsPointXY) def mouseMoved(self, point): pt = self.xform.transform(point) pos = self.posToStr(pt) self.label.setText(pos) self.exportPosition.emit(pos) def posToStr(self, pos): flg = cf.FlagDegreesUseStringSuffix if self.format == 1: f, pr = cf.FormatDegreesMinutes, 4 elif self.format == 2: f, pr = cf.FormatDegreesMinutesSeconds, 2 else: f, pr, flg = cf.FormatDecimalDegrees, 6, cf.FormatFlag(0) return self.sep.join( (cf.formatY(pos.y(), f, pr, flg), cf.formatX(pos.x(), f, pr, flg)))
def initWidgets(self): # If there are advanced parameters — show corresponding groupbox for param in self.alg.parameters: if param.isAdvanced: self.grpAdvanced.show() break # Create widgets and put them in layouts for param in self.alg.parameters: if param.hidden: continue desc = param.description if isinstance(param, ParameterExtent): desc += self.tr(' (xmin, xmax, ymin, ymax)') if isinstance(param, ParameterPoint): desc += self.tr(' (x, y)') if param.optional: desc += self.tr(' [optional]') wrapper = self.getWidgetWrapperFromParameter(param) self.wrappers[param.name] = wrapper widget = wrapper.widget if widget is not None: if isinstance(param, ParameterVector): layout = QHBoxLayout() layout.setSpacing(2) layout.setMargin(0) layout.addWidget(widget) button = QToolButton() icon = QIcon( os.path.join(pluginPath, 'images', 'iterate.png')) button.setIcon(icon) button.setToolTip(self.tr('Iterate over this layer')) button.setCheckable(True) layout.addWidget(button) self.iterateButtons[param.name] = button button.toggled.connect(self.buttonToggled) widget = QWidget() widget.setLayout(layout) tooltips = self.alg.getParameterDescriptions() widget.setToolTip(tooltips.get(param.name, param.description)) if type(widget) is QCheckBox: # checkbox widget - so description is embedded in widget rather than a separate # label widget.setText(desc) else: label = QLabel(desc) # label.setToolTip(tooltip) self.labels[param.name] = label if param.isAdvanced: self.layoutAdvanced.addWidget(label) else: self.layoutMain.insertWidget( self.layoutMain.count() - 2, label) if param.isAdvanced: self.layoutAdvanced.addWidget(widget) else: self.layoutMain.insertWidget(self.layoutMain.count() - 2, widget) for output in self.alg.outputs: if output.hidden: continue label = QLabel(output.description) widget = OutputSelectionPanel(output, self.alg) self.layoutMain.insertWidget(self.layoutMain.count() - 1, label) self.layoutMain.insertWidget(self.layoutMain.count() - 1, widget) if isinstance(output, (OutputRaster, OutputVector, OutputTable)): check = QCheckBox() check.setText( self.tr('Open output file after running algorithm')) check.setChecked(True) self.layoutMain.insertWidget(self.layoutMain.count() - 1, check) self.checkBoxes[output.name] = check self.outputWidgets[output.name] = widget for wrapper in list(self.wrappers.values()): wrapper.postInitialize(list(self.wrappers.values()))
def createWidget(self): if self.dialogType == DIALOG_STANDARD: widget = QWidget() layout = QHBoxLayout() layout.setMargin(0) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(2) self.combo = QgsMapLayerComboBox() layout.addWidget(self.combo) btn = QToolButton() btn.setText('...') btn.setToolTip(self.tr("Select file")) btn.clicked.connect(self.selectFile) layout.addWidget(btn) widget.setLayout(layout) if self.param.optional: self.combo.setAllowEmptyLayer(True) self.combo.setFilters(QgsMapLayerProxyModel.VectorLayer) self.combo.setExcludedProviders(['grass']) try: if iface.activeLayer().type() == QgsMapLayer.VectorLayer: self.combo.setLayer(iface.activeLayer()) except: pass self.combo.currentIndexChanged.connect( lambda: self.widgetValueHasChanged.emit(self)) self.combo.currentTextChanged.connect( lambda: self.widgetValueHasChanged.emit(self)) return widget elif self.dialogType == DIALOG_BATCH: return BatchInputSelectionPanel(self.param, self.row, self.col, self.dialog) else: self.combo = QComboBox() layers = self.dialog.getAvailableValuesOfType( ParameterRaster, OutputRaster) self.combo.setEditable(True) tables = self.dialog.getAvailableValuesOfType( ParameterTable, OutputTable) layers = self.dialog.getAvailableValuesOfType( ParameterVector, OutputVector) if self.param.optional: self.combo.addItem(self.NOT_SELECTED, None) for table in tables: self.combo.addItem(self.dialog.resolveValueDescription(table), table) for layer in layers: self.combo.addItem(self.dialog.resolveValueDescription(layer), layer) widget = QWidget() layout = QHBoxLayout() layout.setMargin(0) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(2) layout.addWidget(self.combo) btn = QToolButton() btn.setText('...') btn.setToolTip(self.tr("Select file")) btn.clicked.connect(self.selectFile) layout.addWidget(btn) widget.setLayout(layout) return widget
def initWidgets(self): #tooltips = self.alg.getParameterDescriptions() # If there are advanced parameters — show corresponding groupbox for param in self.alg.parameters: if param.isAdvanced: self.grpAdvanced.show() break # Create widgets and put them in layouts for param in self.alg.parameters: if param.hidden: continue desc = param.description if isinstance(param, ParameterExtent): desc += self.tr(' (xmin, xmax, ymin, ymax)') if isinstance(param, ParameterPoint): desc += self.tr(' (x, y)') try: if param.optional: desc += self.tr(' [optional]') except: pass widget = self.getWidgetFromParameter(param) self.valueItems[param.name] = widget if isinstance(param, ParameterVector) and \ not self.alg.allowOnlyOpenedLayers: layout = QHBoxLayout() layout.setSpacing(2) layout.setMargin(0) layout.addWidget(widget) button = QToolButton() icon = QIcon(os.path.join(pluginPath, 'images', 'iterate.png')) button.setIcon(icon) button.setToolTip(self.tr('Iterate over this layer')) button.setCheckable(True) layout.addWidget(button) self.iterateButtons[param.name] = button button.toggled.connect(self.buttonToggled) widget = QWidget() widget.setLayout(layout) #~ if param.name in tooltips.keys(): #~ tooltip = tooltips[param.name] #~ else: #~ tooltip = param.description #~ widget.setToolTip(tooltip) if isinstance(param, ParameterBoolean): widget.setText(desc) if param.isAdvanced: self.layoutAdvanced.addWidget(widget) else: self.layoutMain.insertWidget(self.layoutMain.count() - 2, widget) else: label = QLabel(desc) #label.setToolTip(tooltip) self.labels[param.name] = label if param.isAdvanced: self.layoutAdvanced.addWidget(label) self.layoutAdvanced.addWidget(widget) else: self.layoutMain.insertWidget(self.layoutMain.count() - 2, label) self.layoutMain.insertWidget(self.layoutMain.count() - 2, widget) self.widgets[param.name] = widget for output in self.alg.outputs: if output.hidden: continue label = QLabel(output.description) widget = OutputSelectionPanel(output, self.alg) self.layoutMain.insertWidget(self.layoutMain.count() - 1, label) self.layoutMain.insertWidget(self.layoutMain.count() - 1, widget) if isinstance(output, (OutputRaster, OutputVector, OutputTable)): check = QCheckBox() check.setText( self.tr('Open output file after running algorithm')) check.setChecked(True) self.layoutMain.insertWidget(self.layoutMain.count() - 1, check) self.checkBoxes[output.name] = check self.valueItems[output.name] = widget
def initWidgets(self): # If there are advanced parameters — show corresponding groupbox for param in self.alg.parameterDefinitions(): if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced: self.grpAdvanced.show() break widget_context = QgsProcessingParameterWidgetContext() if iface is not None: widget_context.setMapCanvas(iface.mapCanvas()) # Create widgets and put them in layouts for param in self.alg.parameterDefinitions(): if param.flags() & QgsProcessingParameterDefinition.FlagHidden: continue if param.isDestination(): continue else: wrapper = WidgetWrapperFactory.create_wrapper(param, self.parent) self.wrappers[param.name()] = wrapper # For compatibility with 3.x API, we need to check whether the wrapper is # the deprecated WidgetWrapper class. If not, it's the newer # QgsAbstractProcessingParameterWidgetWrapper class # TODO QGIS 4.0 - remove is_python_wrapper = issubclass(wrapper.__class__, WidgetWrapper) if not is_python_wrapper: wrapper.setWidgetContext(widget_context) widget = wrapper.createWrappedWidget(self.processing_context) wrapper.registerProcessingContextGenerator(self.context_generator) else: widget = wrapper.widget if self.in_place and param.name() in ('INPUT', 'OUTPUT'): # don't show the input/output parameter widgets in in-place mode # we still need to CREATE them, because other wrappers may need to interact # with them (e.g. those parameters which need the input layer for field # selections/crs properties/etc) continue if widget is not None: if is_python_wrapper: widget.setToolTip(param.toolTip()) if isinstance(param, QgsProcessingParameterFeatureSource): layout = QHBoxLayout() layout.setSpacing(6) layout.setMargin(0) layout.addWidget(widget) button = QToolButton() icon = QIcon(os.path.join(pluginPath, 'images', 'iterate.png')) button.setIcon(icon) button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) button.setToolTip(self.tr('Iterate over this layer, creating a separate output for every feature in the layer')) button.setCheckable(True) layout.addWidget(button) layout.setAlignment(button, Qt.AlignTop) self.iterateButtons[param.name()] = button button.toggled.connect(self.buttonToggled) widget = QWidget() widget.setLayout(layout) label = None if not is_python_wrapper: label = wrapper.createWrappedLabel() else: label = wrapper.label if label is not None: if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced: self.layoutAdvanced.addWidget(label) else: self.layoutMain.insertWidget( self.layoutMain.count() - 2, label) elif is_python_wrapper: desc = param.description() if isinstance(param, QgsProcessingParameterExtent): desc += self.tr(' (xmin, xmax, ymin, ymax)') if isinstance(param, QgsProcessingParameterPoint): desc += self.tr(' (x, y)') if param.flags() & QgsProcessingParameterDefinition.FlagOptional: desc += self.tr(' [optional]') widget.setText(desc) if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced: self.layoutAdvanced.addWidget(widget) else: self.layoutMain.insertWidget( self.layoutMain.count() - 2, widget) for output in self.alg.destinationParameterDefinitions(): if output.flags() & QgsProcessingParameterDefinition.FlagHidden: continue if self.in_place and param.name() in ('INPUT', 'OUTPUT'): continue label = QLabel(output.description()) widget = DestinationSelectionPanel(output, self.alg) self.layoutMain.insertWidget(self.layoutMain.count() - 1, label) self.layoutMain.insertWidget(self.layoutMain.count() - 1, widget) if isinstance(output, (QgsProcessingParameterRasterDestination, QgsProcessingParameterFeatureSink, QgsProcessingParameterVectorDestination)): check = QCheckBox() check.setText(QCoreApplication.translate('ParametersPanel', 'Open output file after running algorithm')) def skipOutputChanged(checkbox, skipped): checkbox.setEnabled(not skipped) if skipped: checkbox.setChecked(False) check.setChecked(not widget.outputIsSkipped()) check.setEnabled(not widget.outputIsSkipped()) widget.skipOutputChanged.connect(partial(skipOutputChanged, check)) self.layoutMain.insertWidget(self.layoutMain.count() - 1, check) self.checkBoxes[output.name()] = check widget.setToolTip(param.toolTip()) self.outputWidgets[output.name()] = widget for wrapper in list(self.wrappers.values()): wrapper.postInitialize(list(self.wrappers.values()))
def initWidgets(self): # If there are advanced parameters — show corresponding groupbox for param in self.alg.parameters: if param.isAdvanced: self.grpAdvanced.show() break # Create widgets and put them in layouts for param in self.alg.parameters: if param.hidden: continue desc = param.description if isinstance(param, ParameterExtent): desc += self.tr(' (xmin, xmax, ymin, ymax)') if isinstance(param, ParameterPoint): desc += self.tr(' (x, y)') try: if param.optional: desc += self.tr(' [optional]') except: pass widget = self.getWidgetFromParameter(param) self.valueItems[param.name] = widget if isinstance(param, ParameterVector) and \ not self.alg.allowOnlyOpenedLayers: layout = QHBoxLayout() layout.setSpacing(2) layout.setMargin(0) layout.addWidget(widget) button = QToolButton() icon = QIcon(os.path.join(pluginPath, 'images', 'iterate.png')) button.setIcon(icon) button.setToolTip(self.tr('Iterate over this layer')) button.setCheckable(True) layout.addWidget(button) self.iterateButtons[param.name] = button button.toggled.connect(self.buttonToggled) widget = QWidget() widget.setLayout(layout) tooltips = self.alg.getParameterDescriptions() widget.setToolTip(tooltips.get(param.name, param.description)) if isinstance(param, ParameterBoolean): widget.setText(desc) if param.isAdvanced: self.layoutAdvanced.addWidget(widget) else: self.layoutMain.insertWidget( self.layoutMain.count() - 2, widget) else: label = QLabel(desc) #label.setToolTip(tooltip) self.labels[param.name] = label if param.isAdvanced: self.layoutAdvanced.addWidget(label) self.layoutAdvanced.addWidget(widget) else: self.layoutMain.insertWidget( self.layoutMain.count() - 2, label) self.layoutMain.insertWidget( self.layoutMain.count() - 2, widget) self.widgets[param.name] = widget for output in self.alg.outputs: if output.hidden: continue label = QLabel(output.description) widget = OutputSelectionPanel(output, self.alg) self.layoutMain.insertWidget(self.layoutMain.count() - 1, label) self.layoutMain.insertWidget(self.layoutMain.count() - 1, widget) if isinstance(output, (OutputRaster, OutputVector, OutputTable)): check = QCheckBox() check.setText(self.tr('Open output file after running algorithm')) check.setChecked(True) self.layoutMain.insertWidget(self.layoutMain.count() - 1, check) self.checkBoxes[output.name] = check self.valueItems[output.name] = widget if isinstance(output, OutputVector): if output.base_input in self.dependentItems: items = self.dependentItems[output.base_input] else: items = [] self.dependentItems[output.base_input] = items items.append(output) base_input = self.alg.getParameterFromName(output.base_input) if isinstance(base_input, ParameterVector): layers = dataobjects.getVectorLayers(base_input.shapetype) else: layers = dataobjects.getTables() if len(layers) > 0: output.base_layer = layers[0]
def createWidget(self): if self.dialogType == DIALOG_STANDARD: widget = QWidget() layout = QHBoxLayout() layout.setMargin(0) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(2) self.combo = QgsMapLayerComboBox() layout.addWidget(self.combo) btn = QToolButton() btn.setText('...') btn.setToolTip(self.tr("Select file")) btn.clicked.connect(self.selectFile) layout.addWidget(btn) widget.setLayout(layout) filters = QgsMapLayerProxyModel.Filters() if self.param.datatype == [-1] or -1 in self.param.datatype: filters = QgsMapLayerProxyModel.HasGeometry if QgsWkbTypes.PointGeometry in self.param.datatype: filters |= QgsMapLayerProxyModel.PointLayer if QgsWkbTypes.LineGeometry in self.param.datatype: filters |= QgsMapLayerProxyModel.LineLayer if QgsWkbTypes.PolygonGeometry in self.param.datatype: filters |= QgsMapLayerProxyModel.PolygonLayer if self.param.optional: self.combo.setAllowEmptyLayer(True) if ProcessingConfig.getSetting(ProcessingConfig.SHOW_CRS_DEF): self.combo.setShowCrs(True) self.combo.setFilters(filters) self.combo.setExcludedProviders(['grass']) self.combo.currentIndexChanged.connect(lambda: self.widgetValueHasChanged.emit(self)) self.combo.currentTextChanged.connect(lambda: self.widgetValueHasChanged.emit(self)) return widget elif self.dialogType == DIALOG_BATCH: widget = BatchInputSelectionPanel(self.param, self.row, self.col, self.dialog) widget.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self)) return widget else: self.combo = QComboBox() layers = self.dialog.getAvailableValuesOfType(ParameterVector, OutputVector) self.combo.setEditable(True) for layer in layers: self.combo.addItem(self.dialog.resolveValueDescription(layer), layer) if self.param.optional: self.combo.setEditText("") widget = QWidget() layout = QHBoxLayout() layout.setMargin(0) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(2) layout.addWidget(self.combo) btn = QToolButton() btn.setText('...') btn.setToolTip(self.tr("Select file")) btn.clicked.connect(self.selectFile) layout.addWidget(btn) widget.setLayout(layout) return widget
def initWidgets(self): # If there are advanced parameters — show corresponding groupbox for param in self.alg.parameters: if param.isAdvanced: self.grpAdvanced.show() break # Create widgets and put them in layouts for param in self.alg.parameters: if param.hidden: continue desc = param.description if isinstance(param, ParameterExtent): desc += self.tr(' (xmin, xmax, ymin, ymax)') if isinstance(param, ParameterPoint): desc += self.tr(' (x, y)') if param.optional: desc += self.tr(' [optional]') wrapper = self.getWidgetWrapperFromParameter(param) self.wrappers[param.name] = wrapper widget = wrapper.widget if widget is not None: if isinstance(param, ParameterVector): layout = QHBoxLayout() layout.setSpacing(2) layout.setMargin(0) layout.addWidget(widget) button = QToolButton() icon = QIcon(os.path.join(pluginPath, 'images', 'iterate.png')) button.setIcon(icon) button.setToolTip(self.tr('Iterate over this layer')) button.setCheckable(True) layout.addWidget(button) self.iterateButtons[param.name] = button button.toggled.connect(self.buttonToggled) widget = QWidget() widget.setLayout(layout) tooltips = self.alg.getParameterDescriptions() widget.setToolTip(tooltips.get(param.name, param.description)) if type(widget) is QCheckBox: # checkbox widget - so description is embedded in widget rather than a separate # label widget.setText(desc) else: label = QLabel(desc) # label.setToolTip(tooltip) self.labels[param.name] = label if param.isAdvanced: self.layoutAdvanced.addWidget(label) else: self.layoutMain.insertWidget( self.layoutMain.count() - 2, label) if param.isAdvanced: self.layoutAdvanced.addWidget(widget) else: self.layoutMain.insertWidget( self.layoutMain.count() - 2, widget) for output in self.alg.outputs: if output.hidden: continue label = QLabel(output.description) widget = OutputSelectionPanel(output, self.alg) self.layoutMain.insertWidget(self.layoutMain.count() - 1, label) self.layoutMain.insertWidget(self.layoutMain.count() - 1, widget) if isinstance(output, (OutputRaster, OutputVector, OutputTable)): check = QCheckBox() check.setText(self.tr('Open output file after running algorithm')) check.setChecked(True) self.layoutMain.insertWidget(self.layoutMain.count() - 1, check) self.checkBoxes[output.name] = check self.outputWidgets[output.name] = widget for wrapper in list(self.wrappers.values()): wrapper.postInitialize(list(self.wrappers.values()))
class PdokServicesPlugin(object): def __init__(self, iface): # Save reference to the QGIS interface self.iface = iface # docked or dialog, defaults to dialog # 2018 may: RD: deprecating Docked window, as the content is getting to big anyway # if isinstance(QSettings().value("/pdokservicesplugin/docked"), QVariant): # self.docked = QSettings().value("/pdokservicesplugin/docked", QVariant(False)) # else: # self.docked = QSettings().value("/pdokservicesplugin/docked", False) # # # Create the dialog and keep reference # if "True" == self.docked or "true" == self.docked or True is self.docked: # self.dlg = PdokServicesPluginDockWidget() # self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.dlg) # else: # self.dlg = PdokServicesPluginDialog(parent=self.iface.mainWindow()) self.dlg = PdokServicesPluginDialog(parent=self.iface.mainWindow()) # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) self.currentLayer = None self.SETTINGS_SECTION = '/pdokservicesplugin/' self.pointer = None self.pdokgeocoder = PDOKGeoLocator(self.iface) self.geocoderSourceModel = None def getSettingsValue(self, key, default=''): if QSettings().contains(self.SETTINGS_SECTION + key): key = self.SETTINGS_SECTION + key if Qgis.QGIS_VERSION_INT < 10900: # qgis <= 1.8 return str(QSettings().value(key).toString()) else: return str(QSettings().value(key)) else: return default def setSettingsValue(self, key, value): key = self.SETTINGS_SECTION + key if Qgis.QGIS_VERSION_INT < 10900: # qgis <= 1.8 QSettings().setValue(key, QVariant(value)) else: QSettings().setValue(key, value) def initGui(self): # Create action that will start plugin configuration self.runIcon = QIcon( os.path.join(self.plugin_dir, 'icon_add_service.svg')) self.run_action = QAction(self.runIcon, "PDOK Services plugin", self.iface.mainWindow()) self.run_button = QToolButton() self.run_button.setMenu(QMenu()) self.run_button.setPopupMode(QToolButton.MenuButtonPopup) self.run_button.setDefaultAction(self.run_action) self.servicesLoaded = False # connect the action to the run method self.run_action.triggered.connect(self.run) self.setupfq() # Add toolbar button and menu item #self.iface.addToolBarIcon(self.action) self.toolbar = self.iface.addToolBar("PDOK services plugin") self.toolbar.setObjectName("PDOK services plugin") #self.toolbar.addAction(self.run_action) self.toolbar.addWidget(self.run_button) #self.run_button.menu().addSection('Favorieten') self.favourite_1_action = QAction('Favoriet 1', self.iface.mainWindow()) self.favourite_1_action.setIcon(self.runIcon) self.favourite_1_action.triggered.connect( lambda: self.load_favourite(1)) self.set_favourite_action(self.favourite_1_action, 1) self.run_button.menu().addAction(self.favourite_1_action) self.favourite_2_action = QAction('Favoriet 2', self.iface.mainWindow()) self.favourite_2_action.setIcon(self.runIcon) self.favourite_2_action.triggered.connect( lambda: self.load_favourite(2)) self.set_favourite_action(self.favourite_2_action, 2) self.run_button.menu().addAction(self.favourite_2_action) # TODO :-) #self.run_button.menu().addSection('Meest Recent') #self.run_button.menu().addSeparator() self.toolbarSearch = QLineEdit() self.toolbarSearch.setMaximumWidth(200) self.toolbarSearch.setAlignment(Qt.AlignLeft) self.toolbarSearch.setPlaceholderText("PDOK Locatieserver zoek") self.toolbar.addWidget(self.toolbarSearch) self.toolbarSearch.returnPressed.connect(self.searchAddressFromToolbar) # address/point cleanup eraserIcon = QIcon( os.path.join(self.plugin_dir, 'icon_remove_cross.svg')) self.clean_action = QAction(eraserIcon, "Cleanup", self.eraseAddress()) self.toolbar.addAction(self.clean_action) self.clean_action.triggered.connect(self.eraseAddress) self.clean_action.setEnabled(False) self.iface.addPluginToMenu(u"&Pdok Services Plugin", self.run_action) # about self.aboutAction = QAction(QIcon(":/plugins/pdokservicesplugin/icon_help.png"), \ "About", self.iface.mainWindow()) self.aboutAction.setWhatsThis("Pdok Services Plugin About") self.iface.addPluginToMenu(u"&Pdok Services Plugin", self.aboutAction) self.aboutAction.triggered.connect(self.about) self.dlg.ui.btnLoadLayer.clicked.connect(self.loadService) self.dlg.geocoderSearch.returnPressed.connect(self.searchAddress) self.dlg.geocoderSearch.textEdited.connect(self.searchAddress) self.dlg.geocoderSearch.setPlaceholderText( "PDOK Locatieserver zoek, bv postcode of postcode huisnummer") self.dlg.geocoderResultSearch.textChanged.connect( self.filterGeocoderResult) self.dlg.geocoderResultSearch.setPlaceholderText( "een of meer zoekwoorden uit resultaat") #self.iface.mapCanvas().renderStarting.connect(self.extentsChanged) ui = self.dlg.ui cbxs = [ ui.cbx_gem, ui.cbx_wpl, ui.cbx_weg, ui.cbx_pcd, ui.cbx_adr, ui.cbx_pcl, ui.cbx_hmp ] # connect all fq checkboxes with suggest, so upon a change in fq filter we re-search for cbx in cbxs: cbx.stateChanged.connect(self.searchAddress) self.run(True) # for now hiding the pointer as soon as the extent changes #def extentsChanged(self): # self.removePointer() # 2021-02 hiding the check JSON: to much hassle def checkPdokJson(self): myversion = self.getSettingsValue('pdokversion', '1') msgtxt = '' msglvl = 0 # QgsMessageBar.INFO try: response = urllib.request.urlopen( 'http://www.qgis.nl/pdok.version') str_response = response.read().decode('utf-8') pdokversion = json.loads(str_response) if pdokversion > int(myversion): response = urllib.request.urlopen( 'http://www.qgis.nl/pdok.json') str_response = response.read().decode('utf-8') pdokjson = json.loads(str_response) with open(os.path.join(self.plugin_dir, 'pdok.json'), 'w') as outfile: json.dump(pdokjson, outfile) msgtxt = "De laatste versie is opgehaald en zal worden gebruikt " + \ str(pdokversion) + ' (was ' + myversion +')' self.servicesLoaded = False # reset reading of json self.run() self.setSettingsValue('pdokversion', pdokversion) else: msgtxt = "Geen nieuwere versie beschikbaar dan " + str( pdokversion) except Exception as e: #print e msgtxt = "Fout bij ophalen van service info. Netwerk probleem?" msglvl = 2 # QgsMessageBar.CRITICAL # msg if hasattr(self.iface, 'messageBar'): self.iface.messageBar().pushMessage("PDOK services update", msgtxt, level=msglvl, duration=10) else: # 1.8 QMessageBox.information(self.iface.mainWindow(), "Pdok Services Plugin", msgtxt) def showAndRaise(self): self.dlg.show() self.dlg.raise_() # also remove the pointer self.removePointer() def about(self): infoString = "Written by Richard Duivenvoorde\nEmail - [email protected]\n" infoString += "Company - Zuidt - http://www.zuidt.nl\n" infoString += "Source: https://github.com/rduivenvoorde/pdokservicesplugin" QMessageBox.information(self.iface.mainWindow(), "Pdok Services Plugin About", infoString) def unload(self): self.removePointer() # Remove the plugin menu item and icon self.iface.removePluginMenu("&Pdok Services Plugin", self.run_action) self.iface.removePluginMenu("&Pdok Services Plugin", self.aboutAction) del self.toolbarSearch del self.run_action del self.aboutAction def showService(self, selectedIndexes): if len(selectedIndexes) == 0: self.currentLayer = None self.dlg.ui.layerInfo.setHtml('') self.dlg.ui.comboSelectProj.clear() return # needed to scroll To the selected row incase of using the keyboard / arrows self.dlg.servicesView.scrollTo( self.dlg.servicesView.selectedIndexes()[0]) # itemType holds the data (== column 1) self.currentLayer = self.dlg.servicesView.selectedIndexes()[1].data( Qt.UserRole) if isinstance(self.currentLayer, QVariant): self.currentLayer = self.currentLayer.toMap() # QGIS 1.8: QVariants currentLayer = {} for key in list(self.currentLayer.keys()): val = self.currentLayer[key] currentLayer[str(key)] = str(val.toString()) self.currentLayer = currentLayer url = self.currentLayer['url'] title = self.currentLayer['title'] style = '' if 'style' in self.currentLayer: style = self.currentLayer['style'] title += f' [{style}]' servicetitle = self.currentLayer['servicetitle'] layername = self.currentLayer['layers'] abstract = self.currentLayer['abstract'] stype = self.currentLayer['type'].upper() minscale = '' if 'minscale' in self.currentLayer and self.currentLayer[ 'minscale'] != None and self.currentLayer['minscale'] != '': minscale = "min. schaal 1:" + self.currentLayer['minscale'] maxscale = '' if 'maxscale' in self.currentLayer and self.currentLayer[ 'maxscale'] != None and self.currentLayer['maxscale'] != '': maxscale = "max. schaal 1:" + self.currentLayer['maxscale'] self.dlg.ui.layerInfo.setText('') self.dlg.ui.btnLoadLayer.setEnabled(True) self.dlg.ui.layerInfo.setHtml( '<h4>%s</h4><h3>%s</h3><lu><li>%s</li><li> </li><li>%s</li><li>%s</li><li>%s</li><li>%s</li><li>%s</li><li>%s</li></lu>' % (servicetitle, title, abstract, stype, url, layername, style, minscale, maxscale)) self.dlg.ui.comboSelectProj.clear() if stype == "WMS": try: crs = self.currentLayer['crs'] except KeyError: crs = 'EPSG:28992' crs = crs.split(',') self.dlg.ui.comboSelectProj.addItems(crs) for i in range(len(crs)): if crs[i] == 'EPSG:28992': self.dlg.ui.comboSelectProj.setCurrentIndex(i) if stype == "WMTS": tilematrixsets = self.currentLayer['tilematrixsets'].split(',') self.dlg.ui.comboSelectProj.addItems(tilematrixsets) for i in range(len(tilematrixsets)): if tilematrixsets[i].startswith('EPSG:28992'): self.dlg.ui.comboSelectProj.setCurrentIndex(i) def set_favourite_action(self, action, favourite_number): if QSettings().contains( f'/pdokservicesplugin/favourite_{favourite_number}'): layer = QSettings().value( f'/pdokservicesplugin/favourite_{favourite_number}', None) if layer: action.setToolTip(layer['title'].capitalize()) title = layer['title'].capitalize() if 'style' in layer: style = layer['style'] title += f' [{style}]' if 'type' in layer: stype = layer['type'].upper() title += f' ({stype})' action.setText(title) action.setIcon(self.runIcon) def load_favourite(self, favourite_number): if QSettings().contains( f'/pdokservicesplugin/favourite_{favourite_number}'): layer = QSettings().value( f'/pdokservicesplugin/favourite_{favourite_number}', None) if layer and layer in self.pdok['services']: self.currentLayer = layer self.loadService() return QMessageBox.warning(self.iface.mainWindow(), "Geen Favoriet aanwezig (of verouderd)...", ( \ "Maak een Favoriet aan door in de dialoog met services en lagen\n via het context menu (rechter muisknop) een Favoriet te kiezen..." ), QMessageBox.Ok, QMessageBox.Ok) self.run() def loadService(self): if self.currentLayer == None: return servicetype = self.currentLayer['type'] url = self.currentLayer['url'] # some services have an url with query parameters in it, we have to urlencode those: location, query = urllib.parse.splitquery(url) url = location # RD: 20200820: lijkt of het quoten van de query problemen geeft bij WFS, is/was dit nodig??? #if query != None and query != '': # url +=('?'+urllib.parse.quote_plus(query)) title = self.currentLayer['title'] if 'style' in self.currentLayer: style = self.currentLayer['style'] title += f' [{style}]' else: style = '' # == default for this service layers = self.currentLayer['layers'] # mmm, tricky: we take the first one while we can actually want png/gif or jpeg if servicetype == "wms": imgformat = self.currentLayer['imgformats'].split(',')[0] if self.dlg.ui.comboSelectProj.currentIndex() == -1: crs = 'EPSG:28992' else: crs = self.dlg.ui.comboSelectProj.currentText() if Qgis.QGIS_VERSION_INT < 10900: # qgis <= 1.8 uri = url self.iface.addRasterLayer( uri, # service uri title, # name for layer (as seen in QGIS) "wms", # dataprovider key [layers], # array of layername(s) for provider (id's) ["" ], # array of stylename(s) NOTE: ignoring styles here!!! imgformat, # image format searchstring crs) # crs code searchstring else: # qgis > 1.8 uri = "crs=" + crs + "&layers=" + layers + "&styles=" + style + "&format=" + imgformat + "&url=" + url self.iface.addRasterLayer(uri, title, "wms") elif servicetype == "wmts": if Qgis.QGIS_VERSION_INT < 10900: QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ( "Sorry, dit type layer: '" + servicetype.upper() + "' \nkan niet worden geladen in deze versie van QGIS.\nMisschien kunt u QGIS 2.0 installeren (die kan het WEL)?\nOf is de laag niet ook beschikbaar als wms of wfs?" ), QMessageBox.Ok, QMessageBox.Ok) return if self.dlg.ui.comboSelectProj.currentIndex() == -1: tilematrixset = 'EPSG:28992' else: tilematrixset = self.dlg.ui.comboSelectProj.currentText() imgformat = self.currentLayer['imgformats'].split(',')[0] # special case for luchtfoto #if layers=="luchtfoto": # # tileMatrixSet=nltilingschema&crs=EPSG:28992&layers=luchtfoto&styles=&format=image/jpeg&url=http://geodata1.nationaalgeoregister.nl/luchtfoto/wmts/1.0.0/WMTSCapabilities.xml # # {u'layers': u'luchtfoto', u'imgformats': u'image/jpeg', u'title': u'PDOK-achtergrond luchtfoto', u'url': u'http://geodata1.nationaalgeoregister.nl/luchtfoto/wms', u'abstract': u'', u'tilematrixsets': u'nltilingschema', u'type': u'wmts'} # uri = "tileMatrixSet="+tilematrixsets+"&crs=EPSG:28992&layers="+layers+"&styles=&format="+imgformat+"&url="+url #else: # uri = "tileMatrixSet="+tilematrixsets+"&crs=EPSG:28992&layers="+layers+"&styles=&format="+imgformat+"&url="+url; #uri = "tileMatrixSet="+tilematrixsets+"&crs=EPSG:28992&layers="+layers+"&styles=default&format="+imgformat+"&url="+url; if tilematrixset.startswith('EPSG:'): crs = tilematrixset i = crs.find(':', 5) if i > -1: crs = crs[:i] elif tilematrixset.startswith('OGC:1.0'): crs = 'EPSG:3857' uri = "tileMatrixSet=" + tilematrixset + "&crs=" + crs + "&layers=" + layers + "&styles=default&format=" + imgformat + "&url=" + url #print "############ PDOK URI #################" #print uri self.iface.addRasterLayer(uri, title, "wms") elif servicetype == "wfs": location, query = urllib.parse.splitquery(url) #uri = location+"?SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&TYPENAME="+layers+"&SRSNAME=EPSG:28992" #uri = location + "?SERVICE=WFS&REQUEST=GetFeature&TYPENAME=" + layers + "&SRSNAME=EPSG:28992" # adding a bbox paramater forces QGIS to NOT cache features but retrieve new features all the time # QGIS will update the BBOX to the right value #uri += "&BBOX=-10000,310000,290000,650000" uri = " pagingEnabled='true' restrictToRequestBBOX='1' srsname='EPSG:28992' typename='" + layers + "' url='" + url + "' version='2.0.0' " self.iface.addVectorLayer(uri, title, "WFS") elif servicetype == "wcs": # cache=AlwaysCache&crs=EPSG:28992&format=GeoTIFF&identifier=ahn25m:ahn25m&url=http://geodata.nationaalgeoregister.nl/ahn25m/wcs uri = '' # cache=AlwaysCache # cache=PreferNetwork # cache=AlwaysNetwork # cache=AlwaysNetwork&crs=EPSG:28992&format=GeoTIFF&identifier=ahn25m:ahn25m&url=http://geodata.nationaalgeoregister.nl/ahn25m/wcs #uri = "cache=AlwaysNetwork&crs=EPSG:28992&format=image/tiff&version=1.1.1&identifier="+layers+"&url="+url # working for ahn1 ahn2 and ahn3: GEOTIFF_FLOAT32 format = 'GEOTIFF_FLOAT32' # working for ahn25m is only image/tiff if layers == 'ahn25m': format = 'image/tiff' # we handcrated some wcs layers with 2 different image formats: tiff (RGB) and tiff (float32): if 'imgformats' in self.currentLayer: format = self.currentLayer['imgformats'].split(',')[0] uri = "cache=AlwaysNetwork&crs=EPSG:28992&format=" + format + "&identifier=" + layers + "&url=" + url #uri = "cache=AlwaysNetwork&crs=EPSG:28992&format="+format+"&version=1.1.2&identifier=" + layers + "&url=" + url #uri = "cache=AlwaysNetwork&crs=EPSG:28992&format=image/tiff&version=1.1.2&identifier=" + layers + "&url=" + url self.iface.addRasterLayer(uri, title, "wcs") else: QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ( "Sorry, dit type layer: '" + servicetype.upper() + "' \nkan niet worden geladen door de plugin of door QGIS.\nIs het niet beschikbaar als wms, wmts of wfs?" ), QMessageBox.Ok, QMessageBox.Ok) return def filterGeocoderResult(self, string): #print "filtering geocoder results: %s" % string self.dlg.geocoderResultView.selectRow(0) self.geocoderProxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive) self.geocoderProxyModel.setFilterFixedString(string) def searchAddressFromToolbar(self): self.removePointer() self.geocoderSourceModel.clear() self.geocode() def searchAddress(self): self.removePointer() #print "search geocoder for: %s" % self.dlg.geocoderSearch.text() self.geocoderSourceModel.clear() #self.geocode(self.dlg.geocoderSearch.text()) self.suggest() def eraseAddress(self): """ clean the input and remove the pointer """ self.removePointer() if self.geocoderSourceModel is not None: self.geocoderSourceModel.clear() if self.dlg.geocoderSearch is not None: self.dlg.geocoderSearch.clear() if self.toolbarSearch is not None: self.toolbarSearch.clear() def filterLayers(self, string): # remove selection if one row is selected self.dlg.servicesView.selectRow(0) #self.currentLayer = None self.proxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive) self.proxyModel.setFilterFixedString(string) #def addSourceRow(self, service, layer): def addSourceRow(self, serviceLayer): # you can attache different "data's" to to an QStandarditem # default one is the visible one: itemType = QStandardItem("%s" % (serviceLayer["type"].upper())) # userrole is a free form one: # only attach the data to the first item # service layer = a dict/object with all props of the layer itemType.setData(serviceLayer, Qt.UserRole) itemType.setToolTip( "%s - %s" % (serviceLayer["type"].upper(), serviceLayer["title"])) # only wms services have styles (sometimes) layername = serviceLayer["title"] if 'style' in serviceLayer: itemLayername = QStandardItem( "%s [%s]" % (serviceLayer["title"], serviceLayer["style"])) layername = "%s [%s]" % (serviceLayer["title"], serviceLayer["style"]) else: itemLayername = QStandardItem("%s" % (serviceLayer["title"])) itemLayername.setToolTip( "%s - %s" % (serviceLayer["type"].upper(), serviceLayer["servicetitle"])) # itemFilter is the item used to search filter in. That is why layername is a combi of layername + filter here itemFilter = QStandardItem( "%s %s %s %s" % (serviceLayer["type"], layername, serviceLayer["servicetitle"], serviceLayer["abstract"])) itemServicetitle = QStandardItem("%s" % (serviceLayer["servicetitle"])) itemServicetitle.setToolTip( "%s - %s" % (serviceLayer["type"].upper(), serviceLayer["title"])) self.sourceModel.appendRow( [itemLayername, itemType, itemServicetitle, itemFilter]) # run method that performs all the real work def run(self, hiddenDialog=False): # enable possible remote pycharm debugging #import pydevd #pydevd.settrace('localhost', port=5678, stdoutToServer=True, stderrToServer=True) # last viewed/selected tab if QSettings().contains("/pdokservicesplugin/currenttab"): if Qgis.QGIS_VERSION_INT < 10900: # qgis <= 1.8 self.dlg.tabs.widget(QSettings().value( "/pdokservicesplugin/currenttab").toInt()[0]) else: self.dlg.tabs.widget( int(QSettings().value("/pdokservicesplugin/currenttab"))) if self.servicesLoaded == False: pdokjson = os.path.join(self.plugin_dir, "pdok.json") with open(pdokjson, 'r', encoding='utf-8') as f: self.pdok = json.load(f) print(f'self.pdok type = {type(self.pdok)}') self.proxyModel = QSortFilterProxyModel() self.sourceModel = QStandardItemModel() self.proxyModel.setSourceModel(self.sourceModel) # filter == search on itemFilter column: self.proxyModel.setFilterKeyColumn(3) self.dlg.servicesView.setModel(self.proxyModel) self.dlg.servicesView.setEditTriggers( QAbstractItemView.NoEditTriggers) self.geocoderProxyModel = QSortFilterProxyModel() self.geocoderSourceModel = QStandardItemModel() self.geocoderProxyModel.setSourceModel(self.geocoderSourceModel) self.geocoderProxyModel.setFilterKeyColumn(0) self.dlg.geocoderResultView.setModel(self.geocoderProxyModel) self.dlg.geocoderResultView.setEditTriggers( QAbstractItemView.NoEditTriggers) #{"services":[ # {"naam":"WMS NHI","url":"http://geodata.nationaalgeoregister.nl/nhi/ows","layers":["dmlinks","dmnodes"],"type":"wms"}, # {"naam":"WMS NHI","url":"http://geodata.nationaalgeoregister.nl/nhi/ows","layers":["dmlinks","dmnodes"],"type":"wms"} # ]} # for service in self.pdok["services"]: # service[layer] was an array if isinstance(service["layers"], str): self.addSourceRow(service) self.dlg.layerSearch.textChanged.connect(self.filterLayers) self.dlg.layerSearch.setPlaceholderText( "woord uit laagnaam, type of service ") self.dlg.servicesView.selectionModel().selectionChanged.connect( self.showService) self.dlg.servicesView.doubleClicked.connect(self.loadService) self.dlg.servicesView.setContextMenuPolicy(Qt.CustomContextMenu) self.dlg.servicesView.customContextMenuRequested.connect( self.make_favourite) # actually I want to load a service when doubleclicked on header # but as I cannot get this to work, let's disable clicking it then self.dlg.servicesView.verticalHeader().setSectionsClickable(False) self.dlg.servicesView.horizontalHeader().setSectionsClickable( False) #self.dlg.geocoderResultView.doubleClicked.connect(self.zoomToAddress) self.dlg.geocoderResultView.selectionModel( ).selectionChanged.connect(self.zoomToAddress) # hide itemFilter column: self.dlg.servicesView.hideColumn(3) self.servicesLoaded = True self.sourceModel.setHeaderData(2, Qt.Horizontal, "Service") self.sourceModel.setHeaderData(1, Qt.Horizontal, "Type") self.sourceModel.setHeaderData(0, Qt.Horizontal, "Laagnaam [style]") self.sourceModel.horizontalHeaderItem(2).setTextAlignment(Qt.AlignLeft) self.sourceModel.horizontalHeaderItem(1).setTextAlignment(Qt.AlignLeft) self.sourceModel.horizontalHeaderItem(0).setTextAlignment(Qt.AlignLeft) #self.dlg.servicesView.verticalHeader().hide() #self.dlg.servicesView.resizeColumnsToContents() self.dlg.servicesView.setColumnWidth( 0, 300) # set name to 300px (there are some huge layernames) self.dlg.servicesView.horizontalHeader().setStretchLastSection(True) # show the dialog ? if not hiddenDialog: self.dlg.show() # Run the dialog event loop #result = self.dlg.exec_() if Qgis.QGIS_VERSION_INT < 10900: # qgis <= 1.8 QSettings().setValue("/pdokservicesplugin/currenttab", QVariant(self.dlg.tabs.currentIndex())) else: QSettings().setValue("/pdokservicesplugin/currenttab", self.dlg.tabs.currentIndex()) self.removePointer() def make_favourite(self, position): menu = QMenu() create_fav1_action = menu.addAction("Maak Deze Laag Favoriet 1") create_fav2_action = menu.addAction("Maak Deze Laag Favoriet 2") action = menu.exec_(self.dlg.servicesView.mapToGlobal(position)) if action == create_fav1_action: QSettings().setValue("/pdokservicesplugin/favourite_1", self.currentLayer) self.set_favourite_action(self.favourite_1_action, 1) elif action == create_fav2_action: QSettings().setValue("/pdokservicesplugin/favourite_2", self.currentLayer) self.set_favourite_action(self.favourite_2_action, 2) def setupfq(self): """ Setup the fq checkboxes in the gui, by looking into the settings for the 'pdokservicesplugin/checkedfqs' key, which contains a list of type strings like ['weg','adres'] """ checked_fqs = self.getSettingsValue('checkedfqs', []) #self.info('setup fq: {}'.format(checked_fqs)) if len(checked_fqs ) > 0: # else there is not saved state... take gui defaults self.dlg.ui.cbx_gem.setChecked('gemeente' in checked_fqs) self.dlg.ui.cbx_wpl.setChecked('woonplaats' in checked_fqs) self.dlg.ui.cbx_weg.setChecked('weg' in checked_fqs) self.dlg.ui.cbx_pcd.setChecked('postcode' in checked_fqs) self.dlg.ui.cbx_adr.setChecked('adres' in checked_fqs) self.dlg.ui.cbx_pcl.setChecked('perceel' in checked_fqs) self.dlg.ui.cbx_hmp.setChecked('hectometerpaal' in checked_fqs) def createfq(self): """ This creates a fq-string (Filter Query, see https://github.com/PDOK/locatieserver/wiki/Zoekvoorbeelden-Locatieserver) Based on the checkboxes in the dialog. Defaults to '' Example: 'fq=+type:adres+type:gemeente' (only gemeente AND addresses) :return: """ fqlist = [] if self.dlg.ui.cbx_gem.isChecked(): fqlist.append('gemeente') if self.dlg.ui.cbx_wpl.isChecked(): fqlist.append('woonplaats') if self.dlg.ui.cbx_weg.isChecked(): fqlist.append('weg') if self.dlg.ui.cbx_pcd.isChecked(): fqlist.append('postcode') if self.dlg.ui.cbx_adr.isChecked(): fqlist.append('adres') if self.dlg.ui.cbx_pcl.isChecked(): fqlist.append('perceel') if self.dlg.ui.cbx_hmp.isChecked(): fqlist.append('hectometerpaal') self.setSettingsValue('checkedfqs', fqlist) #self.info(self.getSettingsValue('checkedfqs', ['leeg?'])) fq = '' if len(fqlist) > 0: fq = '&fq=+type:' + '+type:'.join(fqlist) return fq def suggest(self): self.dlg.ui.lookupinfo.setHtml('') search_text = self.dlg.geocoderSearch.text() if len(search_text) <= 1: # QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ( \ # "meer input aub: {}".format(search_text) # ), QMessageBox.Ok, QMessageBox.Ok) return # QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ( \ # "zoeken: {}".format(search_text) # ), QMessageBox.Ok, QMessageBox.Ok) results = self.pdokgeocoder.suggest(search_text, self.createfq()) if len(results) == 0: # ignore, as we are suggesting, maybe more characters will reveal something... return for result in results: #print address adrestekst = QStandardItem("%s" % (result["adrestekst"])) adrestekst.setData(result, Qt.UserRole) type = QStandardItem("%s" % (result["type"])) id = QStandardItem("%s" % (result["id"])) score = QStandardItem("%s" % (result["score"])) adrestekst.setData(result, Qt.UserRole) self.geocoderSourceModel.appendRow([adrestekst, type]) self.geocoderSourceModel.setHeaderData(0, Qt.Horizontal, "Resultaat") self.geocoderSourceModel.setHeaderData(1, Qt.Horizontal, "Type") self.geocoderSourceModel.horizontalHeaderItem(0).setTextAlignment( Qt.AlignLeft) self.dlg.geocoderResultView.resizeColumnsToContents() self.dlg.geocoderResultView.horizontalHeader().setStretchLastSection( True) def geocode(self): self.dlg.geocoderSearch.setText(self.toolbarSearch.text()) self.suggest() if self.dlg.geocoderResultView.model().rowCount() > 0: self.dlg.geocoderResultView.selectRow(0) self.zoomToAddress() else: QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ( \ "Niets gevonden.\nProbeer een andere spelling, of alleen postcode/huisnummer?\n\nSelecteer meer (Locatieserver) 'typen' in de PdokServicesPlugin dialoog.\n\nOf gebruik de 'PDOK geocoder'-tab in de PdokServicesPlugin dialoog." ), QMessageBox.Ok, QMessageBox.Ok) # def geocode(self): # self.dlg.ui.lookupinfo.setHtml('') # search_text = self.toolbarSearch.text() # addresses = self.pdokgeocoder.search(search_text) # if len(addresses) == 0: # QMessageBox.warning(self.iface.mainWindow(), "PDOK plugin", ( \ # "Niets gevonden. Probeer een andere spelling of alleen postcode/huisnummer." # ), QMessageBox.Ok, QMessageBox.Ok) # return # for address in addresses: # #print address # adrestekst = QStandardItem("%s" % (address["adrestekst"])) # adrestekst.setData(address, Qt.UserRole) # straat = QStandardItem("%s" % (address["straat"])) # nummer = QStandardItem("%s" % (address["nummer"])) # postcode = QStandardItem("%s" % (address["postcode"])) # plaats = QStandardItem("%s" % (address["plaats"])) # gemeente = QStandardItem("%s" % (address["gemeente"])) # provincie = QStandardItem("%s" % (address["provincie"])) # self.geocoderSourceModel.appendRow([adrestekst, straat, nummer, postcode, plaats, gemeente, provincie]) # # self.dlg.geocoderResultView.selectRow(0) # self.zoomToAddress() # # self.geocoderSourceModel.setHeaderData(0, Qt.Horizontal, "Resultaat") # self.geocoderSourceModel.setHeaderData(1, Qt.Horizontal, "Straat") # self.geocoderSourceModel.setHeaderData(2, Qt.Horizontal, "Nr") # self.geocoderSourceModel.setHeaderData(3, Qt.Horizontal, "Postcode") # self.geocoderSourceModel.setHeaderData(4, Qt.Horizontal, "Plaats") # self.geocoderSourceModel.setHeaderData(5, Qt.Horizontal, "Gemeente") # self.geocoderSourceModel.setHeaderData(6, Qt.Horizontal, "Provincie") # # self.geocoderSourceModel.horizontalHeaderItem(0).setTextAlignment(Qt.AlignLeft) # self.geocoderSourceModel.horizontalHeaderItem(1).setTextAlignment(Qt.AlignLeft) # self.geocoderSourceModel.horizontalHeaderItem(2).setTextAlignment(Qt.AlignLeft) # self.geocoderSourceModel.horizontalHeaderItem(3).setTextAlignment(Qt.AlignLeft) # self.geocoderSourceModel.horizontalHeaderItem(4).setTextAlignment(Qt.AlignLeft) # self.geocoderSourceModel.horizontalHeaderItem(5).setTextAlignment(Qt.AlignLeft) # self.geocoderSourceModel.horizontalHeaderItem(6).setTextAlignment(Qt.AlignLeft) # # self.dlg.geocoderResultView.resizeColumnsToContents() # self.dlg.geocoderResultView.horizontalHeader().setStretchLastSection(True) def zoomToAddress(self): # get x,y from data of record self.removePointer() data = self.dlg.geocoderResultView.selectedIndexes()[0].data( Qt.UserRole) if 'centroide_rd' in data: # free OR lookup service geom = QgsGeometry.fromWkt(data['centroide_rd']) adrestekst = data['adrestekst'] else: # no centroid yet, probably only object id, retrieve it via lookup service id = data['id'] data = self.pdokgeocoder.lookup(id) geom = QgsGeometry.fromWkt(data['centroide_rd']) adrestekst = data['adrestekst'] lookup_data = data['data'] lis = '' for key in lookup_data.keys(): lis = lis + '<li>{}: {}</li>'.format(key, lookup_data[key]) self.dlg.ui.lookupinfo.setHtml('<h4>{}</h4><lu>{}</lu>'.format( adrestekst, lis)) # just always transform from 28992 to mapcanvas crs crs = self.iface.mapCanvas().mapSettings().destinationCrs() crs28992 = QgsCoordinateReferenceSystem() crs28992.createFromId(28992) crsTransform = QgsCoordinateTransform(crs28992, crs, QgsProject.instance()) z = 1587 if adrestekst.lower().startswith('adres'): z = 794 elif adrestekst.lower().startswith('perceel'): z = 794 elif adrestekst.lower().startswith('hectometer'): z = 1587 elif adrestekst.lower().startswith('straat'): z = 3175 elif adrestekst.lower().startswith('postcode'): z = 6350 elif adrestekst.lower().startswith('woonplaats'): z = 25398 elif adrestekst.lower().startswith('gemeente'): z = 50797 elif adrestekst.lower().startswith('provincie'): z = 812750 geom.transform(crsTransform) center = geom.asPoint() self.setPointer(center) # zoom to with center is actually setting a point rectangle and then zoom rect = QgsRectangle(center, center) self.iface.mapCanvas().setExtent(rect) self.iface.mapCanvas().zoomScale(z) self.iface.mapCanvas().refresh() def setPointer(self, point): self.removePointer() self.pointer = QgsVertexMarker(self.iface.mapCanvas()) self.pointer.setColor(QColor(255, 255, 0)) self.pointer.setIconSize(10) self.pointer.setPenWidth(5) self.pointer.setCenter(point) self.clean_action.setEnabled(True) def removePointer(self): if self.pointer is not None and self.pointer.scene() is not None: self.iface.mapCanvas().scene().removeItem(self.pointer) self.pointer = None self.clean_action.setEnabled(False) def info(self, msg=""): QgsMessageLog.logMessage('{}'.format(msg), 'PDOK-services Plugin', Qgis.Info)
class AlgorithmDialogBase(BASE, WIDGET): def __init__(self, alg): super(AlgorithmDialogBase, self).__init__(iface.mainWindow() if iface else None) self.setupUi(self) # don't collapse parameters panel self.splitter.setCollapsible(0, False) # add collapse button to splitter splitterHandle = self.splitter.handle(1) handleLayout = QVBoxLayout() handleLayout.setContentsMargins(0, 0, 0, 0) self.btnCollapse = QToolButton(splitterHandle) self.btnCollapse.setAutoRaise(True) self.btnCollapse.setFixedSize(12, 12) self.btnCollapse.setCursor(Qt.ArrowCursor) handleLayout.addWidget(self.btnCollapse) handleLayout.addStretch() splitterHandle.setLayout(handleLayout) self.settings = QgsSettings() self.splitter.restoreState(self.settings.value("/Processing/dialogBaseSplitter", QByteArray())) self.restoreGeometry(self.settings.value("/Processing/dialogBase", QByteArray())) self.splitterState = self.splitter.saveState() self.splitterChanged(0, 0) self.executed = False self.mainWidget = None self.alg = alg self.setWindowTitle(self.alg.displayName()) self.buttonBox.rejected.connect(self.reject) self.buttonBox.accepted.connect(self.accept) # Rename OK button to Run self.btnRun = self.buttonBox.button(QDialogButtonBox.Ok) self.btnRun.setText(self.tr('Run')) self.buttonCancel.setEnabled(False) self.btnClose = self.buttonBox.button(QDialogButtonBox.Close) self.buttonBox.helpRequested.connect(self.openHelp) self.btnCollapse.clicked.connect(self.toggleCollapsed) self.splitter.splitterMoved.connect(self.splitterChanged) # desktop = QDesktopWidget() # if desktop.physicalDpiX() > 96: # self.txtHelp.setZoomFactor(desktop.physicalDpiX() / 96) algHelp = self.formatHelp(self.alg) if algHelp is None: self.textShortHelp.hide() else: self.textShortHelp.document().setDefaultStyleSheet('''.summary { margin-left: 10px; margin-right: 10px; } h2 { color: #555555; padding-bottom: 15px; } a { text-decoration: none; color: #3498db; font-weight: bold; } p { color: #666666; } b { color: #333333; } dl dd { margin-bottom: 5px; }''') self.textShortHelp.setHtml(algHelp) def linkClicked(url): webbrowser.open(url.toString()) self.textShortHelp.anchorClicked.connect(linkClicked) self.showDebug = ProcessingConfig.getSetting( ProcessingConfig.SHOW_DEBUG_IN_DIALOG) def createFeedback(self): feedback = AlgorithmDialogFeedback(self) feedback.progressChanged.connect(self.setPercentage) feedback.error.connect(self.error) feedback.progress_text.connect(self.setText) feedback.info.connect(self.setInfo) feedback.command_info.connect(self.setCommand) feedback.debug_info.connect(self.setDebugInfo) feedback.console_info.connect(self.setConsoleInfo) self.buttonCancel.clicked.connect(feedback.cancel) return feedback def formatHelp(self, alg): text = alg.shortHelpString() if not text: return None return "<h2>%s</h2>%s" % (alg.displayName(), "".join(["<p>%s</p>" % s for s in text.split("\n")])) def closeEvent(self, event): self._saveGeometry() super(AlgorithmDialogBase, self).closeEvent(event) def setMainWidget(self, widget): if self.mainWidget is not None: QgsProject.instance().layerWasAdded.disconnect(self.mainWidget.layerRegistryChanged) QgsProject.instance().layersWillBeRemoved.disconnect(self.mainWidget.layerRegistryChanged) self.mainWidget = widget self.tabWidget.widget(0).layout().addWidget(self.mainWidget) QgsProject.instance().layerWasAdded.connect(self.mainWidget.layerRegistryChanged) QgsProject.instance().layersWillBeRemoved.connect(self.mainWidget.layerRegistryChanged) def error(self, msg): self.setInfo(msg, True) self.resetGUI() self.tabWidget.setCurrentIndex(1) def resetGUI(self): self.lblProgress.setText('') self.progressBar.setMaximum(100) self.progressBar.setValue(0) self.btnRun.setEnabled(True) self.btnClose.setEnabled(True) def setInfo(self, msg, error=False, escape_html=True): if error: self.txtLog.append('<span style="color:red">{}</span><br />'.format(msg, quote=False)) elif escape_html: self.txtLog.append(html.escape(msg)) else: self.txtLog.append(msg) def setCommand(self, cmd): if self.showDebug: self.txtLog.append('<code>{}<code>'.format(html.escape(cmd, quote=False))) def setDebugInfo(self, msg): if self.showDebug: self.txtLog.append('<span style="color:blue">{}</span>'.format(html.escape(msg, quote=False))) def setConsoleInfo(self, msg): if self.showDebug: self.txtLog.append('<code><span style="color:darkgray">{}</span></code>'.format(html.escape(msg, quote=False))) def setPercentage(self, value): if self.progressBar.maximum() == 0: self.progressBar.setMaximum(100) self.progressBar.setValue(value) def setText(self, text): self.lblProgress.setText(text) self.setInfo(text, False) def getParamValues(self): return {} def accept(self): pass def reject(self): self._saveGeometry() super(AlgorithmDialogBase, self).reject() def finish(self, successful, result, context, feedback): pass def toggleCollapsed(self): if self.helpCollapsed: self.splitter.restoreState(self.splitterState) self.btnCollapse.setArrowType(Qt.RightArrow) else: self.splitterState = self.splitter.saveState() self.splitter.setSizes([1, 0]) self.btnCollapse.setArrowType(Qt.LeftArrow) self.helpCollapsed = not self.helpCollapsed def splitterChanged(self, pos, index): if self.splitter.sizes()[1] == 0: self.helpCollapsed = True self.btnCollapse.setArrowType(Qt.LeftArrow) else: self.helpCollapsed = False self.btnCollapse.setArrowType(Qt.RightArrow) def openHelp(self): algHelp = self.alg.helpUrl() if not algHelp: algHelp = QgsHelp.helpUrl("processing_algs/{}/{}".format( self.alg.provider().id(), self.alg.id())).toString() if algHelp not in [None, ""]: webbrowser.open(algHelp) def _saveGeometry(self): self.settings.setValue("/Processing/dialogBaseSplitter", self.splitter.saveState()) self.settings.setValue("/Processing/dialogBase", self.saveGeometry()) class InvalidParameterValue(Exception): def __init__(self, param, widget): (self.parameter, self.widget) = (param, widget)
def addProviderActions(self, provider): if provider.id() in ProviderActions.actions: toolbarButton = QToolButton() toolbarButton.setObjectName('provideraction_' + provider.id()) toolbarButton.setIcon(provider.icon()) toolbarButton.setToolTip(provider.name()) toolbarButton.setPopupMode(QToolButton.InstantPopup) actions = ProviderActions.actions[provider.id()] menu = QMenu(provider.name(), self) for action in actions: action.setData(self) act = QAction(action.name, menu) act.triggered.connect(action.execute) menu.addAction(act) toolbarButton.setMenu(menu) self.processingToolbar.addWidget(toolbarButton)
def initWidgets(self): # If there are advanced parameters — show corresponding groupbox for param in self.alg.parameterDefinitions(): if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced: self.grpAdvanced.show() break # Create widgets and put them in layouts for param in self.alg.parameterDefinitions(): if param.flags() & QgsProcessingParameterDefinition.FlagHidden: continue if param.isDestination(): continue else: desc = param.description() if isinstance(param, QgsProcessingParameterExtent): desc += self.tr(' (xmin, xmax, ymin, ymax)') if isinstance(param, QgsProcessingParameterPoint): desc += self.tr(' (x, y)') if param.flags() & QgsProcessingParameterDefinition.FlagOptional: desc += self.tr(' [optional]') wrapper = WidgetWrapperFactory.create_wrapper(param, self.parent) self.wrappers[param.name()] = wrapper widget = wrapper.widget if widget is not None: if isinstance(param, QgsProcessingParameterFeatureSource): layout = QHBoxLayout() layout.setSpacing(2) layout.setMargin(0) layout.addWidget(widget) button = QToolButton() icon = QIcon(os.path.join(pluginPath, 'images', 'iterate.png')) button.setIcon(icon) button.setToolTip(self.tr('Iterate over this layer, creating a separate output for every feature in the layer')) button.setCheckable(True) layout.addWidget(button) layout.setAlignment(button, Qt.AlignTop) self.iterateButtons[param.name()] = button button.toggled.connect(self.buttonToggled) widget = QWidget() widget.setLayout(layout) widget.setToolTip(param.toolTip()) if type(widget) is QCheckBox: # checkbox widget - so description is embedded in widget rather than a separate # label widget.setText(desc) else: label = QLabel(desc) # label.setToolTip(tooltip) self.labels[param.name()] = label if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced: self.layoutAdvanced.addWidget(label) else: self.layoutMain.insertWidget( self.layoutMain.count() - 2, label) if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced: self.layoutAdvanced.addWidget(widget) else: self.layoutMain.insertWidget( self.layoutMain.count() - 2, widget) for output in self.alg.destinationParameterDefinitions(): if output.flags() & QgsProcessingParameterDefinition.FlagHidden: continue label = QLabel(output.description()) widget = DestinationSelectionPanel(output, self.alg) self.layoutMain.insertWidget(self.layoutMain.count() - 1, label) self.layoutMain.insertWidget(self.layoutMain.count() - 1, widget) if isinstance(output, (QgsProcessingParameterRasterDestination, QgsProcessingParameterFeatureSink, QgsProcessingParameterVectorDestination)): check = QCheckBox() check.setText(self.tr('Open output file after running algorithm')) check.setChecked(True) self.layoutMain.insertWidget(self.layoutMain.count() - 1, check) self.checkBoxes[output.name()] = check widget.setToolTip(param.toolTip()) self.outputWidgets[output.name()] = widget for wrapper in list(self.wrappers.values()): wrapper.postInitialize(list(self.wrappers.values()))
class AlgorithmDialogBase(BASE, WIDGET): def __init__(self, alg): super(AlgorithmDialogBase, self).__init__(iface.mainWindow() if iface else None) self.setupUi(self) # don't collapse parameters panel self.splitter.setCollapsible(0, False) # add collapse button to splitter splitterHandle = self.splitter.handle(1) handleLayout = QVBoxLayout() handleLayout.setContentsMargins(0, 0, 0, 0) self.btnCollapse = QToolButton(splitterHandle) self.btnCollapse.setAutoRaise(True) self.btnCollapse.setFixedSize(12, 12) self.btnCollapse.setCursor(Qt.ArrowCursor) handleLayout.addWidget(self.btnCollapse) handleLayout.addStretch() splitterHandle.setLayout(handleLayout) self.settings = QgsSettings() self.splitter.restoreState( self.settings.value("/Processing/dialogBaseSplitter", QByteArray())) self.restoreGeometry( self.settings.value("/Processing/dialogBase", QByteArray())) self.splitterState = self.splitter.saveState() self.splitterChanged(0, 0) self.executed = False self.mainWidget = None self.alg = alg self.setWindowTitle(self.alg.displayName()) self.buttonBox.rejected.connect(self.reject) self.buttonBox.accepted.connect(self.accept) # Rename OK button to Run self.btnRun = self.buttonBox.button(QDialogButtonBox.Ok) self.btnRun.setText(self.tr('Run')) self.buttonCancel.setEnabled(False) self.btnClose = self.buttonBox.button(QDialogButtonBox.Close) self.buttonBox.helpRequested.connect(self.openHelp) self.btnCollapse.clicked.connect(self.toggleCollapsed) self.splitter.splitterMoved.connect(self.splitterChanged) # desktop = QDesktopWidget() # if desktop.physicalDpiX() > 96: # self.txtHelp.setZoomFactor(desktop.physicalDpiX() / 96) algHelp = self.formatHelp(self.alg) if algHelp is None: self.textShortHelp.hide() else: self.textShortHelp.document().setDefaultStyleSheet( '''.summary { margin-left: 10px; margin-right: 10px; } h2 { color: #555555; padding-bottom: 15px; } a { text-decoration: none; color: #3498db; font-weight: bold; } p { color: #666666; } b { color: #333333; } dl dd { margin-bottom: 5px; }''' ) self.textShortHelp.setHtml(algHelp) def linkClicked(url): webbrowser.open(url.toString()) self.textShortHelp.anchorClicked.connect(linkClicked) self.showDebug = ProcessingConfig.getSetting( ProcessingConfig.SHOW_DEBUG_IN_DIALOG) def createFeedback(self): feedback = AlgorithmDialogFeedback(self) feedback.progressChanged.connect(self.setPercentage) feedback.error.connect(self.error) feedback.progress_text.connect(self.setText) feedback.info.connect(self.setInfo) feedback.command_info.connect(self.setCommand) feedback.debug_info.connect(self.setDebugInfo) feedback.console_info.connect(self.setConsoleInfo) self.buttonCancel.clicked.connect(feedback.cancel) return feedback def formatHelp(self, alg): text = alg.shortHelpString() if not text: return None return "<h2>%s</h2>%s" % (alg.displayName(), "".join( ["<p>%s</p>" % s for s in text.split("\n")])) def closeEvent(self, event): self._saveGeometry() super(AlgorithmDialogBase, self).closeEvent(event) def setMainWidget(self, widget): if self.mainWidget is not None: QgsProject.instance().layerWasAdded.disconnect( self.mainWidget.layerRegistryChanged) QgsProject.instance().layersWillBeRemoved.disconnect( self.mainWidget.layerRegistryChanged) self.mainWidget = widget self.tabWidget.widget(0).layout().addWidget(self.mainWidget) QgsProject.instance().layerWasAdded.connect( self.mainWidget.layerRegistryChanged) QgsProject.instance().layersWillBeRemoved.connect( self.mainWidget.layerRegistryChanged) def error(self, msg): self.setInfo(msg, True) self.resetGUI() self.tabWidget.setCurrentIndex(1) def resetGUI(self): self.lblProgress.setText('') self.progressBar.setMaximum(100) self.progressBar.setValue(0) self.btnRun.setEnabled(True) self.btnClose.setEnabled(True) def setInfo(self, msg, error=False, escape_html=True): if error: self.txtLog.append( '<span style="color:red">{}</span><br />'.format(msg, quote=False)) elif escape_html: self.txtLog.append(html.escape(msg)) else: self.txtLog.append(msg) def setCommand(self, cmd): if self.showDebug: self.txtLog.append('<code>{}<code>'.format( html.escape(cmd, quote=False))) def setDebugInfo(self, msg): if self.showDebug: self.txtLog.append('<span style="color:blue">{}</span>'.format( html.escape(msg, quote=False))) def setConsoleInfo(self, msg): if self.showDebug: self.txtLog.append( '<code><span style="color:darkgray">{}</span></code>'.format( html.escape(msg, quote=False))) def setPercentage(self, value): if self.progressBar.maximum() == 0: self.progressBar.setMaximum(100) self.progressBar.setValue(value) def setText(self, text): self.lblProgress.setText(text) self.setInfo(text, False) def getParamValues(self): return {} def accept(self): pass def reject(self): self._saveGeometry() super(AlgorithmDialogBase, self).reject() def finish(self, successful, result, context, feedback): pass def toggleCollapsed(self): if self.helpCollapsed: self.splitter.restoreState(self.splitterState) self.btnCollapse.setArrowType(Qt.RightArrow) else: self.splitterState = self.splitter.saveState() self.splitter.setSizes([1, 0]) self.btnCollapse.setArrowType(Qt.LeftArrow) self.helpCollapsed = not self.helpCollapsed def splitterChanged(self, pos, index): if self.splitter.sizes()[1] == 0: self.helpCollapsed = True self.btnCollapse.setArrowType(Qt.LeftArrow) else: self.helpCollapsed = False self.btnCollapse.setArrowType(Qt.RightArrow) def openHelp(self): algHelp = self.alg.helpUrl() if not algHelp: algHelp = QgsHelp.helpUrl("processing_algs/{}/{}".format( self.alg.provider().id(), self.alg.id())).toString() if algHelp not in [None, ""]: webbrowser.open(algHelp) def _saveGeometry(self): self.settings.setValue("/Processing/dialogBaseSplitter", self.splitter.saveState()) self.settings.setValue("/Processing/dialogBase", self.saveGeometry()) class InvalidParameterValue(Exception): def __init__(self, param, widget): (self.parameter, self.widget) = (param, widget)
def __init__(self, model=None): super().__init__(None) self.setAttribute(Qt.WA_DeleteOnClose) self.setupUi(self) self._variables_scope = None # LOTS of bug reports when we include the dock creation in the UI file # see e.g. #16428, #19068 # So just roll it all by hand......! self.propertiesDock = QgsDockWidget(self) self.propertiesDock.setFeatures( QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable) self.propertiesDock.setObjectName("propertiesDock") propertiesDockContents = QWidget() self.verticalDockLayout_1 = QVBoxLayout(propertiesDockContents) self.verticalDockLayout_1.setContentsMargins(0, 0, 0, 0) self.verticalDockLayout_1.setSpacing(0) self.scrollArea_1 = QgsScrollArea(propertiesDockContents) sizePolicy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.scrollArea_1.sizePolicy().hasHeightForWidth()) self.scrollArea_1.setSizePolicy(sizePolicy) self.scrollArea_1.setFocusPolicy(Qt.WheelFocus) self.scrollArea_1.setFrameShape(QFrame.NoFrame) self.scrollArea_1.setFrameShadow(QFrame.Plain) self.scrollArea_1.setWidgetResizable(True) self.scrollAreaWidgetContents_1 = QWidget() self.gridLayout = QGridLayout(self.scrollAreaWidgetContents_1) self.gridLayout.setContentsMargins(6, 6, 6, 6) self.gridLayout.setSpacing(4) self.label_1 = QLabel(self.scrollAreaWidgetContents_1) self.gridLayout.addWidget(self.label_1, 0, 0, 1, 1) self.textName = QLineEdit(self.scrollAreaWidgetContents_1) self.gridLayout.addWidget(self.textName, 0, 1, 1, 1) self.label_2 = QLabel(self.scrollAreaWidgetContents_1) self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1) self.textGroup = QLineEdit(self.scrollAreaWidgetContents_1) self.gridLayout.addWidget(self.textGroup, 1, 1, 1, 1) self.label_1.setText(self.tr("Name")) self.textName.setToolTip(self.tr("Enter model name here")) self.label_2.setText(self.tr("Group")) self.textGroup.setToolTip(self.tr("Enter group name here")) self.scrollArea_1.setWidget(self.scrollAreaWidgetContents_1) self.verticalDockLayout_1.addWidget(self.scrollArea_1) self.propertiesDock.setWidget(propertiesDockContents) self.propertiesDock.setWindowTitle(self.tr("Model Properties")) self.inputsDock = QgsDockWidget(self) self.inputsDock.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable) self.inputsDock.setObjectName("inputsDock") self.inputsDockContents = QWidget() self.verticalLayout_3 = QVBoxLayout(self.inputsDockContents) self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) self.scrollArea_2 = QgsScrollArea(self.inputsDockContents) sizePolicy.setHeightForWidth(self.scrollArea_2.sizePolicy().hasHeightForWidth()) self.scrollArea_2.setSizePolicy(sizePolicy) self.scrollArea_2.setFocusPolicy(Qt.WheelFocus) self.scrollArea_2.setFrameShape(QFrame.NoFrame) self.scrollArea_2.setFrameShadow(QFrame.Plain) self.scrollArea_2.setWidgetResizable(True) self.scrollAreaWidgetContents_2 = QWidget() self.verticalLayout = QVBoxLayout(self.scrollAreaWidgetContents_2) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setSpacing(0) self.inputsTree = QTreeWidget(self.scrollAreaWidgetContents_2) self.inputsTree.setAlternatingRowColors(True) self.inputsTree.header().setVisible(False) self.verticalLayout.addWidget(self.inputsTree) self.scrollArea_2.setWidget(self.scrollAreaWidgetContents_2) self.verticalLayout_3.addWidget(self.scrollArea_2) self.inputsDock.setWidget(self.inputsDockContents) self.addDockWidget(Qt.DockWidgetArea(1), self.inputsDock) self.inputsDock.setWindowTitle(self.tr("Inputs")) self.algorithmsDock = QgsDockWidget(self) self.algorithmsDock.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable) self.algorithmsDock.setObjectName("algorithmsDock") self.algorithmsDockContents = QWidget() self.verticalLayout_4 = QVBoxLayout(self.algorithmsDockContents) self.verticalLayout_4.setContentsMargins(0, 0, 0, 0) self.scrollArea_3 = QgsScrollArea(self.algorithmsDockContents) sizePolicy.setHeightForWidth(self.scrollArea_3.sizePolicy().hasHeightForWidth()) self.scrollArea_3.setSizePolicy(sizePolicy) self.scrollArea_3.setFocusPolicy(Qt.WheelFocus) self.scrollArea_3.setFrameShape(QFrame.NoFrame) self.scrollArea_3.setFrameShadow(QFrame.Plain) self.scrollArea_3.setWidgetResizable(True) self.scrollAreaWidgetContents_3 = QWidget() self.verticalLayout_2 = QVBoxLayout(self.scrollAreaWidgetContents_3) self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) self.verticalLayout_2.setSpacing(4) self.searchBox = QgsFilterLineEdit(self.scrollAreaWidgetContents_3) self.verticalLayout_2.addWidget(self.searchBox) self.algorithmTree = QgsProcessingToolboxTreeView(None, QgsApplication.processingRegistry()) self.algorithmTree.setAlternatingRowColors(True) self.algorithmTree.header().setVisible(False) self.verticalLayout_2.addWidget(self.algorithmTree) self.scrollArea_3.setWidget(self.scrollAreaWidgetContents_3) self.verticalLayout_4.addWidget(self.scrollArea_3) self.algorithmsDock.setWidget(self.algorithmsDockContents) self.addDockWidget(Qt.DockWidgetArea(1), self.algorithmsDock) self.algorithmsDock.setWindowTitle(self.tr("Algorithms")) self.searchBox.setToolTip(self.tr("Enter algorithm name to filter list")) self.searchBox.setShowSearchIcon(True) self.variables_dock = QgsDockWidget(self) self.variables_dock.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable) self.variables_dock.setObjectName("variablesDock") self.variables_dock_contents = QWidget() vl_v = QVBoxLayout() vl_v.setContentsMargins(0, 0, 0, 0) self.variables_editor = QgsVariableEditorWidget() vl_v.addWidget(self.variables_editor) self.variables_dock_contents.setLayout(vl_v) self.variables_dock.setWidget(self.variables_dock_contents) self.addDockWidget(Qt.DockWidgetArea(1), self.variables_dock) self.variables_dock.setWindowTitle(self.tr("Variables")) self.addDockWidget(Qt.DockWidgetArea(1), self.propertiesDock) self.tabifyDockWidget(self.propertiesDock, self.variables_dock) self.variables_editor.scopeChanged.connect(self.variables_changed) self.bar = QgsMessageBar() self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed) self.centralWidget().layout().insertWidget(0, self.bar) try: self.setDockOptions(self.dockOptions() | QMainWindow.GroupedDragging) except: pass if iface is not None: self.mToolbar.setIconSize(iface.iconSize()) self.setStyleSheet(iface.mainWindow().styleSheet()) self.toolbutton_export_to_script = QToolButton() self.toolbutton_export_to_script.setPopupMode(QToolButton.InstantPopup) self.export_to_script_algorithm_action = QAction(QCoreApplication.translate('ModelerDialog', 'Export as Script Algorithm…')) self.toolbutton_export_to_script.addActions([self.export_to_script_algorithm_action]) self.mToolbar.insertWidget(self.mActionExportImage, self.toolbutton_export_to_script) self.export_to_script_algorithm_action.triggered.connect(self.export_as_script_algorithm) self.mActionOpen.setIcon( QgsApplication.getThemeIcon('/mActionFileOpen.svg')) self.mActionSave.setIcon( QgsApplication.getThemeIcon('/mActionFileSave.svg')) self.mActionSaveAs.setIcon( QgsApplication.getThemeIcon('/mActionFileSaveAs.svg')) self.mActionSaveInProject.setIcon( QgsApplication.getThemeIcon('/mAddToProject.svg')) self.mActionZoomActual.setIcon( QgsApplication.getThemeIcon('/mActionZoomActual.svg')) self.mActionZoomIn.setIcon( QgsApplication.getThemeIcon('/mActionZoomIn.svg')) self.mActionZoomOut.setIcon( QgsApplication.getThemeIcon('/mActionZoomOut.svg')) self.mActionExportImage.setIcon( QgsApplication.getThemeIcon('/mActionSaveMapAsImage.svg')) self.mActionZoomToItems.setIcon( QgsApplication.getThemeIcon('/mActionZoomFullExtent.svg')) self.mActionExportPdf.setIcon( QgsApplication.getThemeIcon('/mActionSaveAsPDF.svg')) self.mActionExportSvg.setIcon( QgsApplication.getThemeIcon('/mActionSaveAsSVG.svg')) self.toolbutton_export_to_script.setIcon( QgsApplication.getThemeIcon('/mActionSaveAsPython.svg')) self.mActionEditHelp.setIcon( QgsApplication.getThemeIcon('/mActionEditHelpContent.svg')) self.mActionRun.setIcon( QgsApplication.getThemeIcon('/mActionStart.svg')) self.addDockWidget(Qt.LeftDockWidgetArea, self.propertiesDock) self.addDockWidget(Qt.LeftDockWidgetArea, self.inputsDock) self.addDockWidget(Qt.LeftDockWidgetArea, self.algorithmsDock) self.tabifyDockWidget(self.inputsDock, self.algorithmsDock) self.inputsDock.raise_() self.setWindowFlags(Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint | Qt.WindowCloseButtonHint) settings = QgsSettings() self.restoreState(settings.value("/Processing/stateModeler", QByteArray())) self.restoreGeometry(settings.value("/Processing/geometryModeler", QByteArray())) self.scene = ModelerScene(self, dialog=self) self.scene.setSceneRect(QRectF(0, 0, self.CANVAS_SIZE, self.CANVAS_SIZE)) self.view.setScene(self.scene) self.view.setAcceptDrops(True) self.view.ensureVisible(0, 0, 10, 10) self.view.scale(QgsApplication.desktop().logicalDpiX() / 96, QgsApplication.desktop().logicalDpiX() / 96) def _dragEnterEvent(event): if event.mimeData().hasText() or event.mimeData().hasFormat('application/x-vnd.qgis.qgis.algorithmid'): event.acceptProposedAction() else: event.ignore() def _dropEvent(event): def alg_dropped(algorithm_id, pos): alg = QgsApplication.processingRegistry().createAlgorithmById(algorithm_id) if alg is not None: self._addAlgorithm(alg, pos) else: assert False, algorithm_id def input_dropped(id, pos): if id in [param.id() for param in QgsApplication.instance().processingRegistry().parameterTypes()]: self.addInputOfType(itemId, pos) if event.mimeData().hasFormat('application/x-vnd.qgis.qgis.algorithmid'): data = event.mimeData().data('application/x-vnd.qgis.qgis.algorithmid') stream = QDataStream(data, QIODevice.ReadOnly) algorithm_id = stream.readQString() QTimer.singleShot(0, lambda id=algorithm_id, pos=self.view.mapToScene(event.pos()): alg_dropped(id, pos)) event.accept() elif event.mimeData().hasText(): itemId = event.mimeData().text() QTimer.singleShot(0, lambda id=itemId, pos=self.view.mapToScene(event.pos()): input_dropped(id, pos)) event.accept() else: event.ignore() def _dragMoveEvent(event): if event.mimeData().hasText() or event.mimeData().hasFormat('application/x-vnd.qgis.qgis.algorithmid'): event.accept() else: event.ignore() def _wheelEvent(event): self.view.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) settings = QgsSettings() factor = settings.value('/qgis/zoom_favor', 2.0) # "Normal" mouse has an angle delta of 120, precision mouses provide data # faster, in smaller steps factor = 1.0 + (factor - 1.0) / 120.0 * abs(event.angleDelta().y()) if (event.modifiers() == Qt.ControlModifier): factor = 1.0 + (factor - 1.0) / 20.0 if event.angleDelta().y() < 0: factor = 1 / factor self.view.scale(factor, factor) def _enterEvent(e): QGraphicsView.enterEvent(self.view, e) self.view.viewport().setCursor(Qt.ArrowCursor) def _mouseReleaseEvent(e): QGraphicsView.mouseReleaseEvent(self.view, e) self.view.viewport().setCursor(Qt.ArrowCursor) def _mousePressEvent(e): if e.button() == Qt.MidButton: self.previousMousePos = e.pos() else: QGraphicsView.mousePressEvent(self.view, e) def _mouseMoveEvent(e): if e.buttons() == Qt.MidButton: offset = self.previousMousePos - e.pos() self.previousMousePos = e.pos() self.view.verticalScrollBar().setValue(self.view.verticalScrollBar().value() + offset.y()) self.view.horizontalScrollBar().setValue(self.view.horizontalScrollBar().value() + offset.x()) else: QGraphicsView.mouseMoveEvent(self.view, e) self.view.setDragMode(QGraphicsView.ScrollHandDrag) self.view.dragEnterEvent = _dragEnterEvent self.view.dropEvent = _dropEvent self.view.dragMoveEvent = _dragMoveEvent self.view.wheelEvent = _wheelEvent self.view.enterEvent = _enterEvent self.view.mousePressEvent = _mousePressEvent self.view.mouseMoveEvent = _mouseMoveEvent def _mimeDataInput(items): mimeData = QMimeData() text = items[0].data(0, Qt.UserRole) mimeData.setText(text) return mimeData self.inputsTree.mimeData = _mimeDataInput self.inputsTree.setDragDropMode(QTreeWidget.DragOnly) self.inputsTree.setDropIndicatorShown(True) self.algorithms_model = ModelerToolboxModel(self, QgsApplication.processingRegistry()) self.algorithmTree.setToolboxProxyModel(self.algorithms_model) self.algorithmTree.setDragDropMode(QTreeWidget.DragOnly) self.algorithmTree.setDropIndicatorShown(True) filters = QgsProcessingToolboxProxyModel.Filters(QgsProcessingToolboxProxyModel.FilterModeler) if ProcessingConfig.getSetting(ProcessingConfig.SHOW_ALGORITHMS_KNOWN_ISSUES): filters |= QgsProcessingToolboxProxyModel.FilterShowKnownIssues self.algorithmTree.setFilters(filters) if hasattr(self.searchBox, 'setPlaceholderText'): self.searchBox.setPlaceholderText(QCoreApplication.translate('ModelerDialog', 'Search…')) if hasattr(self.textName, 'setPlaceholderText'): self.textName.setPlaceholderText(self.tr('Enter model name here')) if hasattr(self.textGroup, 'setPlaceholderText'): self.textGroup.setPlaceholderText(self.tr('Enter group name here')) # Connect signals and slots self.inputsTree.doubleClicked.connect(self.addInput) self.searchBox.textChanged.connect(self.algorithmTree.setFilterString) self.algorithmTree.doubleClicked.connect(self.addAlgorithm) # Ctrl+= should also trigger a zoom in action ctrlEquals = QShortcut(QKeySequence("Ctrl+="), self) ctrlEquals.activated.connect(self.zoomIn) self.mActionOpen.triggered.connect(self.openModel) self.mActionSave.triggered.connect(self.save) self.mActionSaveAs.triggered.connect(self.saveAs) self.mActionSaveInProject.triggered.connect(self.saveInProject) self.mActionZoomIn.triggered.connect(self.zoomIn) self.mActionZoomOut.triggered.connect(self.zoomOut) self.mActionZoomActual.triggered.connect(self.zoomActual) self.mActionZoomToItems.triggered.connect(self.zoomToItems) self.mActionExportImage.triggered.connect(self.exportAsImage) self.mActionExportPdf.triggered.connect(self.exportAsPdf) self.mActionExportSvg.triggered.connect(self.exportAsSvg) #self.mActionExportPython.triggered.connect(self.exportAsPython) self.mActionEditHelp.triggered.connect(self.editHelp) self.mActionRun.triggered.connect(self.runModel) if model is not None: self.model = model.create() self.model.setSourceFilePath(model.sourceFilePath()) self.textGroup.setText(self.model.group()) self.textName.setText(self.model.displayName()) self.repaintModel() else: self.model = QgsProcessingModelAlgorithm() self.model.setProvider(QgsApplication.processingRegistry().providerById('model')) self.update_variables_gui() self.fillInputsTree() self.view.centerOn(0, 0) self.help = None self.hasChanged = False
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() sizes = self.splitter.sizes() self.splitter.setSizes(sizes) # ----------------Restore Settings------------------------------------ self.restoreSettingsConsole() # ------------------Toolbar Editor------------------------------------- # Action for Open File openFileBt = QCoreApplication.translate("PythonConsole", "Open Script...") self.openFileButton = QAction(self) self.openFileButton.setCheckable(False) self.openFileButton.setEnabled(True) self.openFileButton.setIcon(QgsApplication.getThemeIcon("console/iconOpenConsole.png")) self.openFileButton.setMenuRole(QAction.PreferencesRole) self.openFileButton.setIconVisibleInMenu(True) self.openFileButton.setToolTip(openFileBt) self.openFileButton.setText(openFileBt) openExtEditorBt = QCoreApplication.translate("PythonConsole", "Open in External Editor") self.openInEditorButton = QAction(self) self.openInEditorButton.setCheckable(False) self.openInEditorButton.setEnabled(True) self.openInEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconShowEditorConsole.png")) self.openInEditorButton.setMenuRole(QAction.PreferencesRole) self.openInEditorButton.setIconVisibleInMenu(True) self.openInEditorButton.setToolTip(openExtEditorBt) self.openInEditorButton.setText(openExtEditorBt) # Action for Save File saveFileBt = QCoreApplication.translate("PythonConsole", "Save") self.saveFileButton = QAction(self) self.saveFileButton.setCheckable(False) self.saveFileButton.setEnabled(False) self.saveFileButton.setIcon(QgsApplication.getThemeIcon("console/iconSaveConsole.png")) self.saveFileButton.setMenuRole(QAction.PreferencesRole) self.saveFileButton.setIconVisibleInMenu(True) self.saveFileButton.setToolTip(saveFileBt) self.saveFileButton.setText(saveFileBt) # Action for Save File As saveAsFileBt = QCoreApplication.translate("PythonConsole", "Save As...") self.saveAsFileButton = QAction(self) self.saveAsFileButton.setCheckable(False) self.saveAsFileButton.setEnabled(True) self.saveAsFileButton.setIcon(QgsApplication.getThemeIcon("console/iconSaveAsConsole.png")) self.saveAsFileButton.setMenuRole(QAction.PreferencesRole) self.saveAsFileButton.setIconVisibleInMenu(True) self.saveAsFileButton.setToolTip(saveAsFileBt) self.saveAsFileButton.setText(saveAsFileBt) # Action Cut cutEditorBt = QCoreApplication.translate("PythonConsole", "Cut") self.cutEditorButton = QAction(self) self.cutEditorButton.setCheckable(False) self.cutEditorButton.setEnabled(True) self.cutEditorButton.setIcon(QgsApplication.getThemeIcon("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.png")) self.runScriptEditorButton.setMenuRole(QAction.PreferencesRole) self.runScriptEditorButton.setIconVisibleInMenu(True) self.runScriptEditorButton.setToolTip(runScriptEditorBt) self.runScriptEditorButton.setText(runScriptEditorBt) # Action Run Script (subprocess) commentEditorBt = QCoreApplication.translate("PythonConsole", "Comment") self.commentEditorButton = QAction(self) self.commentEditorButton.setCheckable(False) self.commentEditorButton.setEnabled(True) self.commentEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconCommentEditorConsole.png")) self.commentEditorButton.setMenuRole(QAction.PreferencesRole) self.commentEditorButton.setIconVisibleInMenu(True) self.commentEditorButton.setToolTip(commentEditorBt) self.commentEditorButton.setText(commentEditorBt) # Action Run Script (subprocess) uncommentEditorBt = QCoreApplication.translate("PythonConsole", "Uncomment") self.uncommentEditorButton = QAction(self) self.uncommentEditorButton.setCheckable(False) self.uncommentEditorButton.setEnabled(True) self.uncommentEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconUncommentEditorConsole.png")) self.uncommentEditorButton.setMenuRole(QAction.PreferencesRole) self.uncommentEditorButton.setIconVisibleInMenu(True) self.uncommentEditorButton.setToolTip(uncommentEditorBt) self.uncommentEditorButton.setText(uncommentEditorBt) # Action for Object browser objList = QCoreApplication.translate("PythonConsole", "Object Inspector...") self.objectListButton = QAction(self) self.objectListButton.setCheckable(True) self.objectListButton.setEnabled(self.settings.value("pythonConsole/enableObjectInsp", False, type=bool)) self.objectListButton.setIcon(QgsApplication.getThemeIcon("console/iconClassBrowserConsole.png")) self.objectListButton.setMenuRole(QAction.PreferencesRole) self.objectListButton.setIconVisibleInMenu(True) self.objectListButton.setToolTip(objList) self.objectListButton.setText(objList) # Action for Find text findText = QCoreApplication.translate("PythonConsole", "Find Text") self.findTextButton = QAction(self) self.findTextButton.setCheckable(True) self.findTextButton.setEnabled(True) self.findTextButton.setIcon(QgsApplication.getThemeIcon("console/iconSearchEditorConsole.png")) self.findTextButton.setMenuRole(QAction.PreferencesRole) self.findTextButton.setIconVisibleInMenu(True) self.findTextButton.setToolTip(findText) self.findTextButton.setText(findText) # ----------------Toolbar Console------------------------------------- # Action Show Editor showEditor = QCoreApplication.translate("PythonConsole", "Show Editor") self.showEditorButton = QAction(self) self.showEditorButton.setEnabled(True) self.showEditorButton.setCheckable(True) self.showEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconShowEditorConsole.png")) self.showEditorButton.setMenuRole(QAction.PreferencesRole) self.showEditorButton.setIconVisibleInMenu(True) self.showEditorButton.setToolTip(showEditor) self.showEditorButton.setText(showEditor) # Action for Clear button clearBt = QCoreApplication.translate("PythonConsole", "Clear Console") self.clearButton = QAction(self) self.clearButton.setCheckable(False) self.clearButton.setEnabled(True) self.clearButton.setIcon(QgsApplication.getThemeIcon("console/iconClearConsole.png")) self.clearButton.setMenuRole(QAction.PreferencesRole) self.clearButton.setIconVisibleInMenu(True) self.clearButton.setToolTip(clearBt) self.clearButton.setText(clearBt) # Action for settings optionsBt = QCoreApplication.translate("PythonConsole", "Options...") self.optionsButton = QAction(self) self.optionsButton.setCheckable(False) self.optionsButton.setEnabled(True) self.optionsButton.setIcon(QgsApplication.getThemeIcon("console/iconSettingsConsole.png")) self.optionsButton.setMenuRole(QAction.PreferencesRole) self.optionsButton.setIconVisibleInMenu(True) self.optionsButton.setToolTip(optionsBt) self.optionsButton.setText(optionsBt) # Action menu for class actionClassBt = QCoreApplication.translate("PythonConsole", "Import Class") self.actionClass = QAction(self) self.actionClass.setCheckable(False) self.actionClass.setEnabled(True) self.actionClass.setIcon(QgsApplication.getThemeIcon("console/iconClassConsole.png")) self.actionClass.setMenuRole(QAction.PreferencesRole) self.actionClass.setIconVisibleInMenu(True) self.actionClass.setToolTip(actionClassBt) self.actionClass.setText(actionClassBt) # Action for Run script runBt = QCoreApplication.translate("PythonConsole", "Run Command") self.runButton = QAction(self) self.runButton.setCheckable(False) self.runButton.setEnabled(True) self.runButton.setIcon(QgsApplication.getThemeIcon("console/iconRunConsole.png")) self.runButton.setMenuRole(QAction.PreferencesRole) self.runButton.setIconVisibleInMenu(True) self.runButton.setToolTip(runBt) self.runButton.setText(runBt) # Help action helpBt = QCoreApplication.translate("PythonConsole", "Help...") self.helpButton = QAction(self) self.helpButton.setCheckable(False) self.helpButton.setEnabled(True) self.helpButton.setIcon(QgsApplication.getThemeIcon("console/iconHelpConsole.png")) self.helpButton.setMenuRole(QAction.PreferencesRole) self.helpButton.setIconVisibleInMenu(True) self.helpButton.setToolTip(helpBt) self.helpButton.setText(helpBt) self.toolBar = QToolBar() self.toolBar.setEnabled(True) self.toolBar.setFocusPolicy(Qt.NoFocus) self.toolBar.setContextMenuPolicy(Qt.DefaultContextMenu) self.toolBar.setLayoutDirection(Qt.LeftToRight) self.toolBar.setIconSize(QSize(16, 16)) self.toolBar.setMovable(False) self.toolBar.setFloatable(False) self.toolBar.addAction(self.clearButton) self.toolBar.addAction(self.actionClass) self.toolBar.addAction(self.runButton) self.toolBar.addSeparator() self.toolBar.addAction(self.showEditorButton) self.toolBar.addSeparator() self.toolBar.addAction(self.optionsButton) self.toolBar.addAction(self.helpButton) self.toolBarEditor = QToolBar() self.toolBarEditor.setEnabled(False) self.toolBarEditor.setFocusPolicy(Qt.NoFocus) self.toolBarEditor.setContextMenuPolicy(Qt.DefaultContextMenu) self.toolBarEditor.setLayoutDirection(Qt.LeftToRight) self.toolBarEditor.setIconSize(QSize(16, 16)) self.toolBarEditor.setMovable(False) self.toolBarEditor.setFloatable(False) self.toolBarEditor.addAction(self.openFileButton) self.toolBarEditor.addAction(self.openInEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.saveFileButton) self.toolBarEditor.addAction(self.saveAsFileButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.runScriptEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.findTextButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.cutEditorButton) self.toolBarEditor.addAction(self.copyEditorButton) self.toolBarEditor.addAction(self.pasteEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.commentEditorButton) self.toolBarEditor.addAction(self.uncommentEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.objectListButton) # Menu Import Class default_command = { (QCoreApplication.translate("PythonConsole", "Import Processing Class"), QgsApplication.getThemeIcon("console/iconProcessingConsole.png")): ["import processing"], (QCoreApplication.translate("PythonConsole", "Import PyQt.QtCore Class"), QgsApplication.getThemeIcon("console/iconQtCoreConsole.png")): ["from qgis.PyQt.QtCore import *"], (QCoreApplication.translate("PythonConsole", "Import PyQt.QtGui Class"), QgsApplication.getThemeIcon("console/iconQtGuiConsole.png")): ["from qgis.PyQt.QtGui import *", "from qgis.PyQt.QtWidgets import *"] } self.classMenu = QMenu() for (title, icon), commands in list(default_command.items()): action = self.classMenu.addAction(icon, title) action.triggered.connect(partial(self.shell.commandConsole, commands)) cM = self.toolBar.widgetForAction(self.actionClass) cM.setMenu(self.classMenu) cM.setPopupMode(QToolButton.InstantPopup) self.widgetButton = QWidget() sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.widgetButton.sizePolicy().hasHeightForWidth()) self.widgetButton.setSizePolicy(sizePolicy) self.widgetButtonEditor = QWidget(self.widgetEditor) sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.widgetButtonEditor.sizePolicy().hasHeightForWidth()) self.widgetButtonEditor.setSizePolicy(sizePolicy) sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.shellOut.sizePolicy().hasHeightForWidth()) self.shellOut.setSizePolicy(sizePolicy) self.shellOut.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.shell.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) # ------------ Layout ------------------------------- self.mainLayout = QGridLayout(self) self.mainLayout.setMargin(0) self.mainLayout.setSpacing(0) self.mainLayout.addWidget(self.widgetButton, 0, 0, 1, 1) self.mainLayout.addWidget(self.splitterEditor, 0, 1, 1, 1) self.shellOutWidget.layout().insertWidget(0, self.toolBar) self.layoutEditor = QGridLayout(self.widgetEditor) self.layoutEditor.setMargin(0) self.layoutEditor.setSpacing(0) self.layoutEditor.addWidget(self.toolBarEditor, 0, 1, 1, 1) self.layoutEditor.addWidget(self.widgetButtonEditor, 1, 0, 2, 1) self.layoutEditor.addWidget(self.tabEditorWidget, 1, 1, 1, 1) self.layoutEditor.addWidget(self.widgetFind, 2, 1, 1, 1) # Layout for the find widget self.layoutFind = QGridLayout(self.widgetFind) self.layoutFind.setContentsMargins(0, 0, 0, 0) self.lineEditFind = QgsFilterLineEdit() placeHolderTxt = QCoreApplication.translate("PythonConsole", "Enter text to find...") self.lineEditFind.setPlaceholderText(placeHolderTxt) self.findNextButton = QToolButton() self.findNextButton.setEnabled(False) toolTipfindNext = QCoreApplication.translate("PythonConsole", "Find Next") self.findNextButton.setToolTip(toolTipfindNext) self.findNextButton.setIcon(QgsApplication.getThemeIcon("console/iconSearchNextEditorConsole.png")) self.findNextButton.setIconSize(QSize(24, 24)) self.findNextButton.setAutoRaise(True) self.findPrevButton = QToolButton() self.findPrevButton.setEnabled(False) toolTipfindPrev = QCoreApplication.translate("PythonConsole", "Find Previous") self.findPrevButton.setToolTip(toolTipfindPrev) self.findPrevButton.setIcon(QgsApplication.getThemeIcon("console/iconSearchPrevEditorConsole.png")) self.findPrevButton.setIconSize(QSize(24, 24)) self.findPrevButton.setAutoRaise(True) self.caseSensitive = QCheckBox() caseSensTr = QCoreApplication.translate("PythonConsole", "Case Sensitive") self.caseSensitive.setText(caseSensTr) self.wholeWord = QCheckBox() wholeWordTr = QCoreApplication.translate("PythonConsole", "Whole Word") self.wholeWord.setText(wholeWordTr) self.wrapAround = QCheckBox() self.wrapAround.setChecked(True) wrapAroundTr = QCoreApplication.translate("PythonConsole", "Wrap Around") self.wrapAround.setText(wrapAroundTr) self.layoutFind.addWidget(self.lineEditFind, 0, 1, 1, 1) self.layoutFind.addWidget(self.findPrevButton, 0, 2, 1, 1) self.layoutFind.addWidget(self.findNextButton, 0, 3, 1, 1) self.layoutFind.addWidget(self.caseSensitive, 0, 4, 1, 1) self.layoutFind.addWidget(self.wholeWord, 0, 5, 1, 1) self.layoutFind.addWidget(self.wrapAround, 0, 6, 1, 1) # ------------ Add first Tab in Editor ------------------------------- # self.tabEditorWidget.newTabEditor(tabName='first', filename=None) # ------------ Signal ------------------------------- self.findTextButton.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.clicked.connect(self._findNext) self.findPrevButton.clicked.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.home()) 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): QgsContextHelp.run("PythonConsole") def openSettings(self): if optionsDialog(self).exec_(): self.shell.refreshSettingsShell() self.shellOut.refreshSettingsOutput() self.tabEditorWidget.refreshSettingsEditor() def callWidgetMessageBar(self, text): self.shellOut.widgetMessageBar(iface, text) def callWidgetMessageBarEditor(self, text, level, timed): self.tabEditorWidget.widgetMessageBar(iface, text, level, timed) def updateTabListScript(self, script, action=None): if action == 'remove': self.tabListScript.remove(script) elif action == 'append': if not self.tabListScript: self.tabListScript = [] if script not in self.tabListScript: self.tabListScript.append(script) else: self.tabListScript = [] self.settings.setValue("pythonConsole/tabScripts", self.tabListScript) def saveSettingsConsole(self): self.settings.setValue("pythonConsole/splitterConsole", self.splitter.saveState()) self.settings.setValue("pythonConsole/splitterObj", self.splitterObj.saveState()) self.settings.setValue("pythonConsole/splitterEditor", self.splitterEditor.saveState()) self.shell.writeHistoryFile(True) def restoreSettingsConsole(self): storedTabScripts = self.settings.value("pythonConsole/tabScripts", []) self.tabListScript = storedTabScripts self.splitter.restoreState(self.settings.value("pythonConsole/splitterConsole", QByteArray())) self.splitterEditor.restoreState(self.settings.value("pythonConsole/splitterEditor", QByteArray())) self.splitterObj.restoreState(self.settings.value("pythonConsole/splitterObj", QByteArray()))
def createWidget(self): if self.dialogType == DIALOG_STANDARD: widget = QWidget() layout = QHBoxLayout() layout.setMargin(0) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(2) self.combo = QgsMapLayerComboBox() layout.addWidget(self.combo) btn = QToolButton() btn.setText('...') btn.setToolTip(self.tr("Select file")) btn.clicked.connect(self.selectFile) layout.addWidget(btn) widget.setLayout(layout) filters = QgsMapLayerProxyModel.Filters() if self.param.datatype == [-1] or -1 in self.param.datatype: filters = QgsMapLayerProxyModel.HasGeometry if QgsWkbTypes.PointGeometry in self.param.datatype: filters |= QgsMapLayerProxyModel.PointLayer if QgsWkbTypes.LineGeometry in self.param.datatype: filters |= QgsMapLayerProxyModel.LineLayer if QgsWkbTypes.PolygonGeometry in self.param.datatype: filters |= QgsMapLayerProxyModel.PolygonLayer try: if iface.activeLayer().type() == QgsMapLayer.VectorLayer: self.combo.setLayer(iface.activeLayer()) except: pass if self.param.optional: self.combo.setAllowEmptyLayer(True) if ProcessingConfig.getSetting(ProcessingConfig.SHOW_CRS_DEF): self.combo.setShowCrs(True) self.combo.setFilters(filters) self.combo.setExcludedProviders(['grass']) self.combo.currentIndexChanged.connect( lambda: self.widgetValueHasChanged.emit(self)) self.combo.currentTextChanged.connect( lambda: self.widgetValueHasChanged.emit(self)) return widget elif self.dialogType == DIALOG_BATCH: widget = BatchInputSelectionPanel(self.param, self.row, self.col, self.dialog) widget.valueChanged.connect( lambda: self.widgetValueHasChanged.emit(self)) return widget else: self.combo = QComboBox() layers = self.dialog.getAvailableValuesOfType( ParameterVector, OutputVector) self.combo.setEditable(True) for layer in layers: self.combo.addItem(self.dialog.resolveValueDescription(layer), layer) if self.param.optional: self.combo.setEditText("") widget = QWidget() layout = QHBoxLayout() layout.setMargin(0) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(2) layout.addWidget(self.combo) btn = QToolButton() btn.setText('...') btn.setToolTip(self.tr("Select file")) btn.clicked.connect(self.selectFile) layout.addWidget(btn) widget.setLayout(layout) return widget
def __init__(self, alg): super(AlgorithmDialogBase, self).__init__(iface.mainWindow() if iface else None) self.setupUi(self) # don't collapse parameters panel self.splitter.setCollapsible(0, False) # add collapse button to splitter splitterHandle = self.splitter.handle(1) handleLayout = QVBoxLayout() handleLayout.setContentsMargins(0, 0, 0, 0) self.btnCollapse = QToolButton(splitterHandle) self.btnCollapse.setAutoRaise(True) self.btnCollapse.setFixedSize(12, 12) self.btnCollapse.setCursor(Qt.ArrowCursor) handleLayout.addWidget(self.btnCollapse) handleLayout.addStretch() splitterHandle.setLayout(handleLayout) self.settings = QgsSettings() self.splitter.restoreState( self.settings.value("/Processing/dialogBaseSplitter", QByteArray())) self.restoreGeometry( self.settings.value("/Processing/dialogBase", QByteArray())) self.splitterState = self.splitter.saveState() self.splitterChanged(0, 0) self.executed = False self.mainWidget = None self.alg = alg self.setWindowTitle(self.alg.displayName()) self.buttonBox.rejected.connect(self.reject) self.buttonBox.accepted.connect(self.accept) # Rename OK button to Run self.btnRun = self.buttonBox.button(QDialogButtonBox.Ok) self.btnRun.setText(self.tr('Run')) self.buttonCancel.setEnabled(False) self.btnClose = self.buttonBox.button(QDialogButtonBox.Close) self.buttonBox.helpRequested.connect(self.openHelp) self.btnCollapse.clicked.connect(self.toggleCollapsed) self.splitter.splitterMoved.connect(self.splitterChanged) # desktop = QDesktopWidget() # if desktop.physicalDpiX() > 96: # self.txtHelp.setZoomFactor(desktop.physicalDpiX() / 96) algHelp = self.formatHelp(self.alg) if algHelp is None: self.textShortHelp.hide() else: self.textShortHelp.document().setDefaultStyleSheet( '''.summary { margin-left: 10px; margin-right: 10px; } h2 { color: #555555; padding-bottom: 15px; } a { text-decoration: none; color: #3498db; font-weight: bold; } p { color: #666666; } b { color: #333333; } dl dd { margin-bottom: 5px; }''' ) self.textShortHelp.setHtml(algHelp) def linkClicked(url): webbrowser.open(url.toString()) self.textShortHelp.anchorClicked.connect(linkClicked) self.showDebug = ProcessingConfig.getSetting( ProcessingConfig.SHOW_DEBUG_IN_DIALOG)
class ModelerDialog(BASE, WIDGET): ALG_ITEM = 'ALG_ITEM' PROVIDER_ITEM = 'PROVIDER_ITEM' GROUP_ITEM = 'GROUP_ITEM' NAME_ROLE = Qt.UserRole TAG_ROLE = Qt.UserRole + 1 TYPE_ROLE = Qt.UserRole + 2 CANVAS_SIZE = 4000 update_model = pyqtSignal() def __init__(self, model=None): super().__init__(None) self.setAttribute(Qt.WA_DeleteOnClose) self.setupUi(self) self._variables_scope = None # LOTS of bug reports when we include the dock creation in the UI file # see e.g. #16428, #19068 # So just roll it all by hand......! self.propertiesDock = QgsDockWidget(self) self.propertiesDock.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable) self.propertiesDock.setObjectName("propertiesDock") propertiesDockContents = QWidget() self.verticalDockLayout_1 = QVBoxLayout(propertiesDockContents) self.verticalDockLayout_1.setContentsMargins(0, 0, 0, 0) self.verticalDockLayout_1.setSpacing(0) self.scrollArea_1 = QgsScrollArea(propertiesDockContents) sizePolicy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.scrollArea_1.sizePolicy().hasHeightForWidth()) self.scrollArea_1.setSizePolicy(sizePolicy) self.scrollArea_1.setFocusPolicy(Qt.WheelFocus) self.scrollArea_1.setFrameShape(QFrame.NoFrame) self.scrollArea_1.setFrameShadow(QFrame.Plain) self.scrollArea_1.setWidgetResizable(True) self.scrollAreaWidgetContents_1 = QWidget() self.gridLayout = QGridLayout(self.scrollAreaWidgetContents_1) self.gridLayout.setContentsMargins(6, 6, 6, 6) self.gridLayout.setSpacing(4) self.label_1 = QLabel(self.scrollAreaWidgetContents_1) self.gridLayout.addWidget(self.label_1, 0, 0, 1, 1) self.textName = QLineEdit(self.scrollAreaWidgetContents_1) self.gridLayout.addWidget(self.textName, 0, 1, 1, 1) self.label_2 = QLabel(self.scrollAreaWidgetContents_1) self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1) self.textGroup = QLineEdit(self.scrollAreaWidgetContents_1) self.gridLayout.addWidget(self.textGroup, 1, 1, 1, 1) self.label_1.setText(self.tr("Name")) self.textName.setToolTip(self.tr("Enter model name here")) self.label_2.setText(self.tr("Group")) self.textGroup.setToolTip(self.tr("Enter group name here")) self.scrollArea_1.setWidget(self.scrollAreaWidgetContents_1) self.verticalDockLayout_1.addWidget(self.scrollArea_1) self.propertiesDock.setWidget(propertiesDockContents) self.propertiesDock.setWindowTitle(self.tr("Model Properties")) self.inputsDock = QgsDockWidget(self) self.inputsDock.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable) self.inputsDock.setObjectName("inputsDock") self.inputsDockContents = QWidget() self.verticalLayout_3 = QVBoxLayout(self.inputsDockContents) self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) self.scrollArea_2 = QgsScrollArea(self.inputsDockContents) sizePolicy.setHeightForWidth( self.scrollArea_2.sizePolicy().hasHeightForWidth()) self.scrollArea_2.setSizePolicy(sizePolicy) self.scrollArea_2.setFocusPolicy(Qt.WheelFocus) self.scrollArea_2.setFrameShape(QFrame.NoFrame) self.scrollArea_2.setFrameShadow(QFrame.Plain) self.scrollArea_2.setWidgetResizable(True) self.scrollAreaWidgetContents_2 = QWidget() self.verticalLayout = QVBoxLayout(self.scrollAreaWidgetContents_2) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setSpacing(0) self.inputsTree = QTreeWidget(self.scrollAreaWidgetContents_2) self.inputsTree.setAlternatingRowColors(True) self.inputsTree.header().setVisible(False) self.verticalLayout.addWidget(self.inputsTree) self.scrollArea_2.setWidget(self.scrollAreaWidgetContents_2) self.verticalLayout_3.addWidget(self.scrollArea_2) self.inputsDock.setWidget(self.inputsDockContents) self.addDockWidget(Qt.DockWidgetArea(1), self.inputsDock) self.inputsDock.setWindowTitle(self.tr("Inputs")) self.algorithmsDock = QgsDockWidget(self) self.algorithmsDock.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable) self.algorithmsDock.setObjectName("algorithmsDock") self.algorithmsDockContents = QWidget() self.verticalLayout_4 = QVBoxLayout(self.algorithmsDockContents) self.verticalLayout_4.setContentsMargins(0, 0, 0, 0) self.scrollArea_3 = QgsScrollArea(self.algorithmsDockContents) sizePolicy.setHeightForWidth( self.scrollArea_3.sizePolicy().hasHeightForWidth()) self.scrollArea_3.setSizePolicy(sizePolicy) self.scrollArea_3.setFocusPolicy(Qt.WheelFocus) self.scrollArea_3.setFrameShape(QFrame.NoFrame) self.scrollArea_3.setFrameShadow(QFrame.Plain) self.scrollArea_3.setWidgetResizable(True) self.scrollAreaWidgetContents_3 = QWidget() self.verticalLayout_2 = QVBoxLayout(self.scrollAreaWidgetContents_3) self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) self.verticalLayout_2.setSpacing(4) self.searchBox = QgsFilterLineEdit(self.scrollAreaWidgetContents_3) self.verticalLayout_2.addWidget(self.searchBox) self.algorithmTree = QgsProcessingToolboxTreeView( None, QgsApplication.processingRegistry()) self.algorithmTree.setAlternatingRowColors(True) self.algorithmTree.header().setVisible(False) self.verticalLayout_2.addWidget(self.algorithmTree) self.scrollArea_3.setWidget(self.scrollAreaWidgetContents_3) self.verticalLayout_4.addWidget(self.scrollArea_3) self.algorithmsDock.setWidget(self.algorithmsDockContents) self.addDockWidget(Qt.DockWidgetArea(1), self.algorithmsDock) self.algorithmsDock.setWindowTitle(self.tr("Algorithms")) self.searchBox.setToolTip( self.tr("Enter algorithm name to filter list")) self.searchBox.setShowSearchIcon(True) self.variables_dock = QgsDockWidget(self) self.variables_dock.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable) self.variables_dock.setObjectName("variablesDock") self.variables_dock_contents = QWidget() vl_v = QVBoxLayout() vl_v.setContentsMargins(0, 0, 0, 0) self.variables_editor = QgsVariableEditorWidget() vl_v.addWidget(self.variables_editor) self.variables_dock_contents.setLayout(vl_v) self.variables_dock.setWidget(self.variables_dock_contents) self.addDockWidget(Qt.DockWidgetArea(1), self.variables_dock) self.variables_dock.setWindowTitle(self.tr("Variables")) self.addDockWidget(Qt.DockWidgetArea(1), self.propertiesDock) self.tabifyDockWidget(self.propertiesDock, self.variables_dock) self.variables_editor.scopeChanged.connect(self.variables_changed) self.bar = QgsMessageBar() self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed) self.centralWidget().layout().insertWidget(0, self.bar) try: self.setDockOptions(self.dockOptions() | QMainWindow.GroupedDragging) except: pass if iface is not None: self.mToolbar.setIconSize(iface.iconSize()) self.setStyleSheet(iface.mainWindow().styleSheet()) self.toolbutton_export_to_script = QToolButton() self.toolbutton_export_to_script.setPopupMode(QToolButton.InstantPopup) self.export_to_script_algorithm_action = QAction( QCoreApplication.translate('ModelerDialog', 'Export as Script Algorithm…')) self.toolbutton_export_to_script.addActions( [self.export_to_script_algorithm_action]) self.mToolbar.insertWidget(self.mActionExportImage, self.toolbutton_export_to_script) self.export_to_script_algorithm_action.triggered.connect( self.export_as_script_algorithm) self.mActionOpen.setIcon( QgsApplication.getThemeIcon('/mActionFileOpen.svg')) self.mActionSave.setIcon( QgsApplication.getThemeIcon('/mActionFileSave.svg')) self.mActionSaveAs.setIcon( QgsApplication.getThemeIcon('/mActionFileSaveAs.svg')) self.mActionSaveInProject.setIcon( QgsApplication.getThemeIcon('/mAddToProject.svg')) self.mActionZoomActual.setIcon( QgsApplication.getThemeIcon('/mActionZoomActual.svg')) self.mActionZoomIn.setIcon( QgsApplication.getThemeIcon('/mActionZoomIn.svg')) self.mActionZoomOut.setIcon( QgsApplication.getThemeIcon('/mActionZoomOut.svg')) self.mActionExportImage.setIcon( QgsApplication.getThemeIcon('/mActionSaveMapAsImage.svg')) self.mActionZoomToItems.setIcon( QgsApplication.getThemeIcon('/mActionZoomFullExtent.svg')) self.mActionExportPdf.setIcon( QgsApplication.getThemeIcon('/mActionSaveAsPDF.svg')) self.mActionExportSvg.setIcon( QgsApplication.getThemeIcon('/mActionSaveAsSVG.svg')) self.toolbutton_export_to_script.setIcon( QgsApplication.getThemeIcon('/mActionSaveAsPython.svg')) self.mActionEditHelp.setIcon( QgsApplication.getThemeIcon('/mActionEditHelpContent.svg')) self.mActionRun.setIcon( QgsApplication.getThemeIcon('/mActionStart.svg')) self.addDockWidget(Qt.LeftDockWidgetArea, self.propertiesDock) self.addDockWidget(Qt.LeftDockWidgetArea, self.inputsDock) self.addDockWidget(Qt.LeftDockWidgetArea, self.algorithmsDock) self.tabifyDockWidget(self.inputsDock, self.algorithmsDock) self.inputsDock.raise_() self.setWindowFlags(Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint | Qt.WindowCloseButtonHint) settings = QgsSettings() self.restoreState( settings.value("/Processing/stateModeler", QByteArray())) self.restoreGeometry( settings.value("/Processing/geometryModeler", QByteArray())) self.scene = ModelerScene(self, dialog=self) self.scene.setSceneRect( QRectF(0, 0, self.CANVAS_SIZE, self.CANVAS_SIZE)) self.view.setScene(self.scene) self.view.setAcceptDrops(True) self.view.ensureVisible(0, 0, 10, 10) self.view.scale(QgsApplication.desktop().logicalDpiX() / 96, QgsApplication.desktop().logicalDpiX() / 96) def _dragEnterEvent(event): if event.mimeData().hasText() or event.mimeData().hasFormat( 'application/x-vnd.qgis.qgis.algorithmid'): event.acceptProposedAction() else: event.ignore() def _dropEvent(event): def alg_dropped(algorithm_id, pos): alg = QgsApplication.processingRegistry().createAlgorithmById( algorithm_id) if alg is not None: self._addAlgorithm(alg, pos) else: assert False, algorithm_id def input_dropped(id, pos): if id in [ param.id() for param in QgsApplication.instance(). processingRegistry().parameterTypes() ]: self.addInputOfType(itemId, pos) if event.mimeData().hasFormat( 'application/x-vnd.qgis.qgis.algorithmid'): data = event.mimeData().data( 'application/x-vnd.qgis.qgis.algorithmid') stream = QDataStream(data, QIODevice.ReadOnly) algorithm_id = stream.readQString() QTimer.singleShot( 0, lambda id=algorithm_id, pos=self.view.mapToScene(event.pos( )): alg_dropped(id, pos)) event.accept() elif event.mimeData().hasText(): itemId = event.mimeData().text() QTimer.singleShot(0, lambda id=itemId, pos=self.view.mapToScene( event.pos()): input_dropped(id, pos)) event.accept() else: event.ignore() def _dragMoveEvent(event): if event.mimeData().hasText() or event.mimeData().hasFormat( 'application/x-vnd.qgis.qgis.algorithmid'): event.accept() else: event.ignore() def _wheelEvent(event): self.view.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) settings = QgsSettings() factor = settings.value('/qgis/zoom_favor', 2.0) # "Normal" mouse has an angle delta of 120, precision mouses provide data # faster, in smaller steps factor = 1.0 + (factor - 1.0) / 120.0 * abs(event.angleDelta().y()) if (event.modifiers() == Qt.ControlModifier): factor = 1.0 + (factor - 1.0) / 20.0 if event.angleDelta().y() < 0: factor = 1 / factor self.view.scale(factor, factor) def _enterEvent(e): QGraphicsView.enterEvent(self.view, e) self.view.viewport().setCursor(Qt.ArrowCursor) def _mouseReleaseEvent(e): QGraphicsView.mouseReleaseEvent(self.view, e) self.view.viewport().setCursor(Qt.ArrowCursor) def _mousePressEvent(e): if e.button() == Qt.MidButton: self.previousMousePos = e.pos() else: QGraphicsView.mousePressEvent(self.view, e) def _mouseMoveEvent(e): if e.buttons() == Qt.MidButton: offset = self.previousMousePos - e.pos() self.previousMousePos = e.pos() self.view.verticalScrollBar().setValue( self.view.verticalScrollBar().value() + offset.y()) self.view.horizontalScrollBar().setValue( self.view.horizontalScrollBar().value() + offset.x()) else: QGraphicsView.mouseMoveEvent(self.view, e) self.view.setDragMode(QGraphicsView.ScrollHandDrag) self.view.dragEnterEvent = _dragEnterEvent self.view.dropEvent = _dropEvent self.view.dragMoveEvent = _dragMoveEvent self.view.wheelEvent = _wheelEvent self.view.enterEvent = _enterEvent self.view.mousePressEvent = _mousePressEvent self.view.mouseMoveEvent = _mouseMoveEvent def _mimeDataInput(items): mimeData = QMimeData() text = items[0].data(0, Qt.UserRole) mimeData.setText(text) return mimeData self.inputsTree.mimeData = _mimeDataInput self.inputsTree.setDragDropMode(QTreeWidget.DragOnly) self.inputsTree.setDropIndicatorShown(True) self.algorithms_model = ModelerToolboxModel( self, QgsApplication.processingRegistry()) self.algorithmTree.setToolboxProxyModel(self.algorithms_model) self.algorithmTree.setDragDropMode(QTreeWidget.DragOnly) self.algorithmTree.setDropIndicatorShown(True) filters = QgsProcessingToolboxProxyModel.Filters( QgsProcessingToolboxProxyModel.FilterModeler) if ProcessingConfig.getSetting( ProcessingConfig.SHOW_ALGORITHMS_KNOWN_ISSUES): filters |= QgsProcessingToolboxProxyModel.FilterShowKnownIssues self.algorithmTree.setFilters(filters) if hasattr(self.searchBox, 'setPlaceholderText'): self.searchBox.setPlaceholderText( QCoreApplication.translate('ModelerDialog', 'Search…')) if hasattr(self.textName, 'setPlaceholderText'): self.textName.setPlaceholderText(self.tr('Enter model name here')) if hasattr(self.textGroup, 'setPlaceholderText'): self.textGroup.setPlaceholderText(self.tr('Enter group name here')) # Connect signals and slots self.inputsTree.doubleClicked.connect(self.addInput) self.searchBox.textChanged.connect(self.algorithmTree.setFilterString) self.algorithmTree.doubleClicked.connect(self.addAlgorithm) # Ctrl+= should also trigger a zoom in action ctrlEquals = QShortcut(QKeySequence("Ctrl+="), self) ctrlEquals.activated.connect(self.zoomIn) self.mActionOpen.triggered.connect(self.openModel) self.mActionSave.triggered.connect(self.save) self.mActionSaveAs.triggered.connect(self.saveAs) self.mActionSaveInProject.triggered.connect(self.saveInProject) self.mActionZoomIn.triggered.connect(self.zoomIn) self.mActionZoomOut.triggered.connect(self.zoomOut) self.mActionZoomActual.triggered.connect(self.zoomActual) self.mActionZoomToItems.triggered.connect(self.zoomToItems) self.mActionExportImage.triggered.connect(self.exportAsImage) self.mActionExportPdf.triggered.connect(self.exportAsPdf) self.mActionExportSvg.triggered.connect(self.exportAsSvg) #self.mActionExportPython.triggered.connect(self.exportAsPython) self.mActionEditHelp.triggered.connect(self.editHelp) self.mActionRun.triggered.connect(self.runModel) if model is not None: self.model = model.create() self.model.setSourceFilePath(model.sourceFilePath()) self.textGroup.setText(self.model.group()) self.textName.setText(self.model.displayName()) self.repaintModel() else: self.model = QgsProcessingModelAlgorithm() self.model.setProvider( QgsApplication.processingRegistry().providerById('model')) self.update_variables_gui() self.fillInputsTree() self.view.centerOn(0, 0) self.help = None self.hasChanged = False def closeEvent(self, evt): settings = QgsSettings() settings.setValue("/Processing/stateModeler", self.saveState()) settings.setValue("/Processing/geometryModeler", self.saveGeometry()) if self.hasChanged: ret = QMessageBox.question( self, self.tr('Save Model?'), self. tr('There are unsaved changes in this model. Do you want to keep those?' ), QMessageBox.Save | QMessageBox.Cancel | QMessageBox.Discard, QMessageBox.Cancel) if ret == QMessageBox.Save: self.saveModel(False) evt.accept() elif ret == QMessageBox.Discard: evt.accept() else: evt.ignore() else: evt.accept() def editHelp(self): alg = self.model dlg = HelpEditionDialog(alg) dlg.exec_() if dlg.descriptions: self.model.setHelpContent(dlg.descriptions) self.hasChanged = True def update_variables_gui(self): variables_scope = QgsExpressionContextScope(self.tr('Model Variables')) for k, v in self.model.variables().items(): variables_scope.setVariable(k, v) variables_context = QgsExpressionContext() variables_context.appendScope(variables_scope) self.variables_editor.setContext(variables_context) self.variables_editor.setEditableScopeIndex(0) def variables_changed(self): self.model.setVariables(self.variables_editor.variablesInActiveScope()) def runModel(self): if len(self.model.childAlgorithms()) == 0: self.bar.pushMessage( "", self. tr("Model doesn't contain any algorithm and/or parameter and can't be executed" ), level=Qgis.Warning, duration=5) return dlg = AlgorithmDialog(self.model.create(), parent=iface.mainWindow()) dlg.exec_() def save(self): self.saveModel(False) def saveAs(self): self.saveModel(True) def saveInProject(self): if not self.can_save(): return self.model.setName(str(self.textName.text())) self.model.setGroup(str(self.textGroup.text())) self.model.setSourceFilePath(None) project_provider = QgsApplication.processingRegistry().providerById( PROJECT_PROVIDER_ID) project_provider.add_model(self.model) self.update_model.emit() self.bar.pushMessage("", self.tr("Model was saved inside current project"), level=Qgis.Success, duration=5) self.hasChanged = False QgsProject.instance().setDirty(True) def zoomIn(self): self.view.setTransformationAnchor(QGraphicsView.NoAnchor) point = self.view.mapToScene( QPoint(self.view.viewport().width() / 2, self.view.viewport().height() / 2)) settings = QgsSettings() factor = settings.value('/qgis/zoom_favor', 2.0) self.view.scale(factor, factor) self.view.centerOn(point) self.repaintModel() def zoomOut(self): self.view.setTransformationAnchor(QGraphicsView.NoAnchor) point = self.view.mapToScene( QPoint(self.view.viewport().width() / 2, self.view.viewport().height() / 2)) settings = QgsSettings() factor = settings.value('/qgis/zoom_favor', 2.0) factor = 1 / factor self.view.scale(factor, factor) self.view.centerOn(point) self.repaintModel() def zoomActual(self): point = self.view.mapToScene( QPoint(self.view.viewport().width() / 2, self.view.viewport().height() / 2)) self.view.resetTransform() self.view.scale(QgsApplication.desktop().logicalDpiX() / 96, QgsApplication.desktop().logicalDpiX() / 96) self.view.centerOn(point) def zoomToItems(self): totalRect = self.scene.itemsBoundingRect() totalRect.adjust(-10, -10, 10, 10) self.view.fitInView(totalRect, Qt.KeepAspectRatio) def exportAsImage(self): self.repaintModel(controls=False) filename, fileFilter = QFileDialog.getSaveFileName( self, self.tr('Save Model As Image'), '', self.tr('PNG files (*.png *.PNG)')) if not filename: return if not filename.lower().endswith('.png'): filename += '.png' totalRect = self.scene.itemsBoundingRect() totalRect.adjust(-10, -10, 10, 10) imgRect = QRectF(0, 0, totalRect.width(), totalRect.height()) img = QImage(totalRect.width(), totalRect.height(), QImage.Format_ARGB32_Premultiplied) img.fill(Qt.white) painter = QPainter() painter.setRenderHint(QPainter.Antialiasing) painter.begin(img) self.scene.render(painter, imgRect, totalRect) painter.end() img.save(filename) self.bar.pushMessage( "", self.tr( "Successfully exported model as image to <a href=\"{}\">{}</a>" ).format( QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5) self.repaintModel(controls=True) def exportAsPdf(self): self.repaintModel(controls=False) filename, fileFilter = QFileDialog.getSaveFileName( self, self.tr('Save Model As PDF'), '', self.tr('PDF files (*.pdf *.PDF)')) if not filename: return if not filename.lower().endswith('.pdf'): filename += '.pdf' totalRect = self.scene.itemsBoundingRect() totalRect.adjust(-10, -10, 10, 10) printerRect = QRectF(0, 0, totalRect.width(), totalRect.height()) printer = QPrinter() printer.setOutputFormat(QPrinter.PdfFormat) printer.setOutputFileName(filename) printer.setPaperSize(QSizeF(printerRect.width(), printerRect.height()), QPrinter.DevicePixel) printer.setFullPage(True) painter = QPainter(printer) self.scene.render(painter, printerRect, totalRect) painter.end() self.bar.pushMessage( "", self.tr( "Successfully exported model as PDF to <a href=\"{}\">{}</a>"). format( QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5) self.repaintModel(controls=True) def exportAsSvg(self): self.repaintModel(controls=False) filename, fileFilter = QFileDialog.getSaveFileName( self, self.tr('Save Model As SVG'), '', self.tr('SVG files (*.svg *.SVG)')) if not filename: return if not filename.lower().endswith('.svg'): filename += '.svg' totalRect = self.scene.itemsBoundingRect() totalRect.adjust(-10, -10, 10, 10) svgRect = QRectF(0, 0, totalRect.width(), totalRect.height()) svg = QSvgGenerator() svg.setFileName(filename) svg.setSize(QSize(totalRect.width(), totalRect.height())) svg.setViewBox(svgRect) svg.setTitle(self.model.displayName()) painter = QPainter(svg) self.scene.render(painter, svgRect, totalRect) painter.end() self.bar.pushMessage( "", self.tr( "Successfully exported model as SVG to <a href=\"{}\">{}</a>"). format( QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5) self.repaintModel(controls=True) def exportAsPython(self): filename, filter = QFileDialog.getSaveFileName( self, self.tr('Save Model As Python Script'), '', self.tr('Processing scripts (*.py *.PY)')) if not filename: return if not filename.lower().endswith('.py'): filename += '.py' text = self.model.asPythonCode() with codecs.open(filename, 'w', encoding='utf-8') as fout: fout.write(text) self.bar.pushMessage( "", self. tr("Successfully exported model as python script to <a href=\"{}\">{}</a>" ).format( QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5) def can_save(self): """ Tests whether a model can be saved, or if it is not yet valid :return: bool """ if str(self.textName.text()).strip() == '': self.bar.pushWarning( "", self.tr('Please a enter model name before saving')) return False return True def saveModel(self, saveAs): if not self.can_save(): return self.model.setName(str(self.textName.text())) self.model.setGroup(str(self.textGroup.text())) if self.model.sourceFilePath() and not saveAs: filename = self.model.sourceFilePath() else: filename, filter = QFileDialog.getSaveFileName( self, self.tr('Save Model'), ModelerUtils.modelsFolders()[0], self.tr('Processing models (*.model3 *.MODEL3)')) if filename: if not filename.endswith('.model3'): filename += '.model3' self.model.setSourceFilePath(filename) if filename: if not self.model.toFile(filename): if saveAs: QMessageBox.warning( self, self.tr('I/O error'), self.tr('Unable to save edits. Reason:\n {0}').format( str(sys.exc_info()[1]))) else: QMessageBox.warning( self, self.tr("Can't save model"), QCoreApplication. translate('QgsPluginInstallerInstallingDialog', ( "This model can't be saved in its original location (probably you do not " "have permission to do it). Please, use the 'Save as…' option." ))) return self.update_model.emit() if saveAs: self.bar.pushMessage( "", self.tr( "Model was correctly saved to <a href=\"{}\">{}</a>"). format( QUrl.fromLocalFile(filename).toString(), QDir.toNativeSeparators(filename)), level=Qgis.Success, duration=5) else: self.bar.pushMessage("", self.tr("Model was correctly saved"), level=Qgis.Success, duration=5) self.hasChanged = False def openModel(self): filename, selected_filter = QFileDialog.getOpenFileName( self, self.tr('Open Model'), ModelerUtils.modelsFolders()[0], self.tr('Processing models (*.model3 *.MODEL3)')) if filename: self.loadModel(filename) def loadModel(self, filename): alg = QgsProcessingModelAlgorithm() if alg.fromFile(filename): self.model = alg self.model.setProvider( QgsApplication.processingRegistry().providerById('model')) self.textGroup.setText(alg.group()) self.textName.setText(alg.name()) self.repaintModel() self.update_variables_gui() self.view.centerOn(0, 0) self.hasChanged = False else: QgsMessageLog.logMessage( self.tr('Could not load model {0}').format(filename), self.tr('Processing'), Qgis.Critical) QMessageBox.critical( self, self.tr('Open Model'), self.tr('The selected model could not be loaded.\n' 'See the log for more information.')) def repaintModel(self, controls=True): self.scene = ModelerScene(self, dialog=self) self.scene.setSceneRect( QRectF(0, 0, self.CANVAS_SIZE, self.CANVAS_SIZE)) self.scene.paintModel(self.model, controls) self.view.setScene(self.scene) def addInput(self): item = self.inputsTree.currentItem() param = item.data(0, Qt.UserRole) self.addInputOfType(param) def addInputOfType(self, paramType, pos=None): dlg = ModelerParameterDefinitionDialog(self.model, paramType) dlg.exec_() if dlg.param is not None: if pos is None: pos = self.getPositionForParameterItem() if isinstance(pos, QPoint): pos = QPointF(pos) component = QgsProcessingModelParameter(dlg.param.name()) component.setDescription(dlg.param.name()) component.setPosition(pos) self.model.addModelParameter(dlg.param, component) self.repaintModel() # self.view.ensureVisible(self.scene.getLastParameterItem()) self.hasChanged = True def getPositionForParameterItem(self): MARGIN = 20 BOX_WIDTH = 200 BOX_HEIGHT = 80 if len(self.model.parameterComponents()) > 0: maxX = max([ i.position().x() for i in list(self.model.parameterComponents().values()) ]) newX = min(MARGIN + BOX_WIDTH + maxX, self.CANVAS_SIZE - BOX_WIDTH) else: newX = MARGIN + BOX_WIDTH / 2 return QPointF(newX, MARGIN + BOX_HEIGHT / 2) def fillInputsTree(self): icon = QIcon(os.path.join(pluginPath, 'images', 'input.svg')) parametersItem = QTreeWidgetItem() parametersItem.setText(0, self.tr('Parameters')) sortedParams = sorted( QgsApplication.instance().processingRegistry().parameterTypes(), key=lambda pt: pt.name()) for param in sortedParams: if param.flags() & QgsProcessingParameterType.ExposeToModeler: paramItem = QTreeWidgetItem() paramItem.setText(0, param.name()) paramItem.setData(0, Qt.UserRole, param.id()) paramItem.setIcon(0, icon) paramItem.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsDragEnabled) paramItem.setToolTip(0, param.description()) parametersItem.addChild(paramItem) self.inputsTree.addTopLevelItem(parametersItem) parametersItem.setExpanded(True) def addAlgorithm(self): algorithm = self.algorithmTree.selectedAlgorithm() if algorithm is not None: alg = QgsApplication.processingRegistry().createAlgorithmById( algorithm.id()) self._addAlgorithm(alg) def _addAlgorithm(self, alg, pos=None): dlg = ModelerParametersDialog(alg, self.model) if dlg.exec_(): alg = dlg.createAlgorithm() if pos is None: alg.setPosition(self.getPositionForAlgorithmItem()) else: alg.setPosition(pos) from processing.modeler.ModelerGraphicItem import ModelerGraphicItem for i, out in enumerate(alg.modelOutputs()): alg.modelOutput(out).setPosition( alg.position() + QPointF(ModelerGraphicItem.BOX_WIDTH, (i + 1.5) * ModelerGraphicItem.BOX_HEIGHT)) self.model.addChildAlgorithm(alg) self.repaintModel() self.hasChanged = True def getPositionForAlgorithmItem(self): MARGIN = 20 BOX_WIDTH = 200 BOX_HEIGHT = 80 if self.model.childAlgorithms(): maxX = max([ alg.position().x() for alg in list(self.model.childAlgorithms().values()) ]) maxY = max([ alg.position().y() for alg in list(self.model.childAlgorithms().values()) ]) newX = min(MARGIN + BOX_WIDTH + maxX, self.CANVAS_SIZE - BOX_WIDTH) newY = min(MARGIN + BOX_HEIGHT + maxY, self.CANVAS_SIZE - BOX_HEIGHT) else: newX = MARGIN + BOX_WIDTH / 2 newY = MARGIN * 2 + BOX_HEIGHT + BOX_HEIGHT / 2 return QPointF(newX, newY) def export_as_script_algorithm(self): dlg = ScriptEditorDialog(None) dlg.editor.setText('\n'.join( self.model.asPythonCode( QgsProcessing.PythonQgsProcessingAlgorithmSubclass, 4))) dlg.show()
def __init__(self, model=None): super().__init__(None) self.setAttribute(Qt.WA_DeleteOnClose) self.setupUi(self) self._variables_scope = None # LOTS of bug reports when we include the dock creation in the UI file # see e.g. #16428, #19068 # So just roll it all by hand......! self.propertiesDock = QgsDockWidget(self) self.propertiesDock.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable) self.propertiesDock.setObjectName("propertiesDock") propertiesDockContents = QWidget() self.verticalDockLayout_1 = QVBoxLayout(propertiesDockContents) self.verticalDockLayout_1.setContentsMargins(0, 0, 0, 0) self.verticalDockLayout_1.setSpacing(0) self.scrollArea_1 = QgsScrollArea(propertiesDockContents) sizePolicy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.scrollArea_1.sizePolicy().hasHeightForWidth()) self.scrollArea_1.setSizePolicy(sizePolicy) self.scrollArea_1.setFocusPolicy(Qt.WheelFocus) self.scrollArea_1.setFrameShape(QFrame.NoFrame) self.scrollArea_1.setFrameShadow(QFrame.Plain) self.scrollArea_1.setWidgetResizable(True) self.scrollAreaWidgetContents_1 = QWidget() self.gridLayout = QGridLayout(self.scrollAreaWidgetContents_1) self.gridLayout.setContentsMargins(6, 6, 6, 6) self.gridLayout.setSpacing(4) self.label_1 = QLabel(self.scrollAreaWidgetContents_1) self.gridLayout.addWidget(self.label_1, 0, 0, 1, 1) self.textName = QLineEdit(self.scrollAreaWidgetContents_1) self.gridLayout.addWidget(self.textName, 0, 1, 1, 1) self.label_2 = QLabel(self.scrollAreaWidgetContents_1) self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1) self.textGroup = QLineEdit(self.scrollAreaWidgetContents_1) self.gridLayout.addWidget(self.textGroup, 1, 1, 1, 1) self.label_1.setText(self.tr("Name")) self.textName.setToolTip(self.tr("Enter model name here")) self.label_2.setText(self.tr("Group")) self.textGroup.setToolTip(self.tr("Enter group name here")) self.scrollArea_1.setWidget(self.scrollAreaWidgetContents_1) self.verticalDockLayout_1.addWidget(self.scrollArea_1) self.propertiesDock.setWidget(propertiesDockContents) self.propertiesDock.setWindowTitle(self.tr("Model Properties")) self.inputsDock = QgsDockWidget(self) self.inputsDock.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable) self.inputsDock.setObjectName("inputsDock") self.inputsDockContents = QWidget() self.verticalLayout_3 = QVBoxLayout(self.inputsDockContents) self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) self.scrollArea_2 = QgsScrollArea(self.inputsDockContents) sizePolicy.setHeightForWidth( self.scrollArea_2.sizePolicy().hasHeightForWidth()) self.scrollArea_2.setSizePolicy(sizePolicy) self.scrollArea_2.setFocusPolicy(Qt.WheelFocus) self.scrollArea_2.setFrameShape(QFrame.NoFrame) self.scrollArea_2.setFrameShadow(QFrame.Plain) self.scrollArea_2.setWidgetResizable(True) self.scrollAreaWidgetContents_2 = QWidget() self.verticalLayout = QVBoxLayout(self.scrollAreaWidgetContents_2) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setSpacing(0) self.inputsTree = QTreeWidget(self.scrollAreaWidgetContents_2) self.inputsTree.setAlternatingRowColors(True) self.inputsTree.header().setVisible(False) self.verticalLayout.addWidget(self.inputsTree) self.scrollArea_2.setWidget(self.scrollAreaWidgetContents_2) self.verticalLayout_3.addWidget(self.scrollArea_2) self.inputsDock.setWidget(self.inputsDockContents) self.addDockWidget(Qt.DockWidgetArea(1), self.inputsDock) self.inputsDock.setWindowTitle(self.tr("Inputs")) self.algorithmsDock = QgsDockWidget(self) self.algorithmsDock.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable) self.algorithmsDock.setObjectName("algorithmsDock") self.algorithmsDockContents = QWidget() self.verticalLayout_4 = QVBoxLayout(self.algorithmsDockContents) self.verticalLayout_4.setContentsMargins(0, 0, 0, 0) self.scrollArea_3 = QgsScrollArea(self.algorithmsDockContents) sizePolicy.setHeightForWidth( self.scrollArea_3.sizePolicy().hasHeightForWidth()) self.scrollArea_3.setSizePolicy(sizePolicy) self.scrollArea_3.setFocusPolicy(Qt.WheelFocus) self.scrollArea_3.setFrameShape(QFrame.NoFrame) self.scrollArea_3.setFrameShadow(QFrame.Plain) self.scrollArea_3.setWidgetResizable(True) self.scrollAreaWidgetContents_3 = QWidget() self.verticalLayout_2 = QVBoxLayout(self.scrollAreaWidgetContents_3) self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) self.verticalLayout_2.setSpacing(4) self.searchBox = QgsFilterLineEdit(self.scrollAreaWidgetContents_3) self.verticalLayout_2.addWidget(self.searchBox) self.algorithmTree = QgsProcessingToolboxTreeView( None, QgsApplication.processingRegistry()) self.algorithmTree.setAlternatingRowColors(True) self.algorithmTree.header().setVisible(False) self.verticalLayout_2.addWidget(self.algorithmTree) self.scrollArea_3.setWidget(self.scrollAreaWidgetContents_3) self.verticalLayout_4.addWidget(self.scrollArea_3) self.algorithmsDock.setWidget(self.algorithmsDockContents) self.addDockWidget(Qt.DockWidgetArea(1), self.algorithmsDock) self.algorithmsDock.setWindowTitle(self.tr("Algorithms")) self.searchBox.setToolTip( self.tr("Enter algorithm name to filter list")) self.searchBox.setShowSearchIcon(True) self.variables_dock = QgsDockWidget(self) self.variables_dock.setFeatures(QDockWidget.DockWidgetFloatable | QDockWidget.DockWidgetMovable) self.variables_dock.setObjectName("variablesDock") self.variables_dock_contents = QWidget() vl_v = QVBoxLayout() vl_v.setContentsMargins(0, 0, 0, 0) self.variables_editor = QgsVariableEditorWidget() vl_v.addWidget(self.variables_editor) self.variables_dock_contents.setLayout(vl_v) self.variables_dock.setWidget(self.variables_dock_contents) self.addDockWidget(Qt.DockWidgetArea(1), self.variables_dock) self.variables_dock.setWindowTitle(self.tr("Variables")) self.addDockWidget(Qt.DockWidgetArea(1), self.propertiesDock) self.tabifyDockWidget(self.propertiesDock, self.variables_dock) self.variables_editor.scopeChanged.connect(self.variables_changed) self.bar = QgsMessageBar() self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed) self.centralWidget().layout().insertWidget(0, self.bar) try: self.setDockOptions(self.dockOptions() | QMainWindow.GroupedDragging) except: pass if iface is not None: self.mToolbar.setIconSize(iface.iconSize()) self.setStyleSheet(iface.mainWindow().styleSheet()) self.toolbutton_export_to_script = QToolButton() self.toolbutton_export_to_script.setPopupMode(QToolButton.InstantPopup) self.export_to_script_algorithm_action = QAction( QCoreApplication.translate('ModelerDialog', 'Export as Script Algorithm…')) self.toolbutton_export_to_script.addActions( [self.export_to_script_algorithm_action]) self.mToolbar.insertWidget(self.mActionExportImage, self.toolbutton_export_to_script) self.export_to_script_algorithm_action.triggered.connect( self.export_as_script_algorithm) self.mActionOpen.setIcon( QgsApplication.getThemeIcon('/mActionFileOpen.svg')) self.mActionSave.setIcon( QgsApplication.getThemeIcon('/mActionFileSave.svg')) self.mActionSaveAs.setIcon( QgsApplication.getThemeIcon('/mActionFileSaveAs.svg')) self.mActionSaveInProject.setIcon( QgsApplication.getThemeIcon('/mAddToProject.svg')) self.mActionZoomActual.setIcon( QgsApplication.getThemeIcon('/mActionZoomActual.svg')) self.mActionZoomIn.setIcon( QgsApplication.getThemeIcon('/mActionZoomIn.svg')) self.mActionZoomOut.setIcon( QgsApplication.getThemeIcon('/mActionZoomOut.svg')) self.mActionExportImage.setIcon( QgsApplication.getThemeIcon('/mActionSaveMapAsImage.svg')) self.mActionZoomToItems.setIcon( QgsApplication.getThemeIcon('/mActionZoomFullExtent.svg')) self.mActionExportPdf.setIcon( QgsApplication.getThemeIcon('/mActionSaveAsPDF.svg')) self.mActionExportSvg.setIcon( QgsApplication.getThemeIcon('/mActionSaveAsSVG.svg')) self.toolbutton_export_to_script.setIcon( QgsApplication.getThemeIcon('/mActionSaveAsPython.svg')) self.mActionEditHelp.setIcon( QgsApplication.getThemeIcon('/mActionEditHelpContent.svg')) self.mActionRun.setIcon( QgsApplication.getThemeIcon('/mActionStart.svg')) self.addDockWidget(Qt.LeftDockWidgetArea, self.propertiesDock) self.addDockWidget(Qt.LeftDockWidgetArea, self.inputsDock) self.addDockWidget(Qt.LeftDockWidgetArea, self.algorithmsDock) self.tabifyDockWidget(self.inputsDock, self.algorithmsDock) self.inputsDock.raise_() self.setWindowFlags(Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint | Qt.WindowCloseButtonHint) settings = QgsSettings() self.restoreState( settings.value("/Processing/stateModeler", QByteArray())) self.restoreGeometry( settings.value("/Processing/geometryModeler", QByteArray())) self.scene = ModelerScene(self, dialog=self) self.scene.setSceneRect( QRectF(0, 0, self.CANVAS_SIZE, self.CANVAS_SIZE)) self.view.setScene(self.scene) self.view.setAcceptDrops(True) self.view.ensureVisible(0, 0, 10, 10) self.view.scale(QgsApplication.desktop().logicalDpiX() / 96, QgsApplication.desktop().logicalDpiX() / 96) def _dragEnterEvent(event): if event.mimeData().hasText() or event.mimeData().hasFormat( 'application/x-vnd.qgis.qgis.algorithmid'): event.acceptProposedAction() else: event.ignore() def _dropEvent(event): def alg_dropped(algorithm_id, pos): alg = QgsApplication.processingRegistry().createAlgorithmById( algorithm_id) if alg is not None: self._addAlgorithm(alg, pos) else: assert False, algorithm_id def input_dropped(id, pos): if id in [ param.id() for param in QgsApplication.instance(). processingRegistry().parameterTypes() ]: self.addInputOfType(itemId, pos) if event.mimeData().hasFormat( 'application/x-vnd.qgis.qgis.algorithmid'): data = event.mimeData().data( 'application/x-vnd.qgis.qgis.algorithmid') stream = QDataStream(data, QIODevice.ReadOnly) algorithm_id = stream.readQString() QTimer.singleShot( 0, lambda id=algorithm_id, pos=self.view.mapToScene(event.pos( )): alg_dropped(id, pos)) event.accept() elif event.mimeData().hasText(): itemId = event.mimeData().text() QTimer.singleShot(0, lambda id=itemId, pos=self.view.mapToScene( event.pos()): input_dropped(id, pos)) event.accept() else: event.ignore() def _dragMoveEvent(event): if event.mimeData().hasText() or event.mimeData().hasFormat( 'application/x-vnd.qgis.qgis.algorithmid'): event.accept() else: event.ignore() def _wheelEvent(event): self.view.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) settings = QgsSettings() factor = settings.value('/qgis/zoom_favor', 2.0) # "Normal" mouse has an angle delta of 120, precision mouses provide data # faster, in smaller steps factor = 1.0 + (factor - 1.0) / 120.0 * abs(event.angleDelta().y()) if (event.modifiers() == Qt.ControlModifier): factor = 1.0 + (factor - 1.0) / 20.0 if event.angleDelta().y() < 0: factor = 1 / factor self.view.scale(factor, factor) def _enterEvent(e): QGraphicsView.enterEvent(self.view, e) self.view.viewport().setCursor(Qt.ArrowCursor) def _mouseReleaseEvent(e): QGraphicsView.mouseReleaseEvent(self.view, e) self.view.viewport().setCursor(Qt.ArrowCursor) def _mousePressEvent(e): if e.button() == Qt.MidButton: self.previousMousePos = e.pos() else: QGraphicsView.mousePressEvent(self.view, e) def _mouseMoveEvent(e): if e.buttons() == Qt.MidButton: offset = self.previousMousePos - e.pos() self.previousMousePos = e.pos() self.view.verticalScrollBar().setValue( self.view.verticalScrollBar().value() + offset.y()) self.view.horizontalScrollBar().setValue( self.view.horizontalScrollBar().value() + offset.x()) else: QGraphicsView.mouseMoveEvent(self.view, e) self.view.setDragMode(QGraphicsView.ScrollHandDrag) self.view.dragEnterEvent = _dragEnterEvent self.view.dropEvent = _dropEvent self.view.dragMoveEvent = _dragMoveEvent self.view.wheelEvent = _wheelEvent self.view.enterEvent = _enterEvent self.view.mousePressEvent = _mousePressEvent self.view.mouseMoveEvent = _mouseMoveEvent def _mimeDataInput(items): mimeData = QMimeData() text = items[0].data(0, Qt.UserRole) mimeData.setText(text) return mimeData self.inputsTree.mimeData = _mimeDataInput self.inputsTree.setDragDropMode(QTreeWidget.DragOnly) self.inputsTree.setDropIndicatorShown(True) self.algorithms_model = ModelerToolboxModel( self, QgsApplication.processingRegistry()) self.algorithmTree.setToolboxProxyModel(self.algorithms_model) self.algorithmTree.setDragDropMode(QTreeWidget.DragOnly) self.algorithmTree.setDropIndicatorShown(True) filters = QgsProcessingToolboxProxyModel.Filters( QgsProcessingToolboxProxyModel.FilterModeler) if ProcessingConfig.getSetting( ProcessingConfig.SHOW_ALGORITHMS_KNOWN_ISSUES): filters |= QgsProcessingToolboxProxyModel.FilterShowKnownIssues self.algorithmTree.setFilters(filters) if hasattr(self.searchBox, 'setPlaceholderText'): self.searchBox.setPlaceholderText( QCoreApplication.translate('ModelerDialog', 'Search…')) if hasattr(self.textName, 'setPlaceholderText'): self.textName.setPlaceholderText(self.tr('Enter model name here')) if hasattr(self.textGroup, 'setPlaceholderText'): self.textGroup.setPlaceholderText(self.tr('Enter group name here')) # Connect signals and slots self.inputsTree.doubleClicked.connect(self.addInput) self.searchBox.textChanged.connect(self.algorithmTree.setFilterString) self.algorithmTree.doubleClicked.connect(self.addAlgorithm) # Ctrl+= should also trigger a zoom in action ctrlEquals = QShortcut(QKeySequence("Ctrl+="), self) ctrlEquals.activated.connect(self.zoomIn) self.mActionOpen.triggered.connect(self.openModel) self.mActionSave.triggered.connect(self.save) self.mActionSaveAs.triggered.connect(self.saveAs) self.mActionSaveInProject.triggered.connect(self.saveInProject) self.mActionZoomIn.triggered.connect(self.zoomIn) self.mActionZoomOut.triggered.connect(self.zoomOut) self.mActionZoomActual.triggered.connect(self.zoomActual) self.mActionZoomToItems.triggered.connect(self.zoomToItems) self.mActionExportImage.triggered.connect(self.exportAsImage) self.mActionExportPdf.triggered.connect(self.exportAsPdf) self.mActionExportSvg.triggered.connect(self.exportAsSvg) #self.mActionExportPython.triggered.connect(self.exportAsPython) self.mActionEditHelp.triggered.connect(self.editHelp) self.mActionRun.triggered.connect(self.runModel) if model is not None: self.model = model.create() self.model.setSourceFilePath(model.sourceFilePath()) self.textGroup.setText(self.model.group()) self.textName.setText(self.model.displayName()) self.repaintModel() else: self.model = QgsProcessingModelAlgorithm() self.model.setProvider( QgsApplication.processingRegistry().providerById('model')) self.update_variables_gui() self.fillInputsTree() self.view.centerOn(0, 0) self.help = None self.hasChanged = False
def initGui(self): # Create action that will start plugin configuration self.runIcon = QIcon( os.path.join(self.plugin_dir, 'icon_add_service.svg')) self.run_action = QAction(self.runIcon, "PDOK Services plugin", self.iface.mainWindow()) self.run_button = QToolButton() self.run_button.setMenu(QMenu()) self.run_button.setPopupMode(QToolButton.MenuButtonPopup) self.run_button.setDefaultAction(self.run_action) self.servicesLoaded = False # connect the action to the run method self.run_action.triggered.connect(self.run) self.setupfq() # Add toolbar button and menu item #self.iface.addToolBarIcon(self.action) self.toolbar = self.iface.addToolBar("PDOK services plugin") self.toolbar.setObjectName("PDOK services plugin") #self.toolbar.addAction(self.run_action) self.toolbar.addWidget(self.run_button) #self.run_button.menu().addSection('Favorieten') self.favourite_1_action = QAction('Favoriet 1', self.iface.mainWindow()) self.favourite_1_action.setIcon(self.runIcon) self.favourite_1_action.triggered.connect( lambda: self.load_favourite(1)) self.set_favourite_action(self.favourite_1_action, 1) self.run_button.menu().addAction(self.favourite_1_action) self.favourite_2_action = QAction('Favoriet 2', self.iface.mainWindow()) self.favourite_2_action.setIcon(self.runIcon) self.favourite_2_action.triggered.connect( lambda: self.load_favourite(2)) self.set_favourite_action(self.favourite_2_action, 2) self.run_button.menu().addAction(self.favourite_2_action) # TODO :-) #self.run_button.menu().addSection('Meest Recent') #self.run_button.menu().addSeparator() self.toolbarSearch = QLineEdit() self.toolbarSearch.setMaximumWidth(200) self.toolbarSearch.setAlignment(Qt.AlignLeft) self.toolbarSearch.setPlaceholderText("PDOK Locatieserver zoek") self.toolbar.addWidget(self.toolbarSearch) self.toolbarSearch.returnPressed.connect(self.searchAddressFromToolbar) # address/point cleanup eraserIcon = QIcon( os.path.join(self.plugin_dir, 'icon_remove_cross.svg')) self.clean_action = QAction(eraserIcon, "Cleanup", self.eraseAddress()) self.toolbar.addAction(self.clean_action) self.clean_action.triggered.connect(self.eraseAddress) self.clean_action.setEnabled(False) self.iface.addPluginToMenu(u"&Pdok Services Plugin", self.run_action) # about self.aboutAction = QAction(QIcon(":/plugins/pdokservicesplugin/icon_help.png"), \ "About", self.iface.mainWindow()) self.aboutAction.setWhatsThis("Pdok Services Plugin About") self.iface.addPluginToMenu(u"&Pdok Services Plugin", self.aboutAction) self.aboutAction.triggered.connect(self.about) self.dlg.ui.btnLoadLayer.clicked.connect(self.loadService) self.dlg.geocoderSearch.returnPressed.connect(self.searchAddress) self.dlg.geocoderSearch.textEdited.connect(self.searchAddress) self.dlg.geocoderSearch.setPlaceholderText( "PDOK Locatieserver zoek, bv postcode of postcode huisnummer") self.dlg.geocoderResultSearch.textChanged.connect( self.filterGeocoderResult) self.dlg.geocoderResultSearch.setPlaceholderText( "een of meer zoekwoorden uit resultaat") #self.iface.mapCanvas().renderStarting.connect(self.extentsChanged) ui = self.dlg.ui cbxs = [ ui.cbx_gem, ui.cbx_wpl, ui.cbx_weg, ui.cbx_pcd, ui.cbx_adr, ui.cbx_pcl, ui.cbx_hmp ] # connect all fq checkboxes with suggest, so upon a change in fq filter we re-search for cbx in cbxs: cbx.stateChanged.connect(self.searchAddress) self.run(True)