Skip to content

Commit 9a2f14b

Browse files
committed
First steps to model/save restore in c++
Models now save to QVariantMap, using QgsXmlUtils to save to an xml based format (with extension .model3)
1 parent 179a377 commit 9a2f14b

File tree

9 files changed

+611
-48
lines changed

9 files changed

+611
-48
lines changed

python/core/processing/qgsprocessingmodelalgorithm.sip

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,20 @@ class QgsProcessingModelAlgorithm : QgsProcessingAlgorithm
139139
.. seealso:: setOutputChildId()
140140
%End
141141

142+
QVariant toVariant() const;
143+
%Docstring
144+
Saves this source to a QVariant.
145+
.. seealso:: loadVariant()
146+
:rtype: QVariant
147+
%End
148+
149+
bool loadVariant( const QVariantMap &map );
150+
%Docstring
151+
Loads this source from a QVariantMap.
152+
.. seealso:: toVariant()
153+
:rtype: bool
154+
%End
155+
142156
};
143157

144158
class Component
@@ -192,6 +206,18 @@ Copies are protected to avoid slicing
192206
%End
193207

194208

209+
void saveCommonProperties( QVariantMap &map ) const;
210+
%Docstring
211+
Saves the component properties to a QVariantMap.
212+
.. seealso:: restoreCommonProperties()
213+
%End
214+
215+
void restoreCommonProperties( const QVariantMap &map );
216+
%Docstring
217+
Restores the component properties from a QVariantMap.
218+
.. seealso:: saveCommonProperties()
219+
%End
220+
195221
};
196222

197223
class ModelParameter : QgsProcessingModelAlgorithm::Component
@@ -227,6 +253,20 @@ Copies are protected to avoid slicing
227253
.. seealso:: parameterName()
228254
%End
229255

256+
QVariant toVariant() const;
257+
%Docstring
258+
Saves this parameter to a QVariant.
259+
.. seealso:: loadVariant()
260+
:rtype: QVariant
261+
%End
262+
263+
bool loadVariant( const QVariantMap &map );
264+
%Docstring
265+
Loads this parameter from a QVariantMap.
266+
.. seealso:: toVariant()
267+
:rtype: bool
268+
%End
269+
230270
};
231271

232272

@@ -273,6 +313,20 @@ Copies are protected to avoid slicing
273313
.. seealso:: outputName()
274314
%End
275315

316+
QVariant toVariant() const;
317+
%Docstring
318+
Saves this output to a QVariant.
319+
.. seealso:: loadVariant()
320+
:rtype: QVariant
321+
%End
322+
323+
bool loadVariant( const QVariantMap &map );
324+
%Docstring
325+
Loads this output from a QVariantMap.
326+
.. seealso:: toVariant()
327+
:rtype: bool
328+
%End
329+
276330
};
277331

278332
class ChildAlgorithm : QgsProcessingModelAlgorithm::Component
@@ -461,6 +515,20 @@ Copies are protected to avoid slicing
461515
.. seealso:: modelOutputs()
462516
%End
463517

518+
QVariant toVariant() const;
519+
%Docstring
520+
Saves this child to a QVariant.
521+
.. seealso:: loadVariant()
522+
:rtype: QVariant
523+
%End
524+
525+
bool loadVariant( const QVariant &child );
526+
%Docstring
527+
Loads this child from a QVariant.
528+
.. seealso:: toVariant()
529+
:rtype: bool
530+
%End
531+
464532
};
465533

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

555+
void setName( const QString &name );
556+
%Docstring
557+
Sets the model ``name``.
558+
.. seealso:: name()
559+
%End
560+
561+
void setGroup( const QString &group );
562+
%Docstring
563+
Sets the model ``group``.
564+
.. seealso:: group()
565+
%End
566+
487567
QMap<QString, QgsProcessingModelAlgorithm::ChildAlgorithm> childAlgorithms() const;
488568
%Docstring
489569
Returns the map of child algorithms contained in the model. The keys
@@ -651,6 +731,20 @@ Copies are protected to avoid slicing
651731
:rtype: QgsProcessingModelAlgorithm.ModelParameter
652732
%End
653733

