Ejemplo n.º 1
0
    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 model files (*.model *.MODEL)', 'AddModelFromFileAction'))
        if filename:
            try:
                settings.setValue('Processing/lastModelsDir',
                                  QFileInfo(filename).absoluteDir().absolutePath())

                ModelerAlgorithm.fromFile(filename)
            except WrongModelException:
                QMessageBox.warning(
                    self.toolbox,
                    self.tr('Error reading model', 'AddModelFromFileAction'),
                    self.tr('The selected file does not contain a valid model', 'AddModelFromFileAction'))
                return
            except:
                QMessageBox.warning(self.toolbox,
                                    self.tr('Error reading model', 'AddModelFromFileAction'),
                                    self.tr('Cannot read file', 'AddModelFromFileAction'))
                return
            destFilename = os.path.join(ModelerUtils.modelsFolders()[0], os.path.basename(filename))
            shutil.copyfile(filename, destFilename)
            algList.reloadProvider('model')
Ejemplo n.º 2
0
 def execute(self):
     filename = QFileDialog.getOpenFileName(
         self.toolbox,
         self.tr("Open model", "AddModelFromFileAction"),
         None,
         self.tr("Processing model files (*.model *.MODEL)", "AddModelFromFileAction"),
     )
     if filename:
         try:
             ModelerAlgorithm.fromFile(filename)
         except WrongModelException:
             QMessageBox.warning(
                 self.toolbox,
                 self.tr("Error reading model", "AddModelFromFileAction"),
                 self.tr("The selected file does not contain a valid model", "AddModelFromFileAction"),
             )
             return
         except:
             QMessageBox.warning(
                 self.toolbox,
                 self.tr("Error reading model", "AddModelFromFileAction"),
                 self.tr("Cannot read file", "AddModelFromFileAction"),
             )
         destFilename = os.path.join(ModelerUtils.modelsFolder(), os.path.basename(filename))
         shutil.copyfile(filename, destFilename)
         self.toolbox.updateProvider("model")
Ejemplo n.º 3
0
    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 model files (*.model3 *.MODEL3)',
                    'AddModelFromFileAction'))
        if filename:
            settings.setValue('Processing/lastModelsDir',
                              QFileInfo(filename).absoluteDir().absolutePath())

            alg = ModelerAlgorithm()
            if not alg.fromFile(filename):
                QMessageBox.warning(
                    self.toolbox,
                    self.tr('Error reading 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()
Ejemplo n.º 4
0
 def execute(self):
     filename = QtGui.QFileDialog.getOpenFileName(
         self.toolbox, self.tr('Open model', 'AddModelFromFileAction'),
         None,
         self.tr('Processing model files (*.model *.MODEL)',
                 'AddModelFromFileAction'))
     if filename:
         try:
             ModelerAlgorithm.fromFile(filename)
         except WrongModelException:
             QtGui.QMessageBox.warning(
                 self.toolbox,
                 self.tr('Error reading model', 'AddModelFromFileAction'),
                 self.tr('The selected file does not contain a valid model',
                         'AddModelFromFileAction'))
             return
         except:
             QtGui.QMessageBox.warning(
                 self.toolbox,
                 self.tr('Error reading model', 'AddModelFromFileAction'),
                 self.tr('Cannot read file', 'AddModelFromFileAction'))
         destFilename = os.path.join(ModelerUtils.modelsFolder(),
                                     os.path.basename(filename))
         shutil.copyfile(filename, destFilename)
         self.toolbox.updateProvider('model')
Ejemplo n.º 5
0
    def execute(self):
        settings = QSettings()
        lastDir = settings.value('Processing/lastModelsDir', '')
        filename = QFileDialog.getOpenFileName(self.toolbox,
                                               self.tr('Open model', 'AddModelFromFileAction'), lastDir,
                                               self.tr('Processing model files (*.model *.MODEL)', 'AddModelFromFileAction'))
        if filename:
            try:
                settings.setValue('Processing/lastModelsDir',
                                  QFileInfo(filename).absoluteDir().absolutePath())

                ModelerAlgorithm.fromFile(filename)
            except WrongModelException:
                QMessageBox.warning(
                    self.toolbox,
                    self.tr('Error reading model', 'AddModelFromFileAction'),
                    self.tr('The selected file does not contain a valid model', 'AddModelFromFileAction'))
                return
            except:
                QMessageBox.warning(self.toolbox,
                                    self.tr('Error reading model', 'AddModelFromFileAction'),
                                    self.tr('Cannot read file', 'AddModelFromFileAction'))
                return
            destFilename = os.path.join(ModelerUtils.modelsFolder(), os.path.basename(filename))
            shutil.copyfile(filename, destFilename)
            self.toolbox.updateProvider('model')
Ejemplo n.º 6
0
    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 = ModelerAlgorithm()
            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.'))
Ejemplo n.º 7
0
 def testRemoveParameter(self):
     folder = os.path.join(os.path.dirname(ModelerAlgorithmProvider.__file__), "models")
     modelfile = os.path.join(folder, "watersheds.model")
     model = ModelerAlgorithm()
     model.openModel(modelfile)
     self.assertTrue(2, len(model.parameters))
     self.assertFalse(model.removeParameter(0))
     self.assertTrue(2, len(model.parameters))
Ejemplo n.º 8
0
 def testRemoveParameter(self):
     folder = os.path.join(
         os.path.dirname(ModelerAlgorithmProvider.__file__), "models")
     modelfile = os.path.join(folder, "watersheds.model")
     model = ModelerAlgorithm()
     model.openModel(modelfile)
     self.assertTrue(2, len(model.parameters))
     self.assertFalse(model.removeParameter(0))
     self.assertTrue(2, len(model.parameters))
Ejemplo n.º 9
0
def modelSuite(modelFile, dialog = "none", threaded = True, unthreaded = True):
    s = unittest.TestSuite()
    model = ModelerAlgorithm()
    model.openModel(modelFile)
    if model.provider is None: # might happen if model is opened from modeler dialog
        model.provider = Providers.providers["model"]
    if threaded:
        s.addTest(ProcessingProviderTestCase(modelFile, model, True, dialog))
    if unthreaded:
        s.addTest(ProcessingProviderTestCase(modelFile, model, False, dialog))
    return s
Ejemplo n.º 10
0
def modelSuite(modelFile, dialog = "none", threaded = True, unthreaded = True):
    s = unittest.TestSuite()
    model = ModelerAlgorithm()
    model.openModel(modelFile)
    if model.provider is None: # might happen if model is opened from modeler dialog
        model.provider = Providers.providers["model"]
    if threaded:
        s.addTest(ProcessingProviderTestCase(modelFile, model, True, dialog))
    if unthreaded:
        s.addTest(ProcessingProviderTestCase(modelFile, model, False, dialog))
    return s
Ejemplo n.º 11
0
 def getAlgorithmFromHookFile(self, hookFile):
     if hookFile.endswith('py'):
         script = ScriptAlgorithm(hookFile)
         script.provider = Providers.providers['script']
         return script
     elif hookFile.endswith('model'):
         model = ModelerAlgorithm()
         model.openModel(hookFile)
         model.provider = Providers.providers['model']
         return model
     else:
         raise Exception("Wrong hook file")
Ejemplo n.º 12
0
 def getAlgorithmFromHookFile(self, hookFile):
     if hookFile.endswith("py"):
         script = ScriptAlgorithm(hookFile)
         script.provider = ModelerUtils.providers["script"]
         return script
     elif hookFile.endswith("model"):
         model = ModelerAlgorithm()
         model.openModel(hookFile)
         model.provider = ModelerUtils.providers["model"]
         return model
     else:
         raise Exception("Wrong hook file")
Ejemplo n.º 13
0
 def getAlgorithmFromHookFile(self, hookFile):
     if hookFile.endswith('py'):
         script = ScriptAlgorithm(hookFile)
         script.provider = Providers.providers['script']
         return script
     elif hookFile.endswith('model'):
         model = ModelerAlgorithm()
         model.openModel(hookFile)                
         model.provider = Providers.providers['model']
         return model
     else:
         raise Exception ("Wrong hook file")
Ejemplo n.º 14
0
 def execute(self):
     filename = QtGui.QFileDialog.getOpenFileName(self.toolbox, 'model files', None,
             '*.model')
     if filename:
         try:
             model = ModelerAlgorithm()
             model.openModel(filename)
         except WrongModelException:
             QtGui.QMessageBox.warning(self.toolbox, "Error reading model", "The selected file does not contain a valid model")
             return
         destFilename = os.path.join(ModelerUtils.modelsFolder(), os.path.basename(filename))
         shutil.copyfile(filename,destFilename)
         self.toolbox.updateProvider('script')
Ejemplo n.º 15
0
 def loadFromFolder(self,folder):
     if not os.path.exists(folder):
         return
     for descriptionFile in os.listdir(folder):
         if descriptionFile.endswith("model"):
             try:
                 alg = ModelerAlgorithm()
                 fullpath = os.path.join(folder ,descriptionFile)
                 alg.openModel(fullpath)
                 if alg.name.strip() != "":
                     alg.provider = self
                     self.algs.append(alg)
             except WrongModelException,e:
                 ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,"Could not load model " + descriptionFile + "\n" + e.msg)
Ejemplo n.º 16
0
 def execute(self):
     filename = QtGui.QFileDialog.getOpenFileName(self.toolbox, 'model files', None,
             '*.model')
     if filename:
         try:
             ModelerAlgorithm.fromJsonFile(filename)
         except WrongModelException:
             QtGui.QMessageBox.warning(self.toolbox, "Error reading model", "The selected file does not contain a valid model")
             return
         except:
             QtGui.QMessageBox.warning(self.toolbox, "Error reading model", "Cannot read file")
         destFilename = os.path.join(ModelerUtils.modelsFolder(), os.path.basename(filename))
         shutil.copyfile(filename,destFilename)
         self.toolbox.updateProvider('script')
Ejemplo n.º 17
0
 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('model'):
                 try:
                     fullpath = os.path.join(path, descriptionFile)
                     alg = ModelerAlgorithm.fromFile(fullpath)
                     if alg.name:
                         alg.provider = self
                         alg.descriptionFile = fullpath
                         self.algs.append(alg)
                     else:
                         ProcessingLog.addToLog(
                             ProcessingLog.LOG_ERROR,
                             self.tr('Could not load model %s',
                                     'ModelerAlgorithmProvider') %
                             descriptionFile)
                 except WrongModelException as e:
                     ProcessingLog.addToLog(
                         ProcessingLog.LOG_ERROR,
                         self.tr('Could not load model %s\n%s',
                                 'ModelerAlgorithmProvider') %
                         (descriptionFile, e.msg))
Ejemplo n.º 18
0
 def loadFromFolder(self, folder):
     if not os.path.exists(folder):
         return
     for descriptionFile in os.listdir(folder):
         if descriptionFile.endswith('model'):
             try:
                 alg = ModelerAlgorithm()
                 fullpath = os.path.join(folder, descriptionFile)
                 alg.openModel(fullpath)
                 if alg.name.strip() != '':
                     alg.provider = self
                     self.algs.append(alg)
             except WrongModelException, e:
                 ProcessingLog.addToLog(
                     ProcessingLog.LOG_ERROR, 'Could not load model ' +
                     descriptionFile + '\n' + e.msg)
Ejemplo n.º 19
0
 def openCombine(self, num):
     folder = \
         os.path.join(os.path.dirname(ModelerAlgorithmProvider.__file__),
                      'models')
     f = os.path.join(folder, 'combine_' + str(num) + 'vector.model')
     try:
         m = ModelerAlgorithm()
         m.openModel(f)
         self.alg = m
         self.alg.provider = Providers.providers['model']
         dlg = ParametersDialog(self.alg)
         dlg.exec_()
     except Exception, e:
         QMessageBox.information(None,QCoreApplication.translate("PUR", "Combine planning unit layers"), \
             QCoreApplication.translate("PUR","GRASS provider is not configured.\nPlease configure it before running this model."))  
         return   
Ejemplo n.º 20
0
    def openModel(self):
        filename = unicode(
            QFileDialog.getOpenFileName(
                self, self.tr('Open Model'),
                ModelerUtils.modelsFolders()[0],
                self.tr('Processing models (*.model *.MODEL)')))
        if filename:
            try:
                alg = ModelerAlgorithm.fromFile(filename)
                self.alg = alg
                self.alg.setModelerView(self)
                self.textGroup.setText(alg.group)
                self.textName.setText(alg.name)
                self.repaintModel()

                self.view.centerOn(0, 0)
                self.hasChanged = False
            except WrongModelException as e:
                ProcessingLog.addToLog(
                    ProcessingLog.LOG_ERROR,
                    self.tr('Could not load model %s\n%s') % (filename, e.msg))
                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.'))
            except Exception as e:
                ProcessingLog.addToLog(
                    ProcessingLog.LOG_ERROR,
                    self.tr('Could not load model %s\n%s') %
                    (filename, e.args[0]))
                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.'))
Ejemplo n.º 21
0
    def openModel(self):
        filename = unicode(QFileDialog.getOpenFileName(self,
                                                       self.tr('Open Model'), ModelerUtils.modelsFolder(),
                                                       self.tr('Processing models (*.model *.MODEL)')))
        if filename:
            try:
                alg = ModelerAlgorithm.fromFile(filename)
                self.alg = alg
                self.alg.setModelerView(self)
                self.textGroup.setText(alg.group)
                self.textName.setText(alg.name)
                self.repaintModel()

                self.view.centerOn(0, 0)
                self.hasChanged = False
            except WrongModelException as e:
                ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
                                       self.tr('Could not load model %s\n%s') % (filename, e.msg))
                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.'))
            except Exception as e:
                ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
                                       self.tr('Could not load model %s\n%s') % (filename, e.args[0]))
                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.'))
