Skip to content

Commit

Permalink
[processing] Add default values in model for destination parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
arnaud-morvan authored and nyalldawson committed May 14, 2018
1 parent 8d5e5c9 commit 4ccd444
Show file tree
Hide file tree
Showing 14 changed files with 225 additions and 5 deletions.
Expand Up @@ -251,6 +251,17 @@ If child model outputs are altered by this method, :py:func:`QgsProcessingModelA
must be called on the parent model.

.. seealso:: :py:func:`modelOutputs`
%End

bool removeModelOutput( const QString &name );
%Docstring
Removes an existing output from the final model outputs.

QgsProcessingModelAlgorithm.updateDestinationParameters() must be called on the parent model.

.. seealso:: :py:func:`modelOutputs`

.. versionadded:: 3.2
%End

QVariant toVariant() const;
Expand Down
19 changes: 19 additions & 0 deletions python/core/processing/models/qgsprocessingmodeloutput.sip.in
Expand Up @@ -23,6 +23,7 @@ Represents a final output created by the model.
%End
public:


QgsProcessingModelOutput( const QString &name = QString(), const QString &description = QString() );
%Docstring
Constructor for QgsProcessingModelOutput with the specified ``name`` and ``description``.
Expand All @@ -40,6 +41,24 @@ Returns the model output name.
Sets the model output ``name``.

.. seealso:: :py:func:`name`
%End

QVariant defaultValue() const;
%Docstring
Returns the default value for the model output parameter.

.. seealso:: :py:func:`setDefaultValue`

.. versionadded:: 3.2
%End

void setDefaultValue( const QVariant &value );
%Docstring
Sets the default value for the model output.

.. seealso:: :py:func:`defaultValue`

.. versionadded:: 3.2
%End

QString childId() const;
Expand Down
15 changes: 15 additions & 0 deletions python/core/processing/qgsprocessingparameters.sip.in
Expand Up @@ -85,6 +85,21 @@ to automatically load the resulting sink/layer after completing processing.

QVariantMap createOptions;

QVariant toVariant() const;
%Docstring
Saves this output layer definition to a QVariantMap, wrapped in a QVariant.
You can use QgsXmlUtils.writeVariant to save it to an XML document.

.. seealso:: :py:func:`loadVariant`
%End

bool loadVariant( const QVariantMap &map );
%Docstring
Loads this output layer definition from a QVariantMap, wrapped in a QVariant.
You can use QgsXmlUtils.readVariant to load it from an XML document.

.. seealso:: :py:func:`toVariant`
%End

operator QVariant() const;

Expand Down
2 changes: 2 additions & 0 deletions python/plugins/processing/gui/AlgorithmDialog.py
Expand Up @@ -111,6 +111,8 @@ def getParameterValues(self):
dest_project = QgsProject.instance()

value = self.mainWidget().outputWidgets[param.name()].getValue()
if value == '':
value = self.parameter.generateTemporaryDestination()
if value and isinstance(value, QgsProcessingOutputLayerDefinition):
value.destinationProject = dest_project
if value:
Expand Down
8 changes: 7 additions & 1 deletion python/plugins/processing/gui/DestinationSelectionPanel.py
Expand Up @@ -85,6 +85,8 @@ def __init__(self, parameter, alg):
elif not isinstance(self.parameter, QgsProcessingParameterFolderDestination):
self.leText.setPlaceholderText(self.SAVE_TO_TEMP_FILE)

self.setValue(self.parameter.defaultValue())

self.btnSelect.clicked.connect(self.selectOutput)
self.leText.textEdited.connect(self.textChanged)

Expand Down Expand Up @@ -285,8 +287,12 @@ def selectDirectory(self):
self.skipOutputChanged.emit(False)

def setValue(self, value):
if value == 'memory:':
if value == 'memory:' or not value:
self.saveToTemporary()
elif isinstance(value, QgsProcessingOutputLayerDefinition):
self.leText.setText(value.sink.staticValue())
self.encoding = value.createOptions['fileEncoding']
self.use_temporary = False
else:
self.leText.setText(value)
self.use_temporary = False
Expand Down
20 changes: 19 additions & 1 deletion python/plugins/processing/modeler/ModelerGraphicItem.py
Expand Up @@ -92,7 +92,7 @@ def __init__(self, element, model, controls, scene=None):
self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
self.setZValue(1000)

if not isinstance(element, QgsProcessingModelOutput) and controls:
if controls:
svg = QSvgRenderer(os.path.join(pluginPath, 'images', 'edit.svg'))
picture = QPicture()
painter = QPainter(picture)
Expand Down Expand Up @@ -224,6 +224,17 @@ def editElement(self):
self.updateAlgorithm(alg)
self.scene.dialog.repaintModel()

elif isinstance(self.element, QgsProcessingModelOutput):
child_alg = self.model.childAlgorithm(self.element.childId())
param_name = '{}:{}'.format(self.element.childId(), self.element.name())
dlg = ModelerParameterDefinitionDialog(self.model,
param=self.model.parameterDefinition(param_name))
if dlg.exec_() and dlg.param is not None:
model_output = child_alg.modelOutput(self.element.name())
model_output.setDescription(dlg.param.description())
model_output.setDefaultValue(dlg.param.defaultValue())
self.model.updateDestinationParameters()

def updateAlgorithm(self, alg):
existing_child = self.model.childAlgorithm(alg.childId())
alg.setPosition(existing_child.position())
Expand All @@ -234,6 +245,8 @@ def updateAlgorithm(self, alg):
alg.position() + QPointF(
ModelerGraphicItem.BOX_WIDTH,
(i + 1.5) * ModelerGraphicItem.BOX_HEIGHT))
#if existing_child.modelOutput(out):
# alg.modelOutput(out).setDefaultValue(existing_child.modelOutput(out).defaultValue())
self.model.setChildAlgorithm(alg)

def removeElement(self):
Expand All @@ -258,6 +271,11 @@ def removeElement(self):
else:
self.scene.dialog.haschanged = True
self.scene.dialog.repaintModel()
elif isinstance(self.element, QgsProcessingModelOutput):
self.model.childAlgorithm(self.element.childId()).removeModelOutput(self.element.name())
self.model.updateDestinationParameters()
self.scene.dialog.haschanged = True
self.scene.dialog.repaintModel()

def getAdjustedText(self, text):
font = QFont('Verdana', 8)
Expand Down
Expand Up @@ -63,9 +63,15 @@
QgsProcessingParameterVectorLayer,
QgsProcessingParameterField,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterBand
)

QgsProcessingParameterBand,
QgsProcessingDestinationParameter,
QgsProcessingParameterFeatureSink,
QgsProcessingParameterFileDestination,
QgsProcessingParameterFolderDestination,
QgsProcessingParameterRasterDestination,
QgsProcessingParameterVectorDestination)

from processing.gui.DestinationSelectionPanel import DestinationSelectionPanel
from processing.gui.enummodelerwidget import EnumModelerWidget
from processing.gui.matrixmodelerwidget import MatrixModelerWidget
from processing.core import parameters
Expand Down Expand Up @@ -293,6 +299,11 @@ def setupUi(self):
self.widget.setFixedRows(self.param.hasFixedNumberRows())
self.verticalLayout.addWidget(self.widget)

elif isinstance(self.param, QgsProcessingDestinationParameter):
self.verticalLayout.addWidget(QLabel(self.tr('Default value')))
self.defaultWidget = DestinationSelectionPanel(self.param, self.alg)
self.verticalLayout.addWidget(self.defaultWidget)

self.verticalLayout.addSpacing(20)
self.requiredCheck = QCheckBox()
self.requiredCheck.setText(self.tr('Mandatory'))
Expand Down Expand Up @@ -425,6 +436,42 @@ def accept(self):
elif (self.paramType == parameters.PARAMETER_MATRIX or
isinstance(self.param, QgsProcessingParameterMatrix)):
self.param = QgsProcessingParameterMatrix(name, description, hasFixedNumberRows=self.widget.fixedRows(), headers=self.widget.headers(), defaultValue=self.widget.value())

# Destination parameter
elif (isinstance(self.param, QgsProcessingParameterFeatureSink)):
self.param = QgsProcessingParameterFeatureSink(
name=name,
description=self.param.description(),
type=self.param.dataType(),
defaultValue=self.defaultWidget.getValue(),
optional=self.param.flags() & QgsProcessingParameterDefinition.FlagOptional)
elif (isinstance(self.param, QgsProcessingParameterFileDestination)):
self.param = QgsProcessingParameterFileDestination(
name=name,
description=self.param.description(),
fileFilter=self.param.fileFilter(),
defaultValue=str(self.defaultWidget.getValue()),
optional=self.param.flags() & QgsProcessingParameterDefinition.FlagOptional)
elif (isinstance(self.param, QgsProcessingParameterFolderDestination)):
self.param = QgsProcessingParameterFolderDestination(
name=name,
description=self.param.description(),
defaultValue=str(self.defaultWidget.getValue()),
optional=self.param.flags() & QgsProcessingParameterDefinition.FlagOptional)
elif (isinstance(self.param, QgsProcessingParameterRasterDestination)):
self.param = QgsProcessingParameterRasterDestination(
name=name,
description=self.param.description(),
defaultValue=str(self.defaultWidget.getValue()),
optional=self.param.flags() & QgsProcessingParameterDefinition.FlagOptional)
elif (isinstance(self.param, QgsProcessingParameterVectorDestination)):
self.param = QgsProcessingParameterVectorDestination(
name=name,
description=self.param.description(),
type=self.param.dataType(),
defaultValue=str(self.defaultWidget.getValue()),
optional=self.param.flags() & QgsProcessingParameterDefinition.FlagOptional)

else:
if self.paramType:
typeId = self.paramType
Expand Down
1 change: 1 addition & 0 deletions src/core/processing/models/qgsprocessingmodelalgorithm.cpp
Expand Up @@ -788,6 +788,7 @@ void QgsProcessingModelAlgorithm::updateDestinationParameters()
param->setFlags( param->flags() & ~QgsProcessingParameterDefinition::FlagHidden );
param->setName( outputIt->childId() + ':' + outputIt->name() );
param->setDescription( outputIt->description() );
param->setDefaultValue( outputIt->defaultValue() );
addParameter( param.release() );
}
}
Expand Down
Expand Up @@ -74,6 +74,12 @@ void QgsProcessingModelChildAlgorithm::setModelOutputs( const QMap<QString, QgsP
}
}

bool QgsProcessingModelChildAlgorithm::removeModelOutput( const QString &name )
{
mModelOutputs.remove( name );
return true;
}

QVariant QgsProcessingModelChildAlgorithm::toVariant() const
{
QVariantMap map;
Expand Down
10 changes: 10 additions & 0 deletions src/core/processing/models/qgsprocessingmodelchildalgorithm.h
Expand Up @@ -237,6 +237,16 @@ class CORE_EXPORT QgsProcessingModelChildAlgorithm : public QgsProcessingModelCo
*/
void setModelOutputs( const QMap<QString, QgsProcessingModelOutput> &outputs );

/**
* Removes an existing output from the final model outputs.
*
* QgsProcessingModelAlgorithm::updateDestinationParameters() must be called on the parent model.
*
* \see modelOutputs()
* \since QGIS 3.2
*/
bool removeModelOutput( const QString &name );

/**
* Saves this child to a QVariant.
* \see loadVariant()
Expand Down
33 changes: 33 additions & 0 deletions src/core/processing/models/qgsprocessingmodeloutput.cpp
Expand Up @@ -28,6 +28,18 @@ QVariant QgsProcessingModelOutput::toVariant() const
{
QVariantMap map;
map.insert( QStringLiteral( "name" ), mName );

if ( mDefaultValue.canConvert<QgsProcessingOutputLayerDefinition>() )
{
QVariantMap defaultMap = mDefaultValue.value<QgsProcessingOutputLayerDefinition>().toVariant().toMap();
defaultMap.insert( QStringLiteral( "class" ), QStringLiteral( "QgsProcessingOutputLayerDefinition" ) );
map.insert( QStringLiteral( "default_value" ), defaultMap );
}
else
{
map.insert( QStringLiteral( "default_value" ), mDefaultValue );
}

map.insert( QStringLiteral( "child_id" ), mChildId );
map.insert( QStringLiteral( "output_name" ), mOutputName );
saveCommonProperties( map );
Expand All @@ -37,6 +49,27 @@ QVariant QgsProcessingModelOutput::toVariant() const
bool QgsProcessingModelOutput::loadVariant( const QVariantMap &map )
{
mName = map.value( QStringLiteral( "name" ) ).toString();

QVariant defaultValue = map.value( QStringLiteral( "default_value" ) );
if ( defaultValue.type() == QVariant::Map )
{
QVariantMap defaultMap = defaultValue.toMap();
if ( defaultMap["class"] == "QgsProcessingOutputLayerDefinition" )
{
QgsProcessingOutputLayerDefinition value( "" );
value.loadVariant( defaultMap );
mDefaultValue = QVariant( value );
}
else
{
mDefaultValue = QVariant();
}
}
else
{
mDefaultValue = map.value( QStringLiteral( "default_value" ) );
}

mChildId = map.value( QStringLiteral( "child_id" ) ).toString();
mOutputName = map.value( QStringLiteral( "output_name" ) ).toString();
restoreCommonProperties( map );
Expand Down
21 changes: 21 additions & 0 deletions src/core/processing/models/qgsprocessingmodeloutput.h
Expand Up @@ -21,6 +21,7 @@
#include "qgis_core.h"
#include "qgis.h"
#include "qgsprocessingmodelcomponent.h"
#include "qgsprocessingparameters.h"

///@cond NOT_STABLE

Expand All @@ -33,6 +34,11 @@ class CORE_EXPORT QgsProcessingModelOutput : public QgsProcessingModelComponent
{
public:

/*
//! Output flags
Q_DECLARE_FLAGS( Flags, QgsProcessingParameterDefinition::Flag )
*/

/**
* Constructor for QgsProcessingModelOutput with the specified \a name and \a description.
*/
Expand All @@ -50,6 +56,20 @@ class CORE_EXPORT QgsProcessingModelOutput : public QgsProcessingModelComponent
*/
void setName( const QString &name ) { mName = name; }

/**
* Returns the default value for the model output parameter.
* \see setDefaultValue()
* \since QGIS 3.2
*/
QVariant defaultValue() const { return mDefaultValue; }

/**
* Sets the default value for the model output.
* \see defaultValue()
* \since QGIS 3.2
*/
void setDefaultValue( const QVariant &value ) { mDefaultValue = value; }

/**
* Returns the child algorithm ID from which this output is generated.
* \see setChildId()
Expand Down Expand Up @@ -89,6 +109,7 @@ class CORE_EXPORT QgsProcessingModelOutput : public QgsProcessingModelComponent
private:

QString mName;
QVariant mDefaultValue;
QString mChildId;
QString mOutputName;
};
Expand Down
16 changes: 16 additions & 0 deletions src/core/processing/qgsprocessingparameters.cpp
Expand Up @@ -29,6 +29,22 @@
#include "qgsprocessingparametertype.h"
#include <functional>


QVariant QgsProcessingOutputLayerDefinition::toVariant() const
{
QVariantMap map;
map.insert( QStringLiteral( "sink" ), sink.toVariant() );
map.insert( QStringLiteral( "create_options" ), createOptions );
return map;
}

bool QgsProcessingOutputLayerDefinition::loadVariant( const QVariantMap &map )
{
sink.loadVariant( map.value( QStringLiteral( "sink" ) ) );
createOptions = map.value( QStringLiteral( "create_options" ) ).toMap();
return true;
}

bool QgsProcessingParameters::isDynamic( const QVariantMap &parameters, const QString &name )
{
QVariant val = parameters.value( name );
Expand Down

0 comments on commit 4ccd444

Please sign in to comment.