[processing] Add default values in model for destination parameters

This commit is contained in:
arnaud.morvan@camptocamp.com 2018-02-24 13:48:41 +00:00 committed by Nyall Dawson
parent 8d5e5c944d
commit 4ccd4446fe
14 changed files with 224 additions and 4 deletions

View File

@ -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;

View File

@ -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``.
@ -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;

View File

@ -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;

View File

@ -111,6 +111,8 @@ class AlgorithmDialog(QgsProcessingAlgorithmDialogBase):
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:

View File

@ -85,6 +85,8 @@ class DestinationSelectionPanel(BASE, WIDGET):
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)
@ -285,8 +287,12 @@ signal """
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

View File

@ -92,7 +92,7 @@ class ModelerGraphicItem(QGraphicsItem):
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)
@ -224,6 +224,17 @@ class ModelerGraphicItem(QGraphicsItem):
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())
@ -234,6 +245,8 @@ class ModelerGraphicItem(QGraphicsItem):
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):
@ -258,6 +271,11 @@ class ModelerGraphicItem(QGraphicsItem):
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)

View File

@ -63,9 +63,15 @@ from qgis.core import (QgsApplication,
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
@ -293,6 +299,11 @@ class ModelerParameterDefinitionDialog(QDialog):
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'))
@ -425,6 +436,42 @@ class ModelerParameterDefinitionDialog(QDialog):
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

View File

@ -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() );
}
}

View File

@ -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;

View File

@ -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()

View File

@ -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 );
@ -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 );

View File

@ -21,6 +21,7 @@
#include "qgis_core.h"
#include "qgis.h"
#include "qgsprocessingmodelcomponent.h"
#include "qgsprocessingparameters.h"
///@cond NOT_STABLE
@ -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.
*/
@ -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()
@ -89,6 +109,7 @@ class CORE_EXPORT QgsProcessingModelOutput : public QgsProcessingModelComponent
private:
QString mName;
QVariant mDefaultValue;
QString mChildId;
QString mOutputName;
};

View File

@ -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 );

View File

@ -153,6 +153,21 @@ class CORE_EXPORT QgsProcessingOutputLayerDefinition
*/
QVariantMap createOptions;
/**
* Saves this output layer definition to a QVariantMap, wrapped in a QVariant.
* You can use QgsXmlUtils::writeVariant to save it to an XML document.
*
* \see loadVariant()
*/
QVariant toVariant() const;
/**
* Loads this output layer definition from a QVariantMap, wrapped in a QVariant.
* You can use QgsXmlUtils::readVariant to load it from an XML document.
*
* \see toVariant()
*/
bool loadVariant( const QVariantMap &map );
//! Allows direct construction of QVariants.
operator QVariant() const