def __init__(self, param): super().__init__(param) self.label = QLabel('') self.units_combo = QComboBox() self.base_units = QgsUnitTypes.DistanceUnknownUnit for u in (QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceKilometers, QgsUnitTypes.DistanceFeet, QgsUnitTypes.DistanceMiles, QgsUnitTypes.DistanceYards): self.units_combo.addItem(QgsUnitTypes.toString(u), u) label_margin = self.fontMetrics().width('X') self.layout().insertSpacing(1, label_margin / 2) self.layout().insertWidget(2, self.label) self.layout().insertWidget(3, self.units_combo) self.layout().insertSpacing(4, label_margin / 2) self.warning_label = QLabel() icon = QgsApplication.getThemeIcon('mIconWarning.svg') size = max(24, self.spnValue.height() * 0.5) self.warning_label.setPixmap(icon.pixmap(icon.actualSize(QSize(size, size)))) self.warning_label.setToolTip(self.tr('Distance is in geographic degrees. Consider reprojecting to a projected local coordinate system for accurate results.')) self.layout().insertWidget(4, self.warning_label) self.layout().insertSpacing(5, label_margin) self.setUnits(QgsUnitTypes.DistanceUnknownUnit)
def populate(self): groups = {} count = 0 provider = algList.algs[self.providerName] algs = list(provider.values()) name = "ACTIVATE_" + self.providerName.upper().replace(" ", "_") active = ProcessingConfig.getSetting(name) # Add algorithms for alg in algs: if not alg.showInToolbox: continue if alg.group in groups: groupItem = groups[alg.group] else: groupItem = QTreeWidgetItem() name = alg.i18n_group or alg.group if not active: groupItem.setForeground(0, Qt.darkGray) groupItem.setText(0, name) groupItem.setToolTip(0, name) groups[alg.group] = groupItem algItem = TreeAlgorithmItem(alg) if not active: algItem.setForeground(0, Qt.darkGray) groupItem.addChild(algItem) count += 1 actions = Processing.actions[self.providerName] for action in actions: if action.group in groups: groupItem = groups[action.group] else: groupItem = QTreeWidgetItem() groupItem.setText(0, action.group) groups[action.group] = groupItem algItem = TreeActionItem(action) groupItem.addChild(algItem) text = self.provider.getDescription() if not active: def activateProvider(): self.toolbox.activateProvider(self.providerName) label = QLabel(text + " <a href='%s'>Activate</a>") label.setStyleSheet("QLabel {background-color: white; color: grey;}") label.linkActivated.connect(activateProvider) self.tree.setItemWidget(self, 0, label) else: text += QCoreApplication.translate("TreeProviderItem", " [{0} geoalgorithms]").format(count) self.setText(0, text) self.setToolTip(0, self.text(0)) for groupItem in list(groups.values()): self.addChild(groupItem) self.setHidden(self.childCount() == 0)
class ProgressBarLogger(QDialog): """A simple dialog with a progress bar and a label""" def __init__(self, title = None): QDialog.__init__(self, None) if title is not None: self.setWindowTitle(title) self.__label = QLabel(self) self.__layout = QVBoxLayout() self.__layout.addWidget(self.__label) self.__progress = QProgressBar(self) self.__layout.addWidget(self.__progress) self.setLayout(self.__layout) self.resize(600, 70) self.setFixedSize(600, 70) self.__progress.hide() self.show() def set_text(self, t): """Gets called when a text is to be logged""" if isinstance(t, tuple): lvl, msg = t else: msg = t self.__label.setText(msg) QCoreApplication.processEvents() def set_progress(self, i, n): """Gets called when there is a progression""" self.__progress.show() self.__progress.setMinimum(0) self.__progress.setMaximum(n) self.__progress.setValue(i) QCoreApplication.processEvents()
class XYDialog(QDialog): crs = None def __init__(self): QDialog.__init__(self) self.setWindowTitle(tr('XY Point drawing tool')) self.X = QLineEdit() self.Y = QLineEdit() X_val = QDoubleValidator() Y_val = QDoubleValidator() self.X.setValidator(X_val) self.Y.setValidator(Y_val) self.crsButton = QPushButton("Projection") self.crsButton.clicked.connect(self.changeCRS) self.crsLabel = QLabel("") buttons = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) buttons.accepted.connect(self.accept) buttons.rejected.connect(self.reject) grid = QGridLayout() grid.addWidget(QLabel("X"), 0, 0) grid.addWidget(QLabel("Y"), 0, 1) grid.addWidget(self.X, 1, 0) grid.addWidget(self.Y, 1, 1) grid.addWidget(self.crsButton, 2, 0) grid.addWidget(self.crsLabel, 2, 1) grid.addWidget(buttons, 3, 0, 1, 2) self.setLayout(grid) def changeCRS(self): projSelector = QgsProjectionSelectionDialog() projSelector.exec_() self.crs = projSelector.crs() self.crsLabel.setText(self.crs.authid()) def getPoint(self, crs): # fix_print_with_import print(crs) dialog = XYDialog() dialog.crs = crs dialog.crsLabel.setText(crs.authid()) result = dialog.exec_() X = 0 Y = 0 if dialog.X.text().strip() and dialog.Y.text().strip(): X = float(dialog.X.text()) Y = float(dialog.Y.text()) return ([QgsPointXY(X, Y), dialog.crs], result == QDialog.Accepted)
def treeItemClicked(self, item): if item.childCount(): return color = {"MODIFIED": QColor(255, 170, 0), "ADDED":Qt.green, "REMOVED":Qt.red , "NO_CHANGE":Qt.white} changeTypeName = ["", "ADDED", "MODIFIED", "REMOVED"] path = item.text(0) if path not in self.changes: return oldfeature = self.changes[path].oldfeature newfeature = self.changes[path].newfeature changetype = self.changes[path].changetype self.attributesTable.clear() self.attributesTable.verticalHeader().show() self.attributesTable.horizontalHeader().show() self.attributesTable.setRowCount(len(newfeature)) self.attributesTable.setVerticalHeaderLabels([a for a in newfeature]) self.attributesTable.setHorizontalHeaderLabels(["Old value", "New value", "Change type"]) for i, attrib in enumerate(newfeature): self.attributesTable.setItem(i, 0, DiffItem(oldfeature.get(attrib, None))) self.attributesTable.setItem(i, 1, DiffItem(newfeature.get(attrib, None))) attribChangeType = changeTypeName[changetype] isChangedGeom = False if changetype == LOCAL_FEATURE_MODIFIED: oldvalue = oldfeature.get(attrib, None) newvalue = newfeature.get(attrib, None) try:# to avoid false change detection due to different precisions oldvalue = QgsGeometry.fromWkt(oldvalue).exportToWkt(7) newvalue = QgsGeometry.fromWkt(newvalue).exportToWkt(7) if oldvalue != newvalue and None not in [oldvalue, newvalue]: widget = QWidget() btn = QPushButton() btn.setText("View detail") g1 = QgsGeometry.fromWkt(oldvalue) g2 = QgsGeometry.fromWkt(newvalue) btn.clicked.connect(lambda: self.viewGeometryChanges(g1, g2)) label = QLabel() label.setText(attribChangeType) layout = QHBoxLayout(widget) layout.addWidget(label); layout.addWidget(btn); layout.setContentsMargins(0, 0, 0, 0) widget.setLayout(layout) self.attributesTable.setItem(i, 2, QTableWidgetItem("")) self.attributesTable.setCellWidget(i, 2, widget) isChangedGeom = True except: pass if oldvalue == newvalue: attribChangeType = "NO_CHANGE" if not isChangedGeom: self.attributesTable.setItem(i, 2, QTableWidgetItem(attribChangeType)) for col in range(3): self.attributesTable.item(i, col).setBackgroundColor(color[attribChangeType]); self.attributesTable.resizeColumnsToContents() self.attributesTable.horizontalHeader().setResizeMode(QHeaderView.Stretch)
def populate(self): groups = {} count = 0 algs = self.provider.algorithms() active = self.provider.isActive() # Add algorithms for alg in algs: if alg.flags() & QgsProcessingAlgorithm.FlagHideFromToolbox: continue if alg.group() in groups: groupItem = groups[alg.group()] else: groupItem = QTreeWidgetItem() name = alg.group() if not active: groupItem.setForeground(0, Qt.darkGray) groupItem.setText(0, name) groupItem.setToolTip(0, name) groups[alg.group()] = groupItem algItem = TreeAlgorithmItem(alg) if not active: algItem.setForeground(0, Qt.darkGray) groupItem.addChild(algItem) count += 1 if self.provider.id() in ProviderActions.actions: actions = ProviderActions.actions[self.provider.id()] for action in actions: if action.group in groups: groupItem = groups[action.group] else: groupItem = QTreeWidgetItem() groupItem.setText(0, action.group) groups[action.group] = groupItem algItem = TreeActionItem(action) groupItem.addChild(algItem) text = self.provider.name() if not active: def activateProvider(): self.toolbox.activateProvider(self.provider.id()) label = QLabel(text + " <a href='%s'>Activate</a>") label.setStyleSheet("QLabel {background-color: white; color: grey;}") label.linkActivated.connect(activateProvider) self.tree.setItemWidget(self, 0, label) else: text += QCoreApplication.translate("TreeProviderItem", " [{0} geoalgorithms]").format(count) self.setText(0, text) self.setToolTip(0, self.text(0)) for groupItem in list(groups.values()): self.addChild(groupItem) self.setHidden(self.childCount() == 0)
def addAlgorithmsFromProvider(self, provider, parent): groups = {} count = 0 algs = provider.algorithms() active = provider.isActive() # Add algorithms for alg in algs: if alg.flags() & QgsProcessingAlgorithm.FlagHideFromToolbox: continue groupItem = None if alg.group() in groups: groupItem = groups[alg.group()] else: # check if group already exists for i in range(parent.childCount()): if parent.child(i).text(0) == alg.group(): groupItem = parent.child(i) groups[alg.group()] = groupItem break if not groupItem: groupItem = TreeGroupItem(alg.group()) if not active: groupItem.setInactive() if provider.id() in ('qgis', 'native', '3d'): groupItem.setIcon(0, provider.icon()) groups[alg.group()] = groupItem algItem = TreeAlgorithmItem(alg) if not active: algItem.setForeground(0, Qt.darkGray) groupItem.addChild(algItem) count += 1 text = provider.name() if not provider.id() in ('qgis', 'native', '3d'): if not active: def activateProvider(): self.activateProvider(provider.id()) label = QLabel(text + " <a href='%s'>Activate</a>") label.setStyleSheet("QLabel {background-color: white; color: grey;}") label.linkActivated.connect(activateProvider) self.algorithmTree.setItemWidget(parent, 0, label) else: parent.setText(0, text) for group, groupItem in sorted(groups.items(), key=operator.itemgetter(1)): parent.addChild(groupItem) if not provider.id() in ('qgis', 'native', '3d'): parent.setHidden(parent.childCount() == 0)
def addLayer(self): table = self.currentTable() if table is not None: layer = table.toMapLayer() layers = QgsMapLayerRegistry.instance().addMapLayers([layer]) if len(layers) != 1: QgsMessageLog.logMessage( self.tr("%1 is an invalid layer - not loaded").replace("%1", layer.publicSource())) msgLabel = QLabel(self.tr( "%1 is an invalid layer and cannot be loaded. Please check the <a href=\"#messageLog\">message log</a> for further info.").replace( "%1", layer.publicSource()), self.mainWindow.infoBar) msgLabel.setWordWrap(True) msgLabel.linkActivated.connect(self.mainWindow.iface.mainWindow().findChild(QWidget, "MessageLog").show) msgLabel.linkActivated.connect(self.mainWindow.iface.mainWindow().raise_) self.mainWindow.infoBar.pushItem(QgsMessageBarItem(msgLabel, QgsMessageBar.WARNING))
def __init__(self): QWidget.__init__(self) self.setWindowTitle(self.tr('Qdraw - Settings')) self.setFixedSize(320, 100) self.center() # default color self.color = QColor(60, 151, 255, 255) self.sld_opacity = QSlider(Qt.Horizontal, self) self.sld_opacity.setRange(0, 255) self.sld_opacity.setValue(255) self.sld_opacity.tracking = True self.sld_opacity.valueChanged.connect(self.handler_opacitySliderValue) self.lbl_opacity = QLabel(self.tr('Opacity') + ': 100%', self) self.dlg_color = QColorDialog(self) btn_chColor = QPushButton(self.tr('Change the drawing color'), self) btn_chColor.clicked.connect(self.handler_chColor) vbox = QVBoxLayout() vbox.addWidget(self.lbl_opacity) vbox.addWidget(self.sld_opacity) vbox.addWidget(btn_chColor) self.setLayout(vbox)
def __init__(self): QDialog.__init__(self) self.setWindowTitle(tr('XY Point drawing tool')) self.X = QLineEdit() self.Y = QLineEdit() X_val = QDoubleValidator() Y_val = QDoubleValidator() self.X.setValidator(X_val) self.Y.setValidator(Y_val) self.crsButton = QPushButton("Projection") self.crsButton.clicked.connect(self.changeCRS) self.crsLabel = QLabel("") buttons = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) buttons.accepted.connect(self.accept) buttons.rejected.connect(self.reject) grid = QGridLayout() grid.addWidget(QLabel("X"), 0, 0) grid.addWidget(QLabel("Y"), 0, 1) grid.addWidget(self.X, 1, 0) grid.addWidget(self.Y, 1, 1) grid.addWidget(self.crsButton, 2, 0) grid.addWidget(self.crsLabel, 2, 1) grid.addWidget(buttons, 3, 0, 1, 2) self.setLayout(grid)
def __init__(self, parent, alg): ParametersPanel.__init__(self, parent, alg) w = QWidget() layout = QVBoxLayout() layout.setMargin(0) layout.setSpacing(6) label = QLabel() label.setText(self.tr("GDAL/OGR console call")) layout.addWidget(label) self.text = QPlainTextEdit() self.text.setReadOnly(True) layout.addWidget(self.text) w.setLayout(layout) self.layoutMain.addWidget(w) self.connectParameterSignals() self.parametersHaveChanged()
def show_error(self, error_text): self.lstSearchResult.clear() new_widget = QLabel() new_widget.setTextFormat(Qt.RichText) new_widget.setOpenExternalLinks(True) new_widget.setWordWrap(True) new_widget.setText( u"<div align='center'> <strong>{}</strong> </div><div align='center' style='margin-top: 3px'> {} </div>".format( self.tr('Error'), error_text ) ) new_item = QListWidgetItem(self.lstSearchResult) new_item.setSizeHint(new_widget.sizeHint()) self.lstSearchResult.addItem(new_item) self.lstSearchResult.setItemWidget( new_item, new_widget )
def set_unit(self): """Set the units label. (Include the frequency.)""" label = '' if self._parameter.frequency: label = self._parameter.frequency if self._parameter.unit.plural: label = '%s %s' % (self._parameter.unit.plural, label) elif self._parameter.unit.name: label = '%s %s' % (self._parameter.unit.name, label) self._unit_widget = QLabel(label) if self._parameter.unit.help_text: self._unit_widget.setToolTip(self._parameter.unit.help_text)
def initGui(self): self.setWindowTitle('New connection') layout = QVBoxLayout() buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Close) horizontalLayout = QHBoxLayout() horizontalLayout.setSpacing(30) horizontalLayout.setMargin(0) nameLabel = QLabel('Name') nameLabel.setMinimumWidth(120) nameLabel.setMaximumWidth(120) self.nameBox = QLineEdit() if self.name is not None: self.nameBox.setText(self.name) horizontalLayout.addWidget(nameLabel) horizontalLayout.addWidget(self.nameBox) layout.addLayout(horizontalLayout) horizontalLayout = QHBoxLayout() horizontalLayout.setSpacing(30) horizontalLayout.setMargin(0) urlLabel = QLabel('URL') urlLabel.setMinimumWidth(120) urlLabel.setMaximumWidth(120) self.urlBox = QLineEdit() if self.url is not None: self.urlBox.setText(self.url) horizontalLayout.addWidget(urlLabel) horizontalLayout.addWidget(self.urlBox) layout.addLayout(horizontalLayout) layout.addWidget(buttonBox) self.setLayout(layout) buttonBox.accepted.connect(self.okPressed) buttonBox.rejected.connect(self.cancelPressed) self.resize(400, 200)
def search_finished_progress(self): self.lstSearchResult.takeItem(0) if self.lstSearchResult.count() == 0: new_widget = QLabel() new_widget.setTextFormat(Qt.RichText) new_widget.setOpenExternalLinks(True) new_widget.setWordWrap(True) new_widget.setText( u"<div align='center'> <strong>{}</strong> </div><div align='center' style='margin-top: 3px'> {} </div>".format( self.tr(u"No results."), self.tr(u"You can add a service to become searchable. Start <a href='{}'>here</a>.").format( u"https://qms.nextgis.com/create" ), ) ) new_item = QListWidgetItem(self.lstSearchResult) new_item.setSizeHint(new_widget.sizeHint()) self.lstSearchResult.addItem(new_item) self.lstSearchResult.setItemWidget( new_item, new_widget )
class ResourceParameterWidget(FloatParameterWidget): """Widget class for Resource parameter.""" # pylint: disable=super-on-old-class def __init__(self, parameter, parent=None): """Constructor .. versionadded:: 2.3 :param parameter: A ResourceParameter object. :type parameter: ResourceParameter, FloatParameter """ # pylint: disable=E1002 super(ResourceParameterWidget, self).__init__(parameter, parent) # pylint: enable=E1002 self.set_unit() def get_parameter(self): """Obtain the parameter object from the current widget state. :returns: A BooleanParameter from the current state of widget """ self._parameter.value = self._input.value() return self._parameter def set_unit(self): """Set the units label. (Include the frequency.)""" label = '' if self._parameter.frequency: label = self._parameter.frequency if self._parameter.unit.plural: label = '%s %s' % (self._parameter.unit.plural, label) elif self._parameter.unit.name: label = '%s %s' % (self._parameter.unit.name, label) self._unit_widget = QLabel(label) if self._parameter.unit.help_text: self._unit_widget.setToolTip(self._parameter.unit.help_text)
def __init__(self, title = None): QDialog.__init__(self, None) if title is not None: self.setWindowTitle(title) self.__label = QLabel(self) self.__layout = QVBoxLayout() self.__layout.addWidget(self.__label) self.__progress = QProgressBar(self) self.__layout.addWidget(self.__progress) self.setLayout(self.__layout) self.resize(600, 70) self.setFixedSize(600, 70) self.__progress.hide() self.show()
def __init__(self): """ Initialize data objects, starts fetching if appropriate, and warn about/removes obsolete plugins """ QObject.__init__(self) # initialize QObject in order to to use self.tr() repositories.load() plugins.getAllInstalled() if repositories.checkingOnStart() and repositories.timeForChecking() and repositories.allEnabled(): # start fetching repositories self.statusLabel = QLabel(self.tr("Looking for new plugins...") + " ", iface.mainWindow().statusBar()) iface.mainWindow().statusBar().insertPermanentWidget(0, self.statusLabel) self.statusLabel.linkActivated.connect(self.showPluginManagerWhenReady) repositories.checkingDone.connect(self.checkingDone) for key in repositories.allEnabled(): repositories.requestFetching(key) else: # no fetching at start, so mark all enabled repositories as requesting to be fetched. for key in repositories.allEnabled(): repositories.setRepositoryData(key, "state", 3) # look for obsolete plugins (the user-installed one is newer than core one) for key in plugins.obsoletePlugins: plugin = plugins.localCache[key] msg = QMessageBox() msg.setIcon(QMessageBox.Warning) msg.setWindowTitle(self.tr("QGIS Python Plugin Installer")) msg.addButton(self.tr("Uninstall (recommended)"), QMessageBox.AcceptRole) msg.addButton(self.tr("I will uninstall it later"), QMessageBox.RejectRole) msg.setText( "%s <b>%s</b><br/><br/>%s" % ( self.tr("Obsolete plugin:"), plugin["name"], self.tr( "QGIS has detected an obsolete plugin that masks its more recent version shipped with this copy of QGIS. This is likely due to files associated with a previous installation of QGIS. Do you want to remove the old plugin right now and unmask the more recent version?" ), ) ) msg.exec_() if not msg.result(): # uninstall, update utils and reload if enabled self.uninstallPlugin(key, quiet=True) updateAvailablePlugins() settings = QSettings() if settings.value("/PythonPlugins/" + key, False, type=bool): settings.setValue("/PythonPlugins/watchDog/" + key, True) loadPlugin(key) startPlugin(key) settings.remove("/PythonPlugins/watchDog/" + key)
def __init__(self, iface): QDialog.__init__(self, iface.mainWindow()) self.workerThread = None self.state = False self.outputLoc = None self.resultStatus = None self.reRun = False self.savedProj = None # Build GUI Elements self.setWindowTitle("SEILAPLAN wird ausgeführt") self.resize(500, 100) self.container = QVBoxLayout() self.progressBar = QProgressBar(self) self.progressBar.setMinimumWidth(500) self.statusLabel = QLabel(self) self.hbox = QHBoxLayout() self.cancelButton = QDialogButtonBox() self.closeButton = QDialogButtonBox() self.resultLabel = ClickLabel(self) self.resultLabel.setMaximumWidth(500) self.resultLabel.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)) self.resultLabel.setWordWrap(True) self.rerunButton = QPushButton("Berechnungen wiederholen") self.rerunButton.setVisible(False) spacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) self.cancelButton.setStandardButtons(QDialogButtonBox.Cancel) self.cancelButton.clicked.connect(self.onAbort) self.closeButton.setStandardButtons(QDialogButtonBox.Close) self.closeButton.clicked.connect(self.onClose) self.hbox.addWidget(self.rerunButton) self.hbox.addItem(spacer) self.hbox.addWidget(self.cancelButton) self.hbox.setAlignment(self.cancelButton, Qt.AlignHCenter) self.hbox.addWidget(self.closeButton) self.hbox.setAlignment(self.closeButton, Qt.AlignHCenter) self.closeButton.hide() self.container.addWidget(self.progressBar) self.container.addWidget(self.statusLabel) self.container.addWidget(self.resultLabel) self.container.addLayout(self.hbox) self.container.setSizeConstraint(QLayout.SetFixedSize) self.setLayout(self.container)
def do_post_offline_convert_action(self): """ Show an information label that the project has been copied with a nice link to open the result folder. """ export_folder = self.get_export_folder_from_dialog() result_label = QLabel(self.tr(u'Finished creating the project at {result_folder}. Please copy this folder to ' u'your QField device.').format( result_folder=u'<a href="{folder}">{folder}</a>'.format(folder=export_folder))) result_label.setTextFormat(Qt.RichText) result_label.setTextInteractionFlags(Qt.TextBrowserInteraction) result_label.linkActivated.connect(lambda: open_folder(export_folder)) result_label.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Preferred) self.iface.messageBar().pushWidget(result_label, Qgis.Info, 0)
class DistanceInputPanel(NumberInputPanel): """ Distance input panel for use outside the modeler - this input panel contains a label showing the distance unit. """ def __init__(self, param): super().__init__(param) self.label = QLabel('') label_margin = self.fontMetrics().width('X') self.layout().insertSpacing(1, label_margin / 2) self.layout().insertWidget(2, self.label) self.layout().insertSpacing(3, label_margin / 2) self.warning_label = QLabel() icon = QgsApplication.getThemeIcon('mIconWarning.svg') size = max(24, self.spnValue.height() * 0.5) self.warning_label.setPixmap(icon.pixmap(icon.actualSize(QSize(size, size)))) self.warning_label.setToolTip(self.tr('Distance is in geographic degrees. Consider reprojecting to a projected local coordinate system for accurate results.')) self.layout().insertWidget(4, self.warning_label) self.layout().insertSpacing(5, label_margin) self.setUnits(QgsUnitTypes.DistanceUnknownUnit) def setUnits(self, units): self.label.setText(QgsUnitTypes.toString(units)) self.warning_label.setVisible(units == QgsUnitTypes.DistanceDegrees) def setUnitParameterValue(self, value): units = QgsUnitTypes.DistanceUnknownUnit layer = self.getLayerFromValue(value) if isinstance(layer, QgsMapLayer): units = layer.crs().mapUnits() elif isinstance(value, QgsCoordinateReferenceSystem): units = value.mapUnits() elif isinstance(value, str): crs = QgsCoordinateReferenceSystem(value) if crs.isValid(): units = crs.mapUnits() self.setUnits(units)
def initGui(self): self.combo = ExtendedComboBox() self.fillCombo() self.combo.setEditable(True) self.label = QLabel("Enter command:") self.errorLabel = QLabel("Enter command:") self.vlayout = QVBoxLayout() self.vlayout.setSpacing(2) self.vlayout.setMargin(0) self.vlayout.addSpacerItem(QSpacerItem(0, OFFSET, QSizePolicy.Maximum, QSizePolicy.Expanding)) self.hlayout = QHBoxLayout() self.hlayout.addWidget(self.label) self.vlayout.addLayout(self.hlayout) self.hlayout2 = QHBoxLayout() self.hlayout2.addWidget(self.combo) self.vlayout.addLayout(self.hlayout2) self.vlayout.addSpacerItem(QSpacerItem(0, OFFSET, QSizePolicy.Maximum, QSizePolicy.Expanding)) self.setLayout(self.vlayout) self.combo.lineEdit().returnPressed.connect(self.run) self.prepareGui()
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 populate(self): groups = {} count = 0 algs = self.provider.algorithms() active = self.provider.isActive() # Add algorithms for alg in algs: if alg.flags() & QgsProcessingAlgorithm.FlagHideFromToolbox: continue if alg.group() in groups: groupItem = groups[alg.group()] else: groupItem = QTreeWidgetItem() name = alg.group() if not active: groupItem.setForeground(0, Qt.darkGray) groupItem.setText(0, name) groupItem.setToolTip(0, name) groups[alg.group()] = groupItem algItem = TreeAlgorithmItem(alg) if not active: algItem.setForeground(0, Qt.darkGray) groupItem.addChild(algItem) count += 1 if self.provider.id() in ProviderActions.actions: actions = ProviderActions.actions[self.provider.id()] for action in actions: if action.group in groups: groupItem = groups[action.group] else: groupItem = QTreeWidgetItem() groupItem.setText(0, action.group) groups[action.group] = groupItem algItem = TreeActionItem(action) groupItem.addChild(algItem) text = self.provider.name() if not active: def activateProvider(): self.toolbox.activateProvider(self.provider.id()) label = QLabel(text + " <a href='%s'>Activate</a>") label.setStyleSheet( "QLabel {background-color: white; color: grey;}") label.linkActivated.connect(activateProvider) self.tree.setItemWidget(self, 0, label) else: text += QCoreApplication.translate( "TreeProviderItem", " [{0} geoalgorithms]").format(count) self.setText(0, text) self.setToolTip(0, self.text(0)) for groupItem in list(groups.values()): self.addChild(groupItem) self.setHidden(self.childCount() == 0)
class CommanderWindow(QDialog): def __init__(self, parent, canvas): self.canvas = canvas QDialog.__init__(self, parent, Qt.FramelessWindowHint) self.commands = imp.load_source('commands', self.commandsFile()) self.initGui() def commandsFolder(self): folder = str(os.path.join(userFolder(), 'commander')) mkdir(folder) return os.path.abspath(folder) def commandsFile(self): f = os.path.join(self.commandsFolder(), 'commands.py') if not os.path.exists(f): with open(f, 'w') as out: out.write('from qgis.core import *\n') out.write('import processing\n\n') out.write('def removeall():\n') out.write('\tmapreg = QgsProject.instance()\n') out.write('\tmapreg.removeAllMapLayers()\n\n') out.write('def load(*args):\n') out.write('\tprocessing.load(args[0])\n') return f def algsListHasChanged(self): self.fillCombo() def initGui(self): self.combo = ExtendedComboBox() self.fillCombo() self.combo.setEditable(True) self.label = QLabel('Enter command:') self.errorLabel = QLabel('Enter command:') self.vlayout = QVBoxLayout() self.vlayout.setSpacing(2) self.vlayout.setMargin(0) self.vlayout.addSpacerItem(QSpacerItem(0, OFFSET, QSizePolicy.Maximum, QSizePolicy.Expanding)) self.hlayout = QHBoxLayout() self.hlayout.addWidget(self.label) self.vlayout.addLayout(self.hlayout) self.hlayout2 = QHBoxLayout() self.hlayout2.addWidget(self.combo) self.vlayout.addLayout(self.hlayout2) self.vlayout.addSpacerItem(QSpacerItem(0, OFFSET, QSizePolicy.Maximum, QSizePolicy.Expanding)) self.setLayout(self.vlayout) self.combo.lineEdit().returnPressed.connect(self.run) self.prepareGui() def fillCombo(self): self.combo.clear() # Add algorithms for provider in list(algList.algs.values()): for alg in provider: self.combo.addItem('Processing algorithm: ' + alg) # Add functions for command in dir(self.commands): if isinstance(self.commands.__dict__.get(command), types.FunctionType): self.combo.addItem('Command: ' + command) # Add menu entries menuActions = [] actions = iface.mainWindow().menuBar().actions() for action in actions: menuActions.extend(self.getActions(action)) for action in menuActions: self.combo.addItem('Menu action: ' + str(action.text())) def prepareGui(self): self.combo.setEditText('') self.combo.setMaximumSize(QSize(self.canvas.rect().width() - 2 * OFFSET, ITEMHEIGHT)) self.combo.view().setStyleSheet('min-height: 150px') self.combo.setFocus(Qt.OtherFocusReason) self.label.setMaximumSize(self.combo.maximumSize()) self.label.setVisible(False) self.adjustSize() pt = self.canvas.rect().topLeft() absolutePt = self.canvas.mapToGlobal(pt) self.move(absolutePt) self.resize(self.canvas.rect().width(), HEIGHT) self.setStyleSheet('CommanderWindow {background-color: #e7f5fe; \ border: 1px solid #b9cfe4;}') def getActions(self, action): menuActions = [] menu = action.menu() if menu is None: menuActions.append(action) return menuActions else: actions = menu.actions() for subaction in actions: if subaction.menu() is not None: menuActions.extend(self.getActions(subaction)) elif not subaction.isSeparator(): menuActions.append(subaction) return menuActions def run(self): s = str(self.combo.currentText()) if s.startswith('Processing algorithm: '): algName = s[len('Processing algorithm: '):] alg = algList.getAlgorithm(algName) if alg is not None: self.close() self.runAlgorithm(alg) elif s.startswith("Command: "): command = s[len("Command: "):] try: self.runCommand(command) self.close() except Exception as e: self.label.setVisible(True) self.label.setText('Error:' + str(e)) elif s.startswith('Menu action: '): actionName = s[len('Menu action: '):] menuActions = [] actions = iface.mainWindow().menuBar().actions() for action in actions: menuActions.extend(self.getActions(action)) for action in menuActions: if action.text() == actionName: self.close() action.trigger() return else: try: self.runCommand(s) self.close() except Exception as e: self.label.setVisible(True) self.label.setText('Error:' + str(e)) def runCommand(self, command): tokens = command.split(' ') if len(tokens) == 1: method = self.commands.__dict__.get(command) if method is not None: method() else: raise Exception('Wrong command') else: method = self.commands.__dict__.get(tokens[0]) if method is not None: method(*tokens[1:]) else: raise Exception('Wrong command') def runAlgorithm(self, alg): alg = alg.getCopy() message = alg.checkBeforeOpeningParametersDialog() if message: dlg = MessageDialog() dlg.setTitle(self.tr('Missing dependency')) dlg.setMessage(message) dlg.exec_() return dlg = alg.getCustomParametersDialog() if not dlg: dlg = AlgorithmDialog(alg) canvas = iface.mapCanvas() prevMapTool = canvas.mapTool() dlg.show() dlg.exec_() if canvas.mapTool() != prevMapTool: try: canvas.mapTool().reset() except: pass canvas.setMapTool(prevMapTool)
def on_backupsqlite_pressed(self): conn = Connection() conn_str = conn.conn_str() a = conn_str.lstrip('sqlite:///') home = os.environ['PYARCHINIT_HOME'] # conn_import = '%s%s%s' % (home, os.sep, # 'pyarchinit_DB_folder/pyarchinit_db.sqlite' # ) #conn_export = '%s%s%s' % (home, os.sep, #'pyarchinit_db_backup/pyarchinit_db_' #+ time.strftime('%Y%m%d_%H_%M_%S_') #+ '.sqlite') PDF_path = '%s%s%s' % (home, os.sep, 'pyarchinit_db_backup/') cfg_rel_path = os.path.join(os.sep, 'pyarchinit_DB_folder', 'config.cfg') file_path = '{}{}'.format(home, cfg_rel_path) conf = open(file_path, "r") data = conf.read() settings = Settings(data) settings.set_configuration() conf.close() dump_dir = PDF_path db_username = settings.USER host = settings.HOST port = settings.PORT database_password = settings.PASSWORD db_names = settings.DATABASE conn_export = '%s' % (dump_dir + 'backup_' + db_names) b = shutil.copy(a, conn_export) i = 0 for c in b: if i == 0: self.progress = self.progressBar_db #("Please Wait!", "Cancel", 0, 100, MainWindow) self.progress.setWindowModality(Qt.WindowModal) self.progress.setWindowTitle( "Loading, Please Wait! (Cloudflare Protection)") self.progress.setMinimum(0) self.progress.setMaximum(100) self.progress.resize(1000, 100) self.progress.show() self.progress.setValue(0) self.progress.setValue(100) self.setLayout(QVBoxLayout()) self.layout().addWidget(self.progress) else: self.image = QLabel('Backup Falied') self.image.setAlignment(Qt.AlignCenter) self.layout().addWidget(self.image)
class SceneItemWidget(QFrame): def __init__(self, scene): QWidget.__init__(self) self.scene = scene self.properties = scene[PROPERTIES] self.setMouseTracking(True) datetime = iso8601.parse_date(self.properties["acquired"]) time = datetime.strftime("%H:%M:%S") date = datetime.strftime("%b %d, %Y") text = f"""{date}<span style="color: rgb(100,100,100);"> {time} UTC</span><br> <b>{PlanetClient.getInstance().item_types_names()[self.properties['item_type']]}</b> """ self.nameLabel = QLabel(text) self.iconLabel = QLabel() self.toolsButton = QLabel() self.toolsButton.setPixmap(COG_ICON.pixmap(QSize(18, 18))) self.toolsButton.mousePressEvent = self.showContextMenu pixmap = QPixmap(PLACEHOLDER_THUMB, "SVG") thumb = pixmap.scaled(48, 48, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.iconLabel.setPixmap(thumb) layout = QHBoxLayout() layout.setMargin(2) vlayout = QVBoxLayout() vlayout.setMargin(0) vlayout.addWidget(self.iconLabel) self.iconWidget = QWidget() self.iconWidget.setFixedSize(48, 48) self.iconWidget.setLayout(vlayout) layout.addWidget(self.iconWidget) layout.addWidget(self.nameLabel) layout.addStretch() layout.addWidget(self.toolsButton) layout.addSpacing(10) self.setLayout(layout) self.nam = QNetworkAccessManager() self.nam.finished.connect(self.iconDownloaded) url = f"{scene['_links']['thumbnail']}?api_key={PlanetClient.getInstance().api_key()}" self.nam.get(QNetworkRequest(QUrl(url))) self.footprint = QgsRubberBand(iface.mapCanvas(), QgsWkbTypes.PolygonGeometry) self.footprint.setStrokeColor(PLANET_COLOR) self.footprint.setWidth(2) self.geom = qgsgeometry_from_geojson(scene[GEOMETRY]) self.setStyleSheet("SceneItemWidget{border: 2px solid transparent;}") def showContextMenu(self, evt): menu = QMenu() add_menu_section_action("Current item", menu) zoom_act = QAction("Zoom to extent", menu) zoom_act.triggered.connect(self.zoom_to_extent) menu.addAction(zoom_act) open_act = QAction("Open in Search Panel", menu) open_act.triggered.connect(self.open_in_explorer) menu.addAction(open_act) menu.exec_(self.toolsButton.mapToGlobal(evt.pos())) def open_in_explorer(self): from .pe_explorer_dockwidget import show_explorer_and_search_daily_images request = build_search_request(string_filter("id", self.scene[ID]), [self.properties[ITEM_TYPE]]) show_explorer_and_search_daily_images(request) def zoom_to_extent(self): rect = QgsRectangle(self.geom.boundingBox()) canvasCrs = iface.mapCanvas().mapSettings().destinationCrs() transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem(4326), canvasCrs, QgsProject.instance()) newrect = transform.transform(rect) newrect.scale(1.05) iface.mapCanvas().setExtent(newrect) iface.mapCanvas().refresh() def iconDownloaded(self, reply): img = QImage() img.loadFromData(reply.readAll()) pixmap = QPixmap(img) thumb = pixmap.scaled(48, 48, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.iconLabel.setPixmap(thumb) def show_footprint(self): rect = QgsRectangle(self.geom.boundingBox()) canvasCrs = iface.mapCanvas().mapSettings().destinationCrs() transform = QgsCoordinateTransform(QgsCoordinateReferenceSystem(4326), canvasCrs, QgsProject.instance()) newrect = transform.transform(rect) self.footprint.setToGeometry(QgsGeometry.fromRect(newrect)) def hide_footprint(self): self.footprint.reset(QgsWkbTypes.PolygonGeometry) def enterEvent(self, event): self.setStyleSheet( "SceneItemWidget{border: 2px solid rgb(0, 157, 165);}") self.show_footprint() def leaveEvent(self, event): self.setStyleSheet("SceneItemWidget{border: 2px solid transparent;}") self.hide_footprint()
def __init__(self, model=None): super().__init__(None) self.setAttribute(Qt.WA_DeleteOnClose) self.setupUi(self) # 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.addDockWidget(Qt.DockWidgetArea(1), self.propertiesDock) 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.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.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.mActionExportPython.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.zoom = 1 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) 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): 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() alg = QgsApplication.processingRegistry().createAlgorithmById( algorithm_id) if alg is not None: self._addAlgorithm(alg, event.pos()) else: assert False, algorithm_id elif event.mimeData().hasText(): itemId = event.mimeData().text() if itemId in [ param.id() for param in QgsApplication.instance(). processingRegistry().parameterTypes() ]: self.addInputOfType(itemId, event.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) self.algorithmTree.setFilters( QgsProcessingToolboxProxyModel.FilterModeler) 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.fillInputsTree() self.view.centerOn(0, 0) self.help = None self.hasChanged = False
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: 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 wrapper.label is not None: if param.flags( ) & QgsProcessingParameterDefinition.FlagAdvanced: self.layoutAdvanced.addWidget(wrapper.label) else: self.layoutMain.insertWidget( self.layoutMain.count() - 2, wrapper.label) 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]') 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 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)') 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 _setupUI(self): self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self.setMinimumHeight(180) self.main_horizontal_layout = QHBoxLayout(self) italic_font = QFont() italic_font.setItalic(True) # deselected widget self.deselected_widget = QListWidget(self) self._set_list_widget_defaults(self.deselected_widget) deselected_label = QLabel() deselected_label.setText('Deselected') deselected_label.setAlignment(Qt.AlignCenter) deselected_label.setFont(italic_font) deselected_v_layout = QVBoxLayout() deselected_v_layout.addWidget(deselected_label) deselected_v_layout.addWidget(self.deselected_widget) # selected widget self.selected_widget = QListWidget(self) self._set_list_widget_defaults(self.selected_widget) selected_label = QLabel() selected_label.setText('Selected') selected_label.setAlignment(Qt.AlignCenter) selected_label.setFont(italic_font) selected_v_layout = QVBoxLayout() selected_v_layout.addWidget(selected_label) selected_v_layout.addWidget(self.selected_widget) # buttons self.buttons_vertical_layout = QVBoxLayout() self.buttons_vertical_layout.setContentsMargins(0, -1, 0, -1) self.select_all_btn = SmallQPushButton('>>') self.deselect_all_btn = SmallQPushButton('<<') self.select_btn = SmallQPushButton('>') self.deselect_btn = SmallQPushButton('<') self.select_btn.setToolTip('Add the selected items') self.deselect_btn.setToolTip('Remove the selected items') self.select_all_btn.setToolTip('Add all') self.deselect_all_btn.setToolTip('Remove all') # add buttons spacer_label = QLabel() # pragmatic way to create a spacer with # the same height of the labels on top # of the lists, in order to align the # buttons with the lists. self.buttons_vertical_layout.addWidget(spacer_label) self.buttons_vertical_layout.addWidget(self.select_btn) self.buttons_vertical_layout.addWidget(self.deselect_btn) self.buttons_vertical_layout.addWidget(self.select_all_btn) self.buttons_vertical_layout.addWidget(self.deselect_all_btn) # add sub widgets self.main_horizontal_layout.addLayout(deselected_v_layout) self.main_horizontal_layout.addLayout(self.buttons_vertical_layout) self.main_horizontal_layout.addLayout(selected_v_layout)
class DistanceInputPanel(NumberInputPanel): """ Distance input panel for use outside the modeler - this input panel contains a label showing the distance unit. """ def __init__(self, param): super().__init__(param) self.label = QLabel('') self.units_combo = QComboBox() self.base_units = QgsUnitTypes.DistanceUnknownUnit for u in (QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceKilometers, QgsUnitTypes.DistanceFeet, QgsUnitTypes.DistanceMiles, QgsUnitTypes.DistanceYards): self.units_combo.addItem(QgsUnitTypes.toString(u), u) label_margin = self.fontMetrics().width('X') self.layout().insertSpacing(1, label_margin / 2) self.layout().insertWidget(2, self.label) self.layout().insertWidget(3, self.units_combo) self.layout().insertSpacing(4, label_margin / 2) self.warning_label = QLabel() icon = QgsApplication.getThemeIcon('mIconWarning.svg') size = max(24, self.spnValue.height() * 0.5) self.warning_label.setPixmap( icon.pixmap(icon.actualSize(QSize(size, size)))) self.warning_label.setToolTip( self. tr('Distance is in geographic degrees. Consider reprojecting to a projected local coordinate system for accurate results.' )) self.layout().insertWidget(4, self.warning_label) self.layout().insertSpacing(5, label_margin) self.setUnits(QgsUnitTypes.DistanceUnknownUnit) def setUnits(self, units): self.label.setText(QgsUnitTypes.toString(units)) if QgsUnitTypes.unitType(units) != QgsUnitTypes.Standard: self.units_combo.hide() self.label.show() else: self.units_combo.setCurrentIndex(self.units_combo.findData(units)) self.units_combo.show() self.label.hide() self.warning_label.setVisible(units == QgsUnitTypes.DistanceDegrees) self.base_units = units def setUnitParameterValue(self, value): units = QgsUnitTypes.DistanceUnknownUnit layer = self.getLayerFromValue(value) if isinstance(layer, QgsMapLayer): units = layer.crs().mapUnits() elif isinstance(value, QgsCoordinateReferenceSystem): units = value.mapUnits() elif isinstance(value, str): crs = QgsCoordinateReferenceSystem(value) if crs.isValid(): units = crs.mapUnits() self.setUnits(units) def getValue(self): val = super().getValue() if isinstance(val, float) and self.units_combo.isVisible(): display_unit = self.units_combo.currentData() return val * QgsUnitTypes.fromUnitToUnitFactor( display_unit, self.base_units) return val def setValue(self, value): try: self.spnValue.setValue(float(value)) except: return
def __init__(self, parent, db_action_type): DbConfigPanel.__init__(self, parent, db_action_type) lbl_host = QLabel(self.tr("Host")) lbl_port = QLabel(self.tr("Port")) lbl_database = QLabel(self.tr("Database")) lbl_schema = QLabel(self.tr("Schema")) lbl_user = QLabel(self.tr("User")) lbl_password = QLabel(self.tr("Password")) self.pg_host_line_edit = QLineEdit() self.pg_host_line_edit.setPlaceholderText(self.tr("Database Hostname")) self.pg_host_line_edit.setText('localhost') self.pg_port_line_edit = QLineEdit() self.pg_port_line_edit.setPlaceholderText( self.tr("[Leave empty to use standard port 5432]")) self.pg_database_line_edit = QLineEdit() self.pg_database_line_edit.setPlaceholderText(self.tr("Database Name")) self.pg_schema_line_edit = QLineEdit() self.pg_schema_line_edit.setPlaceholderText( self.tr("[Leave empty to load all schemas in the database]")) self.pg_user_line_edit = QLineEdit() self.pg_user_line_edit.setPlaceholderText(self.tr("Database Username")) self.pg_password_line_edit = QLineEdit() self.pg_password_line_edit.setEchoMode(QLineEdit.Password) self.pg_password_line_edit.setPlaceholderText( self.tr("[Leave empty to use system password]")) from QgisModelBaker.libili2db.ili2dbconfig import BaseConfiguration if self._db_action_type != DbActionType.EXPORT: self.pg_use_super_login = QCheckBox() self.pg_use_super_login.setText( self.tr( "Generate schema with superuser login from settings ({})"). format(BaseConfiguration().super_pg_user)) layout = QGridLayout(self) layout.addWidget(lbl_host, 0, 0) layout.addWidget(lbl_port, 1, 0) layout.addWidget(lbl_database, 2, 0) layout.addWidget(lbl_schema, 3, 0) layout.addWidget(lbl_user, 4, 0) layout.addWidget(lbl_password, 5, 0) layout.addWidget(self.pg_host_line_edit, 0, 1) layout.addWidget(self.pg_port_line_edit, 1, 1) layout.addWidget(self.pg_database_line_edit, 2, 1) layout.addWidget(self.pg_schema_line_edit, 3, 1) layout.addWidget(self.pg_user_line_edit, 4, 1) layout.addWidget(self.pg_password_line_edit, 5, 1) if self._db_action_type != DbActionType.EXPORT: layout.addWidget(self.pg_use_super_login, 6, 1) # define validators self.validators = Validators() nonEmptyValidator = NonEmptyStringValidator() self.pg_host_line_edit.setValidator(nonEmptyValidator) self.pg_database_line_edit.setValidator(nonEmptyValidator) self.pg_user_line_edit.setValidator(nonEmptyValidator) self.pg_host_line_edit.textChanged.connect( self.validators.validate_line_edits) self.pg_host_line_edit.textChanged.emit(self.pg_host_line_edit.text()) self.pg_database_line_edit.textChanged.connect( self.validators.validate_line_edits) self.pg_database_line_edit.textChanged.emit( self.pg_database_line_edit.text()) self.pg_user_line_edit.textChanged.connect( self.validators.validate_line_edits) self.pg_user_line_edit.textChanged.emit(self.pg_user_line_edit.text()) self.pg_host_line_edit.textChanged.connect(self.notify_fields_modified) self.pg_port_line_edit.textChanged.connect(self.notify_fields_modified) self.pg_database_line_edit.textChanged.connect( self.notify_fields_modified) self.pg_schema_line_edit.textChanged.connect( self.notify_fields_modified) self.pg_user_line_edit.textChanged.connect(self.notify_fields_modified) self.pg_password_line_edit.textChanged.connect( self.notify_fields_modified)
def populate(self): groups = {} count = 0 provider = algList.algs[self.provider_id] algs = list(provider.values()) name = 'ACTIVATE_' + self.provider_id.upper().replace(' ', '_') active = ProcessingConfig.getSetting(name) # Add algorithms for alg in algs: if not alg.showInToolbox: continue if alg.group in groups: groupItem = groups[alg.group] else: groupItem = QTreeWidgetItem() name = alg.i18n_group or alg.group if not active: groupItem.setForeground(0, Qt.darkGray) groupItem.setText(0, name) groupItem.setToolTip(0, name) groups[alg.group] = groupItem algItem = TreeAlgorithmItem(alg) if not active: algItem.setForeground(0, Qt.darkGray) groupItem.addChild(algItem) count += 1 actions = Processing.actions[self.provider_id] for action in actions: if action.group in groups: groupItem = groups[action.group] else: groupItem = QTreeWidgetItem() groupItem.setText(0, action.group) groups[action.group] = groupItem algItem = TreeActionItem(action) groupItem.addChild(algItem) text = self.provider.name() if not active: def activateProvider(): self.toolbox.activateProvider(self.provider_id) label = QLabel(text + " <a href='%s'>Activate</a>") label.setStyleSheet( "QLabel {background-color: white; color: grey;}") label.linkActivated.connect(activateProvider) self.tree.setItemWidget(self, 0, label) else: text += QCoreApplication.translate( "TreeProviderItem", " [{0} geoalgorithms]").format(count) self.setText(0, text) self.setToolTip(0, self.text(0)) for groupItem in list(groups.values()): self.addChild(groupItem) self.setHidden(self.childCount() == 0)
def __init__(self, iface): QtWidgets.QDialog.__init__(self) self.iface = iface self.setupUi(self) self.error = None self.error = None self.data_path, self.data_type = GetOutputFileName( self, 'AequilibraE custom formats', ["Aequilibrae dataset(*.aed)", "Aequilibrae matrix(*.aem)"], '.aed', standard_path()) if self.data_type is None: self.error = 'Path provided is not a valid dataset' self.exit_with_error() self.data_type = self.data_type.upper() if self.data_type == 'AED': self.data_to_show = AequilibraEData() elif self.data_type == 'AEM': self.data_to_show = AequilibraeMatrix() try: self.data_to_show.load(self.data_path) except: self.error = 'Could not load dataset' self.exit_with_error() # Elements that will be used during the displaying self._layout = QVBoxLayout() self.table = QTableView() self._layout.addWidget(self.table) # Settings for displaying self.show_layout = QHBoxLayout() # Thousand separator self.thousand_separator = QCheckBox() self.thousand_separator.setChecked(True) self.thousand_separator.setText('Thousands separator') self.thousand_separator.toggled.connect(self.format_showing) self.show_layout.addWidget(self.thousand_separator) self.spacer = QSpacerItem(5, 0, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.show_layout.addItem(self.spacer) # Decimals txt = QLabel() txt.setText('Decimal places') self.show_layout.addWidget(txt) self.decimals = QSpinBox() self.decimals.valueChanged.connect(self.format_showing) self.decimals.setMinimum(0) self.decimals.setValue(4) self.decimals.setMaximum(10) self.show_layout.addWidget(self.decimals) self._layout.addItem(self.show_layout) # differentiates between matrix and dataset if self.data_type == 'AEM': self.data_to_show.computational_view([self.data_to_show.names[0]]) # Matrices need cores and indices to be set as well self.mat_layout = QHBoxLayout() self.mat_list = QComboBox() for n in self.data_to_show.names: self.mat_list.addItem(n) self.mat_list.currentIndexChanged.connect(self.change_matrix_cores) self.mat_layout.addWidget(self.mat_list) self.idx_list = QComboBox() for i in self.data_to_show.index_names: self.idx_list.addItem(i) self.idx_list.currentIndexChanged.connect(self.change_matrix_cores) self.mat_layout.addWidget(self.idx_list) self._layout.addItem(self.mat_layout) self.change_matrix_cores() self.but_export = QPushButton() self.but_export.setText('Export') self.but_export.clicked.connect(self.export) self.but_close = QPushButton() self.but_close.clicked.connect(self.exit_procedure) self.but_close.setText('Close') self.but_layout = QHBoxLayout() self.but_layout.addWidget(self.but_export) self.but_layout.addWidget(self.but_close) self._layout.addItem(self.but_layout) # We chose to use QTableView. However, if we want to allow the user to edit the dataset # The we need to allow them to switch to the slower QTableWidget # Code below # self.table = QTableWidget(self.data_to_show.entries, self.data_to_show.num_fields) # self.table.setHorizontalHeaderLabels(self.data_to_show.fields) # self.table.setObjectName('data_viewer') # # self.table.setVerticalHeaderLabels([str(x) for x in self.data_to_show.index[:]]) # self.table.clearContents() # # for i in range(self.data_to_show.entries): # for j, f in enumerate(self.data_to_show.fields): # item1 = QTableWidgetItem(str(self.data_to_show.data[f][i])) # item1.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable) # self.table.setItem(i, j, item1) self.resize(700, 500) self.setLayout(self._layout) self.format_showing()
class QgsPluginInstaller(QObject): """ The main class for managing the plugin installer stuff""" statusLabel = None # ----------------------------------------- # def __init__(self): """ Initialize data objects, starts fetching if appropriate, and warn about/removes obsolete plugins """ QObject.__init__(self) # initialize QObject in order to to use self.tr() repositories.load() plugins.getAllInstalled() if repositories.checkingOnStart() and repositories.timeForChecking() and repositories.allEnabled(): # start fetching repositories self.statusLabel = QLabel(self.tr("Looking for new plugins...") + " ", iface.mainWindow().statusBar()) iface.mainWindow().statusBar().insertPermanentWidget(0, self.statusLabel) self.statusLabel.linkActivated.connect(self.showPluginManagerWhenReady) repositories.checkingDone.connect(self.checkingDone) for key in repositories.allEnabled(): repositories.requestFetching(key) else: # no fetching at start, so mark all enabled repositories as requesting to be fetched. for key in repositories.allEnabled(): repositories.setRepositoryData(key, "state", 3) # look for obsolete plugins (the user-installed one is newer than core one) for key in plugins.obsoletePlugins: plugin = plugins.localCache[key] msg = QMessageBox() msg.setIcon(QMessageBox.Warning) msg.setWindowTitle(self.tr("QGIS Python Plugin Installer")) msg.addButton(self.tr("Uninstall (recommended)"), QMessageBox.AcceptRole) msg.addButton(self.tr("I will uninstall it later"), QMessageBox.RejectRole) msg.setText("%s <b>%s</b><br/><br/>%s" % (self.tr("Obsolete plugin:"), plugin["name"], self.tr("QGIS has detected an obsolete plugin that masks its more recent version shipped with this copy of QGIS. This is likely due to files associated with a previous installation of QGIS. Do you want to remove the old plugin right now and unmask the more recent version?"))) msg.exec_() if not msg.result(): # uninstall, update utils and reload if enabled self.uninstallPlugin(key, quiet=True) updateAvailablePlugins() settings = QSettings() if settings.value("/PythonPlugins/" + key, False, type=bool): settings.setValue("/PythonPlugins/watchDog/" + key, True) loadPlugin(key) startPlugin(key) settings.remove("/PythonPlugins/watchDog/" + key) # ----------------------------------------- # def fetchAvailablePlugins(self, reloadMode): """ Fetch plugins from all enabled repositories.""" """ reloadMode = true: Fully refresh data from QSettings to mRepositories """ """ reloadMode = false: Fetch unready repositories only """ QApplication.setOverrideCursor(Qt.WaitCursor) if reloadMode: repositories.load() plugins.clearRepoCache() plugins.getAllInstalled() for key in repositories.allEnabled(): if reloadMode or repositories.all()[key]["state"] == 3: # if state = 3 (error or not fetched yet), try to fetch once again repositories.requestFetching(key) if repositories.fetchingInProgress(): fetchDlg = QgsPluginInstallerFetchingDialog(iface.mainWindow()) fetchDlg.exec_() del fetchDlg for key in repositories.all(): repositories.killConnection(key) QApplication.restoreOverrideCursor() # display error messages for every unavailable reposioty, unless Shift pressed nor all repositories are unavailable keepQuiet = QgsApplication.keyboardModifiers() == Qt.KeyboardModifiers(Qt.ShiftModifier) if repositories.allUnavailable() and repositories.allUnavailable() != repositories.allEnabled(): for key in repositories.allUnavailable(): if not keepQuiet: QMessageBox.warning(iface.mainWindow(), self.tr("QGIS Python Plugin Installer"), self.tr("Error reading repository:") + " " + key + "\n\n" + repositories.all()[key]["error"]) if QgsApplication.keyboardModifiers() == Qt.KeyboardModifiers(Qt.ShiftModifier): keepQuiet = True # finally, rebuild plugins from the caches plugins.rebuild() # ----------------------------------------- # def checkingDone(self): """ Remove the "Looking for new plugins..." label and display a notification instead if any updates or news available """ if not self.statusLabel: # only proceed if the label is present return # rebuild plugins cache plugins.rebuild() # look for news in the repositories plugins.markNews() status = "" # first check for news for key in plugins.all(): if plugins.all()[key]["status"] == "new": status = self.tr("There is a new plugin available") tabIndex = 4 # PLUGMAN_TAB_NEW # then check for updates (and eventually overwrite status) for key in plugins.all(): if plugins.all()[key]["status"] == "upgradeable": status = self.tr("There is a plugin update available") tabIndex = 3 # PLUGMAN_TAB_UPGRADEABLE # finally set the notify label if status: self.statusLabel.setText(u' <a href="%d">%s</a> ' % (tabIndex, status)) else: iface.mainWindow().statusBar().removeWidget(self.statusLabel) self.statusLabel = None # ----------------------------------------- # def exportRepositoriesToManager(self): """ Update manager's repository tree widget with current data """ iface.pluginManagerInterface().clearRepositoryList() for key in repositories.all(): url = repositories.all()[key]["url"] + repositories.urlParams() if repositories.inspectionFilter(): enabled = (key == repositories.inspectionFilter()) else: enabled = repositories.all()[key]["enabled"] iface.pluginManagerInterface().addToRepositoryList({ "name": key, "url": url, "enabled": enabled and "true" or "false", "valid": repositories.all()[key]["valid"] and "true" or "false", "state": str(repositories.all()[key]["state"]), "error": repositories.all()[key]["error"], "inspection_filter": repositories.inspectionFilter() and "true" or "false" }) # ----------------------------------------- # def exportPluginsToManager(self): """ Insert plugins metadata to QgsMetadataRegistry """ iface.pluginManagerInterface().clearPythonPluginMetadata() for key in plugins.all(): plugin = plugins.all()[key] iface.pluginManagerInterface().addPluginMetadata({ "id": key, "plugin_id": plugin["plugin_id"] or "", "name": plugin["name"], "description": plugin["description"], "about": plugin["about"], "category": plugin["category"], "tags": plugin["tags"], "changelog": plugin["changelog"], "author_name": plugin["author_name"], "author_email": plugin["author_email"], "homepage": plugin["homepage"], "tracker": plugin["tracker"], "code_repository": plugin["code_repository"], "version_installed": plugin["version_installed"], "library": plugin["library"], "icon": plugin["icon"], "readonly": plugin["readonly"] and "true" or "false", "installed": plugin["installed"] and "true" or "false", "available": plugin["available"] and "true" or "false", "status": plugin["status"], "error": plugin["error"], "error_details": plugin["error_details"], "experimental": plugin["experimental"] and "true" or "false", "deprecated": plugin["deprecated"] and "true" or "false", "trusted": plugin["trusted"] and "true" or "false", "version_available": plugin["version_available"], "zip_repository": plugin["zip_repository"], "download_url": plugin["download_url"], "filename": plugin["filename"], "downloads": plugin["downloads"], "average_vote": plugin["average_vote"], "rating_votes": plugin["rating_votes"], "pythonic": "true" }) iface.pluginManagerInterface().reloadModel() # ----------------------------------------- # def reloadAndExportData(self): """ Reload All repositories and export data to the Plugin Manager """ self.fetchAvailablePlugins(reloadMode=True) self.exportRepositoriesToManager() self.exportPluginsToManager() # ----------------------------------------- # def showPluginManagerWhenReady(self, * params): """ Open the plugin manager window. If fetching is still in progress, it shows the progress window first """ """ Optionally pass the index of tab to be opened in params """ if self.statusLabel: iface.mainWindow().statusBar().removeWidget(self.statusLabel) self.statusLabel = None self.fetchAvailablePlugins(reloadMode=False) self.exportRepositoriesToManager() self.exportPluginsToManager() # finally, show the plugin manager window tabIndex = -1 if len(params) == 1: indx = str(params[0]) if indx.isdigit() and int(indx) > -1 and int(indx) < 7: tabIndex = int(indx) iface.pluginManagerInterface().showPluginManager(tabIndex) # ----------------------------------------- # def onManagerClose(self): """ Call this method when closing manager window - it resets last-use-dependent values. """ plugins.updateSeenPluginsList() repositories.saveCheckingOnStartLastDate() # ----------------------------------------- # def exportSettingsGroup(self): """ Return QSettings settingsGroup value """ return settingsGroup # ----------------------------------------- # def upgradeAllUpgradeable(self): """ Reinstall all upgradeable plugins """ for key in plugins.allUpgradeable(): self.installPlugin(key, quiet=True) # ----------------------------------------- # def installPlugin(self, key, quiet=False): """ Install given plugin """ error = False infoString = ('', '') plugin = plugins.all()[key] previousStatus = plugin["status"] if not plugin: return if plugin["status"] == "newer" and not plugin["error"]: # ask for confirmation if user downgrades an usable plugin if QMessageBox.warning(iface.mainWindow(), self.tr("QGIS Python Plugin Installer"), self.tr("Are you sure you want to downgrade the plugin to the latest available version? The installed one is newer!"), QMessageBox.Yes, QMessageBox.No) == QMessageBox.No: return dlg = QgsPluginInstallerInstallingDialog(iface.mainWindow(), plugin) dlg.exec_() if dlg.result(): error = True infoString = (self.tr("Plugin installation failed"), dlg.result()) elif not QDir(qgis.utils.home_plugin_path + "/" + key).exists(): error = True infoString = (self.tr("Plugin has disappeared"), self.tr("The plugin seems to have been installed but I don't know where. Probably the plugin package contained a wrong named directory.\nPlease search the list of installed plugins. I'm nearly sure you'll find the plugin there, but I just can't determine which of them it is. It also means that I won't be able to determine if this plugin is installed and inform you about available updates. However the plugin may work. Please contact the plugin author and submit this issue.")) QApplication.setOverrideCursor(Qt.WaitCursor) plugins.getAllInstalled() plugins.rebuild() self.exportPluginsToManager() QApplication.restoreOverrideCursor() else: QApplication.setOverrideCursor(Qt.WaitCursor) # update the list of plugins in plugin handling routines updateAvailablePlugins() # try to load the plugin loadPlugin(plugin["id"]) plugins.getAllInstalled(testLoad=True) plugins.rebuild() plugin = plugins.all()[key] if not plugin["error"]: if previousStatus in ["not installed", "new"]: infoString = (self.tr("Plugin installed successfully"), "") if startPlugin(plugin["id"]): settings = QSettings() settings.setValue("/PythonPlugins/" + plugin["id"], True) else: settings = QSettings() if settings.value("/PythonPlugins/" + key, False, type=bool): # plugin will be reloaded on the fly only if currently loaded reloadPlugin(key) # unloadPlugin + loadPlugin + startPlugin infoString = (self.tr("Plugin reinstalled successfully"), "") else: unloadPlugin(key) # Just for a case. Will exit quietly if really not loaded loadPlugin(key) infoString = (self.tr("Plugin reinstalled successfully"), self.tr("Python plugin reinstalled.\nYou need to restart QGIS in order to reload it.")) if quiet: infoString = (None, None) QApplication.restoreOverrideCursor() else: QApplication.restoreOverrideCursor() if plugin["error"] == "incompatible": message = self.tr("The plugin is not compatible with this version of QGIS. It's designed for QGIS versions:") message += " <b>" + plugin["error_details"] + "</b>" elif plugin["error"] == "dependent": message = self.tr("The plugin depends on some components missing on your system. You need to install the following Python module in order to enable it:") message += "<b> " + plugin["error_details"] + "</b>" else: message = self.tr("The plugin is broken. Python said:") message += "<br><b>" + plugin["error_details"] + "</b>" dlg = QgsPluginInstallerPluginErrorDialog(iface.mainWindow(), message) dlg.exec_() if dlg.result(): # revert installation pluginDir = qgis.utils.home_plugin_path + "/" + plugin["id"] result = removeDir(pluginDir) if QDir(pluginDir).exists(): error = True infoString = (self.tr("Plugin uninstall failed"), result) try: exec ("sys.path_importer_cache.clear()") exec ("import %s" % plugin["id"]) exec ("reload (%s)" % plugin["id"]) except: pass else: try: exec ("del sys.modules[%s]" % plugin["id"]) except: pass plugins.getAllInstalled() plugins.rebuild() self.exportPluginsToManager() if infoString[0]: level = error and QgsMessageBar.CRITICAL or QgsMessageBar.INFO msg = "<b>%s:</b>%s" % (infoString[0], infoString[1]) iface.pluginManagerInterface().pushMessage(msg, level) # ----------------------------------------- # def uninstallPlugin(self, key, quiet=False): """ Uninstall given plugin """ if key in plugins.all(): plugin = plugins.all()[key] else: plugin = plugins.localCache[key] if not plugin: return if not quiet: warning = self.tr("Are you sure you want to uninstall the following plugin?") + "\n(" + plugin["name"] + ")" if plugin["status"] == "orphan" and not plugin["error"]: warning += "\n\n" + self.tr("Warning: this plugin isn't available in any accessible repository!") if QMessageBox.warning(iface.mainWindow(), self.tr("QGIS Python Plugin Installer"), warning, QMessageBox.Yes, QMessageBox.No) == QMessageBox.No: return # unload the plugin QApplication.setOverrideCursor(Qt.WaitCursor) try: unloadPlugin(key) except: pass pluginDir = qgis.utils.home_plugin_path + "/" + plugin["id"] result = removeDir(pluginDir) if result: QApplication.restoreOverrideCursor() msg = "<b>%s:</b>%s" % (self.tr("Plugin uninstall failed"), result) iface.pluginManagerInterface().pushMessage(msg, QgsMessageBar.CRITICAL) else: # safe remove try: unloadPlugin(plugin["id"]) except: pass try: exec ("plugins[%s].unload()" % plugin["id"]) exec ("del plugins[%s]" % plugin["id"]) except: pass try: exec ("del sys.modules[%s]" % plugin["id"]) except: pass plugins.getAllInstalled() plugins.rebuild() self.exportPluginsToManager() QApplication.restoreOverrideCursor() iface.pluginManagerInterface().pushMessage(self.tr("Plugin uninstalled successfully"), QgsMessageBar.INFO) # ----------------------------------------- # def addRepository(self): """ add new repository connection """ dlg = QgsPluginInstallerRepositoryDialog(iface.mainWindow()) dlg.editParams.setText(repositories.urlParams()) dlg.checkBoxEnabled.setCheckState(Qt.Checked) if not dlg.exec_(): return for i in list(repositories.all().values()): if dlg.editURL.text().strip() == i["url"]: iface.pluginManagerInterface().pushMessage(self.tr("Unable to add another repository with the same URL!"), QgsMessageBar.WARNING) return settings = QSettings() settings.beginGroup(reposGroup) reposName = dlg.editName.text() reposURL = dlg.editURL.text().strip() if reposName in repositories.all(): reposName = reposName + "(2)" # add to settings settings.setValue(reposName + "/url", reposURL) settings.setValue(reposName + "/authcfg", dlg.editAuthCfg.text().strip()) settings.setValue(reposName + "/enabled", bool(dlg.checkBoxEnabled.checkState())) # refresh lists and populate widgets plugins.removeRepository(reposName) self.reloadAndExportData() # ----------------------------------------- # def editRepository(self, reposName): """ edit repository connection """ if not reposName: return reposName = reposName.decode('utf-8') checkState = {False: Qt.Unchecked, True: Qt.Checked} dlg = QgsPluginInstallerRepositoryDialog(iface.mainWindow()) dlg.editName.setText(reposName) dlg.editURL.setText(repositories.all()[reposName]["url"]) dlg.editAuthCfg.setText(repositories.all()[reposName]["authcfg"]) dlg.editParams.setText(repositories.urlParams()) dlg.checkBoxEnabled.setCheckState(checkState[repositories.all()[reposName]["enabled"]]) if repositories.all()[reposName]["valid"]: dlg.checkBoxEnabled.setEnabled(True) dlg.labelInfo.setText("") else: dlg.checkBoxEnabled.setEnabled(False) dlg.labelInfo.setText(self.tr("This repository is blocked due to incompatibility with your QGIS version")) dlg.labelInfo.setFrameShape(QFrame.Box) if not dlg.exec_(): return # nothing to do if cancelled for i in list(repositories.all().values()): if dlg.editURL.text().strip() == i["url"] and dlg.editURL.text().strip() != repositories.all()[reposName]["url"]: iface.pluginManagerInterface().pushMessage(self.tr("Unable to add another repository with the same URL!"), QgsMessageBar.WARNING) return # delete old repo from QSettings and create new one settings = QSettings() settings.beginGroup(reposGroup) settings.remove(reposName) newName = dlg.editName.text() if newName in repositories.all() and newName != reposName: newName = newName + "(2)" settings.setValue(newName + "/url", dlg.editURL.text().strip()) settings.setValue(newName + "/authcfg", dlg.editAuthCfg.text().strip()) settings.setValue(newName + "/enabled", bool(dlg.checkBoxEnabled.checkState())) if dlg.editAuthCfg.text().strip() != repositories.all()[reposName]["authcfg"]: repositories.all()[reposName]["authcfg"] = dlg.editAuthCfg.text().strip() if dlg.editURL.text().strip() == repositories.all()[reposName]["url"] and dlg.checkBoxEnabled.checkState() == checkState[repositories.all()[reposName]["enabled"]]: repositories.rename(reposName, newName) self.exportRepositoriesToManager() return # nothing else to do if only repository name was changed plugins.removeRepository(reposName) self.reloadAndExportData() # ----------------------------------------- # def deleteRepository(self, reposName): """ delete repository connection """ if not reposName: return reposName = reposName.decode('utf-8') settings = QSettings() settings.beginGroup(reposGroup) if settings.value(reposName + "/url", "", type=str) == officialRepo[1]: iface.pluginManagerInterface().pushMessage(self.tr("You can't remove the official QGIS Plugin Repository. You can disable it if needed."), QgsMessageBar.WARNING) return warning = self.tr("Are you sure you want to remove the following repository?") + "\n" + reposName if QMessageBox.warning(iface.mainWindow(), self.tr("QGIS Python Plugin Installer"), warning, QMessageBox.Yes, QMessageBox.No) == QMessageBox.No: return # delete from the settings, refresh data and repopulate all the widgets settings.remove(reposName) repositories.remove(reposName) plugins.removeRepository(reposName) self.reloadAndExportData() # ----------------------------------------- # def setRepositoryInspectionFilter(self, reposName=None): """ temporarily block another repositories to fetch only one for inspection """ if reposName is not None: reposName = reposName.decode("utf-8") repositories.setInspectionFilter(reposName) self.reloadAndExportData() # ----------------------------------------- # def sendVote(self, plugin_id, vote): """ send vote via the RPC """ if not plugin_id or not vote: return False url = "http://plugins.qgis.org/plugins/RPC2/" params = "{\"id\":\"djangorpc\",\"method\":\"plugin.vote\",\"params\":[%s,%s]}" % (str(plugin_id), str(vote)) req = QNetworkRequest(QUrl(url)) req.setRawHeader("Content-Type", "application/json") QgsNetworkAccessManager.instance().post(req, params) return True
def show_results(self, api_results, pg_connections=dict()): """Display the results in a table.""" logger.info("Results manager called. Displaying the results") tbl_result = self.tbl_result # Get the name (and other informations) of all databases whose # connection is set up in QGIS if pg_connections == {}: pg_connections = self.pg_connections else: pass # Set table rows if api_results.get("total") >= 10: tbl_result.setRowCount(10) else: tbl_result.setRowCount(api_results.get("total")) # dimensions (see https://github.com/isogeo/isogeo-plugin-qgis/issues/276) hheader = tbl_result.horizontalHeader() # make the entire width of the table is occupied hheader.setSectionResizeMode(1) # make date and icone columns width adapted to their content # so title and adding columns occupy the rest of the available width hheader.setSectionResizeMode(1, 3) hheader.setSectionResizeMode(2, 3) vheader = tbl_result.verticalHeader() # Looping inside the table lines. For each of them, showing the title, # abstract, geometry type, and a button that allow to add the data # to the canvas. count = 0 for i in api_results.get("results"): md = Metadata.clean_attributes(i) # get metadata's keywords from tags, they will be displayed in QGIS # 'layer properties' if the layer is added to the canvas md.keywords = [ md.tags.get(kw) for kw in md.tags if kw.startswith("keyword:isogeo") ] # COLUMN 1 - Title and abstract # Displaying the metadata title inside a button title = md.title_or_name() if title: btn_md_title = QPushButton( plg_tools.format_button_title(title)) else: btn_md_title = QPushButton( self.tr("Undefined", context=__class__.__name__)) btn_md_title.setStyleSheet("font: italic") # Connecting the button to the full metadata popup btn_md_title.pressed.connect(partial(self.md_asked.emit, md._id)) # Putting the abstract as a tooltip on this button if md.abstract: btn_md_title.setToolTip(md.abstract[:300]) else: pass # Insert it in column 1 tbl_result.setCellWidget(count, 0, btn_md_title) # COLUMN 2 - Data last update lbl_date = QLabel(tbl_result) lbl_date.setText(plg_tools.handle_date(md._modified)) lbl_date.setMargin(5) lbl_date.setAlignment(Qt.AlignCenter) tbl_result.setCellWidget(count, 1, lbl_date) # COLUMN 3 - Geometry type lbl_geom = QLabel(tbl_result) if md.geometry: if md.geometry == "TIN": tbl_result.setItem(count, 2, QTableWidgetItem("TIN")) elif md.geometry in known_geom_list: for geom_type in self.pix_geom_dict: if md.geometry in geom_type: geom_item = self.pix_geom_dict.get(geom_type) lbl_geom.setPixmap(geom_item.get("pix")) lbl_geom.setToolTip( self.tr(geom_item.get("tooltip"), context=__class__.__name__)) else: continue else: tbl_result.setItem( count, 2, QTableWidgetItem( self.tr("Unknown geometry", context=__class__.__name__)), ) else: if "rasterDataset" in md.type: lbl_geom.setPixmap(pix_rastr) lbl_geom.setToolTip( self.tr("Raster", context=__class__.__name__)) elif "service" in md.type: lbl_geom.setPixmap(pix_serv) lbl_geom.setToolTip( self.tr("Service", context=__class__.__name__)) else: lbl_geom.setPixmap(pix_nogeo) lbl_geom.setToolTip( self.tr("Unknown geometry", context=__class__.__name__)) lbl_geom.setAlignment(Qt.AlignCenter) tbl_result.setCellWidget(count, 2, lbl_geom) # COLUMN 4 - Add options add_options_dict = {} # Build metadata portal URL if the setting is checked in "Settings" tab add_portal_md_url = int( qsettings.value("isogeo/settings/add_metadata_url_portal", 0)) portal_base_url = self.form_mng.input_portal_url.text() portal_md_url = "" if add_portal_md_url and portal_base_url != "": portal_md_url = portal_base_url + md._id else: pass # Files and PostGIS direct access if md.format: # If the data is a vector and the path is available, store # useful information in the dict if md.format in li_formats_vect and md.path: add_path = self._filepath_builder(md.path) if add_path: params = [ "vector", add_path, md.title, md.abstract, md.keywords, portal_md_url, ] add_options_dict[self.tr( "Data file", context=__class__.__name__)] = params else: pass # Same if the data is a raster elif md.format in li_formats_rastr and md.path: add_path = self._filepath_builder(md.path) if add_path: params = [ "raster", add_path, md.title, md.abstract, md.keywords, portal_md_url, ] add_options_dict[self.tr( "Data file", context=__class__.__name__)] = params else: pass # If the data is a postGIS table and the connexion has # been saved in QGIS. elif md.format == "postgis": if md.path: base_name = md.path else: base_name = "No path" if base_name in pg_connections.keys(): params = {} params["base_name"] = base_name schema_table = md.name if schema_table is not None and "." in schema_table: params["schema"] = schema_table.split(".")[0] params["table"] = schema_table.split(".")[1] params["abstract"] = md.abstract params["title"] = md.title params["keywords"] = md.keywords params["md_portal_url"] = portal_md_url add_options_dict[self.tr( "PostGIS table", context=__class__.__name__)] = params else: pass else: pass else: logger.debug( "Metadata {} has a format ({}) but it's not handled hear or path is" "missing".format(md._id, md.format)) pass # Associated service layers if md.type == "vectorDataset" or md.type == "rasterDataset": for layer in md.serviceLayers: service = layer.get("service") if service is not None: srv_details = { "path": service.get("path", "NR"), "formatVersion": service.get("formatVersion"), } # WMTS if service.get("format") == "wmts": params = self.layer_adder.build_wmts_url( layer, srv_details, rsc_type="ds_dyn_lyr_srv") # EFS, EMS, WMS or WFS elif service.get("format") in list( self.service_dict.keys()): url_builder = self.service_dict.get( service.get("format")).get("url_builder") params = url_builder( layer, srv_details, rsc_type="ds_dyn_lyr_srv", mode="quicky", ) else: params = [0] logger.debug( "Service with no format detected for '{}' metadata : {}" .format(md._id, service)) pass if params[0] != 0: basic_md = [ md.title, md.abstract, md.keywords, portal_md_url, ] params.append(basic_md) add_options_dict["{} : {}".format( params[0], params[1])] = params else: pass # New association mode. For services metadata sheet, the layers # are stored in the purposely named include: "layers". elif md.type == "service": if md.layers is not None: srv_details = { "path": md.path, "formatVersion": md.formatVersion, } # WMTS if md.format == "wmts": for layer in md.layers: name_url = self.layer_adder.build_wmts_url( layer, srv_details, rsc_type="service") if name_url[0] != 0: btn_label = "WMTS : {}".format(name_url[1]) add_options_dict[btn_label] = name_url else: continue # EFS, EMS, WMS or WFS elif md.format in list(self.service_dict.keys()): url_builder = self.service_dict.get( md.format).get("url_builder") for layer in md.layers: name_url = url_builder(layer, srv_details, rsc_type="service", mode="quicky") if name_url[0] != 0: add_options_dict[name_url[5]] = name_url else: continue else: pass else: pass # Now the plugin has tested every possibility for the layer to be # added. The "Add" column has to be filled accordingly. # If the data can't be added, just insert "can't" text. if add_options_dict == {}: text = self.tr("Can't be added", context=__class__.__name__) fake_button = QPushButton(text) fake_button.setStyleSheet("text-align: left") fake_button.setEnabled(False) tbl_result.setCellWidget(count, 3, fake_button) # If the data can be added else: data_info = {"limitations": None, "layer": None} # retrieves data limitations data_info["limitations"] = md.limitations # If there is only one way for the data to be added, insert a button. if len(add_options_dict) == 1: text = list(add_options_dict.keys())[0] params = add_options_dict.get(text) option_type = text.split(" : ")[0] # services if option_type.lower() in list(self.service_dict.keys()): icon = self.service_dict.get( option_type.lower()).get("ico") # PostGIS table elif option_type.startswith( self.tr("PostGIS table", context=__class__.__name__)): icon = ico_pgis # Data file elif option_type.startswith( self.tr("Data file", context=__class__.__name__)): icon = ico_file # Unkown option else: logger.debug( "Undefined add option type : {}/{} --> {}".format( option_type, text, params)) # create the add button with the icon corresponding to the add option add_button = QPushButton(icon, option_type) add_button.setStyleSheet("text-align: left") # connect the widget to the adding method from LayerAdder class data_info["layer"] = ("info", params, count) add_button.pressed.connect( partial(self.lim_checker.check, data_info)) tbl_result.setCellWidget(count, 3, add_button) # Else, add a combobox, storing all possibilities. else: combo = QComboBox() for option in add_options_dict: option_type = option.split(" : ")[0] # services if option_type.lower() in list( self.service_dict.keys()): icon = self.service_dict.get( option_type.lower()).get("ico") # PostGIS table elif option.startswith( self.tr("PostGIS table", context=__class__.__name__)): icon = ico_pgis # Data file elif option.startswith( self.tr("Data file", context=__class__.__name__)): icon = ico_file # Unkown option else: logger.debug( "Undefined add option type : {}/{} --> {}". format(option_type, text, params)) # add a combobox item with the icon corresponding to the add option combo.addItem(icon, option, add_options_dict.get(option)) # connect the widget to the adding method from LayerAdder class data_info["layer"] = ("index", count) combo.activated.connect( partial(self.lim_checker.check, data_info)) combo.model().sort( 0) # sort alphabetically on option prefix. see: #113 tbl_result.setCellWidget(count, 3, combo) # make the widget (button or combobox) width the same as the column width tbl_result.cellWidget(count, 3).setFixedWidth(hheader.sectionSize(3)) count += 1 # dimensions bis (see https://github.com/isogeo/isogeo-plugin-qgis/issues/276) # last column take the width of his content hheader.setSectionResizeMode(3, 3) # the height of the row adapts to the content without falling below 30px vheader.setMinimumSectionSize(30) vheader.setSectionResizeMode(3) # method ending return None
def setupUi(self): type_metadata = QgsApplication.processingRegistry().parameterType( self.param.type() if self.param else self.paramType) self.setWindowTitle( self.tr('{} Parameter Definition').format(type_metadata.name())) self.setMinimumWidth(300) self.verticalLayout = QVBoxLayout(self) self.verticalLayout.setMargin(20) self.label = QLabel(self.tr('Parameter name')) self.verticalLayout.addWidget(self.label) self.nameTextBox = QLineEdit() self.verticalLayout.addWidget(self.nameTextBox) if isinstance(self.param, QgsProcessingParameterDefinition): self.nameTextBox.setText(self.param.description()) if self.paramType == parameters.PARAMETER_TABLE_FIELD or \ isinstance(self.param, QgsProcessingParameterField): self.verticalLayout.addWidget(QLabel(self.tr('Parent layer'))) self.parentCombo = QComboBox() idx = 0 for param in list(self.alg.parameterComponents().values()): definition = self.alg.parameterDefinition( param.parameterName()) if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer)): self.parentCombo.addItem(definition.description(), definition.name()) if self.param is not None: if self.param.parentLayerParameterName( ) == definition.name(): self.parentCombo.setCurrentIndex(idx) idx += 1 self.verticalLayout.addWidget(self.parentCombo) # add the datatype selector self.verticalLayout.addWidget(QLabel(self.tr('Allowed data type'))) self.datatypeCombo = QComboBox() self.datatypeCombo.addItem(self.tr('Any'), -1) self.datatypeCombo.addItem(self.tr('Number'), 0) self.datatypeCombo.addItem(self.tr('String'), 1) self.datatypeCombo.addItem(self.tr('Date/time'), 2) self.verticalLayout.addWidget(self.datatypeCombo) if self.param is not None and self.param.dataType() is not None: # QComboBoxes indexes start at 0, # self.param.datatype start with -1 that is why I need to do +1 datatypeIndex = self.param.dataType() + 1 self.datatypeCombo.setCurrentIndex(datatypeIndex) self.multipleCheck = QCheckBox() self.multipleCheck.setText(self.tr('Accept multiple fields')) self.multipleCheck.setChecked(False) if self.param is not None: self.multipleCheck.setChecked(self.param.allowMultiple()) self.verticalLayout.addWidget(self.multipleCheck) self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultTextBox = QLineEdit() self.defaultTextBox.setToolTip( self. tr('Default field name, or ; separated list of field names for multiple field parameters' )) if self.param is not None: default = self.param.defaultValue() if default is not None: self.defaultTextBox.setText(str(default)) self.verticalLayout.addWidget(self.defaultTextBox) elif self.paramType == parameters.PARAMETER_BAND or \ isinstance(self.param, QgsProcessingParameterBand): self.verticalLayout.addWidget(QLabel(self.tr('Parent layer'))) self.parentCombo = QComboBox() idx = 0 for param in list(self.alg.parameterComponents().values()): definition = self.alg.parameterDefinition( param.parameterName()) if isinstance(definition, (QgsProcessingParameterRasterLayer)): self.parentCombo.addItem(definition.description(), definition.name()) if self.param is not None: if self.param.parentLayerParameterName( ) == definition.name(): self.parentCombo.setCurrentIndex(idx) idx += 1 self.verticalLayout.addWidget(self.parentCombo) elif (self.paramType in (parameters.PARAMETER_VECTOR, parameters.PARAMETER_TABLE) or isinstance(self.param, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer))): self.verticalLayout.addWidget(QLabel(self.tr('Geometry type'))) self.shapetypeCombo = QComboBox() self.shapetypeCombo.addItem(self.tr('Geometry Not Required'), QgsProcessing.TypeVector) self.shapetypeCombo.addItem(self.tr('Point'), QgsProcessing.TypeVectorPoint) self.shapetypeCombo.addItem(self.tr('Line'), QgsProcessing.TypeVectorLine) self.shapetypeCombo.addItem(self.tr('Polygon'), QgsProcessing.TypeVectorPolygon) self.shapetypeCombo.addItem(self.tr('Any Geometry Type'), QgsProcessing.TypeVectorAnyGeometry) if self.param is not None: self.shapetypeCombo.setCurrentIndex( self.shapetypeCombo.findData(self.param.dataTypes()[0])) self.verticalLayout.addWidget(self.shapetypeCombo) elif (self.paramType == parameters.PARAMETER_MULTIPLE or isinstance(self.param, QgsProcessingParameterMultipleLayers)): self.verticalLayout.addWidget(QLabel(self.tr('Data type'))) self.datatypeCombo = QComboBox() self.datatypeCombo.addItem(self.tr('Any Map Layer'), QgsProcessing.TypeMapLayer) self.datatypeCombo.addItem( self.tr('Vector (No Geometry Required)'), QgsProcessing.TypeVector) self.datatypeCombo.addItem(self.tr('Vector (Point)'), QgsProcessing.TypeVectorPoint) self.datatypeCombo.addItem(self.tr('Vector (Line)'), QgsProcessing.TypeVectorLine) self.datatypeCombo.addItem(self.tr('Vector (Polygon)'), QgsProcessing.TypeVectorPolygon) self.datatypeCombo.addItem(self.tr('Vector (Any Geometry Type)'), QgsProcessing.TypeVectorAnyGeometry) self.datatypeCombo.addItem(self.tr('Raster'), QgsProcessing.TypeRaster) self.datatypeCombo.addItem(self.tr('File'), QgsProcessing.TypeFile) if self.param is not None: self.datatypeCombo.setCurrentIndex( self.datatypeCombo.findData(self.param.layerType())) self.verticalLayout.addWidget(self.datatypeCombo) elif (self.paramType in (parameters.PARAMETER_NUMBER, parameters.PARAMETER_DISTANCE, parameters.PARAMETER_SCALE) or isinstance(self.param, (QgsProcessingParameterNumber, QgsProcessingParameterDistance, QgsProcessingParameterScale))): if (self.paramType == parameters.PARAMETER_DISTANCE or isinstance(self.param, QgsProcessingParameterDistance)): self.verticalLayout.addWidget(QLabel(self.tr('Linked input'))) self.parentCombo = QComboBox() self.parentCombo.addItem('', '') idx = 1 for param in list(self.alg.parameterComponents().values()): definition = self.alg.parameterDefinition( param.parameterName()) if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer, QgsProcessingParameterMapLayer, QgsProcessingParameterCrs)): self.parentCombo.addItem(definition.description(), definition.name()) if self.param is not None: if self.param.parentParameterName( ) == definition.name(): self.parentCombo.setCurrentIndex(idx) idx += 1 self.verticalLayout.addWidget(self.parentCombo) elif (self.paramType != parameters.PARAMETER_SCALE and not isinstance(self.param, QgsProcessingParameterScale)): self.verticalLayout.addWidget(QLabel(self.tr('Number type'))) self.type_combo = QComboBox() self.type_combo.addItem(self.tr('Float'), QgsProcessingParameterNumber.Double) self.type_combo.addItem(self.tr('Integer'), QgsProcessingParameterNumber.Integer) if self.param: self.type_combo.setCurrentIndex( self.type_combo.findData(self.param.dataType())) self.verticalLayout.addWidget(self.type_combo) if (self.paramType != parameters.PARAMETER_SCALE and not isinstance(self.param, QgsProcessingParameterScale)): self.verticalLayout.addWidget(QLabel(self.tr('Min value'))) self.minTextBox = QLineEdit() self.verticalLayout.addWidget(self.minTextBox) self.verticalLayout.addWidget(QLabel(self.tr('Max value'))) self.maxTextBox = QLineEdit() self.verticalLayout.addWidget(self.maxTextBox) if self.param is not None: self.minTextBox.setText(str(self.param.minimum())) self.maxTextBox.setText(str(self.param.maximum())) self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultTextBox = QLineEdit() self.defaultTextBox.setText(self.tr('0')) if self.param is not None: default = self.param.defaultValue() if self.param.dataType( ) == QgsProcessingParameterNumber.Integer: default = int(math.floor(float(default))) if default: self.defaultTextBox.setText(str(default)) self.verticalLayout.addWidget(self.defaultTextBox) elif (self.paramType == parameters.PARAMETER_EXPRESSION or isinstance(self.param, QgsProcessingParameterExpression)): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultEdit = QgsExpressionLineEdit() if self.param is not None: self.defaultEdit.setExpression(self.param.defaultValue()) self.verticalLayout.addWidget(self.defaultEdit) self.verticalLayout.addWidget(QLabel(self.tr('Parent layer'))) self.parentCombo = QComboBox() self.parentCombo.addItem(self.tr("None"), None) idx = 1 for param in list(self.alg.parameterComponents().values()): definition = self.alg.parameterDefinition( param.parameterName()) if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer)): self.parentCombo.addItem(definition.description(), definition.name()) if self.param is not None: if self.param.parentLayerParameterName( ) == definition.name(): self.parentCombo.setCurrentIndex(idx) idx += 1 self.verticalLayout.addWidget(self.parentCombo) elif (self.paramType == parameters.PARAMETER_POINT or isinstance(self.param, QgsProcessingParameterPoint)): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultTextBox = QLineEdit() if self.param is not None: self.defaultTextBox.setText(self.param.defaultValue()) self.verticalLayout.addWidget(self.defaultTextBox) elif (self.paramType == parameters.PARAMETER_CRS or isinstance(self.param, QgsProcessingParameterCrs)): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.selector = QgsProjectionSelectionWidget() if self.param is not None: self.selector.setCrs( QgsCoordinateReferenceSystem(self.param.defaultValue())) else: self.selector.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) self.verticalLayout.addWidget(self.selector) elif self.paramType == parameters.PARAMETER_ENUM or \ isinstance(self.param, QgsProcessingParameterEnum): self.widget = EnumModelerWidget(self) if self.param is not None: self.widget.setAllowMultiple(bool(self.param.allowMultiple())) self.widget.setOptions(self.param.options()) self.widget.setDefault(self.param.defaultValue()) self.verticalLayout.addWidget(self.widget) elif self.paramType == parameters.PARAMETER_MATRIX or \ isinstance(self.param, QgsProcessingParameterMatrix): self.widget = MatrixModelerWidget(self) if self.param is not None: self.widget.setValue(self.param.headers(), self.param.defaultValue()) self.widget.setFixedRows(self.param.hasFixedNumberRows()) self.verticalLayout.addWidget(self.widget) elif isinstance(self.param, QgsProcessingDestinationParameter): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultWidget = DestinationSelectionPanel( self.param, self.alg, default_selection=True) self.verticalLayout.addWidget(self.defaultWidget) self.verticalLayout.addSpacing(20) self.requiredCheck = QCheckBox() self.requiredCheck.setText(self.tr('Mandatory')) self.requiredCheck.setChecked(True) if self.param is not None: self.requiredCheck.setChecked( not self.param.flags() & QgsProcessingParameterDefinition.FlagOptional) self.verticalLayout.addWidget(self.requiredCheck) self.advancedCheck = QCheckBox() self.advancedCheck.setText(self.tr('Advanced')) self.advancedCheck.setChecked(False) if self.param is not None: self.advancedCheck.setChecked( self.param.flags() & QgsProcessingParameterDefinition.FlagAdvanced) self.verticalLayout.addWidget(self.advancedCheck) # If child algorithm output is mandatory, disable checkbox if isinstance(self.param, QgsProcessingDestinationParameter): provider_name, child_name, output_name = self.param.name().split( ':') child = self.alg.childAlgorithms()['{}:{}'.format( provider_name, child_name)] model_output = child.modelOutput(output_name) param_def = child.algorithm().parameterDefinition( model_output.childOutputName()) if not (param_def.flags() & QgsProcessingParameterDefinition.FlagOptional): self.requiredCheck.setEnabled(False) self.requiredCheck.setChecked(True) self.advancedCheck.setEnabled(False) self.advancedCheck.setChecked(False) self.buttonBox = QDialogButtonBox(self) self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) self.buttonBox.setObjectName('buttonBox') self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) self.verticalLayout.addStretch() self.verticalLayout.addWidget(self.buttonBox) self.setLayout(self.verticalLayout)
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) # 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.addDockWidget(Qt.DockWidgetArea(1), self.propertiesDock) 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.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.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.mActionExportPython.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.zoom = 1 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) 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): 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() alg = QgsApplication.processingRegistry().createAlgorithmById( algorithm_id) if alg is not None: self._addAlgorithm(alg, event.pos()) else: assert False, algorithm_id elif event.mimeData().hasText(): itemId = event.mimeData().text() if itemId in [ param.id() for param in QgsApplication.instance(). processingRegistry().parameterTypes() ]: self.addInputOfType(itemId, event.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) self.algorithmTree.setFilters( QgsProcessingToolboxProxyModel.FilterModeler) 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.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 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) 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.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.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 createWidgets(self): vlayout = QVBoxLayout() lbl = QLabel( "A column labeled 'ID' with unique increasing numbers for every row will be "\ "added to the output table automatically. In addition to this column it is also "\ "possible to copy one of the columns of the source table to the output table "\ "(tip: if a row identifying column is copied this can later be used for transferring "\ "more data from source table to the new table if necessary).") lbl.setWordWrap(True); vlayout.addWidget(lbl) vlayout.addSpacing(20) self._copyCheck = WidgetEnableCheckBox("Copy column from source table") self.regProp("copy_column_enabled", WizProp(self._copyCheck, False)) vlayout.addWidget(self._copyCheck) glayout = QGridLayout() glayout.setColumnMinimumWidth(0, 20) lbl = QLabel( "The selected column of the source table will be added to the output table "\ "(possibly with a new name). For every object in the output table the value of "\ "its source object will be copied to this column.") lbl.setWordWrap(True); self._copyCheck.addWidget(lbl) glayout.addWidget(lbl, 0, 1, 1, 3) lbl = QLabel("Column in source table") self._copyCheck.addWidget(lbl) glayout.addWidget(lbl, 1, 1) self._sourceCombo = QComboBox() self.regProp("copy_column_in", WizProp(self._sourceCombo, "")) self._copyCheck.addWidget(self._sourceCombo) glayout.addWidget(self._sourceCombo, 1, 2) lbl = QLabel("Column in output table") self._copyCheck.addWidget(lbl) glayout.addWidget(lbl, 2, 1) self._outputEdit = QLineEdit() self.regProp("copy_column_out", WizProp(self._outputEdit, "")) self._copyCheck.addWidget(self._outputEdit) glayout.addWidget(self._outputEdit, 2, 2) vlayout.addLayout(glayout) vlayout.addStretch(1) self.setLayout(vlayout)
def setupUi(self): self.setWindowTitle(self.tr('Parameter Definition')) self.setMinimumWidth(300) self.verticalLayout = QVBoxLayout(self) self.verticalLayout.setMargin(20) self.label = QLabel(self.tr('Parameter name')) self.verticalLayout.addWidget(self.label) self.nameTextBox = QLineEdit() self.verticalLayout.addWidget(self.nameTextBox) if isinstance(self.param, QgsProcessingParameterDefinition): self.nameTextBox.setText(self.param.description()) if self.paramType == parameters.PARAMETER_BOOLEAN or \ isinstance(self.param, QgsProcessingParameterBoolean): self.state = QCheckBox() self.state.setText(self.tr('Checked')) self.state.setChecked(False) if self.param is not None: self.state.setChecked(bool(self.param.defaultValue())) self.verticalLayout.addWidget(self.state) elif self.paramType == parameters.PARAMETER_TABLE_FIELD or \ isinstance(self.param, QgsProcessingParameterField): self.verticalLayout.addWidget(QLabel(self.tr('Parent layer'))) self.parentCombo = QComboBox() idx = 0 for param in list(self.alg.parameterComponents().values()): definition = self.alg.parameterDefinition(param.parameterName()) if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer)): self.parentCombo.addItem(definition.description(), definition.name()) if self.param is not None: if self.param.parentLayerParameterName() == definition.name(): self.parentCombo.setCurrentIndex(idx) idx += 1 self.verticalLayout.addWidget(self.parentCombo) # add the datatype selector self.verticalLayout.addWidget(QLabel(self.tr('Allowed data type'))) self.datatypeCombo = QComboBox() self.datatypeCombo.addItem(self.tr('Any'), -1) self.datatypeCombo.addItem(self.tr('Number'), 0) self.datatypeCombo.addItem(self.tr('String'), 1) self.datatypeCombo.addItem(self.tr('Date/time'), 2) self.verticalLayout.addWidget(self.datatypeCombo) if self.param is not None and self.param.dataType() is not None: # QComboBoxes indexes start at 0, # self.param.datatype start with -1 that is why I need to do +1 datatypeIndex = self.param.dataType() + 1 self.datatypeCombo.setCurrentIndex(datatypeIndex) self.multipleCheck = QCheckBox() self.multipleCheck.setText(self.tr('Accept multiple fields')) self.multipleCheck.setChecked(False) if self.param is not None: self.multipleCheck.setChecked(self.param.allowMultiple()) self.verticalLayout.addWidget(self.multipleCheck) self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultTextBox = QLineEdit() self.defaultTextBox.setToolTip( self.tr('Default field name, or ; separated list of field names for multiple field parameters')) if self.param is not None: default = self.param.defaultValue() if default is not None: self.defaultTextBox.setText(str(default)) self.verticalLayout.addWidget(self.defaultTextBox) elif self.paramType == parameters.PARAMETER_BAND or \ isinstance(self.param, QgsProcessingParameterBand): self.verticalLayout.addWidget(QLabel(self.tr('Parent layer'))) self.parentCombo = QComboBox() idx = 0 for param in list(self.alg.parameterComponents().values()): definition = self.alg.parameterDefinition(param.parameterName()) if isinstance(definition, (QgsProcessingParameterRasterLayer)): self.parentCombo.addItem(definition.description(), definition.name()) if self.param is not None: if self.param.parentLayerParameterName() == definition.name(): self.parentCombo.setCurrentIndex(idx) idx += 1 self.verticalLayout.addWidget(self.parentCombo) elif (self.paramType in ( parameters.PARAMETER_VECTOR, parameters.PARAMETER_TABLE) or isinstance(self.param, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer))): self.verticalLayout.addWidget(QLabel(self.tr('Geometry type'))) self.shapetypeCombo = QComboBox() self.shapetypeCombo.addItem(self.tr('Geometry Not Required'), QgsProcessing.TypeVector) self.shapetypeCombo.addItem(self.tr('Point'), QgsProcessing.TypeVectorPoint) self.shapetypeCombo.addItem(self.tr('Line'), QgsProcessing.TypeVectorLine) self.shapetypeCombo.addItem(self.tr('Polygon'), QgsProcessing.TypeVectorPolygon) self.shapetypeCombo.addItem(self.tr('Any Geometry Type'), QgsProcessing.TypeVectorAnyGeometry) if self.param is not None: self.shapetypeCombo.setCurrentIndex(self.shapetypeCombo.findData(self.param.dataTypes()[0])) self.verticalLayout.addWidget(self.shapetypeCombo) elif (self.paramType == parameters.PARAMETER_MULTIPLE or isinstance(self.param, QgsProcessingParameterMultipleLayers)): self.verticalLayout.addWidget(QLabel(self.tr('Data type'))) self.datatypeCombo = QComboBox() self.datatypeCombo.addItem(self.tr('Any Map Layer'), QgsProcessing.TypeMapLayer) self.datatypeCombo.addItem(self.tr('Vector (No Geometry Required)'), QgsProcessing.TypeVector) self.datatypeCombo.addItem(self.tr('Vector (Point)'), QgsProcessing.TypeVectorPoint) self.datatypeCombo.addItem(self.tr('Vector (Line)'), QgsProcessing.TypeVectorLine) self.datatypeCombo.addItem(self.tr('Vector (Polygon)'), QgsProcessing.TypeVectorPolygon) self.datatypeCombo.addItem(self.tr('Vector (Any Geometry Type)'), QgsProcessing.TypeVectorAnyGeometry) self.datatypeCombo.addItem(self.tr('Raster'), QgsProcessing.TypeRaster) self.datatypeCombo.addItem(self.tr('File'), QgsProcessing.TypeFile) if self.param is not None: self.datatypeCombo.setCurrentIndex(self.datatypeCombo.findData(self.param.layerType())) self.verticalLayout.addWidget(self.datatypeCombo) elif (self.paramType == parameters.PARAMETER_NUMBER or isinstance(self.param, QgsProcessingParameterNumber)): self.verticalLayout.addWidget(QLabel(self.tr('Min value'))) self.minTextBox = QLineEdit() self.verticalLayout.addWidget(self.minTextBox) self.verticalLayout.addWidget(QLabel(self.tr('Max value'))) self.maxTextBox = QLineEdit() self.verticalLayout.addWidget(self.maxTextBox) if self.param is not None: self.minTextBox.setText(str(self.param.minimum())) self.maxTextBox.setText(str(self.param.maximum())) self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultTextBox = QLineEdit() self.defaultTextBox.setText(self.tr('0')) if self.param is not None: default = self.param.defaultValue() if self.param.dataType() == QgsProcessingParameterNumber.Integer: default = int(math.floor(default)) if default: self.defaultTextBox.setText(str(default)) self.verticalLayout.addWidget(self.defaultTextBox) elif (self.paramType == parameters.PARAMETER_EXPRESSION or isinstance(self.param, QgsProcessingParameterExpression)): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultEdit = QgsExpressionLineEdit() if self.param is not None: self.defaultEdit.setExpression(self.param.defaultValue()) self.verticalLayout.addWidget(self.defaultEdit) self.verticalLayout.addWidget(QLabel(self.tr('Parent layer'))) self.parentCombo = QComboBox() self.parentCombo.addItem(self.tr("None"), None) idx = 1 for param in list(self.alg.parameterComponents().values()): definition = self.alg.parameterDefinition(param.parameterName()) if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer)): self.parentCombo.addItem(definition.description(), definition.name()) if self.param is not None: if self.param.parentLayerParameterName() == definition.name(): self.parentCombo.setCurrentIndex(idx) idx += 1 self.verticalLayout.addWidget(self.parentCombo) elif (self.paramType == parameters.PARAMETER_STRING or isinstance(self.param, QgsProcessingParameterString)): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultTextBox = QLineEdit() if self.param is not None: self.defaultTextBox.setText(self.param.defaultValue()) self.verticalLayout.addWidget(self.defaultTextBox) elif (self.paramType == parameters.PARAMETER_FILE or isinstance(self.param, QgsProcessingParameterFile)): self.verticalLayout.addWidget(QLabel(self.tr('Type'))) self.fileFolderCombo = QComboBox() self.fileFolderCombo.addItem(self.tr('File')) self.fileFolderCombo.addItem(self.tr('Folder')) if self.param is not None: self.fileFolderCombo.setCurrentIndex( 1 if self.param.behavior() == QgsProcessingParameterFile.Folder else 0) self.verticalLayout.addWidget(self.fileFolderCombo) elif (self.paramType == parameters.PARAMETER_POINT or isinstance(self.param, QgsProcessingParameterPoint)): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultTextBox = QLineEdit() if self.param is not None: self.defaultTextBox.setText(self.param.defaultValue()) self.verticalLayout.addWidget(self.defaultTextBox) elif (self.paramType == parameters.PARAMETER_CRS or isinstance(self.param, QgsProcessingParameterCrs)): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.selector = QgsProjectionSelectionWidget() if self.param is not None: self.selector.setCrs(QgsCoordinateReferenceSystem(self.param.defaultValue())) else: self.selector.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) self.verticalLayout.addWidget(self.selector) self.verticalLayout.addSpacing(20) self.requiredCheck = QCheckBox() self.requiredCheck.setText(self.tr('Mandatory')) self.requiredCheck.setChecked(True) if self.param is not None: self.requiredCheck.setChecked(not self.param.flags() & QgsProcessingParameterDefinition.FlagOptional) self.verticalLayout.addWidget(self.requiredCheck) self.buttonBox = QDialogButtonBox(self) self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) self.buttonBox.setObjectName('buttonBox') self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) self.verticalLayout.addStretch() self.verticalLayout.addWidget(self.buttonBox) self.setLayout(self.verticalLayout)
def on_backup_pressed(self): home = os.environ['PYARCHINIT_HOME'] PDF_path = '%s%s%s' % (home, os.sep, 'pyarchinit_db_backup/') cfg_rel_path = os.path.join(os.sep, 'pyarchinit_DB_folder', 'config.cfg') file_path = '{}{}'.format(home, cfg_rel_path) conf = open(file_path, "r") data = conf.read() settings = Settings(data) settings.set_configuration() conf.close() dump_dir = PDF_path db_username = settings.USER host = settings.HOST port = settings.PORT database_password = settings.PASSWORD db_names = settings.DATABASE dumper = '-U %s -h %s -p %s -Z 9 -f %s -Fc %s' bkp_file = '%s_%s.backup' % (db_names, time.strftime('%Y%m%d_%H_%M')) file_path = os.path.join(dump_dir, bkp_file) command = 'pg_dump ' + dumper % (db_username, host, port, file_path, db_names) try: p = subprocess.Popen(command, shell=False) except Exception as e: QMessageBox.warning(self, "INFO", str(e), QMessageBox.Ok) #subprocess.call('gzip ' + file_path, shell=False) i = 0 for c in command: if i == 0: self.progress = self.progressBar_db #("Please Wait!", "Cancel", 0, 100, MainWindow) self.progress.setWindowModality(Qt.WindowModal) self.progress.setMinimum(0) self.progress.setMaximum(100) self.progress.setWindowTitle( "Loading, Please Wait! (Cloudflare Protection)") self.progress.resize(1000, 100) self.progress.show() self.progress.setValue(0) self.progress.setValue(100) self.setLayout(QVBoxLayout()) self.layout().addWidget(self.progress) else: self.image = QLabel('Backup Falied') self.image.setAlignment(Qt.AlignCenter) self.layout().addWidget(self.image)
def setupUi(self): self.labels = {} self.widgets = {} self.checkBoxes = {} self.showAdvanced = False self.wrappers = {} self.valueItems = {} self.dependentItems = {} self.resize(650, 450) self.buttonBox = QDialogButtonBox() self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok | QDialogButtonBox.Help) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.verticalLayout = QVBoxLayout() self.verticalLayout.setSpacing(5) self.verticalLayout.setMargin(20) self.bar = QgsMessageBar() self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed) self.verticalLayout.addWidget(self.bar) hLayout = QHBoxLayout() hLayout.setSpacing(5) hLayout.setMargin(0) descriptionLabel = QLabel(self.tr("Description")) self.descriptionBox = QLineEdit() self.descriptionBox.setText(self._alg.displayName()) hLayout.addWidget(descriptionLabel) hLayout.addWidget(self.descriptionBox) self.verticalLayout.addLayout(hLayout) line = QFrame() line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) self.verticalLayout.addWidget(line) for param in self._alg.parameterDefinitions(): if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced: self.advancedButton = QPushButton() self.advancedButton.setText( self.tr('Show advanced parameters')) self.advancedButton.clicked.connect( self.showAdvancedParametersClicked) advancedButtonHLayout = QHBoxLayout() advancedButtonHLayout.addWidget(self.advancedButton) advancedButtonHLayout.addStretch() self.verticalLayout.addLayout(advancedButtonHLayout) break for param in self._alg.parameterDefinitions(): if param.isDestination( ) or param.flags() & QgsProcessingParameterDefinition.FlagHidden: continue 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]') label = QLabel(desc) self.labels[param.name()] = label wrapper = WidgetWrapperFactory.create_wrapper(param, self) self.wrappers[param.name()] = wrapper widget = wrapper.widget if widget is not None: self.valueItems[param.name()] = widget tooltip = param.description() label.setToolTip(tooltip) widget.setToolTip(tooltip) if param.flags( ) & QgsProcessingParameterDefinition.FlagAdvanced: label.setVisible(self.showAdvanced) widget.setVisible(self.showAdvanced) self.widgets[param.name()] = widget self.verticalLayout.addWidget(label) self.verticalLayout.addWidget(widget) for dest in self._alg.destinationParameterDefinitions(): if dest.flags() & QgsProcessingParameterDefinition.FlagHidden: continue if isinstance(dest, (QgsProcessingParameterRasterOutput, QgsProcessingParameterFeatureSink, QgsProcessingParameterFileOutput, QgsProcessingParameterFolderOutput)): label = QLabel(dest.description()) item = QLineEdit() if hasattr(item, 'setPlaceholderText'): item.setPlaceholderText(ModelerParametersDialog.ENTER_NAME) self.verticalLayout.addWidget(label) self.verticalLayout.addWidget(item) self.valueItems[dest.name()] = item label = QLabel(' ') self.verticalLayout.addWidget(label) label = QLabel(self.tr('Parent algorithms')) self.dependenciesPanel = self.getDependenciesPanel() self.verticalLayout.addWidget(label) self.verticalLayout.addWidget(self.dependenciesPanel) self.verticalLayout.addStretch(1000) self.setPreviousValues() self.setWindowTitle(self._alg.displayName()) self.verticalLayout2 = QVBoxLayout() self.verticalLayout2.setSpacing(2) self.verticalLayout2.setMargin(0) self.paramPanel = QWidget() self.paramPanel.setLayout(self.verticalLayout) self.scrollArea = QgsScrollArea() self.scrollArea.setWidget(self.paramPanel) self.scrollArea.setWidgetResizable(True) self.verticalLayout2.addWidget(self.scrollArea) self.verticalLayout2.addWidget(self.buttonBox) self.setLayout(self.verticalLayout2) self.buttonBox.accepted.connect(self.okPressed) self.buttonBox.rejected.connect(self.cancelPressed) self.buttonBox.helpRequested.connect(self.openHelp) QMetaObject.connectSlotsByName(self) for wrapper in list(self.wrappers.values()): wrapper.postInitialize(list(self.wrappers.values()))
class pyarchinit_dbmanagment(QDialog, MAIN_DIALOG_CLASS): MSG_BOX_TITLE = \ 'PyArchInit - pyarchinit_version 0.4 - Scheda gestione DB' HOME = os.environ['PYARCHINIT_HOME'] BK = '{}{}{}'.format(HOME, os.sep, "pyarchinit_db_backup") def __init__(self, iface): super().__init__() self.iface = iface self.setupUi(self) # self.customize_GUI() #call for GUI customizations self.currentLayerId = None def enable_button(self, n): self.backup.setEnabled(n) def enable_button_search(self, n): self.backup.setEnabled(n) def on_backupsqlite_pressed(self): conn = Connection() conn_str = conn.conn_str() a = conn_str.lstrip('sqlite:///') home = os.environ['PYARCHINIT_HOME'] # conn_import = '%s%s%s' % (home, os.sep, # 'pyarchinit_DB_folder/pyarchinit_db.sqlite' # ) #conn_export = '%s%s%s' % (home, os.sep, #'pyarchinit_db_backup/pyarchinit_db_' #+ time.strftime('%Y%m%d_%H_%M_%S_') #+ '.sqlite') PDF_path = '%s%s%s' % (home, os.sep, 'pyarchinit_db_backup/') cfg_rel_path = os.path.join(os.sep, 'pyarchinit_DB_folder', 'config.cfg') file_path = '{}{}'.format(home, cfg_rel_path) conf = open(file_path, "r") data = conf.read() settings = Settings(data) settings.set_configuration() conf.close() dump_dir = PDF_path db_username = settings.USER host = settings.HOST port = settings.PORT database_password = settings.PASSWORD db_names = settings.DATABASE conn_export = '%s' % (dump_dir + 'backup_' + db_names) b = shutil.copy(a, conn_export) i = 0 for c in b: if i == 0: self.progress = self.progressBar_db #("Please Wait!", "Cancel", 0, 100, MainWindow) self.progress.setWindowModality(Qt.WindowModal) self.progress.setWindowTitle( "Loading, Please Wait! (Cloudflare Protection)") self.progress.setMinimum(0) self.progress.setMaximum(100) self.progress.resize(1000, 100) self.progress.show() self.progress.setValue(0) self.progress.setValue(100) self.setLayout(QVBoxLayout()) self.layout().addWidget(self.progress) else: self.image = QLabel('Backup Falied') self.image.setAlignment(Qt.AlignCenter) self.layout().addWidget(self.image) def on_backup_pressed(self): home = os.environ['PYARCHINIT_HOME'] PDF_path = '%s%s%s' % (home, os.sep, 'pyarchinit_db_backup/') cfg_rel_path = os.path.join(os.sep, 'pyarchinit_DB_folder', 'config.cfg') file_path = '{}{}'.format(home, cfg_rel_path) conf = open(file_path, "r") data = conf.read() settings = Settings(data) settings.set_configuration() conf.close() dump_dir = PDF_path db_username = settings.USER host = settings.HOST port = settings.PORT database_password = settings.PASSWORD db_names = settings.DATABASE dumper = '-U %s -h %s -p %s -Z 9 -f %s -Fc %s' bkp_file = '%s_%s.backup' % (db_names, time.strftime('%Y%m%d_%H_%M')) file_path = os.path.join(dump_dir, bkp_file) command = 'pg_dump ' + dumper % (db_username, host, port, file_path, db_names) try: p = subprocess.Popen(command, shell=False) except Exception as e: QMessageBox.warning(self, "INFO", str(e), QMessageBox.Ok) #subprocess.call('gzip ' + file_path, shell=False) i = 0 for c in command: if i == 0: self.progress = self.progressBar_db #("Please Wait!", "Cancel", 0, 100, MainWindow) self.progress.setWindowModality(Qt.WindowModal) self.progress.setMinimum(0) self.progress.setMaximum(100) self.progress.setWindowTitle( "Loading, Please Wait! (Cloudflare Protection)") self.progress.resize(1000, 100) self.progress.show() self.progress.setValue(0) self.progress.setValue(100) self.setLayout(QVBoxLayout()) self.layout().addWidget(self.progress) else: self.image = QLabel('Backup Falied') self.image.setAlignment(Qt.AlignCenter) self.layout().addWidget(self.image) # def on_backup_total_pressed(self): # home = os.environ['PYARCHINIT_HOME'] # PDF_path = '%s%s%s' % (home, os.sep, 'pyarchinit_db_backup/') # filename = '%s%s%s' % (PDF_path, os.sep, 'semivariogramma.png') # username = '******' # defaultdb = 'postgres' # port = '5432' # backupdir = PDF_path # date = time.strftime('%Y-%m-%d-%H-%M-%S') # GET DB NAMES # get_db_names = \ # "psql -U%s -d%s -p%s --tuples-only -c '\l' | awk -F\| '{ print $1 }' | grep -E -v '(template0|template1|^$)'" \ # % (username, defaultdb, port) # MAKE BACKUP OF SYSTEMGRANTS # os.popen('pg_dumpall -p%s -g|gzip -9 -c > %s/system.%s.gz' # % (port, backupdir, date)) # MAKING DB BACKUP # for base in os.popen(get_db_names).readlines(): # try: # app = QtGui.QApplication(sys.argv) # barra = QProgressBar(self) # barra.show() # barra.setMinimum(0) # barra.setMaximum(9) # for a in range(10): # time.sleep(1) # barra.setValue(a) # app.exec_().... # base = base.strip() # fulldir = backupdir + base # if not os.path.exists(fulldir): # os.mkdir(fulldir) # filename = '%s/%s-%s.sql' % (fulldir, base, date) # os.popen('nice -n 19 pg_dump -C -F c -U%s -p%s %s > %s' # % (username, port, base, filename)) # QMessageBox.warning(self, 'Messaggio', # 'Backup completato', QMessageBox.Ok) # except Exception as e: # QMessageBox.warning(self, 'Messaggio', # 'Backup fallito!!' + str(e), # QMessageBox.Ok) def on_upload_pressed(self): s = QgsSettings() dbpath = QFileDialog.getOpenFileName(self, "Set file name", self.BK, " backup (*.backup)")[0] #filename=dbpath.split("/")[-1] if dbpath: self.lineEdit_bk_path.setText(dbpath) s.setValue('', dbpath) def on_restore_pressed(self): try: # barra = QProgressBar(self) # barra.show() # barra.setMinimum(0) # barra.setMaximum(9) # for a in range(10): # time.sleep(1) # barra.setValue(a) path = self.lineEdit_bk_path.text() home = os.environ['PYARCHINIT_HOME'] BK_path = '%s%s%s' % (home, os.sep, 'pyarchinit_db_backup/') cfg_rel_path = os.path.join(os.sep, 'pyarchinit_DB_folder', 'config.cfg') file_path = '{}{}'.format(home, cfg_rel_path) conf = open(file_path, "r") data = conf.read() settings = Settings(data) settings.set_configuration() conf.close() dump_dir = BK_path db_username = self.lineEdit_username_wt.text() host = self.lineEdit_host_wt.text() port = self.lineEdit_port_wt.text() database_password = self.lineEdit_pass_wt.text() db_names = self.lineEdit_database_wt.text() #os.popen('dropdb -U postgres pyarchinit') drop = '-h %s -p %s -U %s %s' command1 = 'dropdb ' + drop % (host, port, db_username, db_names) try: subprocess.call(command1, shell=False) except: pass create = '-h %s -p %s -U %s -e %s -E UTF8 -T template_postgis' command2 = 'createdb ' + create % (host, port, db_username, db_names) subprocess.call(command2, shell=False) #os.popen('createdb -U postgres -p 5432 -h localhost -E UTF8 -T template_postgis_20 -e pyarchinit') restore = '--host %s --port %s --username %s --dbname %s --role postgres %s' command = 'pg_restore ' + restore % (host, port, db_username, db_names, path) subprocess.call(command, shell=False) QMessageBox.warning(self, 'Messaggio', 'Ripristino completato', QMessageBox.Ok) except Exception as e: QMessageBox.warning(self, 'Messaggio', 'Ripristino fallito!!' + str(e), QMessageBox.Ok)
class PlanetExplorer(object): def __init__(self, iface): 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", "{0}Plugin_{1}.qm".format(PE, 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("&{0}".format(P_E)) self.toolbar = None # noinspection PyTypeChecker self.explorer_dock_widget = None self._terms_browser = None if is_segments_write_key_valid(): analytics.write_key = segments_write_key() if is_sentry_dsn_valid(): try: sentry_sdk.init(sentry_dsn(), release=plugin_version(True)) sentry_sdk.set_context( "qgis", { "type": "runtime", "name": Qgis.QGIS_RELEASE_NAME, "version": Qgis.QGIS_VERSION, }, ) system = platform.system() if system == "Darwin": sentry_sdk.set_context( "mac", { "type": "os", "name": "macOS", "version": platform.mac_ver()[0], "kernel_version": platform.uname().release, }, ) if system == "Linux": sentry_sdk.set_context( "linux", { "type": "os", "name": "Linux", "version": platform.release(), "build": platform.version(), }, ) if system == "Windows": sentry_sdk.set_context( "windows", { "type": "os", "name": "Windows", "version": platform.version(), }, ) except Exception: QMessageBox.warning( self.iface.mainWindow(), "Error", "Error initializing Planet Explorer.\n" "Please restart QGIS to load updated libraries.", ) self.qgis_hook = sys.excepthook def plugin_hook(t, value, tb): trace = "".join(traceback.format_exception(t, value, tb)) if PLUGIN_NAMESPACE in trace.lower(): s = "" if issubclass(t, exceptions.Timeout): s = "Connection to Planet server timed out." elif issubclass(t, exceptions.ConnectionError): s = ( "Connection error.\n Verify that your computer is correctly" " connected to the Internet" ) elif issubclass(t, (exceptions.ProxyError, exceptions.InvalidProxyURL)): s = ( "ProxyError.\n Verify that your proxy is correctly configured" " in the QGIS settings" ) elif issubclass(t, planet.api.exceptions.ServerError): s = "Server Error.\n Please, try again later" elif issubclass(t, urllib3.exceptions.ProxySchemeUnknown): s = ( "Proxy Error\n Proxy URL must start with 'http://' or" " 'https://'" ) if s: QMessageBox.warning(self.iface.mainWindow(), "Error", s) else: try: sentry_sdk.capture_exception(value) except Exception: pass # we swallow all exceptions here, to avoid entering an endless loop self.qgis_hook(t, value, tb) else: self.qgis_hook(t, value, tb) sys.excepthook = plugin_hook 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(PE, 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) if add_to_toolbar: self.toolbar.addAction(action) if add_to_menu: self.iface.addPluginToWebMenu(self.menu, action) self.actions.append(action) return action # noinspection PyPep8Naming def initGui(self): self.toolbar = self.iface.addToolBar(P_E) self.toolbar.setObjectName(P_E) self.showdailyimages_act = self.add_action( os.path.join(plugin_path, "resources", "search.svg"), text=self.tr(P_E), callback=toggle_images_search, add_to_menu=True, add_to_toolbar=True, parent=self.iface.mainWindow(), ) self.showbasemaps_act = self.add_action( os.path.join(plugin_path, "resources", "basemap.svg"), text=self.tr("Show Basemaps Search"), callback=toggle_mosaics_search, add_to_menu=True, add_to_toolbar=True, parent=self.iface.mainWindow(), ) self.showinspector_act = self.add_action( os.path.join(plugin_path, "resources", "inspector.svg"), text=self.tr("Show Planet Inspector..."), callback=toggle_inspector, add_to_menu=False, add_to_toolbar=True, parent=self.iface.mainWindow(), ) self.showtasking_act = self.add_action( os.path.join(plugin_path, "resources", "tasking.svg"), text=self.tr("Show Tasking..."), callback=toggle_tasking_widget, add_to_menu=False, add_to_toolbar=True, parent=self.iface.mainWindow(), ) self.add_central_toolbar_button() self.showorders_act = self.add_action( os.path.join(plugin_path, "resources", "orders.svg"), text=self.tr("Show Orders Monitor..."), callback=toggle_orders_monitor, add_to_menu=False, add_to_toolbar=True, parent=self.iface.mainWindow(), ) self.add_user_button() self.add_info_button() self.settings_act = self.add_action( os.path.join(plugin_path, "resources", "cog.svg"), text=self.tr("Settings..."), callback=self.show_settings, add_to_menu=True, add_to_toolbar=False, parent=self.iface.mainWindow(), ) self.provider = BasemapLayerWidgetProvider() QgsGui.layerTreeEmbeddedWidgetRegistry().addProvider(self.provider) QgsProject.instance().projectSaved.connect(self.project_saved) QgsProject.instance().layersAdded.connect(self.layers_added) QgsProject.instance().layerRemoved.connect(self.layer_removed) PlanetClient.getInstance().loginChanged.connect(self.login_changed) self.enable_buttons(False) def add_central_toolbar_button(self): widget = QWidget() widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) layout = QHBoxLayout() layout.addStretch() self.btnLogin = QPushButton() palette = self.btnLogin.palette() palette.setColor(QPalette.Button, PLANET_COLOR) self.btnLogin.setPalette(palette) self.btnLogin.setText("Log in") # self.btnLogin.setAutoRaise(True) self.btnLogin.setAttribute(Qt.WA_TranslucentBackground) self.btnLogin.clicked.connect(self.btn_login_clicked) icon = QIcon(os.path.join(plugin_path, "resources", "planet-logo-p.svg")) labelIcon = QLabel() labelIcon.setPixmap(icon.pixmap(QSize(16, 16))) layout.addWidget(labelIcon) self.labelLoggedIn = QLabel() self.labelLoggedIn.setText("") layout.addWidget(self.labelLoggedIn) layout.addWidget(self.btnLogin) layout.addStretch() widget.setLayout(layout) self.toolbar.addWidget(widget) def btn_login_clicked(self): if PlanetClient.getInstance().has_api_key(): self.logout() else: self.login() def layer_removed(self, layer): self.provider.layerWasRemoved(layer) def layers_added(self, layers): for layer in layers: add_widget_to_layer(layer) def login_changed(self, loggedin): self.provider.updateLayerWidgets() self.enable_buttons(loggedin) if not loggedin: hide_orders_monitor() hide_inspector() def add_info_button(self): info_menu = QMenu() add_menu_section_action("Planet", info_menu) p_com_act = QAction(QIcon(EXT_LINK), "planet.com", info_menu) p_com_act.triggered[bool].connect(lambda: open_link_with_browser(PLANET_COM)) info_menu.addAction(p_com_act) p_explorer_act = QAction(QIcon(EXT_LINK), "Planet Explorer web app", info_menu) p_explorer_act.triggered[bool].connect( lambda: open_link_with_browser(PLANET_EXPLORER) ) info_menu.addAction(p_explorer_act) p_sat_act = QAction(QIcon(EXT_LINK), "Satellite specs PDF", info_menu) p_sat_act.triggered[bool].connect(lambda: open_link_with_browser(SAT_SPECS_PDF)) info_menu.addAction(p_sat_act) p_support_act = QAction(QIcon(EXT_LINK), "Support Community", info_menu) p_support_act.triggered[bool].connect( lambda: open_link_with_browser(PLANET_SUPPORT_COMMUNITY) ) info_menu.addAction(p_support_act) p_whatsnew_act = QAction(QIcon(EXT_LINK), "What's new", info_menu) p_whatsnew_act.triggered[bool].connect( lambda: open_link_with_browser(PLANET_INTEGRATIONS) ) info_menu.addAction(p_whatsnew_act) p_sales_act = QAction(QIcon(EXT_LINK), "Sales", info_menu) p_sales_act.triggered[bool].connect( lambda: open_link_with_browser(PLANET_SALES) ) info_menu.addAction(p_sales_act) add_menu_section_action("Documentation", info_menu) terms_act = QAction("Terms", info_menu) terms_act.triggered[bool].connect(self.show_terms) info_menu.addAction(terms_act) btn = QToolButton() btn.setIcon( QIcon( os.path.join(plugin_path, "resources", "info.svg"), ) ) btn.setMenu(info_menu) btn.setPopupMode(QToolButton.MenuButtonPopup) # Also show menu on click, to keep disclosure triangle visible btn.clicked.connect(btn.showMenu) self.toolbar.addWidget(btn) def add_user_button(self): user_menu = QMenu() self.acct_act = QAction(QIcon(EXT_LINK), "Account", user_menu) self.acct_act.triggered[bool].connect( lambda: QDesktopServices.openUrl(QUrl(ACCOUNT_URL)) ) user_menu.addAction(self.acct_act) self.logout_act = QAction("Logout", user_menu) self.logout_act.triggered[bool].connect(self.logout) user_menu.addAction(self.logout_act) self.user_button = QToolButton() self.user_button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) self.user_button.setIcon( QIcon( os.path.join(plugin_path, "resources", "account.svg"), ) ) self.user_button.setMenu(user_menu) self.user_button.setPopupMode(QToolButton.MenuButtonPopup) # Also show menu on click, to keep disclosure triangle visible self.user_button.clicked.connect(self.user_button.showMenu) self.toolbar.addWidget(self.user_button) def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" PlanetClient.getInstance().log_out() self.provider.updateLayerWidgets() for action in self.actions: self.iface.removePluginWebMenu(self.tr("&{0}".format(P_E)), action) self.iface.removeToolBarIcon(action) # remove the toolbar if self.toolbar is not None: del self.toolbar remove_inspector() remove_explorer() remove_orders_monitor() remove_tasking_widget() QgsGui.layerTreeEmbeddedWidgetRegistry().removeProvider(self.provider.id()) sys.excepthook = self.qgis_hook QgsProject.instance().projectSaved.disconnect(self.project_saved) QgsProject.instance().layersAdded.disconnect(self.layers_added) QgsProject.instance().layerRemoved.disconnect(self.layer_removed) # ----------------------------------------------------------- def show_settings(self): dlg = SettingsDialog() dlg.exec() def show_terms(self, _): if self._terms_browser is None: self._terms_browser = QTextBrowser() self._terms_browser.setReadOnly(True) self._terms_browser.setOpenExternalLinks(True) self._terms_browser.setMinimumSize(600, 700) # TODO: Template terms.html first section, per subscription level # Collect subscription info from self.p_client.user self._terms_browser.setSource( QUrl("qrc:/plugins/planet_explorer/terms.html") ) self._terms_browser.setWindowModality(Qt.ApplicationModal) self._terms_browser.show() def login(self): if Qgis.QGIS_VERSION_INT >= 32000 and platform.system() == "Darwin": text = ( "WARNING: Your configuration may encounter serious issues with the" " Planet QGIS Plugin using QGIS V3.20. We are actively troubleshooting" " the issue with the QGIS team, you can track <a" " href='https://github.com/qgis/QGIS/issues/44182'>Issue 44182" " here</a>. In the meantime, we recommend that you use a QGIS version" " between 3.10 and 3.20, such as the 3.16 long term stable release. For" " further information including instructions on how to downgrade QGIS," " please refer to our <a" " href='https://support.planet.com/hc/en-us/articles/4404372169233'>support" " page here</a>." ) QMessageBox.warning(self.iface.mainWindow(), "Planet Explorer", text) show_explorer() def logout(self): PlanetClient.getInstance().log_out() def enable_buttons(self, loggedin): self.btnLogin.setVisible(not loggedin) labelText = "<b>Welcome to Planet</b>" if not loggedin else "<b>Planet</b>" self.labelLoggedIn.setText(labelText) self.showdailyimages_act.setEnabled(loggedin) self.showbasemaps_act.setEnabled(loggedin) self.showinspector_act.setEnabled(loggedin) self.showorders_act.setEnabled(loggedin) self.showtasking_act.setEnabled(loggedin) self.user_button.setEnabled(loggedin) self.user_button.setText( PlanetClient.getInstance().user()["user_name"] if loggedin else "" ) if loggedin: self.showdailyimages_act.setToolTip( "Show / Hide the Planet Imagery Search Panel" ) self.showbasemaps_act.setToolTip( "Show / Hide the Planet Basemaps Search Panel" ) self.showorders_act.setToolTip("Show / Hide the Order Status Panel") self.showinspector_act.setToolTip("Show / Hide the Planet Inspector Panel") self.showtasking_act.setToolTip("Show / Hide the Tasking Panel") else: self.showdailyimages_act.setToolTip("Login to access Imagery Search") self.showbasemaps_act.setToolTip("Login to access Basemaps Search") self.showorders_act.setToolTip("Login to access Order Status") self.showinspector_act.setToolTip("Login to access Planet Inspector") self.showtasking_act.setToolTip("Login to access Tasking Panel") def project_saved(self): if PlanetClient.getInstance().has_api_key(): def resave(): try: path = QgsProject.instance().absoluteFilePath() if path.lower().endswith(".qgs"): with open(path, encoding="utf-8") as f: s = f.read() with open(path, "w", encoding="utf-8") as f: f.write(s.replace(PlanetClient.getInstance().api_key(), "")) else: tmpfilename = path + ".temp" qgsfilename = ( os.path.splitext(os.path.basename(path))[0] + ".qgs" ) with zipfile.ZipFile(path, "r") as zin: with zipfile.ZipFile(tmpfilename, "w") as zout: zout.comment = zin.comment for item in zin.infolist(): if not item.filename.lower().endswith(".qgs"): zout.writestr(item, zin.read(item.filename)) else: s = zin.read(item.filename).decode("utf-8") s = s.replace( PlanetClient.getInstance().api_key(), "" ) qgsfilename = item.filename os.remove(path) os.rename(tmpfilename, path) with zipfile.ZipFile( path, mode="a", compression=zipfile.ZIP_DEFLATED ) as zf: zf.writestr(qgsfilename, s) except Exception: QMessageBox.warning( self.iface.mainWindow(), "Error saving project", "There was an error while removing API keys from QGIS project" " file.\nThe project that you have just saved might contain" " Planet API keys in plain text.", ) QTimer.singleShot(100, resave)
def _setupUI(self): self.setSizePolicy( QSizePolicy.Preferred, QSizePolicy.Preferred) self.setMinimumHeight(180) self.main_horizontal_layout = QHBoxLayout(self) italic_font = QFont() italic_font.setItalic(True) # deselected widget self.deselected_widget = QListWidget(self) self._set_list_widget_defaults(self.deselected_widget) deselected_label = QLabel() deselected_label.setText('Deselected') deselected_label.setAlignment(Qt.AlignCenter) deselected_label.setFont(italic_font) deselected_v_layout = QVBoxLayout() deselected_v_layout.addWidget(deselected_label) deselected_v_layout.addWidget(self.deselected_widget) # selected widget self.selected_widget = QListWidget(self) self._set_list_widget_defaults(self.selected_widget) selected_label = QLabel() selected_label.setText('Selected') selected_label.setAlignment(Qt.AlignCenter) selected_label.setFont(italic_font) selected_v_layout = QVBoxLayout() selected_v_layout.addWidget(selected_label) selected_v_layout.addWidget(self.selected_widget) # buttons self.buttons_vertical_layout = QVBoxLayout() self.buttons_vertical_layout.setContentsMargins(0, -1, 0, -1) self.select_all_btn = SmallQPushButton('>>') self.deselect_all_btn = SmallQPushButton('<<') self.select_btn = SmallQPushButton('>') self.deselect_btn = SmallQPushButton('<') self.select_btn.setToolTip('Add the selected items') self.deselect_btn.setToolTip('Remove the selected items') self.select_all_btn.setToolTip('Add all') self.deselect_all_btn.setToolTip('Remove all') # add buttons spacer_label = QLabel() # pragmatic way to create a spacer with # the same height of the labels on top # of the lists, in order to align the # buttons with the lists. self.buttons_vertical_layout.addWidget(spacer_label) self.buttons_vertical_layout.addWidget(self.select_btn) self.buttons_vertical_layout.addWidget(self.deselect_btn) self.buttons_vertical_layout.addWidget(self.select_all_btn) self.buttons_vertical_layout.addWidget(self.deselect_all_btn) # add sub widgets self.main_horizontal_layout.addLayout(deselected_v_layout) self.main_horizontal_layout.addLayout(self.buttons_vertical_layout) self.main_horizontal_layout.addLayout(selected_v_layout)
class FieldMappingTab(QWidget, object): """Widget class for field mapping.""" def __init__(self, field_group=None, parent=None, iface=None): """Constructor.""" # Init from parent class QWidget.__init__(self, parent) # Attributes self.layer = None self.metadata = {} self.parent = parent self.iface = iface self.field_group = field_group self.setting = QSettings() # TODO(IS): Make dynamic # Main container self.main_layout = QVBoxLayout() # Inner layout self.header_layout = QHBoxLayout() self.content_layout = QHBoxLayout() self.footer_layout = QHBoxLayout() # Header self.header_label = QLabel() self.header_label.setWordWrap(True) # Content self.field_layout = QVBoxLayout() self.parameter_layout = QHBoxLayout() self.field_description = QLabel(tr('List of fields')) self.field_list = QListWidget() self.field_list.setSelectionMode(QAbstractItemView.ExtendedSelection) self.field_list.setDragDropMode(QAbstractItemView.DragDrop) self.field_list.setDefaultDropAction(Qt.MoveAction) self.field_list.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Expanding) # noinspection PyUnresolvedReferences self.field_list.itemSelectionChanged.connect(self.update_footer) # Footer self.footer_label = QLabel() self.footer_label.setWordWrap(True) # Parameters self.extra_parameters = [(GroupSelectParameter, GroupSelectParameterWidget)] self.parameters = [] self.parameter_container = None # Adding to layout self.header_layout.addWidget(self.header_label) self.field_layout.addWidget(self.field_description) self.field_layout.addWidget(self.field_list) self.field_layout.setSizeConstraint(QLayout.SetMaximumSize) self.content_layout.addLayout(self.field_layout) self.content_layout.addLayout(self.parameter_layout) self.footer_layout.addWidget(self.footer_label) self.main_layout.addLayout(self.header_layout) self.main_layout.addLayout(self.content_layout) self.main_layout.addLayout(self.footer_layout) self.setLayout(self.main_layout) def set_layer(self, layer, keywords=None): """Set layer and update UI accordingly. :param layer: A vector layer that has been already patched with metadata. :type layer: QgsVectorLayer :param keywords: Custom keyword for the layer. :type keywords: dict, None """ self.layer = layer if keywords is not None: self.metadata = keywords else: # Check if it has keywords if not hasattr(layer, 'keywords'): message = 'Layer {layer_name} does not have keywords.'.format( layer_name=layer.name()) raise KeywordNotFoundError(message) self.metadata = layer.keywords self.populate_parameter() def populate_field_list(self, excluded_fields=None): """Helper to add field of the layer to the list. :param excluded_fields: List of field that want to be excluded. :type excluded_fields: list """ # Populate fields list if excluded_fields is None: excluded_fields = [] self.field_list.clear() for field in self.layer.fields(): # Skip if it's excluded if field.name() in excluded_fields: continue # Skip if it's not number (float, int, etc) if field.type() not in qvariant_numbers: continue field_item = QListWidgetItem(self.field_list) field_item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsDragEnabled) field_item.setData(Qt.UserRole, field.name()) field_item.setText(field.name()) self.field_list.addItem(field_item) def populate_parameter(self): """Helper to setup the parameter widget.""" used_fields = [] self.parameters = [] for field in self.field_group.get('fields', []): selected_option = DO_NOT_REPORT options = OrderedDict([ (DO_NOT_REPORT, { 'label': tr('Do not report'), 'value': None, 'type': STATIC, 'constraint': {} }), ]) # Example: count if field['absolute']: # Used in field options field_label = tr('Count fields') else: # Example: ratio # Used in field options field_label = tr('Ratio fields') global_default_value = get_inasafe_default_value_qsetting( self.setting, GLOBAL, field['key']) options[GLOBAL_DEFAULT] = { 'label': tr('Global default'), 'value': global_default_value, 'type': STATIC, 'constraint': {} } default_custom_value = get_inasafe_default_value_qsetting( self.setting, RECENT, field['key']) custom_value = self.metadata.get('inasafe_default_values', {}).get( field['key'], default_custom_value) if field['key'] in self.metadata.get('inasafe_default_values', {}): if custom_value == global_default_value: selected_option = GLOBAL_DEFAULT else: selected_option = CUSTOM_VALUE min_value = field['default_value'].get('min_value', 0) max_value = field['default_value'].get('max_value', 100) default_step = (max_value - min_value) / 100.0 step = field['default_value'].get('increment', default_step) options[CUSTOM_VALUE] = { 'label': tr('Custom'), 'value': custom_value, 'type': SINGLE_DYNAMIC, 'constraint': { 'min': min_value, 'max': max_value, 'step': step } } custom_fields = self.metadata.get('inasafe_fields', {}).get(field['key'], []) if field['key'] in self.metadata.get('inasafe_fields', {}): selected_option = FIELDS if isinstance(custom_fields, str): custom_fields = [custom_fields] options[FIELDS] = { 'label': field_label, 'value': custom_fields, 'type': MULTIPLE_DYNAMIC, 'constraint': {} } used_fields.extend(custom_fields) parameter = GroupSelectParameter() parameter.guid = field['key'] parameter.name = field['name'] parameter.options = options parameter.selected = selected_option parameter.help_text = field['help_text'] parameter.description = field['description'] self.parameters.append(parameter) self.parameter_container = ParameterContainer( parameters=self.parameters, extra_parameters=self.extra_parameters, vertical=False) self.parameter_container.setup_ui() constraints = self.field_group.get('constraints', {}) for key, value in list(constraints.items()): self.parameter_container.add_validator( validators[key], kwargs=value['kwargs'], validation_message=value['message']) self.parameter_layout.addWidget(self.parameter_container) default_ratio_help_text = tr( 'By default, InaSAFE will calculate the default ratio ' 'however users have the option to include this in the ' 'analysis report. If you do not want to see the default ' 'results in the report choose "do not report".') # Set move or copy if self.field_group.get('exclusive', False): # If exclusive, do not add used field. self.populate_field_list(excluded_fields=used_fields) # Use move action since it's exclusive self.field_list.setDefaultDropAction(Qt.MoveAction) # Just make sure that the signal is disconnected try: # noinspection PyUnresolvedReferences self.field_list.itemChanged.disconnect(self.drop_remove) except TypeError: pass # Set header header_text = self.field_group['description'] header_text += '\n\n' + default_ratio_help_text header_text += '\n\n' + tr( 'You can only map one field to one concept.') else: # If not exclusive, add all field. self.populate_field_list() # Use copy action since it's not exclusive self.field_list.setDefaultDropAction(Qt.CopyAction) # noinspection PyUnresolvedReferences self.field_list.itemChanged.connect( partial(self.drop_remove, field_list=self.field_list)) self.connect_drop_remove_parameter() # Set header header_text = self.field_group['description'] header_text += '\n\n' + default_ratio_help_text header_text += '\n\n' + tr( 'You can map one field to more than one concepts.') self.header_label.setText(header_text) def get_parameter_value(self): """Get parameter of the tab. :returns: Dictionary of parameters by type in this format: {'fields': {}, 'values': {}}. :rtype: dict """ parameters = self.parameter_container.get_parameters(True) field_parameters = {} value_parameters = {} for parameter in parameters: if parameter.selected_option_type() in [SINGLE_DYNAMIC, STATIC]: value_parameters[parameter.guid] = parameter.value elif parameter.selected_option_type() == MULTIPLE_DYNAMIC: field_parameters[parameter.guid] = parameter.value return {'fields': field_parameters, 'values': value_parameters} def update_footer(self): """Update footer when the field list change.""" field_item = self.field_list.currentItem() if not field_item: self.footer_label.setText('') return field_name = field_item.data(Qt.UserRole) field = self.layer.fields().field(field_name) index = self.layer.fields().lookupField(field_name) unique_values = list(self.layer.uniqueValues(index)) pretty_unique_values = ', '.join([str(v) for v in unique_values[:10]]) footer_text = tr('Field type: {0}\n').format(field.typeName()) footer_text += tr('Unique values: {0}').format(pretty_unique_values) self.footer_label.setText(footer_text) def connect_drop_remove_parameter(self): parameter_widgets = self.parameter_container.get_parameter_widgets() for parameter_widget in parameter_widgets: field_list = parameter_widget.widget().list_widget field_list.itemChanged.connect( partial(self.drop_remove, field_list=field_list)) @staticmethod def drop_remove(*args, **kwargs): """Action when we need to remove dropped item. :param *args: Position arguments. :type *args: list :param kwargs: Keywords arguments. :type kwargs: dict """ dropped_item = args[0] field_list = kwargs['field_list'] num_duplicate = 0 for i in range(field_list.count()): if dropped_item.text() == field_list.item(i).text(): num_duplicate += 1 if num_duplicate > 1: # Notes(IS): For some reason, removeItemWidget is not working. field_list.takeItem(field_list.row(dropped_item))
def setupUi(self): self.labels = {} self.widgets = {} self.checkBoxes = {} self.showAdvanced = False self.wrappers = {} self.valueItems = {} self.dependentItems = {} self.resize(650, 450) self.buttonBox = QDialogButtonBox() self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok | QDialogButtonBox.Help) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.verticalLayout = QVBoxLayout() self.verticalLayout.setSpacing(5) self.verticalLayout.setMargin(20) self.bar = QgsMessageBar() self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed) self.verticalLayout.addWidget(self.bar) hLayout = QHBoxLayout() hLayout.setSpacing(5) hLayout.setMargin(0) descriptionLabel = QLabel(self.tr("Description")) self.descriptionBox = QLineEdit() self.descriptionBox.setText(self._alg.displayName()) hLayout.addWidget(descriptionLabel) hLayout.addWidget(self.descriptionBox) self.verticalLayout.addLayout(hLayout) line = QFrame() line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) self.verticalLayout.addWidget(line) for param in self._alg.parameterDefinitions(): if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced: self.advancedButton = QPushButton() self.advancedButton.setText(self.tr('Show advanced parameters')) self.advancedButton.clicked.connect( self.showAdvancedParametersClicked) advancedButtonHLayout = QHBoxLayout() advancedButtonHLayout.addWidget(self.advancedButton) advancedButtonHLayout.addStretch() self.verticalLayout.addLayout(advancedButtonHLayout) break for param in self._alg.parameterDefinitions(): if param.isDestination() or param.flags() & QgsProcessingParameterDefinition.FlagHidden: continue 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]') label = QLabel(desc) self.labels[param.name()] = label wrapper = WidgetWrapperFactory.create_wrapper(param, self) self.wrappers[param.name()] = wrapper widget = wrapper.widget if widget is not None: self.valueItems[param.name()] = widget tooltip = param.description() label.setToolTip(tooltip) widget.setToolTip(tooltip) if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced: label.setVisible(self.showAdvanced) widget.setVisible(self.showAdvanced) self.widgets[param.name()] = widget self.verticalLayout.addWidget(label) self.verticalLayout.addWidget(widget) for dest in self._alg.destinationParameterDefinitions(): if dest.flags() & QgsProcessingParameterDefinition.FlagHidden: continue if isinstance(dest, (QgsProcessingParameterRasterDestination, QgsProcessingParameterVectorDestination, QgsProcessingParameterFeatureSink, QgsProcessingParameterFileDestination, QgsProcessingParameterFolderDestination)): label = QLabel(dest.description()) item = QgsFilterLineEdit() if hasattr(item, 'setPlaceholderText'): item.setPlaceholderText(ModelerParametersDialog.ENTER_NAME) self.verticalLayout.addWidget(label) self.verticalLayout.addWidget(item) self.valueItems[dest.name()] = item label = QLabel(' ') self.verticalLayout.addWidget(label) label = QLabel(self.tr('Parent algorithms')) self.dependenciesPanel = self.getDependenciesPanel() self.verticalLayout.addWidget(label) self.verticalLayout.addWidget(self.dependenciesPanel) self.verticalLayout.addStretch(1000) self.setPreviousValues() self.setWindowTitle(self._alg.displayName()) self.verticalLayout2 = QVBoxLayout() self.verticalLayout2.setSpacing(2) self.verticalLayout2.setMargin(0) self.paramPanel = QWidget() self.paramPanel.setLayout(self.verticalLayout) self.scrollArea = QgsScrollArea() self.scrollArea.setWidget(self.paramPanel) self.scrollArea.setWidgetResizable(True) self.verticalLayout2.addWidget(self.scrollArea) self.verticalLayout2.addWidget(self.buttonBox) self.setLayout(self.verticalLayout2) self.buttonBox.accepted.connect(self.okPressed) self.buttonBox.rejected.connect(self.cancelPressed) self.buttonBox.helpRequested.connect(self.openHelp) QMetaObject.connectSlotsByName(self) for wrapper in list(self.wrappers.values()): wrapper.postInitialize(list(self.wrappers.values()))
def setupUi(self): self.checkBoxes = {} self.showAdvanced = False self.wrappers = {} self.valueItems = {} self.dependentItems = {} self.algorithmItem = None self.resize(650, 450) self.buttonBox = QDialogButtonBox() self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok | QDialogButtonBox.Help) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.verticalLayout = QVBoxLayout() self.verticalLayout.setSpacing(5) self.verticalLayout.setMargin(20) self.bar = QgsMessageBar() self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed) self.verticalLayout.addWidget(self.bar) hLayout = QHBoxLayout() hLayout.setSpacing(5) hLayout.setMargin(0) descriptionLabel = QLabel(self.tr("Description")) self.descriptionBox = QLineEdit() self.descriptionBox.setText(self._alg.displayName()) hLayout.addWidget(descriptionLabel) hLayout.addWidget(self.descriptionBox) self.verticalLayout.addLayout(hLayout) line = QFrame() line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) self.verticalLayout.addWidget(line) widget_context = QgsProcessingParameterWidgetContext() widget_context.setProject(QgsProject.instance()) if iface is not None: widget_context.setMapCanvas(iface.mapCanvas()) widget_context.setModel(self.model) widget_context.setModelChildAlgorithmId(self.childId) self.algorithmItem = QgsGui.instance().processingGuiRegistry( ).algorithmConfigurationWidget(self._alg) if self.algorithmItem: self.algorithmItem.setWidgetContext(widget_context) self.algorithmItem.registerProcessingContextGenerator( self.context_generator) if self.configuration: self.algorithmItem.setConfiguration(self.configuration) self.verticalLayout.addWidget(self.algorithmItem) for param in self._alg.parameterDefinitions(): if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced: self.advancedButton = QPushButton() self.advancedButton.setText( self.tr('Show advanced parameters')) self.advancedButton.clicked.connect( self.showAdvancedParametersClicked) advancedButtonHLayout = QHBoxLayout() advancedButtonHLayout.addWidget(self.advancedButton) advancedButtonHLayout.addStretch() self.verticalLayout.addLayout(advancedButtonHLayout) break for param in self._alg.parameterDefinitions(): if param.isDestination( ) or param.flags() & QgsProcessingParameterDefinition.FlagHidden: continue wrapper = WidgetWrapperFactory.create_wrapper(param, self) self.wrappers[param.name()] = wrapper wrapper.setWidgetContext(widget_context) wrapper.registerProcessingContextGenerator(self.context_generator) if issubclass(wrapper.__class__, QgsProcessingModelerParameterWidget): widget = wrapper else: widget = wrapper.widget if widget is not None: self.valueItems[param.name()] = widget if issubclass(wrapper.__class__, QgsProcessingModelerParameterWidget): label = wrapper.createLabel() else: tooltip = param.description() widget.setToolTip(tooltip) label = wrapper.label self.widget_labels[param.name()] = label if param.flags( ) & QgsProcessingParameterDefinition.FlagAdvanced: label.setVisible(self.showAdvanced) widget.setVisible(self.showAdvanced) self.verticalLayout.addWidget(label) self.verticalLayout.addWidget(widget) for dest in self._alg.destinationParameterDefinitions(): if dest.flags() & QgsProcessingParameterDefinition.FlagHidden: continue if isinstance(dest, (QgsProcessingParameterRasterDestination, QgsProcessingParameterVectorDestination, QgsProcessingParameterFeatureSink, QgsProcessingParameterFileDestination, QgsProcessingParameterFolderDestination)): label = QLabel(dest.description()) item = QgsFilterLineEdit() if hasattr(item, 'setPlaceholderText'): item.setPlaceholderText( self.tr('[Enter name if this is a final result]')) self.verticalLayout.addWidget(label) self.verticalLayout.addWidget(item) self.valueItems[dest.name()] = item label = QLabel(' ') self.verticalLayout.addWidget(label) label = QLabel(self.tr('Parent algorithms')) self.dependenciesPanel = self.getDependenciesPanel() self.verticalLayout.addWidget(label) self.verticalLayout.addWidget(self.dependenciesPanel) self.verticalLayout.addStretch(1000) self.setPreviousValues() self.setWindowTitle(self._alg.displayName()) self.verticalLayout2 = QVBoxLayout() self.verticalLayout2.setSpacing(2) self.verticalLayout2.setMargin(0) self.paramPanel = QWidget() self.paramPanel.setLayout(self.verticalLayout) self.scrollArea = QgsScrollArea() self.scrollArea.setWidget(self.paramPanel) self.scrollArea.setWidgetResizable(True) self.verticalLayout2.addWidget(self.scrollArea) self.verticalLayout2.addWidget(self.buttonBox) self.setLayout(self.verticalLayout2) self.buttonBox.accepted.connect(self.okPressed) self.buttonBox.rejected.connect(self.cancelPressed) self.buttonBox.helpRequested.connect(self.openHelp) QMetaObject.connectSlotsByName(self)
def __init__(self, field_group=None, parent=None, iface=None): """Constructor.""" # Init from parent class QWidget.__init__(self, parent) # Attributes self.layer = None self.metadata = {} self.parent = parent self.iface = iface self.field_group = field_group self.setting = QSettings() # TODO(IS): Make dynamic # Main container self.main_layout = QVBoxLayout() # Inner layout self.header_layout = QHBoxLayout() self.content_layout = QHBoxLayout() self.footer_layout = QHBoxLayout() # Header self.header_label = QLabel() self.header_label.setWordWrap(True) # Content self.field_layout = QVBoxLayout() self.parameter_layout = QHBoxLayout() self.field_description = QLabel(tr('List of fields')) self.field_list = QListWidget() self.field_list.setSelectionMode(QAbstractItemView.ExtendedSelection) self.field_list.setDragDropMode(QAbstractItemView.DragDrop) self.field_list.setDefaultDropAction(Qt.MoveAction) self.field_list.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Expanding) # noinspection PyUnresolvedReferences self.field_list.itemSelectionChanged.connect(self.update_footer) # Footer self.footer_label = QLabel() self.footer_label.setWordWrap(True) # Parameters self.extra_parameters = [(GroupSelectParameter, GroupSelectParameterWidget)] self.parameters = [] self.parameter_container = None # Adding to layout self.header_layout.addWidget(self.header_label) self.field_layout.addWidget(self.field_description) self.field_layout.addWidget(self.field_list) self.field_layout.setSizeConstraint(QLayout.SetMaximumSize) self.content_layout.addLayout(self.field_layout) self.content_layout.addLayout(self.parameter_layout) self.footer_layout.addWidget(self.footer_label) self.main_layout.addLayout(self.header_layout) self.main_layout.addLayout(self.content_layout) self.main_layout.addLayout(self.footer_layout) self.setLayout(self.main_layout)
class DistanceInputPanel(NumberInputPanel): """ Distance input panel for use outside the modeler - this input panel contains a label showing the distance unit. """ def __init__(self, param): super().__init__(param) self.label = QLabel('') self.units_combo = QComboBox() self.base_units = QgsUnitTypes.DistanceUnknownUnit for u in (QgsUnitTypes.DistanceMeters, QgsUnitTypes.DistanceKilometers, QgsUnitTypes.DistanceFeet, QgsUnitTypes.DistanceMiles, QgsUnitTypes.DistanceYards): self.units_combo.addItem(QgsUnitTypes.toString(u), u) label_margin = self.fontMetrics().width('X') self.layout().insertSpacing(1, label_margin / 2) self.layout().insertWidget(2, self.label) self.layout().insertWidget(3, self.units_combo) self.layout().insertSpacing(4, label_margin / 2) self.warning_label = QLabel() icon = QgsApplication.getThemeIcon('mIconWarning.svg') size = max(24, self.spnValue.height() * 0.5) self.warning_label.setPixmap(icon.pixmap(icon.actualSize(QSize(size, size)))) self.warning_label.setToolTip(self.tr('Distance is in geographic degrees. Consider reprojecting to a projected local coordinate system for accurate results.')) self.layout().insertWidget(4, self.warning_label) self.layout().insertSpacing(5, label_margin) self.setUnits(QgsUnitTypes.DistanceUnknownUnit) def setUnits(self, units): self.label.setText(QgsUnitTypes.toString(units)) if QgsUnitTypes.unitType(units) != QgsUnitTypes.Standard: self.units_combo.hide() self.label.show() else: self.units_combo.setCurrentIndex(self.units_combo.findData(units)) self.units_combo.show() self.label.hide() self.warning_label.setVisible(units == QgsUnitTypes.DistanceDegrees) self.base_units = units def setUnitParameterValue(self, value): units = QgsUnitTypes.DistanceUnknownUnit layer = self.getLayerFromValue(value) if isinstance(layer, QgsMapLayer): units = layer.crs().mapUnits() elif isinstance(value, QgsCoordinateReferenceSystem): units = value.mapUnits() elif isinstance(value, str): crs = QgsCoordinateReferenceSystem(value) if crs.isValid(): units = crs.mapUnits() self.setUnits(units) def getValue(self): val = super().getValue() if isinstance(val, float) and self.units_combo.isVisible(): display_unit = self.units_combo.currentData() return val * QgsUnitTypes.fromUnitToUnitFactor(display_unit, self.base_units) return val def setValue(self, value): try: self.spnValue.setValue(float(value)) except: return
def addAlgorithmsFromProvider(self, provider, parent): groups = {} count = 0 algs = provider.algorithms() active = provider.isActive() # Add algorithms for alg in algs: if alg.flags() & QgsProcessingAlgorithm.FlagHideFromToolbox: continue groupItem = None if alg.group() in groups: groupItem = groups[alg.group()] else: # check if group already exists for i in range(parent.childCount()): if parent.child(i).text(0) == alg.group(): groupItem = parent.child(i) groups[alg.group()] = groupItem break if not groupItem: groupItem = TreeGroupItem(alg.group()) if not active: groupItem.setInactive() if provider.id() in ('qgis', 'native', '3d'): groupItem.setIcon(0, provider.icon()) groups[alg.group()] = groupItem algItem = TreeAlgorithmItem(alg) if not active: algItem.setForeground(0, Qt.darkGray) groupItem.addChild(algItem) count += 1 if provider.id() in ProviderActions.actions: actions = ProviderActions.actions[provider.id()] for action in actions: if action.group in groups: groupItem = groups[action.group] else: groupItem = TreeGroupItem(action.group) groups[action.group] = groupItem algItem = TreeActionItem(action) groupItem.addChild(algItem) text = provider.name() if not provider.id() in ('qgis', 'native', '3d'): if not active: def activateProvider(): self.activateProvider(provider.id()) label = QLabel( text + " <a href='%s'>Activate</a>") label.setStyleSheet( "QLabel {background-color: white; color: grey;}") label.linkActivated.connect(activateProvider) self.algorithmTree.setItemWidget(parent, 0, label) else: parent.setText(0, text) for group, groupItem in sorted(groups.items(), key=operator.itemgetter(1)): parent.addChild(groupItem) if not provider.id() in ('qgis', 'native', '3d'): parent.setHidden(parent.childCount() == 0)
def setupUi(self): self.setWindowTitle(self.tr('Parameter definition')) self.setMinimumWidth(300) self.verticalLayout = QVBoxLayout(self) self.verticalLayout.setMargin(20) self.label = QLabel(self.tr('Parameter name')) self.verticalLayout.addWidget(self.label) self.nameTextBox = QLineEdit() self.verticalLayout.addWidget(self.nameTextBox) if isinstance(self.param, Parameter): self.nameTextBox.setText(self.param.description) if self.paramType == ModelerParameterDefinitionDialog.PARAMETER_BOOLEAN or \ isinstance(self.param, ParameterBoolean): self.state = QCheckBox() self.state.setText(self.tr('Checked')) self.state.setChecked(False) if self.param is not None: self.state.setChecked(bool(self.param.value)) self.verticalLayout.addWidget(self.state) elif self.paramType == ModelerParameterDefinitionDialog.PARAMETER_TABLE_FIELD or \ isinstance(self.param, ParameterTableField): self.verticalLayout.addWidget(QLabel(self.tr('Parent layer'))) self.parentCombo = QComboBox() idx = 0 for param in list(self.alg.inputs.values()): if isinstance(param.param, (ParameterVector, ParameterTable)): self.parentCombo.addItem(param.param.description, param.param.name) if self.param is not None: if self.param.parent == param.param.name: self.parentCombo.setCurrentIndex(idx) idx += 1 self.verticalLayout.addWidget(self.parentCombo) # add the datatype selector self.verticalLayout.addWidget(QLabel(self.tr('Allowed data type'))) self.datatypeCombo = QComboBox() self.datatypeCombo.addItem(self.tr('Any'), -1) self.datatypeCombo.addItem(self.tr('Number'), 0) self.datatypeCombo.addItem(self.tr('String'), 1) self.datatypeCombo.addItem(self.tr('Date/time'), 2) self.verticalLayout.addWidget(self.datatypeCombo) if self.param is not None and self.param.datatype is not None: # QComboBoxes indexes start at 0, # self.param.datatype start with -1 that is why I need to do +1 datatypeIndex = self.param.datatype + 1 self.datatypeCombo.setCurrentIndex(datatypeIndex) self.multipleCheck = QCheckBox() self.multipleCheck.setText(self.tr('Accept multiple fields')) self.multipleCheck.setChecked(False) if self.param is not None: self.multipleCheck.setChecked(self.param.multiple) self.verticalLayout.addWidget(self.multipleCheck) elif (self.paramType == ModelerParameterDefinitionDialog.PARAMETER_VECTOR or isinstance(self.param, ParameterVector)): self.verticalLayout.addWidget(QLabel(self.tr('Shape type'))) self.shapetypeCombo = QComboBox() self.shapetypeCombo.addItem(self.tr('Any')) self.shapetypeCombo.addItem(self.tr('Point')) self.shapetypeCombo.addItem(self.tr('Line')) self.shapetypeCombo.addItem(self.tr('Polygon')) if self.param is not None: self.shapetypeCombo.setCurrentIndex(self.param.datatype[0] + 1) self.verticalLayout.addWidget(self.shapetypeCombo) elif (self.paramType == ModelerParameterDefinitionDialog.PARAMETER_MULTIPLE or isinstance(self.param, ParameterMultipleInput)): self.verticalLayout.addWidget(QLabel(self.tr('Data type'))) self.datatypeCombo = QComboBox() self.datatypeCombo.addItem(self.tr('Vector (any)')) self.datatypeCombo.addItem(self.tr('Vector (point)')) self.datatypeCombo.addItem(self.tr('Vector (line)')) self.datatypeCombo.addItem(self.tr('Vector (polygon)')) self.datatypeCombo.addItem(self.tr('Raster')) self.datatypeCombo.addItem(self.tr('File')) if self.param is not None: self.datatypeCombo.setCurrentIndex(self.param.datatype + 1) self.verticalLayout.addWidget(self.datatypeCombo) elif (self.paramType == ModelerParameterDefinitionDialog.PARAMETER_NUMBER or isinstance(self.param, ParameterNumber)): self.verticalLayout.addWidget(QLabel(self.tr('Min value'))) self.minTextBox = QLineEdit() self.verticalLayout.addWidget(self.minTextBox) self.verticalLayout.addWidget(QLabel(self.tr('Max value'))) self.maxTextBox = QLineEdit() self.verticalLayout.addWidget(self.maxTextBox) if self.param is not None: self.minTextBox.setText(str(self.param.min)) self.maxTextBox.setText(str(self.param.max)) self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultTextBox = QLineEdit() self.defaultTextBox.setText(self.tr('0')) if self.param is not None: default = self.param.default if self.param.isInteger: default = int(math.floor(default)) if default: self.defaultTextBox.setText(str(default)) self.verticalLayout.addWidget(self.defaultTextBox) elif (self.paramType == ModelerParameterDefinitionDialog.PARAMETER_EXPRESSION or isinstance(self.param, ParameterExpression)): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultEdit = QgsExpressionLineEdit() if self.param is not None: self.defaultEdit.setExpression(self.param.default) self.verticalLayout.addWidget(self.defaultEdit) self.verticalLayout.addWidget(QLabel(self.tr('Parent layer'))) self.parentCombo = QComboBox() self.parentCombo.addItem(self.tr("None"), None) idx = 1 for param in list(self.alg.inputs.values()): if isinstance(param.param, (ParameterVector, ParameterTable)): self.parentCombo.addItem(param.param.description, param.param.name) if self.param is not None: if self.param.parent_layer == param.param.name: self.parentCombo.setCurrentIndex(idx) idx += 1 self.verticalLayout.addWidget(self.parentCombo) elif (self.paramType == ModelerParameterDefinitionDialog.PARAMETER_STRING or isinstance(self.param, ParameterString)): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultTextBox = QLineEdit() if self.param is not None: self.defaultTextBox.setText(self.param.default) self.verticalLayout.addWidget(self.defaultTextBox) elif (self.paramType == ModelerParameterDefinitionDialog.PARAMETER_FILE or isinstance(self.param, ParameterFile)): self.verticalLayout.addWidget(QLabel(self.tr('Type'))) self.fileFolderCombo = QComboBox() self.fileFolderCombo.addItem(self.tr('File')) self.fileFolderCombo.addItem(self.tr('Folder')) if self.param is not None: self.fileFolderCombo.setCurrentIndex( 1 if self.param.isFolder else 0) self.verticalLayout.addWidget(self.fileFolderCombo) elif (self.paramType == ModelerParameterDefinitionDialog.PARAMETER_POINT or isinstance(self.param, ParameterPoint)): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.defaultTextBox = QLineEdit() if self.param is not None: self.defaultTextBox.setText(self.param.default) self.verticalLayout.addWidget(self.defaultTextBox) elif (self.paramType == ModelerParameterDefinitionDialog.PARAMETER_CRS or isinstance(self.param, ParameterCrs)): self.verticalLayout.addWidget(QLabel(self.tr('Default value'))) self.selector = QgsProjectionSelectionWidget() if self.param is not None: self.selector.setCrs( QgsCoordinateReferenceSystem(self.param.default)) else: self.selector.setCrs(QgsCoordinateReferenceSystem('EPSG:4326')) self.verticalLayout.addWidget(self.selector) self.verticalLayout.addSpacing(20) self.requiredCheck = QCheckBox() self.requiredCheck.setText(self.tr('Mandatory')) self.requiredCheck.setChecked(True) if self.param is not None: self.requiredCheck.setChecked(not self.param.optional) self.verticalLayout.addWidget(self.requiredCheck) self.buttonBox = QDialogButtonBox(self) self.buttonBox.setOrientation(Qt.Horizontal) self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) self.buttonBox.setObjectName('buttonBox') self.buttonBox.accepted.connect(self.okPressed) self.buttonBox.rejected.connect(self.cancelPressed) self.verticalLayout.addStretch() self.verticalLayout.addWidget(self.buttonBox) self.setLayout(self.verticalLayout)
class QgsPluginInstaller(QObject): """ The main class for managing the plugin installer stuff""" statusLabel = None # ----------------------------------------- # def __init__(self): """ Initialize data objects, starts fetching if appropriate, and warn about/removes obsolete plugins """ QObject.__init__( self) # initialize QObject in order to to use self.tr() repositories.load() plugins.getAllInstalled() if repositories.checkingOnStart() and repositories.timeForChecking( ) and repositories.allEnabled(): # start fetching repositories self.statusLabel = QLabel(iface.mainWindow().statusBar()) iface.mainWindow().statusBar().addPermanentWidget(self.statusLabel) self.statusLabel.linkActivated.connect( self.showPluginManagerWhenReady) repositories.checkingDone.connect(self.checkingDone) for key in repositories.allEnabled(): repositories.requestFetching(key) else: # no fetching at start, so mark all enabled repositories as requesting to be fetched. for key in repositories.allEnabled(): repositories.setRepositoryData(key, "state", 3) # look for obsolete plugins updates (the user-installed one is older than the core one) for key in plugins.obsoletePlugins: plugin = plugins.localCache[key] msg = QMessageBox() msg.setIcon(QMessageBox.Warning) msg.setWindowTitle(self.tr("QGIS Python Plugin Installer")) msg.addButton(self.tr("Uninstall (recommended)"), QMessageBox.AcceptRole) msg.addButton(self.tr("I will uninstall it later"), QMessageBox.RejectRole) msg.setText("%s <b>%s</b><br/><br/>%s" % ( self.tr("Obsolete plugin:"), plugin["name"], self. tr("QGIS has detected an obsolete plugin that masks its more recent version shipped with this copy of QGIS. This is likely due to files associated with a previous installation of QGIS. Do you want to remove the old plugin right now and unmask the more recent version?" ))) msg.exec_() if not msg.result(): # uninstall the update, update utils and reload if enabled self.uninstallPlugin(key, quiet=True) updateAvailablePlugins() settings = QgsSettings() if settings.value("/PythonPlugins/" + key, False, type=bool): settings.setValue("/PythonPlugins/watchDog/" + key, True) loadPlugin(key) startPlugin(key) settings.remove("/PythonPlugins/watchDog/" + key) # ----------------------------------------- # def fetchAvailablePlugins(self, reloadMode): """ Fetch plugins from all enabled repositories.""" """ reloadMode = true: Fully refresh data from QgsSettings to mRepositories """ """ reloadMode = false: Fetch unready repositories only """ QApplication.setOverrideCursor(Qt.WaitCursor) if reloadMode: repositories.load() plugins.clearRepoCache() plugins.getAllInstalled() for key in repositories.allEnabled(): if reloadMode or repositories.all( )[key]["state"] == 3: # if state = 3 (error or not fetched yet), try to fetch once again repositories.requestFetching(key, force_reload=reloadMode) if repositories.fetchingInProgress(): fetchDlg = QgsPluginInstallerFetchingDialog(iface.mainWindow()) fetchDlg.exec_() del fetchDlg for key in repositories.all(): repositories.killConnection(key) QApplication.restoreOverrideCursor() # display error messages for every unavailable repository, unless Shift pressed nor all repositories are unavailable keepQuiet = QgsApplication.keyboardModifiers() == Qt.KeyboardModifiers( Qt.ShiftModifier) if repositories.allUnavailable( ) and repositories.allUnavailable() != repositories.allEnabled(): for key in repositories.allUnavailable(): if not keepQuiet: QMessageBox.warning( iface.mainWindow(), self.tr("QGIS Python Plugin Installer"), self.tr("Error reading repository:") + " " + key + "\n\n" + repositories.all()[key]["error"]) if QgsApplication.keyboardModifiers() == Qt.KeyboardModifiers( Qt.ShiftModifier): keepQuiet = True # finally, rebuild plugins from the caches plugins.rebuild() # ----------------------------------------- # def checkingDone(self): """ Remove the "Looking for new plugins..." label and display a notification instead if any updates or news available """ if not self.statusLabel: # only proceed if the label is present return # rebuild plugins cache plugins.rebuild() # look for news in the repositories plugins.markNews() status = "" icon = "" # first check for news for key in plugins.all(): if plugins.all()[key]["status"] == "new": status = self.tr("There is a new plugin available") icon = "pluginNew.svg" tabIndex = 4 # PLUGMAN_TAB_NEW # then check for updates (and eventually overwrite status) for key in plugins.all(): if plugins.all()[key]["status"] == "upgradeable": status = self.tr("There is a plugin update available") icon = "pluginUpgrade.svg" tabIndex = 3 # PLUGMAN_TAB_UPGRADEABLE # finally set the notify label if status: self.statusLabel.setText( u'<a href="%d"><img src="qrc:/images/themes/default/%s"></a>' % (tabIndex, icon)) self.statusLabel.setToolTip(status) else: iface.mainWindow().statusBar().removeWidget(self.statusLabel) self.statusLabel = None # ----------------------------------------- # def exportRepositoriesToManager(self): """ Update manager's repository tree widget with current data """ iface.pluginManagerInterface().clearRepositoryList() for key in repositories.all(): url = repositories.all()[key]["url"] + repositories.urlParams() if repositories.inspectionFilter(): enabled = (key == repositories.inspectionFilter()) else: enabled = repositories.all()[key]["enabled"] iface.pluginManagerInterface().addToRepositoryList({ "name": key, "url": url, "enabled": enabled and "true" or "false", "valid": repositories.all()[key]["valid"] and "true" or "false", "state": str(repositories.all()[key]["state"]), "error": repositories.all()[key]["error"], "inspection_filter": repositories.inspectionFilter() and "true" or "false" }) # ----------------------------------------- # def exportPluginsToManager(self): """ Insert plugins metadata to QgsMetadataRegistry """ iface.pluginManagerInterface().clearPythonPluginMetadata() for key in plugins.all(): plugin = plugins.all()[key] iface.pluginManagerInterface().addPluginMetadata({ "id": key, "plugin_id": plugin["plugin_id"] or "", "name": plugin["name"], "description": plugin["description"], "about": plugin["about"], "category": plugin["category"], "tags": plugin["tags"], "changelog": plugin["changelog"], "author_name": plugin["author_name"], "author_email": plugin["author_email"], "homepage": plugin["homepage"], "tracker": plugin["tracker"], "code_repository": plugin["code_repository"], "version_installed": plugin["version_installed"], "library": plugin["library"], "icon": plugin["icon"], "readonly": plugin["readonly"] and "true" or "false", "installed": plugin["installed"] and "true" or "false", "available": plugin["available"] and "true" or "false", "status": plugin["status"], "status_exp": plugin["status_exp"], "error": plugin["error"], "error_details": plugin["error_details"], "create_date": plugin["create_date"], "update_date": plugin["update_date"], "create_date_stable": plugin["create_date_stable"], "update_date_stable": plugin["update_date_stable"], "create_date_experimental": plugin["create_date_experimental"], "update_date_experimental": plugin["update_date_experimental"], "experimental": plugin["experimental"] and "true" or "false", "deprecated": plugin["deprecated"] and "true" or "false", "trusted": plugin["trusted"] and "true" or "false", "version_available": plugin["version_available"], "version_available_stable": plugin["version_available_stable"] or "", "version_available_experimental": plugin["version_available_experimental"] or "", "zip_repository": plugin["zip_repository"], "download_url": plugin["download_url"], "download_url_stable": plugin["download_url_stable"], "download_url_experimental": plugin["download_url_experimental"], "filename": plugin["filename"], "downloads": plugin["downloads"], "average_vote": plugin["average_vote"], "rating_votes": plugin["rating_votes"], "plugin_dependencies": plugin.get("plugin_dependencies", None), "pythonic": "true" }) iface.pluginManagerInterface().reloadModel() # ----------------------------------------- # def reloadAndExportData(self): """ Reload All repositories and export data to the Plugin Manager """ self.fetchAvailablePlugins(reloadMode=True) self.exportRepositoriesToManager() self.exportPluginsToManager() # ----------------------------------------- # def showPluginManagerWhenReady(self, *params): """ Open the plugin manager window. If fetching is still in progress, it shows the progress window first """ """ Optionally pass the index of tab to be opened in params """ if self.statusLabel: iface.mainWindow().statusBar().removeWidget(self.statusLabel) self.statusLabel = None self.fetchAvailablePlugins(reloadMode=False) self.exportRepositoriesToManager() self.exportPluginsToManager() # finally, show the plugin manager window tabIndex = -1 if len(params) == 1: indx = str(params[0]) if indx.isdigit() and int(indx) > -1 and int(indx) < 7: tabIndex = int(indx) iface.pluginManagerInterface().showPluginManager(tabIndex) # ----------------------------------------- # def onManagerClose(self): """ Call this method when closing manager window - it resets last-use-dependent values. """ plugins.updateSeenPluginsList() repositories.saveCheckingOnStartLastDate() # ----------------------------------------- # def exportSettingsGroup(self): """ Return QgsSettings settingsGroup value """ return settingsGroup # ----------------------------------------- # def upgradeAllUpgradeable(self): """ Reinstall all upgradeable plugins """ for key in plugins.allUpgradeable(): self.installPlugin(key, quiet=True) # ----------------------------------------- # def installPlugin(self, key, quiet=False, stable=True): """ Install given plugin """ error = False status_key = 'status' if stable else 'status_exp' infoString = ('', '') plugin = plugins.all()[key] previousStatus = plugin[status_key] if not plugin: return if plugin[status_key] == "newer" and not plugin[ "error"]: # ask for confirmation if user downgrades an usable plugin if QMessageBox.warning( iface.mainWindow(), self.tr("QGIS Python Plugin Installer"), self. tr("Are you sure you want to downgrade the plugin to the latest available version? The installed one is newer!" ), QMessageBox.Yes, QMessageBox.No) == QMessageBox.No: return dlg = QgsPluginInstallerInstallingDialog(iface.mainWindow(), plugin, stable=stable) dlg.exec_() plugin_path = qgis.utils.home_plugin_path + "/" + key if dlg.result(): error = True infoString = (self.tr("Plugin installation failed"), dlg.result()) elif not QDir(plugin_path).exists(): error = True infoString = ( self.tr("Plugin has disappeared"), self. tr("The plugin seems to have been installed but it's not possible to know where. The directory \"{}\" " "has not been found. Probably the plugin package contained a wrong named directory.\nPlease search " "the list of installed plugins. You should find the plugin there, but it's not possible to " "determine which of them it is and it's also not possible to inform you about available updates. " "Please contact the plugin author and submit this issue." ).format(plugin_path)) QApplication.setOverrideCursor(Qt.WaitCursor) plugins.getAllInstalled() plugins.rebuild() self.exportPluginsToManager() QApplication.restoreOverrideCursor() else: QApplication.setOverrideCursor(Qt.WaitCursor) # update the list of plugins in plugin handling routines updateAvailablePlugins() self.processDependencies(plugin["id"]) # try to load the plugin loadPlugin(plugin["id"]) plugins.getAllInstalled() plugins.rebuild() plugin = plugins.all()[key] if not plugin["error"]: if previousStatus in ["not installed", "new"]: infoString = (self.tr("Plugin installed successfully"), "") if startPlugin(plugin["id"]): settings = QgsSettings() settings.setValue("/PythonPlugins/" + plugin["id"], True) else: settings = QgsSettings() if settings.value( "/PythonPlugins/" + key, False, type=bool ): # plugin will be reloaded on the fly only if currently loaded reloadPlugin( key) # unloadPlugin + loadPlugin + startPlugin infoString = ( self.tr("Plugin reinstalled successfully"), "") else: unloadPlugin( key ) # Just for a case. Will exit quietly if really not loaded loadPlugin(key) infoString = ( self.tr("Plugin reinstalled successfully"), self. tr("Python plugin reinstalled.\nYou need to restart QGIS in order to reload it." )) if quiet: infoString = (None, None) QApplication.restoreOverrideCursor() else: QApplication.restoreOverrideCursor() if plugin["error"] == "incompatible": message = self.tr( "The plugin is not compatible with this version of QGIS. It's designed for QGIS versions:" ) message += " <b>" + plugin["error_details"] + "</b>" elif plugin["error"] == "dependent": message = self.tr( "The plugin depends on some components missing on your system. You need to install the following Python module in order to enable it:" ) message += "<b> " + plugin["error_details"] + "</b>" else: message = self.tr("The plugin is broken. Python said:") message += "<br><b>" + plugin["error_details"] + "</b>" dlg = QgsPluginInstallerPluginErrorDialog( iface.mainWindow(), message) dlg.exec_() if dlg.result(): # revert installation pluginDir = qgis.utils.home_plugin_path + "/" + plugin["id"] result = removeDir(pluginDir) if QDir(pluginDir).exists(): error = True infoString = (self.tr("Plugin uninstall failed"), result) try: exec("sys.path_importer_cache.clear()") exec("import %s" % plugin["id"]) exec("reload (%s)" % plugin["id"]) except: pass else: try: exec("del sys.modules[%s]" % plugin["id"]) except: pass plugins.getAllInstalled() plugins.rebuild() self.exportPluginsToManager() if infoString[0]: level = error and Qgis.Critical or Qgis.Info msg = "<b>%s</b>" % infoString[0] if infoString[1]: msg += "<b>:</b> %s" % infoString[1] iface.pluginManagerInterface().pushMessage(msg, level) # ----------------------------------------- # def uninstallPlugin(self, key, quiet=False): """ Uninstall given plugin """ if key in plugins.all(): plugin = plugins.all()[key] else: plugin = plugins.localCache[key] if not plugin: return if not quiet: warning = self.tr( "Are you sure you want to uninstall the following plugin?" ) + "\n(" + plugin["name"] + ")" if plugin["status"] == "orphan" and not plugin["error"]: warning += "\n\n" + self.tr( "Warning: this plugin isn't available in any accessible repository!" ) if QMessageBox.warning(iface.mainWindow(), self.tr("QGIS Python Plugin Installer"), warning, QMessageBox.Yes, QMessageBox.No) == QMessageBox.No: return # unload the plugin QApplication.setOverrideCursor(Qt.WaitCursor) try: unloadPlugin(key) except: pass pluginDir = qgis.utils.home_plugin_path + "/" + plugin["id"] result = removeDir(pluginDir) if result: QApplication.restoreOverrideCursor() msg = "<b>%s:</b>%s" % (self.tr("Plugin uninstall failed"), result) iface.pluginManagerInterface().pushMessage(msg, Qgis.Critical) else: # safe remove try: unloadPlugin(plugin["id"]) except: pass try: exec("plugins[%s].unload()" % plugin["id"]) exec("del plugins[%s]" % plugin["id"]) except: pass try: exec("del sys.modules[%s]" % plugin["id"]) except: pass try: exec("del plugins_metadata_parser[%s]" % plugin["id"]) except: pass plugins.getAllInstalled() plugins.rebuild() self.exportPluginsToManager() QApplication.restoreOverrideCursor() iface.pluginManagerInterface().pushMessage( self.tr("Plugin uninstalled successfully"), Qgis.Info) # ----------------------------------------- # def addRepository(self): """ add new repository connection """ dlg = QgsPluginInstallerRepositoryDialog(iface.mainWindow()) dlg.editParams.setText(repositories.urlParams()) dlg.checkBoxEnabled.setCheckState(Qt.Checked) if not dlg.exec_(): return for i in list(repositories.all().values()): if dlg.editURL.text().strip() == i["url"]: iface.pluginManagerInterface().pushMessage( self.tr( "Unable to add another repository with the same URL!"), Qgis.Warning) return settings = QgsSettings() settings.beginGroup(reposGroup) reposName = dlg.editName.text() reposURL = dlg.editURL.text().strip() if reposName in repositories.all(): reposName = reposName + "(2)" # add to settings settings.setValue(reposName + "/url", reposURL) settings.setValue(reposName + "/authcfg", dlg.editAuthCfg.text().strip()) settings.setValue(reposName + "/enabled", bool(dlg.checkBoxEnabled.checkState())) # refresh lists and populate widgets plugins.removeRepository(reposName) self.reloadAndExportData() # ----------------------------------------- # def editRepository(self, reposName): """ edit repository connection """ if not reposName: return checkState = {False: Qt.Unchecked, True: Qt.Checked} dlg = QgsPluginInstallerRepositoryDialog(iface.mainWindow()) dlg.editName.setText(reposName) dlg.editURL.setText(repositories.all()[reposName]["url"]) dlg.editAuthCfg.setText(repositories.all()[reposName]["authcfg"]) dlg.editParams.setText(repositories.urlParams()) dlg.checkBoxEnabled.setCheckState( checkState[repositories.all()[reposName]["enabled"]]) if repositories.all()[reposName]["valid"]: dlg.checkBoxEnabled.setEnabled(True) dlg.labelInfo.setText("") else: dlg.checkBoxEnabled.setEnabled(False) dlg.labelInfo.setText( self. tr("This repository is blocked due to incompatibility with your QGIS version" )) dlg.labelInfo.setFrameShape(QFrame.Box) if not dlg.exec_(): return # nothing to do if canceled for i in list(repositories.all().values()): if dlg.editURL.text().strip() == i["url"] and dlg.editURL.text( ).strip() != repositories.all()[reposName]["url"]: iface.pluginManagerInterface().pushMessage( self.tr( "Unable to add another repository with the same URL!"), Qgis.Warning) return # delete old repo from QgsSettings and create new one settings = QgsSettings() settings.beginGroup(reposGroup) settings.remove(reposName) newName = dlg.editName.text() if newName in repositories.all() and newName != reposName: newName = newName + "(2)" settings.setValue(newName + "/url", dlg.editURL.text().strip()) settings.setValue(newName + "/authcfg", dlg.editAuthCfg.text().strip()) settings.setValue(newName + "/enabled", bool(dlg.checkBoxEnabled.checkState())) if dlg.editAuthCfg.text().strip() != repositories.all( )[reposName]["authcfg"]: repositories.all()[reposName]["authcfg"] = dlg.editAuthCfg.text( ).strip() if dlg.editURL.text().strip() == repositories.all( )[reposName]["url"] and dlg.checkBoxEnabled.checkState() == checkState[ repositories.all()[reposName]["enabled"]]: repositories.rename(reposName, newName) self.exportRepositoriesToManager() return # nothing else to do if only repository name was changed plugins.removeRepository(reposName) self.reloadAndExportData() # ----------------------------------------- # def deleteRepository(self, reposName): """ delete repository connection """ if not reposName: return settings = QgsSettings() settings.beginGroup(reposGroup) if settings.value(reposName + "/url", "", type=str) == officialRepo[1]: iface.pluginManagerInterface().pushMessage( self. tr("You can't remove the official QGIS Plugin Repository. You can disable it if needed." ), Qgis.Warning) return warning = self.tr( "Are you sure you want to remove the following repository?" ) + "\n" + reposName if QMessageBox.warning(iface.mainWindow(), self.tr("QGIS Python Plugin Installer"), warning, QMessageBox.Yes, QMessageBox.No) == QMessageBox.No: return # delete from the settings, refresh data and repopulate all the widgets settings.remove(reposName) repositories.remove(reposName) plugins.removeRepository(reposName) self.reloadAndExportData() # ----------------------------------------- # def setRepositoryInspectionFilter(self, reposName=None): """ temporarily block another repositories to fetch only one for inspection """ repositories.setInspectionFilter(reposName) self.reloadAndExportData() # ----------------------------------------- # def sendVote(self, plugin_id, vote): """ send vote via the RPC """ if not plugin_id or not vote: return False url = "http://plugins.qgis.org/plugins/RPC2/" params = { "id": "djangorpc", "method": "plugin.vote", "params": [str(plugin_id), str(vote)] } req = QNetworkRequest(QUrl(url)) req.setAttribute( QNetworkRequest.Attribute( QgsNetworkRequestParameters.AttributeInitiatorClass), "QgsPluginInstaller") req.setAttribute( QNetworkRequest.Attribute( QgsNetworkRequestParameters.AttributeInitiatorRequestId), "sendVote") req.setRawHeader(b"Content-Type", b"application/json") QgsNetworkAccessManager.instance().post( req, bytes(json.dumps(params), "utf-8")) return True def installFromZipFile(self, filePath): if not os.path.isfile(filePath): return settings = QgsSettings() settings.setValue(settingsGroup + '/lastZipDirectory', QFileInfo(filePath).absoluteDir().absolutePath()) with zipfile.ZipFile(filePath, 'r') as zf: pluginName = os.path.split(zf.namelist()[0])[0] pluginFileName = os.path.splitext(os.path.basename(filePath))[0] if not pluginName: msg_box = QMessageBox() msg_box.setIcon(QMessageBox.Warning) msg_box.setWindowTitle( self.tr("QGIS Python Install from ZIP Plugin Installer")) msg_box.setText( self. tr("The Zip file is not a valid QGIS python plugin. No root folder was found inside." )) msg_box.setStandardButtons(QMessageBox.Ok) more_info_btn = msg_box.addButton(self.tr("More Information"), QMessageBox.HelpRole) msg_box.exec() if msg_box.clickedButton() == more_info_btn: QgsHelp.openHelp( "plugins/plugins.html#the-install-from-zip-tab") return pluginsDirectory = qgis.utils.home_plugin_path if not QDir(pluginsDirectory).exists(): QDir().mkpath(pluginsDirectory) pluginDirectory = QDir.cleanPath( os.path.join(pluginsDirectory, pluginName)) # If the target directory already exists as a link, # remove the link without resolving QFile(pluginDirectory).remove() password = None infoString = None success = False keepTrying = True while keepTrying: try: # Test extraction. If fails, then exception will be raised and no removing occurs unzip(filePath, pluginsDirectory, password) # Removing old plugin files if exist removeDir(pluginDirectory) # Extract new files unzip(filePath, pluginsDirectory, password) keepTrying = False success = True except Exception as e: success = False if 'password' in str(e): infoString = self.tr('Aborted by user') if 'Bad password' in str(e): msg = self.tr( 'Wrong password. Please enter a correct password to the zip file.' ) else: msg = self.tr( 'The zip file is encrypted. Please enter password.' ) # Display a password dialog with QgsPasswordLineEdit dlg = QDialog() dlg.setWindowTitle(self.tr('Enter password')) buttonBox = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal) buttonBox.rejected.connect(dlg.reject) buttonBox.accepted.connect(dlg.accept) lePass = QgsPasswordLineEdit() layout = QVBoxLayout() layout.addWidget(QLabel(msg)) layout.addWidget(lePass) layout.addWidget(buttonBox) dlg.setLayout(layout) keepTrying = dlg.exec_() password = lePass.text() else: infoString = self.tr( "Failed to unzip the plugin package\n{}.\nProbably it is broken" .format(filePath)) keepTrying = False if success: updateAvailablePlugins() self.processDependencies(pluginName) loadPlugin(pluginName) plugins.getAllInstalled() plugins.rebuild() if settings.contains('/PythonPlugins/' + pluginName): if settings.value('/PythonPlugins/' + pluginName, False, bool): startPlugin(pluginName) reloadPlugin(pluginName) else: unloadPlugin(pluginName) loadPlugin(pluginName) else: if startPlugin(pluginName): settings.setValue('/PythonPlugins/' + pluginName, True) self.exportPluginsToManager() msg = "<b>%s</b>" % self.tr("Plugin installed successfully") else: msg = "<b>%s:</b> %s" % (self.tr("Plugin installation failed"), infoString) level = Qgis.Info if success else Qgis.Critical iface.pluginManagerInterface().pushMessage(msg, level) def processDependencies(self, plugin_id): """Processes plugin dependencies :param plugin_id: plugin id :type plugin_id: str """ to_install, to_upgrade, not_found = find_dependencies(plugin_id) if to_install or to_upgrade or not_found: dlg = QgsPluginDependenciesDialog(plugin_id, to_install, to_upgrade, not_found) if dlg.exec_() == QgsPluginDependenciesDialog.Accepted: actions = dlg.actions() for dependency_plugin_id, action in actions.items(): try: self.installPlugin(dependency_plugin_id) if action == 'install': iface.pluginManagerInterface().pushMessage( self. tr("Plugin dependency <b>%s</b> successfully installed" ) % dependency_plugin_id, Qgis.Info) else: iface.pluginManagerInterface().pushMessage( self. tr("Plugin dependency <b>%s</b> successfully upgraded" ) % dependency_plugin_id, Qgis.Info) except Exception as ex: if action == 'install': iface.pluginManagerInterface().pushMessage( self. tr("Error installing plugin dependency <b>%s</b>: %s" ) % (dependency_plugin_id, ex), Qgis.Warning) else: iface.pluginManagerInterface().pushMessage( self. tr("Error upgrading plugin dependency <b>%s</b>: %s" ) % (dependency_plugin_id, ex), Qgis.Warning)
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 installFromZipFile(self, filePath): if not os.path.isfile(filePath): return settings = QgsSettings() settings.setValue(settingsGroup + '/lastZipDirectory', QFileInfo(filePath).absoluteDir().absolutePath()) with zipfile.ZipFile(filePath, 'r') as zf: pluginName = os.path.split(zf.namelist()[0])[0] pluginFileName = os.path.splitext(os.path.basename(filePath))[0] if not pluginName: msg_box = QMessageBox() msg_box.setIcon(QMessageBox.Warning) msg_box.setWindowTitle( self.tr("QGIS Python Install from ZIP Plugin Installer")) msg_box.setText( self. tr("The Zip file is not a valid QGIS python plugin. No root folder was found inside." )) msg_box.setStandardButtons(QMessageBox.Ok) more_info_btn = msg_box.addButton(self.tr("More Information"), QMessageBox.HelpRole) msg_box.exec() if msg_box.clickedButton() == more_info_btn: QgsHelp.openHelp( "plugins/plugins.html#the-install-from-zip-tab") return pluginsDirectory = qgis.utils.home_plugin_path if not QDir(pluginsDirectory).exists(): QDir().mkpath(pluginsDirectory) pluginDirectory = QDir.cleanPath( os.path.join(pluginsDirectory, pluginName)) # If the target directory already exists as a link, # remove the link without resolving QFile(pluginDirectory).remove() password = None infoString = None success = False keepTrying = True while keepTrying: try: # Test extraction. If fails, then exception will be raised and no removing occurs unzip(filePath, pluginsDirectory, password) # Removing old plugin files if exist removeDir(pluginDirectory) # Extract new files unzip(filePath, pluginsDirectory, password) keepTrying = False success = True except Exception as e: success = False if 'password' in str(e): infoString = self.tr('Aborted by user') if 'Bad password' in str(e): msg = self.tr( 'Wrong password. Please enter a correct password to the zip file.' ) else: msg = self.tr( 'The zip file is encrypted. Please enter password.' ) # Display a password dialog with QgsPasswordLineEdit dlg = QDialog() dlg.setWindowTitle(self.tr('Enter password')) buttonBox = QDialogButtonBox( QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal) buttonBox.rejected.connect(dlg.reject) buttonBox.accepted.connect(dlg.accept) lePass = QgsPasswordLineEdit() layout = QVBoxLayout() layout.addWidget(QLabel(msg)) layout.addWidget(lePass) layout.addWidget(buttonBox) dlg.setLayout(layout) keepTrying = dlg.exec_() password = lePass.text() else: infoString = self.tr( "Failed to unzip the plugin package\n{}.\nProbably it is broken" .format(filePath)) keepTrying = False if success: updateAvailablePlugins() self.processDependencies(pluginName) loadPlugin(pluginName) plugins.getAllInstalled() plugins.rebuild() if settings.contains('/PythonPlugins/' + pluginName): if settings.value('/PythonPlugins/' + pluginName, False, bool): startPlugin(pluginName) reloadPlugin(pluginName) else: unloadPlugin(pluginName) loadPlugin(pluginName) else: if startPlugin(pluginName): settings.setValue('/PythonPlugins/' + pluginName, True) self.exportPluginsToManager() msg = "<b>%s</b>" % self.tr("Plugin installed successfully") else: msg = "<b>%s:</b> %s" % (self.tr("Plugin installation failed"), infoString) level = Qgis.Info if success else Qgis.Critical iface.pluginManagerInterface().pushMessage(msg, level)
def treeItemChanged(self, current, previous): qgsgeom1 = None qgsgeom2 = None crs = "EPSG:4326" if not isinstance(current, FeatureItem): self.attributesTable.clear() self.attributesTable.setRowCount(0) return color = {"MODIFIED": QColor(255, 170, 0), "ADDED":Qt.green, "REMOVED":Qt.red , "NO_CHANGE":Qt.white} path = current.layername + "/" + current.featureid featurediff = self.changes[path].featurediff() self.attributesTable.clear() self.attributesTable.verticalHeader().show() self.attributesTable.horizontalHeader().show() self.attributesTable.setRowCount(len(featurediff)) self.attributesTable.setVerticalHeaderLabels([a["attributename"] for a in featurediff]) self.attributesTable.setHorizontalHeaderLabels(["Old value", "New value", "Change type"]) for i, attrib in enumerate(featurediff): try: if attrib["changetype"] == "MODIFIED": oldvalue = attrib["oldvalue"] newvalue = attrib["newvalue"] elif attrib["changetype"] == "ADDED": newvalue = attrib["newvalue"] oldvalue = "" elif attrib["changetype"] == "REMOVED": oldvalue = attrib["oldvalue"] newvalue = "" else: oldvalue = newvalue = attrib["oldvalue"] except: oldvalue = newvalue = "" self.attributesTable.setItem(i, 0, DiffItem(oldvalue)) self.attributesTable.setItem(i, 1, DiffItem(newvalue)) try: self.attributesTable.setItem(i, 2, QTableWidgetItem("")) if qgsgeom1 is None or qgsgeom2 is None: if "crs" in attrib: crs = attrib["crs"] qgsgeom1 = QgsGeometry.fromWkt(oldvalue) qgsgeom2 = QgsGeometry.fromWkt(newvalue) if qgsgeom1 is not None and qgsgeom2 is not None: widget = QWidget() btn = QPushButton() btn.setText("View detail") btn.clicked.connect(lambda: self.viewGeometryChanges(qgsgeom1, qgsgeom2, crs)) label = QLabel() label.setText(attrib["changetype"]) layout = QHBoxLayout(widget) layout.addWidget(label); layout.addWidget(btn); layout.setContentsMargins(0, 0, 0, 0) widget.setLayout(layout) self.attributesTable.setCellWidget(i, 2, widget) else: self.attributesTable.setItem(i, 2, QTableWidgetItem(attrib["changetype"])) else: self.attributesTable.setItem(i, 2, QTableWidgetItem(attrib["changetype"])) except: self.attributesTable.setItem(i, 2, QTableWidgetItem(attrib["changetype"])) for col in range(3): self.attributesTable.item(i, col).setBackgroundColor(color[attrib["changetype"]]); self.attributesTable.resizeColumnsToContents() self.attributesTable.horizontalHeader().setResizeMode(QHeaderView.Stretch)
def add_table_control_tab_dockwidget(self): """ Create a tab for the measure group within the Rule group tab in the dockwidget. """ tab = QWidget() layout = QVBoxLayout(tab) tab.setLayout(layout) label_field = QLabel(tab) label_field.setGeometry(10, 10, 300, 21) label_field.setText("Measure variable: {}".format( self.combobox_input_rule_measure_variable.currentText())) label_field = QLabel(tab) label_field.setGeometry(10, 40, 300, 21) label_field.setText("Operator: {}".format( self.combobox_input_rule_operator.currentText())) label_field = QLabel(tab) label_field.setGeometry(310, 10, 300, 21) label_field.setText("Structure type: {}".format( self.combobox_input_structure_table.currentText())) label_field = QLabel(tab) label_field.setGeometry(310, 40, 300, 21) label_field.setText("Structure id: {}".format( self.combobox_input_structure_id.currentText())) label_field = QLabel(tab) label_field.setGeometry(310, 70, 741, 21) label_field.setText("Action type: {}".format( self.combobox_input_action_type.currentText())) table_control_table = QTableWidget(tab) table_control_table.setGeometry(10, 100, 741, 181) table_control_table.insertColumn(0) table_control_table.setHorizontalHeaderItem( 0, QTableWidgetItem("measuring_value")) table_control_table.insertColumn(1) table_control_table.setHorizontalHeaderItem( 1, QTableWidgetItem("action_value")) table_control_table.setEditTriggers(QAbstractItemView.NoEditTriggers) self.dockwidget_controlled_structures.table_control_view = table_control_table self.dockwidget_controlled_structures.tab_table_control_view.insertTab( 0, tab, "Table control: {}".format(str(self.table_control_id)))
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()))