Skip to content

Commit

Permalink
Models can now be saved and restored
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Jun 20, 2017
1 parent f21f502 commit d3a2f7c
Show file tree
Hide file tree
Showing 10 changed files with 140 additions and 106 deletions.
5 changes: 1 addition & 4 deletions python/core/processing/qgsprocessingmodelalgorithm.sip
Original file line number Diff line number Diff line change
Expand Up @@ -675,15 +675,12 @@ Copies are protected to avoid slicing
.. seealso:: removeModelParameter()
%End

bool removeModelParameter( const QString &name );
void removeModelParameter( const QString &name );
%Docstring
Removes an existing model parameter by ``name``. The definition of the matching parameter
is deleted.
Returns false if the parameter could not be deleted (e.g. if a child algorithm
depends on the parameter).
.. seealso:: addModelParameter()
.. seealso:: updateModelParameter()
:rtype: bool
%End

bool childAlgorithmsDependOnParameter( const QString &name ) const;
Expand Down
8 changes: 8 additions & 0 deletions python/core/processing/qgsprocessingparameters.sip
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,14 @@ class QgsProcessingParameters
:rtype: list of str
%End

static QgsProcessingParameterDefinition *parameterFromVariantMap( const QVariantMap &map ) /Factory/;
%Docstring
Creates a new QgsProcessingParameterDefinition using the configuration from a
supplied variant ``map``.
The caller takes responsibility for deleting the returned object.
:rtype: QgsProcessingParameterDefinition
%End

};


Expand Down
64 changes: 0 additions & 64 deletions python/plugins/processing/modeler/ModelerAlgorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,70 +301,6 @@ def shortHelpString(self):
return str(self.helpContent['ALG_DESC'])
return None

def todict(self):
keys = ["inputs", "_group", "_name", "algs", "helpContent"]
return {k: v for k, v in list(self.__dict__.items()) if k in keys}

def toJson(self):
def todict(o):
if isinstance(o, QPointF):
return {"class": "point", "values": {"x": o.x(), "y": o.y()}}
try:
d = o.todict()
return {"class": o.__class__.__module__ + "." + o.__class__.__name__, "values": d}
except Exception:
pass
return json.dumps(self, default=todict, indent=4)

@staticmethod
def fromJson(s):
def fromdict(d):
try:
fullClassName = d["class"]
if isinstance(fullClassName, str):
tokens = fullClassName.split(".")
else:
tokens = fullClassName.__class__.__name__.split(".")
className = tokens[-1]
moduleName = ".".join(tokens[:-1])
values = d["values"]
if className == "point":
return QPointF(values["x"], values["y"])

def _import(name):
__import__(name)
return sys.modules[name]

if moduleName.startswith("processing.parameters"):
moduleName = "processing.core.parameters"
module = _import(moduleName)
clazz = getattr(module, className)
instance = clazz()
for k, v in list(values.items()):
# upgrade old model files
if k == 'group':
k = '_group'
elif k == 'name':
instance.__dict__['_name'] = v
k = 'modeler_name'
if not issubclass(clazz, GeoAlgorithm):
instance.__dict__['name'] = v
instance.__dict__[k] = v
return instance
except KeyError:
return d
except Exception as e:
raise e

try:
model = json.loads(s, object_hook=fromdict)
except Exception as e:
raise WrongModelException(e.args[0])

if hasattr(model, "modeler_name"):
model._name = model.modeler_name
return model

def toPython(self):
s = ['##%s=name' % self.name()]
for param in list(self.parameterComponents().values()):
Expand Down
8 changes: 4 additions & 4 deletions python/plugins/processing/modeler/ModelerGraphicItem.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,9 @@ def editElement(self):
param=self.model.parameterDefinition(self.element.parameterName()))
dlg.exec_()
if dlg.param is not None:
self.model.updateModelParameter(dlg.param)
self.model.removeModelParameter(self.element.parameterName())
self.element.setParameterName(dlg.param.name())
# also need to update the model's stored component
self.model.childAlgorithm(self.element.childId()).setParameterName(dlg.param.name())
self.model.addModelParameter(dlg.param, self.element)
self.text = dlg.param.description()
self.update()
elif isinstance(self.element, QgsProcessingModelAlgorithm.ChildAlgorithm):
Expand Down Expand Up @@ -228,11 +227,12 @@ def updateAlgorithm(self, alg):

