def executeSql(self): sql = self._getSqlQuery() if sql == "": return with OverrideCursor(Qt.WaitCursor): # delete the old model old_model = self.viewResult.model() self.viewResult.setModel(None) if old_model: old_model.deleteLater() cols = [] quotedCols = [] try: # set the new model model = self.db.sqlResultModel(sql, self) self.viewResult.setModel(model) self.lblResult.setText( self.tr("{0} rows, {1:.1f} seconds").format( model.affectedRows(), model.secs())) cols = self.viewResult.model().columnNames() for col in cols: quotedCols.append(self.db.connector.quoteId(col)) except BaseError as e: DlgDbError.showError(e, self) self.uniqueModel.clear() self.geomCombo.clear() return self.setColumnCombos(cols, quotedCols) self.update()
def executeSqlCompleted(self): self.updateUiWhileSqlExecution(False) with OverrideCursor(Qt.WaitCursor): if self.modelAsync.task.status() == QgsTask.Complete: model = self.modelAsync.model cols = [] quotedCols = [] self.viewResult.setModel(model) self.lblResult.setText( self.tr("{0} rows, {1:.1f} seconds").format( model.affectedRows(), model.secs())) cols = self.viewResult.model().columnNames() for col in cols: quotedCols.append(self.db.connector.quoteId(col)) self.setColumnCombos(cols, quotedCols) self.update() elif not self.modelAsync.canceled: DlgDbError.showError(self.modelAsync.error, self) self.uniqueModel.clear() self.geomCombo.clear() pass
def deleteConstraint(self): """ delete a constraint """ index = self.currentConstraint() if index == -1: return m = self.viewConstraints.model() constr = m.getObject(index) res = QMessageBox.question( self, self.tr("Are you sure"), self.tr("Really delete constraint '{0}'?").format(constr.name), QMessageBox.Yes | QMessageBox.No) if res != QMessageBox.Yes: return with OverrideCursor(Qt.WaitCursor): self.aboutToChangeTable.emit() try: constr.delete() self.refresh() except BaseError as e: DlgDbError.showError(e, self)
def editColumn(self): """ open dialog to change column info and alter table appropriately """ index = self.currentColumn() if index == -1: return m = self.viewFields.model() # get column in table # (there can be missing number if someone deleted a column) fld = m.getObject(index) dlg = DlgFieldProperties(self, fld, self.table) if not dlg.exec_(): return new_fld = dlg.getField(True) with OverrideCursor(Qt.WaitCursor): self.aboutToChangeTable.emit() try: fld.update(new_fld.name, new_fld.type2String(), new_fld.notNull, new_fld.default2String()) self.refresh() except BaseError as e: DlgDbError.showError(e, self)
def createGeomColumn(self): """ first check whether everything's fine """ if self.editName.text() == "": QMessageBox.critical(self, self.tr("DB Manager"), self.tr("field name must not be empty")) return name = self.editName.text() geom_type = self.GEOM_TYPES[self.cboType.currentIndex()] dim = self.spinDim.value() try: srid = int(self.editSrid.text()) except ValueError: srid = -1 createSpatialIndex = False # now create the geometry column with OverrideCursor(Qt.WaitCursor): try: self.table.addGeometryColumn(name, geom_type, srid, dim, createSpatialIndex) except DbError as e: DlgDbError.showError(e, self) return self.accept()
def createSpatialIndex(self): """ create spatial index for the geometry column """ if self.table.type != self.table.VectorType: QMessageBox.information( self, self.tr("DB Manager"), self.tr("The selected table has no geometry.")) return res = QMessageBox.question( self, self.tr("Create Spatial Index"), self.tr("Create spatial index for field {0}?").format( self.table.geomColumn), QMessageBox.Yes | QMessageBox.No) if res != QMessageBox.Yes: return # TODO: first check whether the index doesn't exist already with OverrideCursor(Qt.WaitCursor): self.aboutToChangeTable.emit() try: self.table.createSpatialIndex() self.refresh() except BaseError as e: DlgDbError.showError(e, self)
def accept(self): keepOpen = ProcessingConfig.getSetting(ProcessingConfig.KEEP_DIALOG_OPEN) parameters = self.getParamValues() if parameters: with OverrideCursor(Qt.WaitCursor): self.feedback = FieldCalculatorFeedback(self) self.feedback.progressChanged.connect(self.setPercentage) context = dataobjects.createContext() ProcessingLog.addToLog(self.alg.asPythonCommand(parameters, context)) QgsGui.instance().processingRecentAlgorithmLog().push(self.alg.id()) self.executed, results = execute(self.alg, parameters, context, self.feedback) self.setPercentage(0) if self.executed: handleAlgorithmResults(self.alg, context, self.feedback, not keepOpen, parameters) self._wasExecuted = self.executed or self._wasExecuted if not keepOpen: QDialog.reject(self)
def _get_catalog(self): """convenience function to init catalog wrapper""" auth = None if self.disable_ssl_verification: try: auth = Authentication(verify=False) except NameError: pass # connect to the server with OverrideCursor(Qt.WaitCursor): try: self.catalog = get_catalog_service( self.catalog_url, catalog_type=self.catalog_type, timeout=self.timeout, username=self.catalog_username, password=self.catalog_password, auth=auth) return True except Exception as err: msg = self.tr('Error connecting to service: {0}').format(err) QMessageBox.warning(self, self.tr('CSW Connection error'), msg) return False
def runAlgorithm(self): alg_parameters = [] feedback = self.createFeedback() load_layers = self.mainWidget().checkLoadLayersOnCompletion.isChecked() project = QgsProject.instance() if load_layers else None for row in range(self.mainWidget().batchRowCount()): parameters = self.mainWidget().parametersForRow( row, destinationProject=project, warnOnInvalid=True) alg_parameters.append(parameters) task = QgsScopedProxyProgressTask( self.tr('Batch Processing - {0}').format( self.algorithm().displayName())) multi_feedback = QgsProcessingMultiStepFeedback( len(alg_parameters), feedback) feedback.progressChanged.connect(task.setProgress) with OverrideCursor(Qt.WaitCursor): self.mainWidget().setEnabled(False) self.cancelButton().setEnabled(True) # Make sure the Log tab is visible before executing the algorithm try: self.showLog() self.repaint() except: pass start_time = time.time() algorithm_results = [] for count, parameters in enumerate(alg_parameters): if feedback.isCanceled(): break self.setProgressText( QCoreApplication.translate( 'BatchAlgorithmDialog', '\nProcessing algorithm {0}/{1}…').format( count + 1, len(alg_parameters))) self.setInfo( self.tr('<b>Algorithm {0} starting…</b>').format( self.algorithm().displayName()), escapeHtml=False) multi_feedback.setCurrentStep(count) parameters = self.algorithm().preprocessParameters(parameters) feedback.pushInfo(self.tr('Input parameters:')) feedback.pushCommandInfo(pformat(parameters)) feedback.pushInfo('') # important - we create a new context for each iteration # this avoids holding onto resources and layers from earlier iterations, # and allows batch processing of many more items then is possible # if we hold on to these layers context = dataobjects.createContext(feedback) alg_start_time = time.time() ret, results = execute(self.algorithm(), parameters, context, multi_feedback) if ret: self.setInfo(QCoreApplication.translate( 'BatchAlgorithmDialog', 'Algorithm {0} correctly executed…').format( self.algorithm().displayName()), escapeHtml=False) feedback.pushInfo( self.tr( 'Execution completed in {0:0.2f} seconds'.format( time.time() - alg_start_time))) feedback.pushInfo(self.tr('Results:')) feedback.pushCommandInfo(pformat(results)) feedback.pushInfo('') algorithm_results.append(results) else: break handleAlgorithmResults(self.algorithm(), context, multi_feedback, False, parameters) feedback.pushInfo( self.tr('Batch execution completed in {0:0.2f} seconds'.format( time.time() - start_time))) task = None self.finish(algorithm_results) self.cancelButton().setEnabled(False)
def search(self): """execute search""" self.catalog = None self.constraints = [] # clear all fields and disable buttons self.lblResults.clear() self.treeRecords.clear() self.reset_buttons() # save some settings self.settings.setValue('/MetaSearch/returnRecords', self.spnRecords.cleanText()) # set current catalog current_text = self.cmbConnectionsSearch.currentText() key = '/MetaSearch/%s' % current_text self.catalog_url = self.settings.value('%s/url' % key) self.catalog_username = self.settings.value('%s/username' % key) self.catalog_password = self.settings.value('%s/password' % key) # start position and number of records to return self.startfrom = 0 self.maxrecords = self.spnRecords.value() # set timeout self.timeout = self.spnTimeout.value() # bbox # CRS is WGS84 with axis order longitude, latitude # defined by 'urn:ogc:def:crs:OGC:1.3:CRS84' minx = self.leWest.text() miny = self.leSouth.text() maxx = self.leEast.text() maxy = self.leNorth.text() bbox = [minx, miny, maxx, maxy] # only apply spatial filter if bbox is not global # even for a global bbox, if a spatial filter is applied, then # the CSW server will skip records without a bbox if bbox != ['-180', '-90', '180', '90']: self.constraints.append( BBox(bbox, crs='urn:ogc:def:crs:OGC:1.3:CRS84')) # keywords if self.leKeywords.text(): # TODO: handle multiple word searches keywords = self.leKeywords.text() self.constraints.append(PropertyIsLike('csw:AnyText', keywords)) if len(self.constraints) > 1: # exclusive search (a && b) self.constraints = [self.constraints] # build request if not self._get_csw(): return # TODO: allow users to select resources types # to find ('service', 'dataset', etc.) try: with OverrideCursor(Qt.WaitCursor): self.catalog.getrecords2(constraints=self.constraints, maxrecords=self.maxrecords, esn='full') except ExceptionReport as err: QMessageBox.warning(self, self.tr('Search error'), self.tr('Search error: {0}').format(err)) return except Exception as err: QMessageBox.warning(self, self.tr('Connection error'), self.tr('Connection error: {0}').format(err)) return if self.catalog.results['matches'] == 0: self.lblResults.setText(self.tr('0 results')) return self.display_results()
def tabChanged(self, index): with OverrideCursor(Qt.WaitCursor): try: self.refreshTabs() except BaseError as e: DlgDbError.showError(e, self)
def createTable(self): """Creates table with chosen fields, optionally add a geometry column """ if not self.hasSchemas: schema = None else: schema = str(self.cboSchema.currentText()) if len(schema) == 0: QMessageBox.information( self, self.tr("DB Manager"), self.tr("A valid schema must be selected first.")) return table = str(self.editName.text()) if len(table) == 0: QMessageBox.information(self, self.tr("DB Manager"), self.tr("A valid table name is required.")) return m = self.fields.model() if m.rowCount() == 0: QMessageBox.information(self, self.tr("DB Manager"), self.tr("At least one field is required.")) return useGeomColumn = self.chkGeomColumn.isChecked() if useGeomColumn: geomColumn = str(self.editGeomColumn.text()) if len(geomColumn) == 0: QMessageBox.information( self, self.tr("DB Manager"), self.tr("A name is required for the geometry column.")) return geomType = self.GEOM_TYPES[self.cboGeomType.currentIndex()] geomDim = self.spinGeomDim.value() try: geomSrid = int(self.editGeomSrid.text()) except ValueError: geomSrid = 0 useSpatialIndex = self.chkSpatialIndex.isChecked() flds = m.getFields() pk_index = self.cboPrimaryKey.currentIndex() if pk_index >= 0: flds[pk_index].primaryKey = True # commit to DB with OverrideCursor(Qt.WaitCursor): try: if not useGeomColumn: self.db.createTable(table, flds, schema) else: geom = geomColumn, geomType, geomSrid, geomDim, useSpatialIndex self.db.createVectorTable(table, flds, geom, schema) except (ConnectionError, DbError) as e: DlgDbError.showError(e, self) # clear UI self.editName.clear() self.fields.model().removeRows(0, self.fields.model().rowCount()) self.cboPrimaryKey.clear() self.chkGeomColumn.setChecked(False) self.chkSpatialIndex.setChecked(False) self.editGeomSrid.clear() self.cboGeomType.setEnabled(False) self.editGeomColumn.setEnabled(False) self.spinGeomDim.setEnabled(False) self.editGeomSrid.setEnabled(False) self.chkSpatialIndex.setEnabled(False) QMessageBox.information(self, self.tr("DB Manager"), self.tr("Table created successfully."))
def accept(self): if self.mode == self.ASK_FOR_INPUT_MODE: # create the input layer (if not already done) and # update available options self.reloadInputLayer() # sanity checks if self.inLayer is None: QMessageBox.critical(self, self.tr("Import to Database"), self.tr("Input layer missing or not valid.")) return if self.cboTable.currentText() == "": QMessageBox.critical(self, self.tr("Import to Database"), self.tr("Output table name is required.")) return if self.chkSourceSrid.isEnabled() and self.chkSourceSrid.isChecked(): if not self.widgetSourceSrid.crs().isValid(): QMessageBox.critical( self, self.tr("Import to Database"), self.tr("Invalid source srid: must be a valid crs.")) return if self.chkTargetSrid.isEnabled() and self.chkTargetSrid.isChecked(): if not self.widgetTargetSrid.crs().isValid(): QMessageBox.critical( self, self.tr("Import to Database"), self.tr("Invalid target srid: must be a valid crs.")) return with OverrideCursor(Qt.WaitCursor): # store current input layer crs and encoding, so I can restore it prevInCrs = self.inLayer.crs() prevInEncoding = self.inLayer.dataProvider().encoding() try: schema = self.outUri.schema() if not self.cboSchema.isEnabled( ) else self.cboSchema.currentText() table = self.cboTable.currentText() # get pk and geom field names from the source layer or use the # ones defined by the user srcUri = QgsDataSourceUri(self.inLayer.source()) pk = srcUri.keyColumn() if not self.chkPrimaryKey.isChecked( ) else self.editPrimaryKey.text() if not pk: pk = self.default_pk if self.inLayer.isSpatial() and self.chkGeomColumn.isEnabled(): geom = srcUri.geometryColumn( ) if not self.chkGeomColumn.isChecked( ) else self.editGeomColumn.text() if not geom: geom = self.default_geom else: geom = None options = {} if self.chkLowercaseFieldNames.isEnabled( ) and self.chkLowercaseFieldNames.isChecked(): pk = pk.lower() if geom: geom = geom.lower() options['lowercaseFieldNames'] = True # get output params, update output URI self.outUri.setDataSource(schema, table, geom, "", pk) typeName = self.db.dbplugin().typeName() providerName = self.db.dbplugin().providerName() if typeName == 'gpkg': uri = self.outUri.database() options['update'] = True options['driverName'] = 'GPKG' options['layerName'] = table else: uri = self.outUri.uri(False) if self.chkDropTable.isChecked(): options['overwrite'] = True if self.chkSinglePart.isEnabled( ) and self.chkSinglePart.isChecked(): options['forceSinglePartGeometryType'] = True outCrs = QgsCoordinateReferenceSystem() if self.chkTargetSrid.isEnabled( ) and self.chkTargetSrid.isChecked(): outCrs = self.widgetTargetSrid.crs() # update input layer crs and encoding if self.chkSourceSrid.isEnabled( ) and self.chkSourceSrid.isChecked(): inCrs = self.widgetSourceSrid.crs() self.inLayer.setCrs(inCrs) if self.chkEncoding.isEnabled() and self.chkEncoding.isChecked( ): enc = self.cboEncoding.currentText() self.inLayer.setProviderEncoding(enc) onlySelected = self.chkSelectedFeatures.isChecked() # do the import! ret, errMsg = QgsVectorLayerExporter.exportLayer( self.inLayer, uri, providerName, outCrs, onlySelected, options) except Exception as e: ret = -1 errMsg = str(e) finally: # restore input layer crs and encoding self.inLayer.setCrs(prevInCrs) self.inLayer.setProviderEncoding(prevInEncoding) if ret != 0: output = QgsMessageViewer() output.setTitle(self.tr("Import to Database")) output.setMessageAsPlainText( self.tr("Error {0}\n{1}").format(ret, errMsg)) output.showMessage() return # create spatial index if self.chkSpatialIndex.isEnabled() and self.chkSpatialIndex.isChecked( ): self.db.connector.createSpatialIndex((schema, table), geom) # add comment on table supportCom = self.db.supportsComment() if self.chkCom.isEnabled() and self.chkCom.isChecked() and supportCom: # using connector executing COMMENT ON TABLE query (with editCome.text() value) com = self.editCom.text() self.db.connector.commentTable(schema, table, com) self.db.connection().reconnect() self.db.refresh() QMessageBox.information(self, self.tr("Import to Database"), self.tr("Import was successful.")) return QDialog.accept(self)
def accept(self): # sanity checks if self.editOutputFile.text() == "": QMessageBox.information(self, self.tr("Export to file"), self.tr("Output file name is required")) return if self.chkSourceSrid.isEnabled() and self.chkSourceSrid.isChecked(): try: sourceSrid = int(self.editSourceSrid.text()) except ValueError: QMessageBox.information( self, self.tr("Export to file"), self.tr("Invalid source srid: must be an integer")) return if self.chkTargetSrid.isEnabled() and self.chkTargetSrid.isChecked(): try: targetSrid = int(self.editTargetSrid.text()) except ValueError: QMessageBox.information( self, self.tr("Export to file"), self.tr("Invalid target srid: must be an integer")) return with OverrideCursor(Qt.WaitCursor): # store current input layer crs, so I can restore it later prevInCrs = self.inLayer.crs() try: uri = self.editOutputFile.text() providerName = "ogr" options = {} # set the OGR driver will be used driverName = self.cboFileFormat.currentData() options['driverName'] = driverName # set the output file encoding if self.chkEncoding.isEnabled() and self.chkEncoding.isChecked( ): enc = self.cboEncoding.currentText() options['fileEncoding'] = enc if self.chkDropTable.isChecked(): options['overwrite'] = True outCrs = QgsCoordinateReferenceSystem() if self.chkTargetSrid.isEnabled( ) and self.chkTargetSrid.isChecked(): targetSrid = int(self.editTargetSrid.text()) outCrs = QgsCoordinateReferenceSystem(targetSrid) # update input layer crs if self.chkSourceSrid.isEnabled( ) and self.chkSourceSrid.isChecked(): sourceSrid = int(self.editSourceSrid.text()) inCrs = QgsCoordinateReferenceSystem(sourceSrid) self.inLayer.setCrs(inCrs) # do the export! ret, errMsg = QgsVectorLayerExporter.exportLayer( self.inLayer, uri, providerName, outCrs, False, options) except Exception as e: ret = -1 errMsg = str(e) finally: # restore input layer crs and encoding self.inLayer.setCrs(prevInCrs) if ret != 0: QMessageBox.warning(self, self.tr("Export to file"), self.tr("Error {0}\n{1}").format(ret, errMsg)) return # create spatial index # if self.chkSpatialIndex.isEnabled() and self.chkSpatialIndex.isChecked(): # self.db.connector.createSpatialIndex( (schema, table), geom ) QMessageBox.information(self, self.tr("Export to file"), self.tr("Export finished.")) return QDialog.accept(self)
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)) with OverrideCursor(Qt.WaitCursor): plugins.getAllInstalled() plugins.rebuild() self.exportPluginsToManager() 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 show_metadata(self): """show record metadata""" if not self.treeRecords.selectedItems(): return item = self.treeRecords.currentItem() if not item: return identifier = get_item_data(item, 'identifier') self.disable_ssl_verification = self.disableSSLVerification.isChecked() auth = None if self.disable_ssl_verification: try: auth = Authentication(verify=False) except NameError: pass try: with OverrideCursor(Qt.WaitCursor): if auth is not None: cat = CatalogueServiceWeb( self.catalog_url, timeout=self.timeout, # spellok username=self.catalog_username, password=self.catalog_password, auth=auth) else: # older owslib version without the auth keyword cat = CatalogueServiceWeb( self.catalog_url, timeout=self.timeout, # spellok username=self.catalog_username, password=self.catalog_password) cat.getrecordbyid( [self.catalog.records[identifier].identifier]) except ExceptionReport as err: QMessageBox.warning( self, self.tr('GetRecords error'), self.tr('Error getting response: {0}').format(err)) return except KeyError as err: QMessageBox.warning(self, self.tr('Record parsing error'), self.tr('Unable to locate record identifier')) return record = cat.records[identifier] record.xml_url = cat.request crd = RecordDialog() metadata = render_template('en', self.context, record, 'record_metadata_dc.html') style = QgsApplication.reportStyleSheet() crd.textMetadata.document().setDefaultStyleSheet(style) crd.textMetadata.setHtml(metadata) crd.exec_()
def installFromZipFile(self, filePath): if not os.path.isfile(filePath): return settings = QgsSettings() settings.setValue(settingsGroup + '/lastZipDirectory', QFileInfo(filePath).absoluteDir().absolutePath()) pluginName = None with zipfile.ZipFile(filePath, 'r') as zf: # search for metadata.txt. In case of multiple files, we can assume that # the shortest path relates <pluginname>/metadata.txt metadatafiles = sorted(f for f in zf.namelist() if f.endswith('metadata.txt')) if len(metadatafiles) > 0: pluginName = os.path.split(metadatafiles[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: with OverrideCursor(Qt.WaitCursor): updateAvailablePlugins() self.processDependencies(pluginName) loadPlugin(pluginName) plugins.getAllInstalled() plugins.rebuild() if settings.contains('/PythonPlugins/' + pluginName): # Plugin was available? if settings.value('/PythonPlugins/' + pluginName, False, bool): # Plugin was also active? reloadPlugin( pluginName ) # unloadPlugin + loadPlugin + startPlugin 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 accept(self): alg_parameters = [] feedback = self.createFeedback() load_layers = self.mainWidget().checkLoadLayersOnCompletion.isChecked() project = QgsProject.instance() if load_layers else None for row in range(self.mainWidget().tblParameters.rowCount()): col = 0 parameters = {} for param in self.algorithm().parameterDefinitions(): if param.flags() & QgsProcessingParameterDefinition.FlagHidden or param.isDestination(): continue wrapper = self.mainWidget().wrappers[row][col] parameters[param.name()] = wrapper.value() if not param.checkValueIsAcceptable(wrapper.value()): self.messageBar().pushMessage("", self.tr('Wrong or missing parameter value: {0} (row {1})').format( param.description(), row + 1), level=Qgis.Warning, duration=5) return col += 1 count_visible_outputs = 0 for out in self.algorithm().destinationParameterDefinitions(): if out.flags() & QgsProcessingParameterDefinition.FlagHidden: continue count_visible_outputs += 1 widget = self.mainWidget().tblParameters.cellWidget(row, col) text = widget.getValue() if out.checkValueIsAcceptable(text): if isinstance(out, (QgsProcessingParameterRasterDestination, QgsProcessingParameterFeatureSink)): # load rasters and sinks on completion parameters[out.name()] = QgsProcessingOutputLayerDefinition(text, project) else: parameters[out.name()] = text col += 1 else: self.messageBar().pushMessage("", self.tr('Wrong or missing output value: {0} (row {1})').format( out.description(), row + 1), level=Qgis.Warning, duration=5) return alg_parameters.append(parameters) with OverrideCursor(Qt.WaitCursor): self.mainWidget().setEnabled(False) self.cancelButton().setEnabled(True) # Make sure the Log tab is visible before executing the algorithm try: self.showLog() self.repaint() except: pass start_time = time.time() algorithm_results = [] for count, parameters in enumerate(alg_parameters): if feedback.isCanceled(): break self.setProgressText(QCoreApplication.translate('BatchAlgorithmDialog', '\nProcessing algorithm {0}/{1}…').format(count + 1, len(alg_parameters))) self.setInfo(self.tr('<b>Algorithm {0} starting…</b>').format(self.algorithm().displayName()), escapeHtml=False) feedback.pushInfo(self.tr('Input parameters:')) feedback.pushCommandInfo(pformat(parameters)) feedback.pushInfo('') # important - we create a new context for each iteration # this avoids holding onto resources and layers from earlier iterations, # and allows batch processing of many more items then is possible # if we hold on to these layers context = dataobjects.createContext(feedback) alg_start_time = time.time() ret, results = execute(self.algorithm(), parameters, context, feedback) if ret: self.setInfo(QCoreApplication.translate('BatchAlgorithmDialog', 'Algorithm {0} correctly executed…').format(self.algorithm().displayName()), escapeHtml=False) feedback.setProgress(100) feedback.pushInfo( self.tr('Execution completed in {0:0.2f} seconds'.format(time.time() - alg_start_time))) feedback.pushInfo(self.tr('Results:')) feedback.pushCommandInfo(pformat(results)) feedback.pushInfo('') algorithm_results.append(results) else: break handleAlgorithmResults(self.algorithm(), context, feedback, False) feedback.pushInfo(self.tr('Batch execution completed in {0:0.2f} seconds'.format(time.time() - start_time))) self.finish(algorithm_results) self.cancelButton().setEnabled(False)
def runNextStep(self): self.stopBlinking() test = self.tests[self.currentTest] step = test.steps[self.currentTestStep] self.btnSkip.setEnabled(True) self.btnCancel.setEnabled(True) if os.path.exists(step.description): with open(step.description) as f: html = ''.join(f.readlines()) self.webView.setHtml(html) else: if step.function is not None: self.webView.setHtml( step.description + '<p><b>[This is an automated step. Please, wait until it has been completed]</b></p>' ) else: self.webView.setHtml( step.description + '<p><b>[Click on the right-hand side buttons once you have performed this step]</b></p>' ) QCoreApplication.processEvents() if self.currentTestStep == len(test.steps) - 1: if step.function is not None: self.btnTestOk.setEnabled(False) self.btnTestFailed.setEnabled(False) self.btnNextStep.setEnabled(False) self.btnSkip.setEnabled(False) self.btnCancel.setEnabled(False) self.webView.setEnabled(False) QCoreApplication.processEvents() try: if step.busyCursor: with OverrideCursor(Qt.WaitCursor): step.function() else: step.function() QCoreApplication.processEvents() self.testPasses() except Exception as e: if isinstance(e, AssertionError): self.testFails('{}\n{}'.format(str(e), traceback.format_exc())) else: self.testContainsError('{}\n{}'.format( str(e), traceback.format_exc())) else: self.btnTestOk.setEnabled(True) self.btnTestOk.setText('Test Passes') self.btnTestFailed.setEnabled(True) self.btnTestFailed.setText('Test Fails') self.webView.setEnabled(True) self.btnNextStep.setEnabled(False) if step.prestep: try: if step.busyCursor: with OverrideCursor(Qt.WaitCursor): step.prestep() else: step.prestep() QCoreApplication.processEvents() except Exception as e: if isinstance(e, AssertionError): self.testFailsAtSetup('{}\n{}'.format( str(e), traceback.format_exc())) else: self.testContainsError('{}\n{}'.format( str(e), traceback.format_exc())) else: if step.function is not None: self.btnTestOk.setEnabled(False) self.btnTestFailed.setEnabled(False) self.btnNextStep.setEnabled(False) self.btnSkip.setEnabled(False) self.btnCancel.setEnabled(False) self.webView.setEnabled(False) QCoreApplication.processEvents() try: if step.busyCursor: with OverrideCursor(Qt.WaitCursor): step.function() else: step.function() QCoreApplication.processEvents() self.currentTestStep += 1 self.runNextStep() except Exception as e: if isinstance(e, AssertionError): self.testFails('{}\n{}'.format(str(e), traceback.format_exc())) else: self.testContainsError('{}\n{}'.format( str(e), traceback.format_exc())) else: self.currentTestStep += 1 self.webView.setEnabled(True) self.btnNextStep.setEnabled(not step.isVerifyStep) if step.isVerifyStep: self.btnTestOk.setEnabled(True) self.btnTestOk.setText('Step Passes') self.btnTestFailed.setEnabled(True) self.btnTestFailed.setText('Step Fails') else: self.btnTestOk.setEnabled(False) self.btnTestFailed.setEnabled(False) if step.prestep: try: if step.busyCursor: with OverrideCursor(Qt.WaitCursor): step.prestep() else: step.prestep() QCoreApplication.processEvents() except Exception as e: if isinstance(e, AssertionError): self.testFailsAtSetup('{}\n{}'.format( str(e), traceback.format_exc())) else: self.testContainsError('{}\n{}'.format( str(e), traceback.format_exc())) if step.function is None: self.startBlinking()