734+
bool toFile( const QString &path ) const;
735+
%Docstring
736+
Writes the model to a file, at the specified ``path``.
737+
.. seealso:: fromFile()
738+
:rtype: bool
739+
%End
740+
741+
bool fromFile( const QString &path );
742+
%Docstring
743+
Reads the model from a file, at the specified ``path``.
744+
.. seealso:: toFile()
745+
:rtype: bool
746+
%End
747+
654748
};
655749

656750

python/plugins/processing/modeler/AddModelFromFileAction.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,22 +56,16 @@ def execute(self):
5656
self.tr('Open model', 'AddModelFromFileAction'), lastDir,
5757
self.tr('Processing model files (*.model *.MODEL)', 'AddModelFromFileAction'))
5858
if filename:
59-
try:
60-
settings.setValue('Processing/lastModelsDir',
61-
QFileInfo(filename).absoluteDir().absolutePath())
59+
settings.setValue('Processing/lastModelsDir',
60+
QFileInfo(filename).absoluteDir().absolutePath())
6261

63-
ModelerAlgorithm.fromFile(filename)
64-
except WrongModelException:
62+
alg = ModelerAlgorithm()
63+
if not alg.fromFile(filename):
6564
QMessageBox.warning(
6665
self.toolbox,
6766
self.tr('Error reading model', 'AddModelFromFileAction'),
6867
self.tr('The selected file does not contain a valid model', 'AddModelFromFileAction'))
6968
return
70-
except:
71-
QMessageBox.warning(self.toolbox,
72-
self.tr('Error reading model', 'AddModelFromFileAction'),
73-
self.tr('Cannot read file', 'AddModelFromFileAction'))
74-
return
7569
destFilename = os.path.join(ModelerUtils.modelsFolders()[0], os.path.basename(filename))
7670
shutil.copyfile(filename, destFilename)
7771
QgsApplication.processingRegistry().providerById('model').refreshAlgorithms()

python/plugins/processing/modeler/ModelerAlgorithm.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -365,15 +365,6 @@ def _import(name):
365365
model._name = model.modeler_name
366366
return model
367367

368-
@staticmethod
369-
def fromFile(filename):
370-
with open(filename) as f:
371-
s = f.read()
372-
alg = ModelerAlgorithm.fromJson(s)
373-
if alg:
374-
alg.descriptionFile = filename
375-
return alg
376-
377368
def toPython(self):
378369
s = ['##%s=name' % self.name()]
379370
for param in list(self.parameterComponents().values()):

python/plugins/processing/modeler/ModelerAlgorithmProvider.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,13 @@
2727

2828
import os
2929

30+
from qgis.PyQt.QtXml import QDomDocument
31+
3032
from qgis.core import (QgsApplication,
3133
QgsProcessingProvider,
3234
QgsMessageLog,
33-
QgsProcessingUtils)
35+
QgsProcessingUtils,
36+
QgsXmlUtils)
3437

3538
from processing.core.ProcessingConfig import ProcessingConfig, Setting
3639
from processing.modeler.ModelerUtils import ModelerUtils
@@ -98,13 +101,15 @@ def loadFromFolder(self, folder):
98101
return
99102
for path, subdirs, files in os.walk(folder):
100103
for descriptionFile in files:
101-
if descriptionFile.endswith('model'):
104+
if descriptionFile.endswith('model3'):
102105
try:
103106
fullpath = os.path.join(path, descriptionFile)
104-
alg = ModelerAlgorithm.fromFile(fullpath)
105-
if alg.name():
106-
alg.descriptionFile = fullpath
107-
self.algs.append(alg)
107+
108+
alg = ModelerAlgorithm()
109+
if alg.fromFile(fullpath):
110+
if alg.name():
111+
alg.descriptionFile = fullpath
112+
self.algs.append(alg)
108113
else:
109114
QgsMessageLog.logMessage(self.tr('Could not load model {0}', 'ModelerAlgorithmProvider').format(descriptionFile),
110115
self.tr('Processing'), QgsMessageLog.CRITICAL)