def removeElement(self):
if isinstance(self.element, QgsProcessingModelAlgorithm.ModelParameter):
if not self.model.removeModelParameter(self.element.parameterName()):
if self.model.childAlgorithmsDependOnParameter(self.element.parameterName()):
QMessageBox.warning(None, 'Could not remove element',
'Other elements depend on the selected one.\n'
'Remove them before trying to remove it.')
else:
self.model.removeModelParameter(self.element.parameterName())
self.scene.dialog.haschanged = True
self.scene.dialog.repaintModel()
elif isinstance(self.element, QgsProcessingModelAlgorithm.ChildAlgorithm):
Expand Down
18 changes: 14 additions & 4 deletions python/plugins/processing/modeler/ModelerParametersDialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ def getAvailableDependencies(self): # spellok
return opts

def getDependenciesPanel(self):
return MultipleInputPanel([alg.description for alg in self.getAvailableDependencies()]) # spellok
return MultipleInputPanel([alg.description() for alg in self.getAvailableDependencies()]) # spellok

def showAdvancedParametersClicked(self):
self.showAdvanced = not self.showAdvanced
Expand Down Expand Up @@ -250,7 +250,7 @@ def getAvailableValuesOfType(self, paramType, outTypes=[], dataType=None):
dependent = []
else:
dependent = list(self.model.dependentChildAlgorithms(self._algName))
dependent.insert(self._algName)
dependent.append(self._algName)
for alg in list(self.model.childAlgorithms().values()):
if alg.childId() not in dependent:
for out in alg.algorithm().outputDefinitions():
Expand Down Expand Up @@ -291,6 +291,10 @@ def setPreviousValues(self):
value = alg.parameterSources()[param.name()]
else:
value = param.defaultValue()

if isinstance(value, QgsProcessingModelAlgorithm.ChildParameterSource) and value.source() == QgsProcessingModelAlgorithm.ChildParameterSource.StaticValue:
value = value.staticValue()

self.wrappers[param.name()].setValue(value)
for name, out in list(alg.modelOutputs().items()):
self.valueItems[name].setText(out.description())
Expand All @@ -316,11 +320,17 @@ def createAlgorithm(self):
val.staticValue())) \
or (not isinstance(val,
QgsProcessingModelAlgorithm.ChildParameterSource) and not param.checkValueIsAcceptable(
val)):
val))\
or (val is None and not param.flags() & QgsProcessingParameterDefinition.FlagOptional):
self.bar.pushMessage("Error", "Wrong or missing value for parameter '%s'" % param.description(),
level=QgsMessageBar.WARNING)
return None
alg.addParameterSource(param.name(), val)
if val is None:
continue
elif isinstance(val, QgsProcessingModelAlgorithm.ChildParameterSource):
alg.addParameterSource(param.name(), val)
else:
alg.addParameterSource(param.name(), QgsProcessingModelAlgorithm.ChildParameterSource.fromStaticValue(val))

# outputs = self._alg.outputDefinitions()
# for output in outputs:
Expand Down
17 changes: 5 additions & 12 deletions src/core/processing/qgsprocessingmodelalgorithm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -396,11 +396,11 @@ bool QgsProcessingModelAlgorithm::loadVariant( const QVariant &model )
QVariantMap::const_iterator paramDefIt = paramDefMap.constBegin();
for ( ; paramDefIt != paramDefMap.constEnd(); ++paramDefIt )
{
//QgsProcessingParameterDefinition *param;
//if ( !param.loadVariant( paramDefIt.value().toMap() ) )
// return false;
QgsProcessingParameterDefinition *param = QgsProcessingParameters::parameterFromVariantMap( paramDefIt.value().toMap() );
if ( !param )
return false;

//mParameterComponents.insert( param.parameterName(), param );
addParameter( param );
}

return true;
Expand Down Expand Up @@ -505,14 +505,10 @@ void QgsProcessingModelAlgorithm::updateModelParameter( QgsProcessingParameterDe
addParameter( definition );
}

bool QgsProcessingModelAlgorithm::removeModelParameter( const QString &name )
void QgsProcessingModelAlgorithm::removeModelParameter( const QString &name )
{
if ( childAlgorithmsDependOnParameter( name ) )
return false;

removeParameter( name );
mParameterComponents.remove( name );
return true;
}

bool QgsProcessingModelAlgorithm::childAlgorithmsDependOnParameter( const QString &name ) const
Expand Down Expand Up @@ -772,9 +768,6 @@ QVariant QgsProcessingModelAlgorithm::ModelParameter::toVariant() const
{
QVariantMap map;
map.insert( QStringLiteral( "name" ), mParameterName );

//TODO - parameter definition

saveCommonProperties( map );
return map;
}
Expand Down
4 changes: 1 addition & 3 deletions src/core/processing/qgsprocessingmodelalgorithm.h
Original file line number Diff line number Diff line change
Expand Up @@ -673,12 +673,10 @@ class CORE_EXPORT QgsProcessingModelAlgorithm : public QgsProcessingAlgorithm
/**
* Removes an existing model parameter by \a name. The definition of the matching parameter
* is deleted.
* Returns false if the parameter could not be deleted (e.g. if a child algorithm
* depends on the parameter).
* \see addModelParameter()
* \see updateModelParameter()
*/
bool removeModelParameter( const QString &name );
void removeModelParameter( const QString &name );

