Skip to content

Commit

Permalink
First steps to model/save restore in c++
Browse files Browse the repository at this point in the history
Models now save to QVariantMap, using QgsXmlUtils to save to
an xml based format (with extension .model3)
  • Loading branch information
nyalldawson committed Jun 20, 2017
1 parent 179a377 commit 9a2f14b
Show file tree
Hide file tree
Showing 9 changed files with 611 additions and 48 deletions.
94 changes: 94 additions & 0 deletions python/core/processing/qgsprocessingmodelalgorithm.sip
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,20 @@ class QgsProcessingModelAlgorithm : QgsProcessingAlgorithm
.. seealso:: setOutputChildId()
%End

QVariant toVariant() const;
%Docstring
Saves this source to a QVariant.
.. seealso:: loadVariant()
:rtype: QVariant
%End

bool loadVariant( const QVariantMap &map );
%Docstring
Loads this source from a QVariantMap.
.. seealso:: toVariant()
:rtype: bool
%End

};

class Component
Expand Down Expand Up @@ -192,6 +206,18 @@ Copies are protected to avoid slicing
%End


void saveCommonProperties( QVariantMap &map ) const;
%Docstring
Saves the component properties to a QVariantMap.
.. seealso:: restoreCommonProperties()
%End

void restoreCommonProperties( const QVariantMap &map );
%Docstring
Restores the component properties from a QVariantMap.
.. seealso:: saveCommonProperties()
%End

};

class ModelParameter : QgsProcessingModelAlgorithm::Component
Expand Down Expand Up @@ -227,6 +253,20 @@ Copies are protected to avoid slicing
.. seealso:: parameterName()
%End

QVariant toVariant() const;
%Docstring
Saves this parameter to a QVariant.
.. seealso:: loadVariant()
:rtype: QVariant
%End

bool loadVariant( const QVariantMap &map );
%Docstring
Loads this parameter from a QVariantMap.
.. seealso:: toVariant()
:rtype: bool
%End

};


Expand Down Expand Up @@ -273,6 +313,20 @@ Copies are protected to avoid slicing
.. seealso:: outputName()
%End

QVariant toVariant() const;
%Docstring
Saves this output to a QVariant.
.. seealso:: loadVariant()
:rtype: QVariant
%End

bool loadVariant( const QVariantMap &map );
%Docstring
Loads this output from a QVariantMap.
.. seealso:: toVariant()
:rtype: bool
%End

};

class ChildAlgorithm : QgsProcessingModelAlgorithm::Component
Expand Down Expand Up @@ -461,6 +515,20 @@ Copies are protected to avoid slicing
.. seealso:: modelOutputs()
%End

QVariant toVariant() const;
%Docstring
Saves this child to a QVariant.
.. seealso:: loadVariant()
:rtype: QVariant
%End

bool loadVariant( const QVariant &child );
%Docstring
Loads this child from a QVariant.
.. seealso:: toVariant()
:rtype: bool
%End

};

QgsProcessingModelAlgorithm( const QString &name = QString(), const QString &group = QString() );
Expand All @@ -484,6 +552,18 @@ Copies are protected to avoid slicing
virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) const;

void setName( const QString &name );
%Docstring
Sets the model ``name``.
.. seealso:: name()
%End

void setGroup( const QString &group );
%Docstring
Sets the model ``group``.
.. seealso:: group()
%End

QMap<QString, QgsProcessingModelAlgorithm::ChildAlgorithm> childAlgorithms() const;
%Docstring
Returns the map of child algorithms contained in the model. The keys
Expand Down Expand Up @@ -651,6 +731,20 @@ Copies are protected to avoid slicing
:rtype: QgsProcessingModelAlgorithm.ModelParameter
%End

bool toFile( const QString &path ) const;
%Docstring
Writes the model to a file, at the specified ``path``.
.. seealso:: fromFile()
:rtype: bool
%End

bool fromFile( const QString &path );
%Docstring
Reads the model from a file, at the specified ``path``.
.. seealso:: toFile()
:rtype: bool
%End

};


Expand Down
14 changes: 4 additions & 10 deletions python/plugins/processing/modeler/AddModelFromFileAction.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,22 +56,16 @@ def execute(self):
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())
settings.setValue('Processing/lastModelsDir',
QFileInfo(filename).absoluteDir().absolutePath())