python/plugins/processing/modeler/ModelerDialog.py

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@
4242
QgsSettings,
4343
QgsMessageLog,
4444
QgsProcessingUtils,
45-
QgsProcessingModelAlgorithm)
45+
QgsProcessingModelAlgorithm,
46+
QgsXmlUtils)
4647
from qgis.gui import QgsMessageBar
4748
from processing.gui.HelpEditionDialog import HelpEditionDialog
4849
from processing.gui.AlgorithmDialog import AlgorithmDialog
@@ -52,6 +53,7 @@
5253
from processing.modeler.ModelerUtils import ModelerUtils
5354
from processing.modeler.ModelerScene import ModelerScene
5455
from processing.modeler.WrongModelException import WrongModelException
56+
from qgis.PyQt.QtXml import QDomDocument
5557

5658
pluginPath = os.path.split(os.path.dirname(__file__))[0]
5759
WIDGET, BASE = uic.loadUiType(
@@ -435,25 +437,21 @@ def saveModel(self, saveAs):
435437
self, self.tr('Warning'), self.tr('Please enter group and model names before saving')
436438
)
437439
return
438-
self.model._name = str(self.textName.text())
439-
self.model._group = str(self.textGroup.text())
440+
self.model.setName(str(self.textName.text()))
441+
self.model.setGroup(str(self.textGroup.text()))
440442
if self.model.descriptionFile is not None and not saveAs:
441443
filename = self.model.descriptionFile
442444
else:
443445
filename, filter = QFileDialog.getSaveFileName(self,
444446
self.tr('Save Model'),
445447
ModelerUtils.modelsFolders()[0],
446-
self.tr('Processing models (*.model)'))
448+
self.tr('Processing models (*.model3)'))
447449
if filename:
448-
if not filename.endswith('.model'):
449-
filename += '.model'
450+
if not filename.endswith('.model3'):
451+
filename += '.model3'
450452
self.model.descriptionFile = filename
451453
if filename:
452-
text = self.model.toJson()
453-
try:
454-
with codecs.open(filename, 'w', encoding='utf-8') as fout:
455-
fout.write(text)
456-
except:
454+
if not self.model.toFile(filename):
457455
if saveAs:
458456
QMessageBox.warning(self, self.tr('I/O error'),
459457
self.tr('Unable to save edits. Reason:\n {0}').format(str(sys.exc_info()[1])))
@@ -475,28 +473,22 @@ def openModel(self):
475473
ModelerUtils.modelsFolders()[0],
476474
self.tr('Processing models (*.model *.MODEL)'))
477475
if filename:
478-
try:
479-
alg = ModelerAlgorithm.fromFile(filename)
476+
alg = ModelerAlgorithm()
477+
if alg.fromFile(filename):
480478
self.model = alg
481-
self.textGroup.setText(alg._group)
482-
self.textName.setText(alg._name)
479+
self.textGroup.setText(alg.group())
480+
self.textName.setText(alg.name())
483481
self.repaintModel()
484482

485483
self.view.centerOn(0, 0)
486484
self.hasChanged = False
487-
except WrongModelException as e:
488-
QgsMessageLog.logMessage(self.tr('Could not load model {0}\n{1}').format(filename, e.msg),
485+
else:
486+
QgsMessageLog.logMessage(self.tr('Could not load model {0}').format(filename),
489487
self.tr('Processing'),
490488
QgsMessageLog.CRITICAL)
491489
QMessageBox.critical(self, self.tr('Could not open model'),
492490
self.tr('The selected model could not be loaded.\n'
493491
'See the log for more information.'))
494-
except Exception as e:
495-
QgsMessageLog.logMessage(self.tr('Could not load model {0}\n{1}').format(filename, e.args[0]),
496-
self.tr('Processing'), QgsMessageLog.CRITICAL)
497-
QMessageBox.critical(self, self.tr('Could not open model'),
498-
self.tr('The selected model could not be loaded.\n'
499-
'See the log for more information.'))
500492

501493
def repaintModel(self, controls=True):
502494
self.scene = ModelerScene(self, dialog=self)

0 commit comments

Comments
 (0)