Ejemplo n.º 22
0
    def openModel(self):
        filename, selected_filter = QFileDialog.getOpenFileName(self,
                                                                self.tr('Open Model'),
                                                                ModelerUtils.modelsFolders()[0],
                                                                self.tr('Processing models (*.model *.MODEL)'))
        if filename:
            try:
                alg = ModelerAlgorithm.fromFile(filename)
                self.alg = alg
                self.alg.setModelerView(self)
                self.textGroup.setText(alg._group)
                self.textName.setText(alg._name)
                self.repaintModel()

                self.view.centerOn(0, 0)
                self.hasChanged = False
            except WrongModelException as e:
                QgsMessageLog.logMessage(self.tr('Could not load model {0}\n{1}').format(filename, e.msg),
                                         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.'))
            except Exception as e:
                QgsMessageLog.logMessage(self.tr('Could not load model {0}\n{1}').format(filename, e.args[0]),
                                         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.'))
Ejemplo n.º 23
0
    def openModel(self):
        filename, selected_filter = QFileDialog.getOpenFileName(self,
                                                                self.tr('Open Model'),
                                                                ModelerUtils.modelsFolders()[0],
                                                                self.tr('Processing models (*.model *.MODEL)'))
        if filename:
            try:
                alg = ModelerAlgorithm.fromFile(filename)
                self.alg = alg
                self.alg.setModelerView(self)
                self.textGroup.setText(alg._group)
                self.textName.setText(alg._name)
                self.repaintModel()

                self.view.centerOn(0, 0)
                self.hasChanged = False
            except WrongModelException as e:
                QgsMessageLog.logMessage(self.tr('Could not load model {0}\n{1}').format(filename, e.msg),
                                         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.'))
            except Exception as e:
                QgsMessageLog.logMessage(self.tr('Could not load model {0}\n{1}').format(filename, e.args[0]),
                                         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.'))
Ejemplo n.º 24
0
 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('model'):
                 try:
                     alg = ModelerAlgorithm()
                     fullpath = os.path.join(path, descriptionFile)
                     alg.openModel(fullpath)
                     if alg.name.strip() != '':
                         alg.provider = self
                         self.algs.append(alg)
                 except WrongModelException, e:
                     ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
                             'Could not load model ' + descriptionFile + '\n'
                             + e.msg)
Ejemplo n.º 25
0
 def testRemoveAlgorithm(self):
     folder = os.path.join(
         os.path.dirname(ModelerAlgorithmProvider.__file__), "models")
     modelfile = os.path.join(folder, "noinputs.model")
     model = ModelerAlgorithm()
     model.openModel(modelfile)
     model.provider = Providers.providers['model']
     self.assertTrue(2, len(model.algs))
     self.assertFalse(model.removeAlgorithm(0))
     self.assertTrue(model.removeAlgorithm(len(model.algs) - 1))
     model.execute(None)
     outputs = model.outputs
     self.assertEquals(1, len(outputs))
     output = outputs[0].value
     self.assertTrue(os.path.exists(output))
Ejemplo n.º 26
0
    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 model files (*.model3 *.MODEL3)', 'AddModelFromFileAction'))
        if filename:
            settings.setValue('Processing/lastModelsDir',
                              QFileInfo(filename).absoluteDir().absolutePath())

            alg = ModelerAlgorithm()
            if not alg.fromFile(filename):
                QMessageBox.warning(
                    self.toolbox,
                    self.tr('Error reading 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()
Ejemplo n.º 27
0
    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 = ModelerAlgorithm()
                        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 _loadModels(self):
        """Load models from the 'models' sub directory

        :return: List of ModelerAlgorithm
        """

        self.models = []

        for f in glob.glob(os.path.join(self.modeldir, '*.model')):
            m = ModelerAlgorithm.fromFile(f)
            m.provider = self
            self.models.append(m)
Ejemplo n.º 29
0
 def testRemoveAlgorithm(self):
     folder = os.path.join(os.path.dirname(ModelerAlgorithmProvider.__file__), "models")
     modelfile = os.path.join(folder, "noinputs.model")
     model = ModelerAlgorithm()
     model.openModel(modelfile)
     model.provider = Providers.providers["model"]
     self.assertTrue(2, len(model.algs))
     self.assertFalse(model.removeAlgorithm(0))
     self.assertTrue(model.removeAlgorithm(len(model.algs) - 1))
     model.execute(None)
     outputs = model.outputs
     self.assertEquals(1, len(outputs))
     output = outputs[0].value
     self.assertTrue(os.path.exists(output))
    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 = ModelerAlgorithm()
                        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)
Ejemplo n.º 31
0
    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 = ModelerAlgorithm()
            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.'))
Ejemplo n.º 32
0
 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('model'):
                 try:
                     fullpath = os.path.join(path, descriptionFile)
                     alg = ModelerAlgorithm.fromFile(fullpath)
                     alg.provider = self
                     self.algs.append(alg)
                 except WrongModelException, e:
                     ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
                         self.tr('Could not load model %s\n%s', 'ModelerAlgorithmProvider') % (descriptionFile, e.msg))
Ejemplo n.º 33
0
    def testModelerAlgorithmHasDependencies(self):
        # test hasDependencies from ModelerAlgorithm

        m = ModelerAlgorithm()

        a = Algorithm("qgis:clip")
        m.addAlgorithm(a)
        a2 = Algorithm("qgis:clip")
        m.addAlgorithm(a2)

        # test parent algorithm dependency
        self.assertEqual(m.hasDependencies('QGISCLIP_1'), False)
        a2.dependencies = ['QGISCLIP_1']
        self.assertEqual(m.hasDependencies('QGISCLIP_1'), True)

        # test output algorithm dependency
        a2.dependencies = []
        a.outputs['OUTPUT'] = ModelerOutput('out')
        a2.params['INPUT'] = ValueFromOutput('QGISCLIP_1', 'OUTPUT')
        self.assertEqual(m.hasDependencies('QGISCLIP_1'), True)
Ejemplo n.º 34
0
 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('model'):
                 try:
                     fullpath = os.path.join(path, descriptionFile)
                     alg = ModelerAlgorithm.fromFile(fullpath)
                     alg.provider = self
                     self.algs.append(alg)
                 except WrongModelException, e:
                     ProcessingLog.addToLog(
                         ProcessingLog.LOG_ERROR, 'Could not load model ' +
                         descriptionFile + '\n' + e.msg)
Ejemplo n.º 35
0
 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('model'):
                 try:
                     fullpath = os.path.join(path, descriptionFile)
                     alg = ModelerAlgorithm.fromFile(fullpath)
                     if alg.name():
                         alg.descriptionFile = fullpath
                         self.algs.append(alg)
                     else:
                         ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
                                                self.tr('Could not load model {0}', 'ModelerAlgorithmProvider').format(descriptionFile))
                 except WrongModelException as e:
                     ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
                                            self.tr('Could not load model {0}\n{1}', 'ModelerAlgorithmProvider').format(descriptionFile, e.msg))
Ejemplo n.º 36
0
    def testModelerAlgorithmHasDependencies(self):
        # test hasDependencies from ModelerAlgorithm

        m = ModelerAlgorithm()

        a = Algorithm("qgis:clip")
        m.addAlgorithm(a)
        a2 = Algorithm("qgis:clip")
        m.addAlgorithm(a2)

        # test parent algorithm dependency
        self.assertEqual(m.hasDependencies("QGISCLIP_1"), False)
        a2.dependencies = ["QGISCLIP_1"]
        self.assertEqual(m.hasDependencies("QGISCLIP_1"), True)

        # test output algorithm dependency
        a2.dependencies = []
        a.outputs["OUTPUT"] = ModelerOutput("out")
        a2.params["INPUT"] = ValueFromOutput("QGISCLIP_1", "OUTPUT")
        self.assertEqual(m.hasDependencies("QGISCLIP_1"), True)
Ejemplo n.º 37
0
    def testModelerAlgorithmHasDependencies(self):
        # test hasDependencies from ModelerAlgorithm

        m = ModelerAlgorithm()

        a = Algorithm("qgis:clip")
        m.addAlgorithm(a)
        a2 = Algorithm("qgis:clip")
        m.addAlgorithm(a2)

        # test parent algorithm dependency
        self.assertEqual(m.hasDependencies('QGISCLIP_1'), False)
        a2.dependencies = ['QGISCLIP_1']
        self.assertEqual(m.hasDependencies('QGISCLIP_1'), True)

        # test output algorithm dependency
        a2.dependencies = []
        a.outputs['OUTPUT'] = ModelerOutput('out')
        a2.params['INPUT'] = ValueFromOutput('QGISCLIP_1', 'OUTPUT')
        self.assertEqual(m.hasDependencies('QGISCLIP_1'), True)
Ejemplo n.º 38
0
 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("model"):
                 try:
                     fullpath = os.path.join(path, descriptionFile)
                     alg = ModelerAlgorithm.fromFile(fullpath)
                     if alg.name:
                         alg.provider = self
                         alg.descriptionFile = fullpath
                         self.algs.append(alg)
                     else:
                         ProcessingLog.addToLog(
                             ProcessingLog.LOG_ERROR,
                             self.tr("Could not load model %s", "ModelerAlgorithmProvider") % descriptionFile,
                         )
                 except WrongModelException as e:
                     ProcessingLog.addToLog(
                         ProcessingLog.LOG_ERROR,
                         self.tr("Could not load model %s\n%s", "ModelerAlgorithmProvider")
                         % (descriptionFile, e.msg),
                     )
Ejemplo n.º 39
0
    def testModelerParametersDialogAvailableValuesOfType(self):
        # test getAvailableValuesOfType from ModelerParametersDialog

        m = ModelerAlgorithm()
        string_param_1 = ModelerParameter(ParameterString('string', 'string desc'))
        m.addParameter(string_param_1)
        string_param_2 = ModelerParameter(ParameterString('string2', 'string desc'))
        m.addParameter(string_param_2)
        num_param = ModelerParameter(ParameterNumber('number', 'number desc'))
        m.addParameter(num_param)
        table_field_param = ModelerParameter(ParameterTableField('field', 'field desc'))
        m.addParameter(table_field_param)
        file_param = ModelerParameter(ParameterFile('file', 'file desc'))
        m.addParameter(file_param)

        dlg = ModelerParametersDialog(m, m)
        # test single types
        self.assertEqual(set(p.name for p in dlg.getAvailableValuesOfType(ParameterNumber)),
                         set(['number']))
        self.assertEqual(set(p.name for p in dlg.getAvailableValuesOfType(ParameterTableField)),
                         set(['field']))
        self.assertEqual(set(p.name for p in dlg.getAvailableValuesOfType(ParameterFile)),
                         set(['file']))

        # test multiple types
        self.assertEqual(set(p.name for p in dlg.getAvailableValuesOfType([ParameterString, ParameterNumber, ParameterFile])),
                         set(['string', 'string2', 'number', 'file']))
Ejemplo n.º 40
0
    def __init__(self, alg=None):
        super(ModelerDialog, self).__init__(None)
        self.setupUi(self)

        self.zoom = 1

        self.setWindowFlags(Qt.WindowMinimizeButtonHint
                            | Qt.WindowMaximizeButtonHint
                            | Qt.WindowCloseButtonHint)

        settings = QSettings()
        self.splitter.restoreState(
            settings.value("/Processing/splitterModeler", QByteArray()))
        self.restoreGeometry(
            settings.value("/Processing/geometryModeler", QByteArray()))

        self.tabWidget.setCurrentIndex(0)
        self.scene = ModelerScene(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():
                text = event.mimeData().text()
                if text in ModelerParameterDefinitionDialog.paramTypes:
                    self.addInputOfType(text, event.pos())
                else:
                    alg = algList.getAlgorithm(text)
                    if alg is not None:
                        self._addAlgorithm(alg.getCopy(), 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)
            factor = 1.05
            if event.delta() > 0:
                factor = 1 / factor
            self.view.scale(factor, factor)
            self.repaintModel()

        def _enterEvent(e):
            QGraphicsView.enterEvent(self.view, e)
            self.view.viewport().setCursor(Qt.ArrowCursor)

        def _mousePressEvent(e):
            QGraphicsView.mousePressEvent(self.view, e)
            self.view.viewport().setCursor(Qt.ArrowCursor)

        def _mouseReleaseEvent(e):
            QGraphicsView.mouseReleaseEvent(self.view, e)
            self.view.viewport().setCursor(Qt.ArrowCursor)

        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.mouseReleaseEvent = _mouseReleaseEvent

        def _mimeDataInput(items):
            mimeData = QMimeData()
            text = items[0].text(0)
            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.commandLineName())
            return mimeData

        self.algorithmTree.mimeData = _mimeDataAlgorithm

        self.algorithmTree.setDragDropMode(QTreeWidget.DragOnly)
        self.algorithmTree.setDropIndicatorShown(True)

        # Set icons
        self.btnOpen.setIcon(
            QgsApplication.getThemeIcon('/mActionFileOpen.svg'))
        self.btnSave.setIcon(
            QgsApplication.getThemeIcon('/mActionFileSave.svg'))
        self.btnSaveAs.setIcon(
            QgsApplication.getThemeIcon('/mActionFileSaveAs.svg'))
        self.btnExportImage.setIcon(
            QgsApplication.getThemeIcon('/mActionSaveMapAsImage.svg'))
        self.btnExportPython.setIcon(
            QgsApplication.getThemeIcon('/console/iconSaveAsConsole.png'))
        self.btnEditHelp.setIcon(
            QIcon(os.path.join(pluginPath, 'images', 'edithelp.png')))
        self.btnRun.setIcon(
            QIcon(os.path.join(pluginPath, 'images', 'runalgorithm.png')))

        if hasattr(self.searchBox, 'setPlaceholderText'):
            self.searchBox.setPlaceholderText(self.tr('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.fillAlgorithmTree)
        self.algorithmTree.doubleClicked.connect(self.addAlgorithm)

        self.btnOpen.clicked.connect(self.openModel)
        self.btnSave.clicked.connect(self.save)
        self.btnSaveAs.clicked.connect(self.saveAs)
        self.btnExportImage.clicked.connect(self.exportAsImage)
        self.btnExportPython.clicked.connect(self.exportAsPython)
        self.btnEditHelp.clicked.connect(self.editHelp)
        self.btnRun.clicked.connect(self.runModel)

        if alg is not None:
            self.alg = alg
            self.textGroup.setText(alg.group)
            self.textName.setText(alg.name)
            self.repaintModel()

        else:
            self.alg = ModelerAlgorithm()
            self.alg.modelerdialog = self

        self.fillInputsTree()
        self.fillAlgorithmTree()

        self.view.centerOn(0, 0)
        self.alg.setModelerView(self)
        self.help = None
        # Indicates whether to update or not the toolbox after
        # closing this dialog
        self.update = False

        self.hasChanged = False
Ejemplo n.º 41
0
class ModelerDialog(BASE, WIDGET):

    CANVAS_SIZE = 4000

    def __init__(self, alg=None):
        super(ModelerDialog, self).__init__(None)
        self.setupUi(self)

        self.zoom = 1

        self.setWindowFlags(Qt.WindowMinimizeButtonHint
                            | Qt.WindowMaximizeButtonHint
                            | Qt.WindowCloseButtonHint)

        settings = QSettings()
        self.splitter.restoreState(
            settings.value("/Processing/splitterModeler", QByteArray()))
        self.restoreGeometry(
            settings.value("/Processing/geometryModeler", QByteArray()))

        self.tabWidget.setCurrentIndex(0)
        self.scene = ModelerScene(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():
                text = event.mimeData().text()
                if text in ModelerParameterDefinitionDialog.paramTypes:
                    self.addInputOfType(text, event.pos())
                else:
                    alg = algList.getAlgorithm(text)
                    if alg is not None:
                        self._addAlgorithm(alg.getCopy(), 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)
            factor = 1.05
            if event.delta() > 0:
                factor = 1 / factor
            self.view.scale(factor, factor)
            self.repaintModel()

        def _enterEvent(e):
            QGraphicsView.enterEvent(self.view, e)
            self.view.viewport().setCursor(Qt.ArrowCursor)

        def _mousePressEvent(e):
            QGraphicsView.mousePressEvent(self.view, e)
            self.view.viewport().setCursor(Qt.ArrowCursor)

        def _mouseReleaseEvent(e):
            QGraphicsView.mouseReleaseEvent(self.view, e)
            self.view.viewport().setCursor(Qt.ArrowCursor)

        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.mouseReleaseEvent = _mouseReleaseEvent

        def _mimeDataInput(items):
            mimeData = QMimeData()
            text = items[0].text(0)
            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.commandLineName())
            return mimeData

        self.algorithmTree.mimeData = _mimeDataAlgorithm

        self.algorithmTree.setDragDropMode(QTreeWidget.DragOnly)
        self.algorithmTree.setDropIndicatorShown(True)

        # Set icons
        self.btnOpen.setIcon(
            QgsApplication.getThemeIcon('/mActionFileOpen.svg'))
        self.btnSave.setIcon(
            QgsApplication.getThemeIcon('/mActionFileSave.svg'))
        self.btnSaveAs.setIcon(
            QgsApplication.getThemeIcon('/mActionFileSaveAs.svg'))
        self.btnExportImage.setIcon(
            QgsApplication.getThemeIcon('/mActionSaveMapAsImage.svg'))
        self.btnExportPython.setIcon(
            QgsApplication.getThemeIcon('/console/iconSaveAsConsole.png'))
        self.btnEditHelp.setIcon(
            QIcon(os.path.join(pluginPath, 'images', 'edithelp.png')))
        self.btnRun.setIcon(
            QIcon(os.path.join(pluginPath, 'images', 'runalgorithm.png')))

        if hasattr(self.searchBox, 'setPlaceholderText'):
            self.searchBox.setPlaceholderText(self.tr('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.fillAlgorithmTree)
        self.algorithmTree.doubleClicked.connect(self.addAlgorithm)

        self.btnOpen.clicked.connect(self.openModel)
        self.btnSave.clicked.connect(self.save)
        self.btnSaveAs.clicked.connect(self.saveAs)
        self.btnExportImage.clicked.connect(self.exportAsImage)
        self.btnExportPython.clicked.connect(self.exportAsPython)
        self.btnEditHelp.clicked.connect(self.editHelp)
        self.btnRun.clicked.connect(self.runModel)

        if alg is not None:
            self.alg = alg
            self.textGroup.setText(alg.group)
            self.textName.setText(alg.name)
            self.repaintModel()

        else:
            self.alg = ModelerAlgorithm()
            self.alg.modelerdialog = self

        self.fillInputsTree()
        self.fillAlgorithmTree()

        self.view.centerOn(0, 0)
        self.alg.setModelerView(self)
        self.help = None
        # Indicates whether to update or not the toolbox after
        # closing this dialog
        self.update = False

        self.hasChanged = False

    def closeEvent(self, evt):
        settings = QSettings()
        settings.setValue("/Processing/splitterModeler",
                          self.splitter.saveState())
        settings.setValue("/Processing/geometryModeler", self.saveGeometry())

        if self.hasChanged:
            ret = QMessageBox.question(
                self, self.tr('Unsaved changes'),
                self.tr('There are unsaved changes in model. Continue?'),
                QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

            if ret == QMessageBox.Yes:
                evt.accept()
            else:
                evt.ignore()
        else:
            evt.accept()

    def editHelp(self):
        if self.alg.provider is None:
            # Might happen if model is opened from modeler dialog
            self.alg.provider = algList.getProviderFromName('model')
        alg = self.alg.getCopy()
        dlg = HelpEditionDialog(alg)
        dlg.exec_()
        if dlg.descriptions:
            self.alg.helpContent = dlg.descriptions
            self.hasChanged = True

    def runModel(self):
        if len(self.alg.algs) == 0:
            QMessageBox.warning(
                self, self.tr('Empty model'),
                self.tr("Model doesn't contains any algorithms and/or "
                        "parameters and can't be executed"))
            return

        if self.alg.provider is None:
            # Might happen if model is opened from modeler dialog
            self.alg.provider = algList.getProviderFromName('model')
        alg = self.alg.getCopy()
        dlg = AlgorithmDialog(alg)
        dlg.exec_()

    def save(self):
        self.saveModel(False)

    def saveAs(self):
        self.saveModel(True)

    def exportAsImage(self):
        filename = unicode(
            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 = QRectF(0, 0, 1, 1)
        for item in self.scene.items():
            totalRect = totalRect.united(item.sceneBoundingRect())
        totalRect.adjust(-10, -10, 10, 10)

        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, totalRect, totalRect)
        painter.end()

        img.save(filename)

    def exportAsPython(self):
        filename = unicode(
            QFileDialog.getSaveFileName(self,
                                        self.tr('Save Model As Python Script'),
                                        '',
                                        self.tr('Python files (*.py *.PY)')))
        if not filename:
            return

        if not filename.lower().endswith('.py'):
            filename += '.py'

        text = self.alg.toPython()
        with codecs.open(filename, 'w', encoding='utf-8') as fout:
            fout.write(text)
        QMessageBox.information(self, self.tr('Model exported'),
                                self.tr('Model was correctly exported.'))

    def saveModel(self, saveAs):
        if unicode(self.textGroup.text()).strip() == '' \
                or unicode(self.textName.text()).strip() == '':
            QMessageBox.warning(
                self, self.tr('Warning'),
                self.tr('Please enter group and model names before saving'))
            return
        self.alg.name = unicode(self.textName.text())
        self.alg.group = unicode(self.textGroup.text())
        if self.alg.descriptionFile is not None and not saveAs:
            filename = self.alg.descriptionFile
        else:
            filename = unicode(
                QFileDialog.getSaveFileName(
                    self, self.tr('Save Model'),
                    ModelerUtils.modelsFolders()[0],
                    self.tr('Processing models (*.model)')))
            if filename:
                if not filename.endswith('.model'):
                    filename += '.model'
                self.alg.descriptionFile = filename
        if filename:
            text = self.alg.toJson()
            try:
                fout = codecs.open(filename, 'w', encoding='utf-8')
            except:
                if saveAs:
                    QMessageBox.warning(
                        self, self.tr('I/O error'),
                        self.tr('Unable to save edits. Reason:\n %s') %
                        unicode(sys.exc_info()[1]))
                else:
                    QMessageBox.warning(
                        self, self.tr("Can't save model"),
                        self.tr("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
            fout.write(text)
            fout.close()
            self.update = True
            QMessageBox.information(self, self.tr('Model saved'),
                                    self.tr('Model was correctly saved.'))

            self.hasChanged = False

    def openModel(self):
        filename = unicode(
            QFileDialog.getOpenFileName(
                self, self.tr('Open Model'),
                ModelerUtils.modelsFolders()[0],
                self.tr('Processing models (*.model *.MODEL)')))
        if filename:
            try:
                alg = ModelerAlgorithm.fromFile(filename)
                self.alg = alg
                self.alg.setModelerView(self)
                self.textGroup.setText(alg.group)
                self.textName.setText(alg.name)
                self.repaintModel()

                self.view.centerOn(0, 0)
                self.hasChanged = False
            except WrongModelException as e:
                ProcessingLog.addToLog(
                    ProcessingLog.LOG_ERROR,
                    self.tr('Could not load model %s\n%s') % (filename, e.msg))
                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.'))
            except Exception as e:
                ProcessingLog.addToLog(
                    ProcessingLog.LOG_ERROR,
                    self.tr('Could not load model %s\n%s') %
                    (filename, e.args[0]))
                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 repaintModel(self):
        self.scene = ModelerScene()
        self.scene.setSceneRect(
            QRectF(0, 0, ModelerAlgorithm.CANVAS_SIZE,
                   ModelerAlgorithm.CANVAS_SIZE))
        self.scene.paintModel(self.alg)
        self.view.setScene(self.scene)

    def addInput(self):
        item = self.inputsTree.currentItem()
        paramType = unicode(item.text(0))
        self.addInputOfType(paramType)

    def addInputOfType(self, paramType, pos=None):
        if paramType in ModelerParameterDefinitionDialog.paramTypes:
            dlg = ModelerParameterDefinitionDialog(self.alg, paramType)
            dlg.exec_()
            if dlg.param is not None:
                if pos is None:
                    pos = self.getPositionForParameterItem()
                if isinstance(pos, QPoint):
                    pos = QPointF(pos)
                self.alg.addParameter(ModelerParameter(dlg.param, pos))
                self.repaintModel()
                # self.view.ensureVisible(self.scene.getLastParameterItem())
                self.hasChanged = True

    def getPositionForParameterItem(self):
        MARGIN = 20
        BOX_WIDTH = 200
        BOX_HEIGHT = 80
        if self.alg.inputs:
            maxX = max([i.pos.x() for i in self.alg.inputs.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.png'))
        parametersItem = QTreeWidgetItem()
        parametersItem.setText(0, self.tr('Parameters'))
        for paramType in ModelerParameterDefinitionDialog.paramTypes:
            paramItem = QTreeWidgetItem()
            paramItem.setText(0, paramType)
            paramItem.setIcon(0, icon)
            paramItem.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable
                               | Qt.ItemIsDragEnabled)
            parametersItem.addChild(paramItem)
        self.inputsTree.addTopLevelItem(parametersItem)
        parametersItem.setExpanded(True)

    def addAlgorithm(self):
        item = self.algorithmTree.currentItem()
        if isinstance(item, TreeAlgorithmItem):
            alg = algList.getAlgorithm(item.alg.commandLineName())
            self._addAlgorithm(alg.getCopy())

    def _addAlgorithm(self, alg, pos=None):
        dlg = alg.getCustomModelerParametersDialog(self.alg)
        if not dlg:
            dlg = ModelerParametersDialog(alg, self.alg)
        dlg.exec_()
        if dlg.alg is not None:
            if pos is None:
                dlg.alg.pos = self.getPositionForAlgorithmItem()
            else:
                dlg.alg.pos = pos
            if isinstance(dlg.alg.pos, QPoint):
                dlg.alg.pos = QPointF(pos)
            from processing.modeler.ModelerGraphicItem import ModelerGraphicItem
            for i, out in enumerate(dlg.alg.outputs):
                dlg.alg.outputs[out].pos = dlg.alg.pos + QPointF(
                    ModelerGraphicItem.BOX_WIDTH,
                    (i + 1.5) * ModelerGraphicItem.BOX_HEIGHT)
            self.alg.addAlgorithm(dlg.alg)
            self.repaintModel()
            self.hasChanged = True

    def getPositionForAlgorithmItem(self):
        MARGIN = 20
        BOX_WIDTH = 200
        BOX_HEIGHT = 80
        if self.alg.algs:
            maxX = max([alg.pos.x() for alg in self.alg.algs.values()])
            maxY = max([alg.pos.y() for alg in self.alg.algs.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 fillAlgorithmTree(self):
        self.fillAlgorithmTreeUsingProviders()
        self.algorithmTree.sortItems(0, Qt.AscendingOrder)

        text = unicode(self.searchBox.text())
        if text != '':
            self.algorithmTree.expandAll()

    def fillAlgorithmTreeUsingProviders(self):
        self.algorithmTree.clear()
        text = unicode(self.searchBox.text())
        allAlgs = algList.algs
        for providerName in allAlgs.keys():
            name = 'ACTIVATE_' + providerName.upper().replace(' ', '_')
            if not ProcessingConfig.getSetting(name):
                continue
            groups = {}
            algs = allAlgs[providerName].values()

            # Add algorithms
            for alg in algs:
                if not alg.showInModeler or alg.allowOnlyOpenedLayers:
                    continue
                if alg.commandLineName() == self.alg.commandLineName():
                    continue
                if text == '' or text.lower() in alg.name.lower():
                    if alg.group in groups:
                        groupItem = groups[alg.group]
                    else:
                        groupItem = QTreeWidgetItem()
                        name = alg.i18n_group or alg.group
                        groupItem.setText(0, name)
                        groupItem.setToolTip(0, name)
                        groups[alg.group] = groupItem
                    algItem = TreeAlgorithmItem(alg)
                    groupItem.addChild(algItem)

            if len(groups) > 0:
                providerItem = QTreeWidgetItem()
                provider = algList.getProviderFromName(providerName)
                providerItem.setText(0, provider.getDescription())
                providerItem.setToolTip(0, provider.getDescription())
                providerItem.setIcon(0, provider.getIcon())
                for groupItem in groups.values():
                    providerItem.addChild(groupItem)
                self.algorithmTree.addTopLevelItem(providerItem)
                providerItem.setExpanded(text != '')
                for groupItem in groups.values():
                    if text != '':
                        groupItem.setExpanded(True)

        self.algorithmTree.sortItems(0, Qt.AscendingOrder)
Ejemplo n.º 42
0
class ModelerDialog(BASE, WIDGET):

    CANVAS_SIZE = 4000

    update_model = pyqtSignal()

    def __init__(self, alg=None):
        super(ModelerDialog, self).__init__(None)
        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.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 = QSettings()
        self.restoreState(settings.value("/Processing/stateModeler", QByteArray()))
        self.restoreGeometry(settings.value("/Processing/geometryModeler", QByteArray()))

        self.scene = ModelerScene(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():
                text = event.mimeData().text()
                if text in ModelerParameterDefinitionDialog.paramTypes:
                    self.addInputOfType(text, event.pos())
                else:
                    alg = algList.getAlgorithm(text)
                    if alg is not None:
                        self._addAlgorithm(alg.getCopy(), 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 = QSettings()
            factor = settings.value('/qgis/zoom_favor', 2.0)
            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)
            self.repaintModel()

        def _enterEvent(e):
            QGraphicsView.enterEvent(self.view, e)
            self.view.viewport().setCursor(Qt.ArrowCursor)

        def _mousePressEvent(e):
            QGraphicsView.mousePressEvent(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.mousePressEvent = _mousePressEvent
        self.view.mouseMoveEvent = _mouseMoveEvent

        def _mimeDataInput(items):
            mimeData = QMimeData()
            text = items[0].text(0)
            mimeData.setText(text)
            return mimeData

        self.inputsTree.mimeData = _mimeDataInput

        self.inputsTree.setDragDropMode(QTreeWidget.DragOnly)
        self.inputsTree.setDropIndicatorShown(True)

        def _mimeDataAlgorithm(items):
            item = items[0]
            if isinstance(item, TreeAlgorithmItem):
                mimeData = QMimeData()
                mimeData.setText(item.alg.commandLineName())
            return mimeData

        self.algorithmTree.mimeData = _mimeDataAlgorithm

        self.algorithmTree.setDragDropMode(QTreeWidget.DragOnly)
        self.algorithmTree.setDropIndicatorShown(True)

        if hasattr(self.searchBox, 'setPlaceholderText'):
            self.searchBox.setPlaceholderText(self.tr('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.fillAlgorithmTree)
        self.algorithmTree.doubleClicked.connect(self.addAlgorithm)

        # Ctrl+= should also trigger a zoom in action
        ctrlEquals = QShortcut(QKeySequence("Ctrl+="), self)
        ctrlEquals.activated.connect(self.zoomIn)

        iconSize = settings.value("iconsize", 24)
        self.mToolbar.setIconSize(QSize(iconSize, iconSize))
        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 alg is not None:
            self.alg = alg
            self.textGroup.setText(alg.group)
            self.textName.setText(alg.name)
            self.repaintModel()

        else:
            self.alg = ModelerAlgorithm()
            self.alg.modelerdialog = self

        self.fillInputsTree()
        self.fillAlgorithmTree()

        self.view.centerOn(0, 0)
        self.alg.setModelerView(self)
        self.help = None

        self.hasChanged = False

    def closeEvent(self, evt):
        settings = QSettings()
        settings.setValue("/Processing/stateModeler", self.saveState())
        settings.setValue("/Processing/geometryModeler", self.saveGeometry())

        if self.hasChanged:
            ret = QMessageBox.question(
                self, self.tr('Save?'),
                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):
        if self.alg.provider is None:
            # Might happen if model is opened from modeler dialog
            self.alg.provider = QgsApplication.processingRegistry().providerById('model')
        alg = self.alg.getCopy()
        dlg = HelpEditionDialog(alg)
        dlg.exec_()
        if dlg.descriptions:
            self.alg.helpContent = dlg.descriptions
            self.hasChanged = True

    def runModel(self):
        if len(self.alg.algs) == 0:
            self.bar.pushMessage("", "Model doesn't contain any algorithm and/or parameter and can't be executed", level=QgsMessageBar.WARNING, duration=5)
            return

        if self.alg.provider is None:
            # Might happen if model is opened from modeler dialog
            self.alg.provider = QgsApplication.processingRegistry().providerById('model')
        alg = self.alg.getCopy()
        dlg = AlgorithmDialog(alg)
        dlg.exec_()

    def save(self):
        self.saveModel(False)

    def saveAs(self):
        self.saveModel(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 = QSettings()
        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 = QSettings()
        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("", "Model was correctly exported as image", level=QgsMessageBar.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('SVG 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("", "Model was correctly exported as PDF", level=QgsMessageBar.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.alg.name)

        painter = QPainter(svg)
        self.scene.render(painter, svgRect, totalRect)
        painter.end()

        self.bar.pushMessage("", "Model was correctly exported as SVG", level=QgsMessageBar.SUCCESS, duration=5)
        self.repaintModel(controls=True)

    def exportAsPython(self):
        filename, filter = QFileDialog.getSaveFileName(self,
                                                       self.tr('Save Model As Python Script'), '',
                                                       self.tr('Python files (*.py *.PY)'))
        if not filename:
            return

        if not filename.lower().endswith('.py'):
            filename += '.py'

        text = self.alg.toPython()
        with codecs.open(filename, 'w', encoding='utf-8') as fout:
            fout.write(text)

        self.bar.pushMessage("", "Model was correctly exported as python script", level=QgsMessageBar.SUCCESS, duration=5)

    def saveModel(self, saveAs):
        if str(self.textGroup.text()).strip() == '' \
                or str(self.textName.text()).strip() == '':
            QMessageBox.warning(
                self, self.tr('Warning'), self.tr('Please enter group and model names before saving')
            )
            return
        self.alg.name = str(self.textName.text())
        self.alg.group = str(self.textGroup.text())
        if self.alg.descriptionFile is not None and not saveAs:
            filename = self.alg.descriptionFile
        else:
            filename, filter = QFileDialog.getSaveFileName(self,
                                                           self.tr('Save Model'),
                                                           ModelerUtils.modelsFolders()[0],
                                                           self.tr('Processing models (*.model)'))
            if filename:
                if not filename.endswith('.model'):
                    filename += '.model'
                self.alg.descriptionFile = filename
        if filename:
            text = self.alg.toJson()
            try:
                with codecs.open(filename, 'w', encoding='utf-8') as fout:
                    fout.write(text)
            except:
                if saveAs:
                    QMessageBox.warning(self, self.tr('I/O error'),
                                        self.tr('Unable to save edits. Reason:\n %s') % str(sys.exc_info()[1]))
                else:
                    QMessageBox.warning(self, self.tr("Can't save model"),
                                        self.tr("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()
            self.bar.pushMessage("", "Model was correctly saved", level=QgsMessageBar.SUCCESS, duration=5)

            self.hasChanged = False

    def openModel(self):
        filename, selected_filter = str(QFileDialog.getOpenFileName(self,
                                                                    self.tr('Open Model'), ModelerUtils.modelsFolders()[0],
                                                                    self.tr('Processing models (*.model *.MODEL)')))
        if filename:
            try:
                alg = ModelerAlgorithm.fromFile(filename)
                self.alg = alg
                self.alg.setModelerView(self)
                self.textGroup.setText(alg.group)
                self.textName.setText(alg.name)
                self.repaintModel()

                self.view.centerOn(0, 0)
                self.hasChanged = False
            except WrongModelException as e:
                ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
                                       self.tr('Could not load model %s\n%s') % (filename, e.msg))
                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.'))
            except Exception as e:
                ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
                                       self.tr('Could not load model %s\n%s') % (filename, e.args[0]))
                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 repaintModel(self, controls=True):
        self.scene = ModelerScene()
        self.scene.setSceneRect(QRectF(0, 0, ModelerAlgorithm.CANVAS_SIZE,
                                       ModelerAlgorithm.CANVAS_SIZE))
        self.scene.paintModel(self.alg, controls)
        self.view.setScene(self.scene)

    def addInput(self):
        item = self.inputsTree.currentItem()
        paramType = str(item.text(0))
        self.addInputOfType(paramType)

    def addInputOfType(self, paramType, pos=None):
        if paramType in ModelerParameterDefinitionDialog.paramTypes:
            dlg = ModelerParameterDefinitionDialog(self.alg, paramType)
            dlg.exec_()
            if dlg.param is not None:
                if pos is None:
                    pos = self.getPositionForParameterItem()
                if isinstance(pos, QPoint):
                    pos = QPointF(pos)
                self.alg.addParameter(ModelerParameter(dlg.param, pos))
                self.repaintModel()
                # self.view.ensureVisible(self.scene.getLastParameterItem())
                self.hasChanged = True

    def getPositionForParameterItem(self):
        MARGIN = 20
        BOX_WIDTH = 200
        BOX_HEIGHT = 80
        if self.alg.inputs:
            maxX = max([i.pos.x() for i in list(self.alg.inputs.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'))
        for paramType in ModelerParameterDefinitionDialog.paramTypes:
            paramItem = QTreeWidgetItem()
            paramItem.setText(0, paramType)
            paramItem.setIcon(0, icon)
            paramItem.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsDragEnabled)
            parametersItem.addChild(paramItem)
        self.inputsTree.addTopLevelItem(parametersItem)
        parametersItem.setExpanded(True)

    def addAlgorithm(self):
        item = self.algorithmTree.currentItem()
        if isinstance(item, TreeAlgorithmItem):
            alg = algList.getAlgorithm(item.alg.commandLineName())
            self._addAlgorithm(alg.getCopy())

    def _addAlgorithm(self, alg, pos=None):
        dlg = alg.getCustomModelerParametersDialog(self.alg)
        if not dlg:
            dlg = ModelerParametersDialog(alg, self.alg)
        dlg.exec_()
        if dlg.alg is not None:
            if pos is None:
                dlg.alg.pos = self.getPositionForAlgorithmItem()
            else:
                dlg.alg.pos = pos
            if isinstance(dlg.alg.pos, QPoint):
                dlg.alg.pos = QPointF(pos)
            from processing.modeler.ModelerGraphicItem import ModelerGraphicItem
            for i, out in enumerate(dlg.alg.outputs):
                dlg.alg.outputs[out].pos = dlg.alg.pos + QPointF(ModelerGraphicItem.BOX_WIDTH, (i + 1.5)
                                                                 * ModelerGraphicItem.BOX_HEIGHT)
            self.alg.addAlgorithm(dlg.alg)
            self.repaintModel()
            self.hasChanged = True

    def getPositionForAlgorithmItem(self):
        MARGIN = 20
        BOX_WIDTH = 200
        BOX_HEIGHT = 80
        if self.alg.algs:
            maxX = max([alg.pos.x() for alg in list(self.alg.algs.values())])
            maxY = max([alg.pos.y() for alg in list(self.alg.algs.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 fillAlgorithmTree(self):
        self.fillAlgorithmTreeUsingProviders()
        self.algorithmTree.sortItems(0, Qt.AscendingOrder)

        text = str(self.searchBox.text())
        if text != '':
            self.algorithmTree.expandAll()

    def fillAlgorithmTreeUsingProviders(self):
        self.algorithmTree.clear()
        text = str(self.searchBox.text())
        search_strings = text.split(' ')
        allAlgs = algList.algs
        for provider_id in list(allAlgs.keys()):
            name = 'ACTIVATE_' + provider_id.upper().replace(' ', '_')
            if not ProcessingConfig.getSetting(name):
                continue
            groups = {}
            algs = list(allAlgs[provider_id].values())

            # Add algorithms
            for alg in algs:
                if not alg.showInModeler:
                    continue
                if alg.commandLineName() == self.alg.commandLineName():
                    continue

                item_text = [alg.name.lower()]
                item_text.extend(alg.tags.split(','))

                show = not search_strings or all(
                    any(part in t for t in item_text)
                    for part in search_strings)

                if show:
                    if alg.group in groups:
                        groupItem = groups[alg.group]
                    else:
                        groupItem = QTreeWidgetItem()
                        name = alg.i18n_group or alg.group
                        groupItem.setText(0, name)
                        groupItem.setToolTip(0, name)
                        groups[alg.group] = groupItem
                    algItem = TreeAlgorithmItem(alg)
                    groupItem.addChild(algItem)

            if len(groups) > 0:
                providerItem = QTreeWidgetItem()
                provider = QgsApplication.processingRegistry().providerById(provider_id)
                providerItem.setText(0, provider.name())
                providerItem.setToolTip(0, provider.name())
                providerItem.setIcon(0, provider.icon())
                for groupItem in list(groups.values()):
                    providerItem.addChild(groupItem)
                self.algorithmTree.addTopLevelItem(providerItem)
                providerItem.setExpanded(text != '')
                for groupItem in list(groups.values()):
                    if text != '':
                        groupItem.setExpanded(True)

        self.algorithmTree.sortItems(0, Qt.AscendingOrder)
Ejemplo n.º 43
0
    def testModelerParametersDialogAvailableValuesOfType(self):
        # test getAvailableValuesOfType from ModelerParametersDialog

        m = ModelerAlgorithm()
        string_param_1 = ModelerParameter(ParameterString("string", "string desc"))
        m.addParameter(string_param_1)
        string_param_2 = ModelerParameter(ParameterString("string2", "string desc"))
        m.addParameter(string_param_2)
        num_param = ModelerParameter(ParameterNumber("number", "number desc"))
        m.addParameter(num_param)
        table_field_param = ModelerParameter(ParameterTableField("field", "field desc"))
        m.addParameter(table_field_param)
        file_param = ModelerParameter(ParameterFile("file", "file desc"))
        m.addParameter(file_param)

        dlg = ModelerParametersDialog(m, m)
        # test single types
        self.assertEqual(set(p.name for p in dlg.getAvailableValuesOfType(ParameterNumber)), set(["number"]))
        self.assertEqual(set(p.name for p in dlg.getAvailableValuesOfType(ParameterTableField)), set(["field"]))
        self.assertEqual(set(p.name for p in dlg.getAvailableValuesOfType(ParameterFile)), set(["file"]))

        # test multiple types
        self.assertEqual(
            set(p.name for p in dlg.getAvailableValuesOfType([ParameterString, ParameterNumber, ParameterFile])),
            set(["string", "string2", "number", "file"]),
        )
Ejemplo n.º 44
0
    def __init__(self, alg=None):
        super(ModelerDialog, self).__init__(None)
        self.setupUi(self)

        self.zoom = 1

        self.setWindowFlags(Qt.WindowMinimizeButtonHint |
                            Qt.WindowMaximizeButtonHint |
                            Qt.WindowCloseButtonHint)

        settings = QSettings()
        self.splitter.restoreState(settings.value("/Processing/splitterModeler", QByteArray()))
        self.restoreGeometry(settings.value("/Processing/geometryModeler", QByteArray()))

        self.tabWidget.setCurrentIndex(0)
        self.scene = ModelerScene(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():
                text = event.mimeData().text()
                if text in ModelerParameterDefinitionDialog.paramTypes:
                    self.addInputOfType(text, event.pos())
                else:
                    alg = ModelerUtils.getAlgorithm(text)
                    if alg is not None:
                        self._addAlgorithm(alg.getCopy(), 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)
            factor = 1.05
            if event.delta() > 0:
                factor = 1 / factor
            self.view.scale(factor, factor)
            self.repaintModel()

        def _enterEvent(e):
            QGraphicsView.enterEvent(self.view, e)
            self.view.viewport().setCursor(Qt.ArrowCursor)

        def _mousePressEvent(e):
            QGraphicsView.mousePressEvent(self.view, e)
            self.view.viewport().setCursor(Qt.ArrowCursor)

        def _mouseReleaseEvent(e):
            QGraphicsView.mouseReleaseEvent(self.view, e)
            self.view.viewport().setCursor(Qt.ArrowCursor)

        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.mouseReleaseEvent = _mouseReleaseEvent

        def _mimeDataInput(items):
            mimeData = QMimeData()
            text = items[0].text(0)
            mimeData.setText(text)
            return mimeData

        self.inputsTree.mimeData = _mimeDataInput

        self.inputsTree.setDragDropMode(QTreeWidget.DragOnly)
        self.inputsTree.setDropIndicatorShown(True)

        def _mimeDataAlgorithm(items):
            item = items[0]
            if isinstance(item, TreeAlgorithmItem):
                mimeData = QMimeData()
                mimeData.setText(item.alg.commandLineName())
            return mimeData

        self.algorithmTree.mimeData = _mimeDataAlgorithm

        self.algorithmTree.setDragDropMode(QTreeWidget.DragOnly)
        self.algorithmTree.setDropIndicatorShown(True)

        # Set icons
        self.btnOpen.setIcon(QgsApplication.getThemeIcon('/mActionFileOpen.svg'))
        self.btnSave.setIcon(QgsApplication.getThemeIcon('/mActionFileSave.svg'))
        self.btnSaveAs.setIcon(QgsApplication.getThemeIcon('/mActionFileSaveAs.svg'))
        self.btnExportImage.setIcon(QgsApplication.getThemeIcon('/mActionSaveMapAsImage.png'))
        self.btnExportPython.setIcon(QgsApplication.getThemeIcon('/console/iconSaveAsConsole.png'))
        self.btnEditHelp.setIcon(QIcon(os.path.join(pluginPath, 'images', 'edithelp.png')))
        self.btnRun.setIcon(QIcon(os.path.join(pluginPath, 'images', 'runalgorithm.png')))

        # Fill trees with inputs and algorithms
        self.fillInputsTree()
        self.fillAlgorithmTree()

        if hasattr(self.searchBox, 'setPlaceholderText'):
            self.searchBox.setPlaceholderText(self.tr('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.fillAlgorithmTree)
        self.algorithmTree.doubleClicked.connect(self.addAlgorithm)

        self.btnOpen.clicked.connect(self.openModel)
        self.btnSave.clicked.connect(self.save)
        self.btnSaveAs.clicked.connect(self.saveAs)
        self.btnExportImage.clicked.connect(self.exportAsImage)
        self.btnExportPython.clicked.connect(self.exportAsPython)
        self.btnEditHelp.clicked.connect(self.editHelp)
        self.btnRun.clicked.connect(self.runModel)

        if alg is not None:
            self.alg = alg
            self.textGroup.setText(alg.group)
            self.textName.setText(alg.name)
            self.repaintModel()

        else:
            self.alg = ModelerAlgorithm()
            self.alg.modelerdialog = self

        self.view.centerOn(0, 0)
        self.alg.setModelerView(self)
        self.help = None
        # Indicates whether to update or not the toolbox after
        # closing this dialog
        self.update = False

        self.hasChanged = False
Ejemplo n.º 45
0
class ModelerDialog(BASE, WIDGET):

    USE_CATEGORIES = '/Processing/UseSimplifiedInterface'
    CANVAS_SIZE = 4000

    def __init__(self, alg=None):
        super(ModelerDialog, self).__init__(None)
        self.setupUi(self)

        self.zoom = 1

        self.setWindowFlags(Qt.WindowMinimizeButtonHint |
                            Qt.WindowMaximizeButtonHint |
                            Qt.WindowCloseButtonHint)

        settings = QSettings()
        self.splitter.restoreState(settings.value("/Processing/splitterModeler", QByteArray()))
        self.restoreGeometry(settings.value("/Processing/geometryModeler", QByteArray()))

        self.tabWidget.setCurrentIndex(0)
        self.scene = ModelerScene(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():
                text = event.mimeData().text()
                if text in ModelerParameterDefinitionDialog.paramTypes:
                    self.addInputOfType(text, event.pos())
                else:
                    alg = ModelerUtils.getAlgorithm(text)
                    if alg is not None:
                        self._addAlgorithm(alg.getCopy(), 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)
            factor = 1.05
            if event.delta() > 0:
                factor = 1 / factor
            self.view.scale(factor, factor)
            self.repaintModel()

        def _enterEvent(e):
            QGraphicsView.enterEvent(self.view, e)
            self.view.viewport().setCursor(Qt.ArrowCursor)

        def _mousePressEvent(e):
            QGraphicsView.mousePressEvent(self.view, e)
            self.view.viewport().setCursor(Qt.ArrowCursor)

        def _mouseReleaseEvent(e):
            QGraphicsView.mouseReleaseEvent(self.view, e)
            self.view.viewport().setCursor(Qt.ArrowCursor)

        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.mouseReleaseEvent = _mouseReleaseEvent

        def _mimeDataInput(items):
            mimeData = QMimeData()
            text = items[0].text(0)
            mimeData.setText(text)
            return mimeData

        self.inputsTree.mimeData = _mimeDataInput

        self.inputsTree.setDragDropMode(QTreeWidget.DragOnly)
        self.inputsTree.setDropIndicatorShown(True)

        def _mimeDataAlgorithm(items):
            item = items[0]
            if isinstance(item, TreeAlgorithmItem):
                mimeData = QMimeData()
                mimeData.setText(item.alg.commandLineName())
            return mimeData

        self.algorithmTree.mimeData = _mimeDataAlgorithm

        self.algorithmTree.setDragDropMode(QTreeWidget.DragOnly)
        self.algorithmTree.setDropIndicatorShown(True)

        # Set icons
        self.btnOpen.setIcon(QgsApplication.getThemeIcon('/mActionFileOpen.svg'))
        self.btnSave.setIcon(QgsApplication.getThemeIcon('/mActionFileSave.svg'))
        self.btnSaveAs.setIcon(QgsApplication.getThemeIcon('/mActionFileSaveAs.svg'))
        self.btnExportImage.setIcon(QgsApplication.getThemeIcon('/mActionSaveMapAsImage.png'))
        self.btnExportPython.setIcon(QgsApplication.getThemeIcon('/console/iconSaveAsConsole.png'))
        self.btnEditHelp.setIcon(QIcon(os.path.join(pluginPath, 'images', 'edithelp.png')))
        self.btnRun.setIcon(QIcon(os.path.join(pluginPath, 'images', 'runalgorithm.png')))

        # Fill trees with inputs and algorithms
        self.fillInputsTree()
        self.fillAlgorithmTree()

        if hasattr(self.searchBox, 'setPlaceholderText'):
            self.searchBox.setPlaceholderText(self.tr('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.fillAlgorithmTree)
        self.algorithmTree.doubleClicked.connect(self.addAlgorithm)

        self.btnOpen.clicked.connect(self.openModel)
        self.btnSave.clicked.connect(self.save)
        self.btnSaveAs.clicked.connect(self.saveAs)
        self.btnExportImage.clicked.connect(self.exportAsImage)
        self.btnExportPython.clicked.connect(self.exportAsPython)
        self.btnEditHelp.clicked.connect(self.editHelp)
        self.btnRun.clicked.connect(self.runModel)

        if alg is not None:
            self.alg = alg
            self.textGroup.setText(alg.group)
            self.textName.setText(alg.name)
            self.repaintModel()

        else:
            self.alg = ModelerAlgorithm()
            self.alg.modelerdialog = self

        self.view.centerOn(0, 0)
        self.alg.setModelerView(self)
        self.help = None
        # Indicates whether to update or not the toolbox after
        # closing this dialog
        self.update = False

        self.hasChanged = False

    def closeEvent(self, evt):
        settings = QSettings()
        settings.setValue("/Processing/splitterModeler", self.splitter.saveState())
        settings.setValue("/Processing/geometryModeler", self.saveGeometry())

        if self.hasChanged:
            ret = QMessageBox.question(
                self, self.tr('Unsaved changes'),
                self.tr('There are unsaved changes in model. Continue?'),
                QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

            if ret == QMessageBox.Yes:
                evt.accept()
            else:
                evt.ignore()
        else:
            evt.accept()

    def editHelp(self):
        if self.alg.provider is None:
            # Might happen if model is opened from modeler dialog
            self.alg.provider = ModelerUtils.providers['model']
        alg = self.alg.getCopy()
        dlg = HelpEditionDialog(alg)
        dlg.exec_()
        if dlg.descriptions:
            self.alg.helpContent = dlg.descriptions
            self.hasChanged = True

    def runModel(self):
        if len(self.alg.algs) == 0:
            QMessageBox.warning(self, self.tr('Empty model'),
                                self.tr("Model doesn't contains any algorithms and/or "
                                        "parameters and can't be executed"))
            return

        if self.alg.provider is None:
            # Might happen if model is opened from modeler dialog
            self.alg.provider = ModelerUtils.providers['model']
        alg = self.alg.getCopy()
        dlg = AlgorithmDialog(alg)
        dlg.exec_()

    def save(self):
        self.saveModel(False)

    def saveAs(self):
        self.saveModel(True)

    def exportAsImage(self):
        filename = unicode(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 = QRectF(0, 0, 1, 1)
        for item in self.scene.items():
            totalRect = totalRect.united(item.sceneBoundingRect())
        totalRect.adjust(-10, -10, 10, 10)

        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, totalRect, totalRect)
        painter.end()

        img.save(filename)

    def exportAsPython(self):
        filename = unicode(QFileDialog.getSaveFileName(self,
                                                       self.tr('Save Model As Python Script'), '',
                                                       self.tr('Python files (*.py *.PY)')))
        if not filename:
            return

        if not filename.lower().endswith('.py'):
            filename += '.py'

        text = self.alg.toPython()
        with codecs.open(filename, 'w', encoding='utf-8') as fout:
            fout.write(text)
        QMessageBox.information(self, self.tr('Model exported'),
                                self.tr('Model was correctly exported.'))

    def saveModel(self, saveAs):
        if unicode(self.textGroup.text()).strip() == '' \
                or unicode(self.textName.text()).strip() == '':
            QMessageBox.warning(
                self, self.tr('Warning'), self.tr('Please enter group and model names before saving')
            )
            return
        self.alg.name = unicode(self.textName.text())
        self.alg.group = unicode(self.textGroup.text())
        if self.alg.descriptionFile is not None and not saveAs:
            filename = self.alg.descriptionFile
        else:
            filename = unicode(QFileDialog.getSaveFileName(self,
                                                           self.tr('Save Model'),
                                                           ModelerUtils.modelsFolder(),
                                                           self.tr('Processing models (*.model)')))
            if filename:
                if not filename.endswith('.model'):
                    filename += '.model'
                self.alg.descriptionFile = filename
        if filename:
            text = self.alg.toJson()
            try:
                fout = codecs.open(filename, 'w', encoding='utf-8')
            except:
                if saveAs:
                    QMessageBox.warning(self, self.tr('I/O error'),
                                        self.tr('Unable to save edits. Reason:\n %s') % unicode(sys.exc_info()[1]))
                else:
                    QMessageBox.warning(self, self.tr("Can't save model"),
                                        self.tr("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
            fout.write(text)
            fout.close()
            self.update = True
            QMessageBox.information(self, self.tr('Model saved'),
                                    self.tr('Model was correctly saved.'))

            self.hasChanged = False

    def openModel(self):
        filename = unicode(QFileDialog.getOpenFileName(self,
                                                       self.tr('Open Model'), ModelerUtils.modelsFolder(),
                                                       self.tr('Processing models (*.model *.MODEL)')))
        if filename:
            try:
                alg = ModelerAlgorithm.fromFile(filename)
                self.alg = alg
                self.alg.setModelerView(self)
                self.textGroup.setText(alg.group)
                self.textName.setText(alg.name)
                self.repaintModel()

                self.view.centerOn(0, 0)
                self.hasChanged = False
            except WrongModelException as e:
                ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
                                       self.tr('Could not load model %s\n%s') % (filename, e.msg))
                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.'))
            except Exception as e:
                ProcessingLog.addToLog(ProcessingLog.LOG_ERROR,
                                       self.tr('Could not load model %s\n%s') % (filename, e.args[0]))
                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 repaintModel(self):
        self.scene = ModelerScene()
        self.scene.setSceneRect(QRectF(0, 0, ModelerAlgorithm.CANVAS_SIZE,
                                       ModelerAlgorithm.CANVAS_SIZE))
        self.scene.paintModel(self.alg)
        self.view.setScene(self.scene)

    def addInput(self):
        item = self.inputsTree.currentItem()
        paramType = unicode(item.text(0))
        self.addInputOfType(paramType)

    def addInputOfType(self, paramType, pos=None):
        if paramType in ModelerParameterDefinitionDialog.paramTypes:
            dlg = ModelerParameterDefinitionDialog(self.alg, paramType)
            dlg.exec_()
            if dlg.param is not None:
                if pos is None:
                    pos = self.getPositionForParameterItem()
                if isinstance(pos, QPoint):
                    pos = QPointF(pos)
                self.alg.addParameter(ModelerParameter(dlg.param, pos))
                self.repaintModel()
                #self.view.ensureVisible(self.scene.getLastParameterItem())
                self.hasChanged = True

    def getPositionForParameterItem(self):
        MARGIN = 20
        BOX_WIDTH = 200
        BOX_HEIGHT = 80
        if self.alg.inputs:
            maxX = max([i.pos.x() for i in self.alg.inputs.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.png'))
        parametersItem = QTreeWidgetItem()
        parametersItem.setText(0, self.tr('Parameters'))
        for paramType in ModelerParameterDefinitionDialog.paramTypes:
            paramItem = QTreeWidgetItem()
            paramItem.setText(0, paramType)
            paramItem.setIcon(0, icon)
            paramItem.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsDragEnabled)
            parametersItem.addChild(paramItem)
        self.inputsTree.addTopLevelItem(parametersItem)
        parametersItem.setExpanded(True)

    def addAlgorithm(self):
        item = self.algorithmTree.currentItem()
        if isinstance(item, TreeAlgorithmItem):
            alg = ModelerUtils.getAlgorithm(item.alg.commandLineName())
            self._addAlgorithm(alg.getCopy())

    def _addAlgorithm(self, alg, pos=None):
        dlg = alg.getCustomModelerParametersDialog(self.alg)
        if not dlg:
            dlg = ModelerParametersDialog(alg, self.alg)
        dlg.exec_()
        if dlg.alg is not None:
            if pos is None:
                dlg.alg.pos = self.getPositionForAlgorithmItem()
            else:
                dlg.alg.pos = pos
            if isinstance(dlg.alg.pos, QPoint):
                dlg.alg.pos = QPointF(pos)
            from processing.modeler.ModelerGraphicItem import ModelerGraphicItem
            for i, out in enumerate(dlg.alg.outputs):
                dlg.alg.outputs[out].pos = dlg.alg.pos + QPointF(ModelerGraphicItem.BOX_WIDTH, (i + 1.5)
                                                                 * ModelerGraphicItem.BOX_HEIGHT)
            self.alg.addAlgorithm(dlg.alg)
            self.repaintModel()
            self.hasChanged = True

    def getPositionForAlgorithmItem(self):
        MARGIN = 20
        BOX_WIDTH = 200
        BOX_HEIGHT = 80
        if self.alg.algs:
            maxX = max([alg.pos.x() for alg in self.alg.algs.values()])
            maxY = max([alg.pos.y() for alg in self.alg.algs.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 fillAlgorithmTree(self):
        self.fillAlgorithmTreeUsingProviders()
        self.algorithmTree.sortItems(0, Qt.AscendingOrder)

        text = unicode(self.searchBox.text())
        if text != '':
            self.algorithmTree.expandAll()

    def fillAlgorithmTreeUsingProviders(self):
        self.algorithmTree.clear()
        text = unicode(self.searchBox.text())
        allAlgs = ModelerUtils.allAlgs
        for providerName in allAlgs.keys():
            name = 'ACTIVATE_' + providerName.upper().replace(' ', '_')
            if not ProcessingConfig.getSetting(name):
                continue
            groups = {}
            provider = allAlgs[providerName]
            algs = provider.values()

            # Add algorithms
            for alg in algs:
                if not alg.showInModeler or alg.allowOnlyOpenedLayers:
                    continue
                if text == '' or text.lower() in alg.name.lower():
                    if alg.group in groups:
                        groupItem = groups[alg.group]
                    else:
                        groupItem = QTreeWidgetItem()
                        name = alg.i18n_group or alg.group
                        groupItem.setText(0, name)
                        groupItem.setToolTip(0, name)
                        groups[alg.group] = groupItem
                    algItem = TreeAlgorithmItem(alg)
                    groupItem.addChild(algItem)

            if len(groups) > 0:
                providerItem = QTreeWidgetItem()
                providerItem.setText(0,
                                     ModelerUtils.providers[providerName].getDescription())
                providerItem.setToolTip(0,
                                        ModelerUtils.providers[providerName].getDescription())
                providerItem.setIcon(0,
                                     ModelerUtils.providers[providerName].getIcon())
                for groupItem in groups.values():
                    providerItem.addChild(groupItem)
                self.algorithmTree.addTopLevelItem(providerItem)
                providerItem.setExpanded(text != '')
                for groupItem in groups.values():
                    if text != '':
                        groupItem.setExpanded(True)

        self.algorithmTree.sortItems(0, Qt.AscendingOrder)
Ejemplo n.º 46
0
    def testComputingDependecies(self):
        folder = os.path.join(os.path.dirname(ModelerAlgorithmProvider.__file__), "models")
        modelfile = os.path.join(folder, "watersheds.model")
        model = ModelerAlgorithm()
        model.openModel(modelfile)
        self.assertTrue(2, len(model.parameters))
        self.assertTrue(5, len(model.algs))
        dependent = model.getDependentAlgorithms(0)
        self.assertEquals([0, 1, 2, 3, 4], dependent)
        dependent = model.getDependentAlgorithms(1)
        self.assertEquals([1, 2, 3, 4], dependent)
        dependent = model.getDependentAlgorithms(2)
        self.assertEquals([2, 3, 4], dependent)
        dependent = model.getDependentAlgorithms(3)
        self.assertEquals([3, 4], dependent)
        dependent = model.getDependentAlgorithms(4)
        self.assertEquals([4], dependent)

        depends = model.getDependsOnAlgorithms(0)
        self.assertEquals([], depends)
        depends = model.getDependsOnAlgorithms(1)
        self.assertEquals([0], depends)
        depends = model.getDependsOnAlgorithms(2)
        self.assertEquals([1, 0], depends)
        depends = model.getDependsOnAlgorithms(3)
        self.assertEquals([2, 1, 0], depends)
        depends = model.getDependsOnAlgorithms(4)
        self.assertEquals([3, 2, 1, 0], depends)
Ejemplo n.º 47
0
    def testComputingDependecies(self):
        folder = \
            os.path.join(os.path.dirname(ModelerAlgorithmProvider.__file__),
                         'models')
        modelfile = os.path.join(folder, 'watersheds.model')
        model = ModelerAlgorithm()
        model.openModel(modelfile)
        self.assertTrue(2, len(model.parameters))
        self.assertTrue(5, len(model.algs))
        dependent = model.getDependentAlgorithms(0)
        self.assertEquals([0, 1, 2, 3, 4], dependent)
        dependent = model.getDependentAlgorithms(1)
        self.assertEquals([1, 2, 3, 4], dependent)
        dependent = model.getDependentAlgorithms(2)
        self.assertEquals([2, 3, 4], dependent)
        dependent = model.getDependentAlgorithms(3)
        self.assertEquals([3, 4], dependent)
        dependent = model.getDependentAlgorithms(4)
        self.assertEquals([4], dependent)

        depends = model.getDependsOnAlgorithms(0)
        self.assertEquals([], depends)
        depends = model.getDependsOnAlgorithms(1)
        self.assertEquals([0], depends)
        depends = model.getDependsOnAlgorithms(2)
        self.assertEquals([1, 0], depends)
        depends = model.getDependsOnAlgorithms(3)
        self.assertEquals([2, 1, 0], depends)
        depends = model.getDependsOnAlgorithms(4)
        self.assertEquals([3, 2, 1, 0], depends)
Ejemplo n.º 48
0
class ModelerDialog(BASE, WIDGET):

    CANVAS_SIZE = 4000

    update_model = pyqtSignal()

    def __init__(self, alg=None):
        super(ModelerDialog, self).__init__(None)
        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.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)
        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():
                text = event.mimeData().text()
                if text in ModelerParameterDefinitionDialog.paramTypes:
                    self.addInputOfType(text, event.pos())
                else:
                    alg = QgsApplication.processingRegistry().algorithmById(text)
                    if alg is not None:
                        self._addAlgorithm(alg.getCopy(), 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)
            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)
            self.repaintModel()

        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].text(0)
            mimeData.setText(text)
            return mimeData

        self.inputsTree.mimeData = _mimeDataInput

        self.inputsTree.setDragDropMode(QTreeWidget.DragOnly)
        self.inputsTree.setDropIndicatorShown(True)

        def _mimeDataAlgorithm(items):
            item = items[0]
            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(self.tr('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.fillAlgorithmTree)
        self.algorithmTree.doubleClicked.connect(self.addAlgorithm)

        # Ctrl+= should also trigger a zoom in action
        ctrlEquals = QShortcut(QKeySequence("Ctrl+="), self)
        ctrlEquals.activated.connect(self.zoomIn)

        try:
            iconSize = int(settings.value("iconsize", 24))
        except:
            iconSize = 24
        self.mToolbar.setIconSize(QSize(iconSize, iconSize))
        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 alg is not None:
            self.alg = alg
            self.textGroup.setText(alg._group)
            self.textName.setText(alg.displayName())
            self.repaintModel()

        else:
            self.alg = ModelerAlgorithm()
            self.alg.modelerdialog = self

        self.fillInputsTree()
        self.fillAlgorithmTree()

        self.view.centerOn(0, 0)
        self.alg.setModelerView(self)
        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?'),
                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.alg.getCopy()
        dlg = HelpEditionDialog(alg)
        dlg.exec_()
        if dlg.descriptions:
            self.alg.helpContent = dlg.descriptions
            self.hasChanged = True

    def runModel(self):
        if len(self.alg.algs) == 0:
            self.bar.pushMessage("", "Model doesn't contain any algorithm and/or parameter and can't be executed", level=QgsMessageBar.WARNING, duration=5)
            return

        alg = self.alg.getCopy()
        dlg = AlgorithmDialog(alg)
        dlg.exec_()

    def save(self):
        self.saveModel(False)

    def saveAs(self):
        self.saveModel(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("", "Model was correctly exported as image", level=QgsMessageBar.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("", "Model was correctly exported as PDF", level=QgsMessageBar.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.alg.displayName())

        painter = QPainter(svg)
        self.scene.render(painter, svgRect, totalRect)
        painter.end()

        self.bar.pushMessage("", "Model was correctly exported as SVG", level=QgsMessageBar.SUCCESS, duration=5)
        self.repaintModel(controls=True)

    def exportAsPython(self):
        filename, filter = QFileDialog.getSaveFileName(self,
                                                       self.tr('Save Model As Python Script'), '',
                                                       self.tr('Python files (*.py *.PY)'))
        if not filename:
            return

        if not filename.lower().endswith('.py'):
            filename += '.py'

        text = self.alg.toPython()
        with codecs.open(filename, 'w', encoding='utf-8') as fout:
            fout.write(text)

        self.bar.pushMessage("", "Model was correctly exported as python script", level=QgsMessageBar.SUCCESS, duration=5)

    def saveModel(self, saveAs):
        if str(self.textGroup.text()).strip() == '' \
                or str(self.textName.text()).strip() == '':
            QMessageBox.warning(
                self, self.tr('Warning'), self.tr('Please enter group and model names before saving')
            )
            return
        self.alg._name = str(self.textName.text())
        self.alg._group = str(self.textGroup.text())
        if self.alg.descriptionFile is not None and not saveAs:
            filename = self.alg.descriptionFile
        else:
            filename, filter = QFileDialog.getSaveFileName(self,
                                                           self.tr('Save Model'),
                                                           ModelerUtils.modelsFolders()[0],
                                                           self.tr('Processing models (*.model)'))
            if filename:
                if not filename.endswith('.model'):
                    filename += '.model'
                self.alg.descriptionFile = filename
        if filename:
            text = self.alg.toJson()
            try:
                with codecs.open(filename, 'w', encoding='utf-8') as fout:
                    fout.write(text)
            except:
                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"),
                                        self.tr("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()
            self.bar.pushMessage("", "Model was correctly saved", level=QgsMessageBar.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 (*.model *.MODEL)'))
        if filename:
            try:
                alg = ModelerAlgorithm.fromFile(filename)
                self.alg = alg
                self.alg.setModelerView(self)
                self.textGroup.setText(alg._group)
                self.textName.setText(alg._name)
                self.repaintModel()

                self.view.centerOn(0, 0)
                self.hasChanged = False
            except WrongModelException as e:
                QgsMessageLog.logMessage(self.tr('Could not load model {0}\n{1}').format(filename, e.msg),
                                         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.'))
            except Exception as e:
                QgsMessageLog.logMessage(self.tr('Could not load model {0}\n{1}').format(filename, e.args[0]),
                                         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 repaintModel(self, controls=True):
        self.scene = ModelerScene()
        self.scene.setSceneRect(QRectF(0, 0, ModelerAlgorithm.CANVAS_SIZE,
                                       ModelerAlgorithm.CANVAS_SIZE))
        self.scene.paintModel(self.alg, controls)
        self.view.setScene(self.scene)

    def addInput(self):
        item = self.inputsTree.currentItem()
        paramType = str(item.text(0))
        self.addInputOfType(paramType)

    def addInputOfType(self, paramType, pos=None):
        if paramType in ModelerParameterDefinitionDialog.paramTypes:
            dlg = ModelerParameterDefinitionDialog(self.alg, paramType)
            dlg.exec_()
            if dlg.param is not None:
                if pos is None:
                    pos = self.getPositionForParameterItem()
                if isinstance(pos, QPoint):
                    pos = QPointF(pos)
                self.alg.addParameter(ModelerParameter(dlg.param, pos))
                self.repaintModel()
                # self.view.ensureVisible(self.scene.getLastParameterItem())
                self.hasChanged = True

    def getPositionForParameterItem(self):
        MARGIN = 20
        BOX_WIDTH = 200
        BOX_HEIGHT = 80
        if self.alg.inputs:
            maxX = max([i.pos.x() for i in list(self.alg.inputs.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'))
        for paramType in ModelerParameterDefinitionDialog.paramTypes:
            paramItem = QTreeWidgetItem()
            paramItem.setText(0, paramType)
            paramItem.setIcon(0, icon)
            paramItem.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsDragEnabled)
            parametersItem.addChild(paramItem)
        self.inputsTree.addTopLevelItem(parametersItem)
        parametersItem.setExpanded(True)

    def addAlgorithm(self):
        item = self.algorithmTree.currentItem()
        if isinstance(item, TreeAlgorithmItem):
            alg = QgsApplication.processingRegistry().algorithmById(item.alg.id())
            self._addAlgorithm(alg.getCopy())

    def _addAlgorithm(self, alg, pos=None):
        dlg = alg.getCustomModelerParametersDialog(self.alg)
        if not dlg:
            dlg = ModelerParametersDialog(alg, self.alg)
        dlg.exec_()
        if dlg.alg is not None:
            if pos is None:
                dlg.alg.pos = self.getPositionForAlgorithmItem()
            else:
                dlg.alg.pos = pos
            if isinstance(dlg.alg.pos, QPoint):
                dlg.alg.pos = QPointF(pos)
            from processing.modeler.ModelerGraphicItem import ModelerGraphicItem
            for i, out in enumerate(dlg.alg.outputs):
                dlg.alg.outputs[out].pos = dlg.alg.pos + QPointF(ModelerGraphicItem.BOX_WIDTH, (i + 1.5) *
                                                                 ModelerGraphicItem.BOX_HEIGHT)
            self.alg.addAlgorithm(dlg.alg)
            self.repaintModel()
            self.hasChanged = True

    def getPositionForAlgorithmItem(self):
        MARGIN = 20
        BOX_WIDTH = 200
        BOX_HEIGHT = 80
        if self.alg.algs:
            maxX = max([alg.pos.x() for alg in list(self.alg.algs.values())])
            maxY = max([alg.pos.y() for alg in list(self.alg.algs.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 fillAlgorithmTree(self):
        self.fillAlgorithmTreeUsingProviders()
        self.algorithmTree.sortItems(0, Qt.AscendingOrder)

        text = str(self.searchBox.text())
        if text != '':
            self.algorithmTree.expandAll()

    def fillAlgorithmTreeUsingProviders(self):
        self.algorithmTree.clear()
        text = str(self.searchBox.text())
        search_strings = text.split(' ')
        for provider in QgsApplication.processingRegistry().providers():
            if not provider.isActive():
                continue
            groups = {}

            # Add algorithms
            for alg in provider.algorithms():
                if alg.flags() & QgsProcessingAlgorithm.FlagHideFromModeler:
                    continue
                if alg.id() == self.alg.id():
                    continue

                item_text = [alg.displayName().lower()]
                item_text.extend(alg.tags())

                show = not search_strings or all(
                    any(part in t for t in item_text)
                    for part in search_strings)

                if show:
                    if alg.group() in groups:
                        groupItem = groups[alg.group()]
                    else:
                        groupItem = QTreeWidgetItem()
                        name = alg.group()
                        groupItem.setText(0, name)
                        groupItem.setToolTip(0, name)
                        groups[alg.group()] = groupItem
                    algItem = TreeAlgorithmItem(alg)
                    groupItem.addChild(algItem)

            if len(groups) > 0:
                providerItem = QTreeWidgetItem()
                providerItem.setText(0, provider.name())
                providerItem.setToolTip(0, provider.name())
                providerItem.setIcon(0, provider.icon())
                for groupItem in list(groups.values()):
                    providerItem.addChild(groupItem)
                self.algorithmTree.addTopLevelItem(providerItem)
                providerItem.setExpanded(text != '')
                for groupItem in list(groups.values()):
                    if text != '':
                        groupItem.setExpanded(True)

        self.algorithmTree.sortItems(0, Qt.AscendingOrder)
Ejemplo n.º 49
0
    def __init__(self, alg=None):
        super(ModelerDialog, self).__init__(None)
        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.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)
        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():
                text = event.mimeData().text()
                if text in ModelerParameterDefinitionDialog.paramTypes:
                    self.addInputOfType(text, event.pos())
                else:
                    alg = QgsApplication.processingRegistry().algorithmById(text)
                    if alg is not None:
                        self._addAlgorithm(alg.getCopy(), 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)
            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)
            self.repaintModel()

        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].text(0)
            mimeData.setText(text)
            return mimeData

        self.inputsTree.mimeData = _mimeDataInput

        self.inputsTree.setDragDropMode(QTreeWidget.DragOnly)
        self.inputsTree.setDropIndicatorShown(True)

        def _mimeDataAlgorithm(items):
            item = items[0]
            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(self.tr('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.fillAlgorithmTree)
        self.algorithmTree.doubleClicked.connect(self.addAlgorithm)

        # Ctrl+= should also trigger a zoom in action
        ctrlEquals = QShortcut(QKeySequence("Ctrl+="), self)
        ctrlEquals.activated.connect(self.zoomIn)

        try:
            iconSize = int(settings.value("iconsize", 24))
        except:
            iconSize = 24
        self.mToolbar.setIconSize(QSize(iconSize, iconSize))
        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 alg is not None:
            self.alg = alg
            self.textGroup.setText(alg._group)
            self.textName.setText(alg.displayName())
            self.repaintModel()

        else:
            self.alg = ModelerAlgorithm()
            self.alg.modelerdialog = self

        self.fillInputsTree()
        self.fillAlgorithmTree()

        self.view.centerOn(0, 0)
        self.alg.setModelerView(self)
        self.help = None

        self.hasChanged = False
Ejemplo n.º 50
0
    def testModelerParametersDialogAvailableValuesOfType(self):
        # test getAvailableValuesOfType from ModelerParametersDialog

        m = ModelerAlgorithm()
        string_param_1 = ModelerParameter(
            ParameterString('string', 'string desc'))
        m.addParameter(string_param_1)
        string_param_2 = ModelerParameter(
            ParameterString('string2', 'string desc'))
        m.addParameter(string_param_2)
        num_param = ModelerParameter(ParameterNumber('number', 'number desc'))
        m.addParameter(num_param)
        table_field_param = ModelerParameter(
            ParameterTableField('field', 'field desc'))
        m.addParameter(table_field_param)
        file_param = ModelerParameter(ParameterFile('file', 'file desc'))
        m.addParameter(file_param)

        dlg = ModelerParametersDialog(m, m)
        # test single types
        self.assertEqual(
            set(p.name for p in dlg.getAvailableValuesOfType(ParameterNumber)),
            set(['number']))
        self.assertEqual(
            set(p.name
                for p in dlg.getAvailableValuesOfType(ParameterTableField)),
            set(['field']))
        self.assertEqual(
            set(p.name for p in dlg.getAvailableValuesOfType(ParameterFile)),
            set(['file']))

        # test multiple types
        self.assertEqual(
            set(p.name for p in dlg.getAvailableValuesOfType(
                [ParameterString, ParameterNumber, ParameterFile])),
            set(['string', 'string2', 'number', 'file']))
Ejemplo n.º 51
0
    def __init__(self, alg=None):
        super(ModelerDialog, self).__init__(None)
        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.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 = QSettings()
        self.restoreState(settings.value("/Processing/stateModeler", QByteArray()))
        self.restoreGeometry(settings.value("/Processing/geometryModeler", QByteArray()))

        self.scene = ModelerScene(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():
                text = event.mimeData().text()
                if text in ModelerParameterDefinitionDialog.paramTypes:
                    self.addInputOfType(text, event.pos())
                else:
                    alg = algList.getAlgorithm(text)
                    if alg is not None:
                        self._addAlgorithm(alg.getCopy(), 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 = QSettings()
            factor = settings.value('/qgis/zoom_favor', 2.0)
            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)
            self.repaintModel()

        def _enterEvent(e):
            QGraphicsView.enterEvent(self.view, e)
            self.view.viewport().setCursor(Qt.ArrowCursor)

        def _mousePressEvent(e):
            QGraphicsView.mousePressEvent(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.mousePressEvent = _mousePressEvent
        self.view.mouseMoveEvent = _mouseMoveEvent

        def _mimeDataInput(items):
            mimeData = QMimeData()
            text = items[0].text(0)
            mimeData.setText(text)
            return mimeData

        self.inputsTree.mimeData = _mimeDataInput

        self.inputsTree.setDragDropMode(QTreeWidget.DragOnly)
        self.inputsTree.setDropIndicatorShown(True)

        def _mimeDataAlgorithm(items):
            item = items[0]
            if isinstance(item, TreeAlgorithmItem):
                mimeData = QMimeData()
                mimeData.setText(item.alg.commandLineName())
            return mimeData

        self.algorithmTree.mimeData = _mimeDataAlgorithm

        self.algorithmTree.setDragDropMode(QTreeWidget.DragOnly)
        self.algorithmTree.setDropIndicatorShown(True)

        if hasattr(self.searchBox, 'setPlaceholderText'):
            self.searchBox.setPlaceholderText(self.tr('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.fillAlgorithmTree)
        self.algorithmTree.doubleClicked.connect(self.addAlgorithm)

        # Ctrl+= should also trigger a zoom in action
        ctrlEquals = QShortcut(QKeySequence("Ctrl+="), self)
        ctrlEquals.activated.connect(self.zoomIn)

        iconSize = settings.value("iconsize", 24)
        self.mToolbar.setIconSize(QSize(iconSize, iconSize))
        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 alg is not None:
            self.alg = alg
            self.textGroup.setText(alg.group)
            self.textName.setText(alg.name)
            self.repaintModel()

        else:
            self.alg = ModelerAlgorithm()
            self.alg.modelerdialog = self

        self.fillInputsTree()
        self.fillAlgorithmTree()

        self.view.centerOn(0, 0)
        self.alg.setModelerView(self)
        self.help = None

        self.hasChanged = False