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 execute(self): settings = QgsSettings() lastDir = settings.value('Processing/lastModelsDir', '') filename, selected_filter = QFileDialog.getOpenFileName(self.toolbox, self.tr('Open Model', 'AddModelFromFileAction'), lastDir, self.tr('Processing models (*.model3 *.MODEL3)', 'AddModelFromFileAction')) if filename: settings.setValue('Processing/lastModelsDir', QFileInfo(filename).absoluteDir().absolutePath()) alg = QgsProcessingModelAlgorithm() if not alg.fromFile(filename): QMessageBox.warning( self.toolbox, self.tr('Open Model', 'AddModelFromFileAction'), self.tr('The selected file does not contain a valid model', 'AddModelFromFileAction')) return destFilename = os.path.join(ModelerUtils.modelsFolders()[0], os.path.basename(filename)) shutil.copyfile(filename, destFilename) QgsApplication.processingRegistry().providerById('model').refreshAlgorithms()
def loadFromFolder(self, folder): if not os.path.exists(folder): return for path, subdirs, files in os.walk(folder): for descriptionFile in files: if descriptionFile.endswith('model3'): try: fullpath = os.path.join(path, descriptionFile) alg = QgsProcessingModelAlgorithm() if alg.fromFile(fullpath): if alg.name(): alg.setSourceFilePath(fullpath) self.algs.append(alg) else: QgsMessageLog.logMessage(self.tr('Could not load model {0}', 'ModelerAlgorithmProvider').format(descriptionFile), self.tr('Processing'), QgsMessageLog.CRITICAL) except WrongModelException as e: QgsMessageLog.logMessage(self.tr('Could not load model {0}\n{1}', 'ModelerAlgorithmProvider').format(descriptionFile, e.msg), self.tr('Processing'), QgsMessageLog.CRITICAL)
def testModelerParametersDialogAvailableValuesOfType(self): # test getAvailableValuesOfType from ModelerParametersDialog m = QgsProcessingModelAlgorithm() string_param_1 = QgsProcessingModelParameter('string') m.addModelParameter(QgsProcessingParameterString('string'), string_param_1) string_param_2 = QgsProcessingModelParameter('string2') m.addModelParameter(QgsProcessingParameterString('string2'), string_param_2) num_param = QgsProcessingModelParameter('number') m.addModelParameter(QgsProcessingParameterNumber('number'), num_param) table_field_param = QgsProcessingModelParameter('field') m.addModelParameter(QgsProcessingParameterField('field'), table_field_param) file_param = QgsProcessingModelParameter('file') m.addModelParameter(QgsProcessingParameterFile('file'), file_param) dlg = ModelerParametersDialog(m, m) # test single types self.assertEqual( set(p.parameterName() for p in dlg.getAvailableValuesOfType( QgsProcessingParameterNumber)), set(['number'])) self.assertEqual( set(p.parameterName() for p in dlg.getAvailableValuesOfType( QgsProcessingParameterField)), set(['field'])) self.assertEqual( set(p.parameterName() for p in dlg.getAvailableValuesOfType( QgsProcessingParameterFile)), set(['file'])) # test multiple types self.assertEqual( set(p.parameterName() for p in dlg.getAvailableValuesOfType([ QgsProcessingParameterString, QgsProcessingParameterNumber, QgsProcessingParameterFile ])), set(['string', 'string2', 'number', 'file']))
def add_processing_models(self, provider_id): if not (provider_id == 'model' or provider_id is None): return if provider_id is not None: # If method acted as slot QgsApplication.processingRegistry().providerAdded.disconnect(self.add_processing_models) # Add ladm_col models basepath = os.path.dirname(os.path.abspath(__file__)) plugin_models_dir = os.path.join(basepath, "processing", "models") for filename in glob.glob(os.path.join(plugin_models_dir, '*.model3')): alg = QgsProcessingModelAlgorithm() if not alg.fromFile(filename): self.log.logMessage("Couldn't load model from {}".format(filename), PLUGIN_NAME, Qgis.Critical) return destFilename = os.path.join(ModelerUtils.modelsFolders()[0], os.path.basename(filename)) shutil.copyfile(filename, destFilename) QgsApplication.processingRegistry().providerById('model').refreshAlgorithms()
def __init__(self, model=None, parent=None): super().__init__(parent) self._model = None if iface is not None: self.toolbar().setIconSize(iface.iconSize()) self.setStyleSheet(iface.mainWindow().styleSheet()) self.scene = ModelerScene(self) self.scene.setSceneRect( QRectF(0, 0, self.CANVAS_SIZE, self.CANVAS_SIZE)) self.scene.rebuildRequired.connect(self.repaintModel) self.scene.componentChanged.connect(self.componentChanged) self.view().setScene(self.scene) self.view().ensureVisible(0, 0, 10, 10) self.view().scale(QgsApplication.desktop().logicalDpiX() / 96, QgsApplication.desktop().logicalDpiX() / 96) self.actionOpen().triggered.connect(self.openModel) self.actionSaveInProject().triggered.connect(self.saveInProject) self.actionEditHelp().triggered.connect(self.editHelp) self.actionRun().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.updateVariablesGui() self.view().centerOn(0, 0) self.help = None
def checkConstructWrapper(self, param, expected_wrapper_class): alg = QgsApplication.processingRegistry().createAlgorithmById( 'native:centroids') # algorithm dialog dlg = AlgorithmDialog(alg) wrapper = WidgetWrapperFactory.create_wrapper_from_class(param, dlg) self.assertIsNotNone(wrapper) self.assertIsInstance(wrapper, expected_wrapper_class) self.assertEqual(wrapper.dialog, dlg) self.assertIsNotNone(wrapper.widget) wrapper.widget.deleteLater() del wrapper.widget del wrapper alg = QgsApplication.processingRegistry().createAlgorithmById( 'native:centroids') # batch dialog dlg = BatchAlgorithmDialog(alg) wrapper = WidgetWrapperFactory.create_wrapper_from_class(param, dlg) self.assertIsNotNone(wrapper) self.assertIsInstance(wrapper, expected_wrapper_class) self.assertEqual(wrapper.dialog, dlg) self.assertIsNotNone(wrapper.widget) alg = QgsApplication.processingRegistry().createAlgorithmById( 'native:centroids') # modeler dialog model = QgsProcessingModelAlgorithm() dlg = ModelerParametersDialog(alg, model) wrapper = WidgetWrapperFactory.create_wrapper_from_class(param, dlg) self.assertIsNotNone(wrapper) self.assertIsInstance(wrapper, expected_wrapper_class) self.assertEqual(wrapper.dialog, dlg) self.assertIsNotNone(wrapper.widget) wrapper.widget.deleteLater() del wrapper.widget
def test_OTBParameterChoice_Gui(self): """ This test is similar to GuiTests in processing that is done on other parameter widget in processing Main difference is this test uses create_wrapper_from_metadata() rather than create_wrapper_from_class() like rest of processing widgets. """ param = OtbParameterChoice('test') alg = QgsApplication.processingRegistry().createAlgorithmById( 'otb:Smoothing') # algorithm dialog dlg = AlgorithmDialog(alg) wrapper = WidgetWrapperFactory.create_wrapper_from_metadata(param, dlg) self.assertIsNotNone(wrapper) self.assertIsInstance(wrapper, OtbChoiceWidgetWrapper) self.assertEqual(wrapper.dialog, dlg) self.assertIsNotNone(wrapper.widget) alg = QgsApplication.processingRegistry().createAlgorithmById( 'otb:Smoothing') # batch dialog dlg = BatchAlgorithmDialog(alg) wrapper = WidgetWrapperFactory.create_wrapper_from_metadata(param, dlg) self.assertIsNotNone(wrapper) self.assertIsInstance(wrapper, OtbChoiceWidgetWrapper) self.assertEqual(wrapper.dialog, dlg) self.assertIsNotNone(wrapper.widget) alg = QgsApplication.processingRegistry().createAlgorithmById( 'otb:Smoothing') # modeler dialog model = QgsProcessingModelAlgorithm() dlg = ModelerParametersDialog(alg, model) wrapper = WidgetWrapperFactory.create_wrapper_from_metadata(param, dlg) self.assertIsNotNone(wrapper) self.assertIsInstance(wrapper, OtbChoiceWidgetWrapper) self.assertEqual(wrapper.dialog, dlg) self.assertIsNotNone(wrapper.widget)
def execute(self): settings = QgsSettings() lastDir = settings.value('Processing/lastModelsDir', '') filename, selected_filter = QFileDialog.getOpenFileName(self.toolbox, self.tr('Open Model', 'AddModelFromFileAction'), lastDir, self.tr('Processing models (*.model3 *.MODEL3)', 'AddModelFromFileAction')) if filename: settings.setValue('Processing/lastModelsDir', QFileInfo(filename).absoluteDir().absolutePath()) alg = QgsProcessingModelAlgorithm() if not alg.fromFile(filename): QMessageBox.warning( self.toolbox, self.tr('Open Model', 'AddModelFromFileAction'), self.tr('The selected file does not contain a valid model', 'AddModelFromFileAction')) return if QgsApplication.instance().processingRegistry().algorithmById('model:{}'.format(alg.id())): QMessageBox.warning( self.toolbox, self.tr('Open Model', 'AddModelFromFileAction'), self.tr('Model with the same name already exists', 'AddModelFromFileAction')) return destFilename = os.path.join(ModelerUtils.modelsFolders()[0], os.path.basename(filename)) if os.path.exists(destFilename): reply = QMessageBox.question( self.toolbox, self.tr('Open Model', 'AddModelFromFileAction'), self.tr('There is already a model file with the same name. Overwrite?', 'AddModelFromFileAction'), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if reply == QMessageBox.Yes: shutil.copyfile(filename, destFilename) QgsApplication.processingRegistry().providerById('model').refreshAlgorithms()
def openModel(self): filename, selected_filter = QFileDialog.getOpenFileName(self, self.tr('Open Model'), ModelerUtils.modelsFolders()[0], self.tr('Processing models (*.model3 *.MODEL3)')) if 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'), QgsMessageLog.CRITICAL) QMessageBox.critical(self, self.tr('Could not open model'), self.tr('The selected model could not be loaded.\n' 'See the log for more information.'))
def __init__(self, model=None): super().__init__(None) self.setAttribute(Qt.WA_DeleteOnClose) self.setupUi(self) 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 self.mToolbar.setIconSize(iface.iconSize()) self.mActionOpen.setIcon( QgsApplication.getThemeIcon('/mActionFileOpen.svg')) self.mActionSave.setIcon( QgsApplication.getThemeIcon('/mActionFileSave.svg')) self.mActionSaveAs.setIcon( QgsApplication.getThemeIcon('/mActionFileSaveAs.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(): event.acceptProposedAction() else: event.ignore() def _dropEvent(event): if event.mimeData().hasText(): itemId = event.mimeData().text() if itemId in [ param.id() for param in QgsApplication.instance(). processingRegistry().parameterTypes() ]: self.addInputOfType(itemId, event.pos()) else: alg = QgsApplication.processingRegistry( ).createAlgorithmById(itemId) if alg is not None: self._addAlgorithm(alg, event.pos()) event.accept() else: event.ignore() def _dragMoveEvent(event): if event.mimeData().hasText(): 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) def _mimeDataAlgorithm(items): item = items[0] mimeData = None if isinstance(item, TreeAlgorithmItem): mimeData = QMimeData() mimeData.setText(item.alg.id()) return mimeData self.algorithmTree.mimeData = _mimeDataAlgorithm self.algorithmTree.setDragDropMode(QTreeWidget.DragOnly) self.algorithmTree.setDropIndicatorShown(True) 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.textChanged) 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.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.fillTreeUsingProviders() self.view.centerOn(0, 0) self.help = None self.hasChanged = False
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 runModel(self, modelName=None): """ Executes chosen model, if possible. :param modelPath: (str) path to the model to be registered. """ if self.modelComboBox.currentIndex() < 1: return if not modelName or isinstance(modelName, bool): modelName = self.model() modelPath = self.modelPath() else: modelPath = os.path.join(self.defaultModelPath(), modelName) alg = QgsProcessingModelAlgorithm() if not self.modelExists(modelName): # if model was manually removed and combo box was not refreshed self.iface.messageBar().pushMessage( self.tr('Failed'), self.tr("model {model} seems to have been deleted.").format(model=modelName), level=Qgis.Critical, duration=5 ) return alg.fromFile(modelPath) alg.initAlgorithm() # as this tool assumes that every parameter is pre-set, only output shall # be passed on - ALL outputs from this tool is set to memory layers. param = {vl.name() : "memory:" for vl in alg.parameterDefinitions()} msg = self.tr("Would you like to run {model}").format(model=modelName) if self.options()["checkBeforeRunModel"] and not self.confirmAction(msg): return try: out = processing.run(alg, param) self.iface.messageBar().pushMessage( self.tr('Sucess'), self.tr("model {model} finished.").format(model=modelName), level=Qgis.Info, duration=5 ) QgsMessageLog.logMessage( self.tr( "Model {model} finished running with no errors. You may" " check model output on Processing log tab." ).format(model=modelName), 'DSGTools Plugin', Qgis.Info ) if not self.options()["loadModelOutput"]: return for var, value in out.items(): if isinstance(value, QgsMapLayer): value.setName( "{model} {layername}".format(model=modelName, layername=var) ) self.addLayerToGroup( value, "DSGTools Validation Toolbar Output", modelName ) except Exception as e: msg = self.tr( "Unable to run (check Processing tab for details on model " "execution log) {model}:\n{error}" ).format(model=modelName, error=str(e)) self.iface.messageBar().pushMessage( self.tr("Model {model} failed").format(model=modelName), self.tr("check log for more information."), level=Qgis.Critical, duration=5 ) QgsMessageLog.logMessage(msg, 'DSGTools Plugin',Qgis.Info)