ModelerAlgorithm.fromFile(filename)
except WrongModelException:
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
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)
QgsApplication.processingRegistry().providerById('model').refreshAlgorithms()
9 changes: 0 additions & 9 deletions python/plugins/processing/modeler/ModelerAlgorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,15 +365,6 @@ def _import(name):
model._name = model.modeler_name
return model

@staticmethod
def fromFile(filename):
with open(filename) as f:
s = f.read()
alg = ModelerAlgorithm.fromJson(s)
if alg:
alg.descriptionFile = filename
return alg

def toPython(self):
s = ['##%s=name' % self.name()]
for param in list(self.parameterComponents().values()):
Expand Down
17 changes: 11 additions & 6 deletions python/plugins/processing/modeler/ModelerAlgorithmProvider.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,13 @@

import os

from qgis.PyQt.QtXml import QDomDocument

from qgis.core import (QgsApplication,
QgsProcessingProvider,
QgsMessageLog,
QgsProcessingUtils)
QgsProcessingUtils,
QgsXmlUtils)

from processing.core.ProcessingConfig import ProcessingConfig, Setting
from processing.modeler.ModelerUtils import ModelerUtils
Expand Down Expand Up @@ -98,13 +101,15 @@ def loadFromFolder(self, folder):
return
for path, subdirs, files in os.walk(folder):
for descriptionFile in files:
if descriptionFile.endswith('model'):
if descriptionFile.endswith('model3'):
try:
fullpath = os.path.join(path, descriptionFile)
alg = ModelerAlgorithm.fromFile(fullpath)
if alg.name():
alg.descriptionFile = fullpath
self.algs.append(alg)

alg = ModelerAlgorithm()
if alg.fromFile(fullpath):
if alg.name():
alg.descriptionFile = fullpath
self.algs.append(alg)
else:
QgsMessageLog.logMessage(self.tr('Could not load model {0}', 'ModelerAlgorithmProvider').format(descriptionFile),
self.tr('Processing'), QgsMessageLog.CRITICAL)
Expand Down
38 changes: 15 additions & 23 deletions python/plugins/processing/modeler/ModelerDialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@
QgsSettings,
QgsMessageLog,
QgsProcessingUtils,
QgsProcessingModelAlgorithm)
QgsProcessingModelAlgorithm,
QgsXmlUtils)
from qgis.gui import QgsMessageBar
from processing.gui.HelpEditionDialog import HelpEditionDialog
from processing.gui.AlgorithmDialog import AlgorithmDialog
Expand All @@ -52,6 +53,7 @@
from processing.modeler.ModelerUtils import ModelerUtils
from processing.modeler.ModelerScene import ModelerScene
from processing.modeler.WrongModelException import WrongModelException
from qgis.PyQt.QtXml import QDomDocument

pluginPath = os.path.split(os.path.dirname(__file__))[0]
WIDGET, BASE = uic.loadUiType(
Expand Down Expand Up @@ -435,25 +437,21 @@ def saveModel(self, saveAs):
self, self.tr('Warning'), self.tr('Please enter group and model names before saving')
)
return
self.model._name = str(self.textName.text())
self.model._group = str(self.textGroup.text())
self.model.setName(str(self.textName.text()))
self.model.setGroup(str(self.textGroup.text()))
if self.model.descriptionFile is not None and not saveAs:
filename = self.model.descriptionFile
else:
filename, filter = QFileDialog.getSaveFileName(self,
self.tr('Save Model'),
ModelerUtils.modelsFolders()[0],
self.tr('Processing models (*.model)'))
self.tr('Processing models (*.model3)'))
if filename:
if not filename.endswith('.model'):
filename += '.model'
if not filename.endswith('.model3'):
filename += '.model3'
self.model.descriptionFile = filename
if filename:
text = self.model.toJson()
try:
with codecs.open(filename, 'w', encoding='utf-8') as fout:
fout.write(text)
except:
if not self.model.toFile(filename):
if saveAs:
QMessageBox.warning(self, self.tr('I/O error'),
self.tr('Unable to save edits. Reason:\n {0}').format(str(sys.exc_info()[1])))
Expand All @@ -475,28 +473,22 @@ def openModel(self):
ModelerUtils.modelsFolders()[0],
self.tr('Processing models (*.model *.MODEL)'))
if filename:
try:
alg = ModelerAlgorithm.fromFile(filename)
alg = ModelerAlgorithm()
if alg.fromFile(filename):
self.model = alg
self.textGroup.setText(alg._group)
self.textName.setText(alg._name)
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),
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.'))
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, dialog=self)
Expand Down
Loading

0 comments on commit 9a2f14b

Please sign in to comment.