/**
* Returns true if any child algorithms depend on the model parameter
Expand Down
56 changes: 56 additions & 0 deletions src/core/processing/qgsprocessingparameters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,61 @@ QStringList QgsProcessingParameters::parameterAsFields( const QgsProcessingParam
return resultStringList;
}

QgsProcessingParameterDefinition *QgsProcessingParameters::parameterFromVariantMap( const QVariantMap &map )
{
QString type = map.value( QStringLiteral( "parameter_type" ) ).toString();
QString name = map.value( QStringLiteral( "name" ) ).toString();
std::unique_ptr< QgsProcessingParameterDefinition > def;
if ( type == QStringLiteral( "boolean" ) )
def.reset( new QgsProcessingParameterBoolean( name ) );
else if ( type == QStringLiteral( "crs" ) )
def.reset( new QgsProcessingParameterCrs( name ) );
else if ( type == QStringLiteral( "layer" ) )
def.reset( new QgsProcessingParameterMapLayer( name ) );
else if ( type == QStringLiteral( "extent" ) )
def.reset( new QgsProcessingParameterExtent( name ) );
else if ( type == QStringLiteral( "point" ) )
def.reset( new QgsProcessingParameterPoint( name ) );
else if ( type == QStringLiteral( "file" ) )
def.reset( new QgsProcessingParameterFile( name ) );
else if ( type == QStringLiteral( "matrix" ) )
def.reset( new QgsProcessingParameterMatrix( name ) );
else if ( type == QStringLiteral( "multilayer" ) )
def.reset( new QgsProcessingParameterMultipleLayers( name ) );
else if ( type == QStringLiteral( "number" ) )
def.reset( new QgsProcessingParameterNumber( name ) );
else if ( type == QStringLiteral( "range" ) )
def.reset( new QgsProcessingParameterRange( name ) );
else if ( type == QStringLiteral( "raster" ) )
def.reset( new QgsProcessingParameterRasterLayer( name ) );
else if ( type == QStringLiteral( "enum" ) )
def.reset( new QgsProcessingParameterEnum( name ) );
else if ( type == QStringLiteral( "string" ) )
def.reset( new QgsProcessingParameterString( name ) );
else if ( type == QStringLiteral( "expression" ) )
def.reset( new QgsProcessingParameterExpression( name ) );
else if ( type == QStringLiteral( "table" ) )
def.reset( new QgsProcessingParameterTable( name ) );
else if ( type == QStringLiteral( "field" ) )
def.reset( new QgsProcessingParameterTableField( name ) );
else if ( type == QStringLiteral( "source" ) )
def.reset( new QgsProcessingParameterFeatureSource( name ) );
else if ( type == QStringLiteral( "sink" ) )
def.reset( new QgsProcessingParameterFeatureSink( name ) );
else if ( type == QStringLiteral( "rasterOut" ) )
def.reset( new QgsProcessingParameterRasterOutput( name ) );
else if ( type == QStringLiteral( "fileOut" ) )
def.reset( new QgsProcessingParameterFileOutput( name ) );
else if ( type == QStringLiteral( "folderOut" ) )
def.reset( new QgsProcessingParameterFolderOutput( name ) );

if ( !def )
return nullptr;

def->fromVariantMap( map );
return def.release();
}

//
// QgsProcessingParameterDefinition
//
Expand Down Expand Up @@ -744,6 +799,7 @@ QString QgsProcessingParameterDefinition::valueAsPythonString( const QVariant &v
QVariantMap QgsProcessingParameterDefinition::toVariantMap() const
{
QVariantMap map;
map.insert( QStringLiteral( "parameter_type" ), type() );
map.insert( QStringLiteral( "name" ), mName );
map.insert( QStringLiteral( "description" ), mDescription );
map.insert( QStringLiteral( "default" ), mDefault );
Expand Down
7 changes: 7 additions & 0 deletions src/core/processing/qgsprocessingparameters.h
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,13 @@ class CORE_EXPORT QgsProcessingParameters
*/
static QStringList parameterAsFields( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context );

/**
* Creates a new QgsProcessingParameterDefinition using the configuration from a
* supplied variant \a map.
* The caller takes responsibility for deleting the returned object.
*/
static QgsProcessingParameterDefinition *parameterFromVariantMap( const QVariantMap &map ) SIP_FACTORY;

};


Expand Down
Loading

0 comments on commit d3a2f7c

Please sign in to comment.