Skip to content
Permalink
Browse files

[processing] Finish default values in model for destination parameters

  • Loading branch information
arnaud-morvan authored and nyalldawson committed May 11, 2018
1 parent c5f478c commit 81dabd185c45516d2742d63613adf3369ee8321f
@@ -23,7 +23,6 @@ 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``.
@@ -91,6 +91,8 @@ 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`

.. versionadded:: 3.2
%End

bool loadVariant( const QVariantMap &map );
@@ -99,6 +101,8 @@ 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`

.. versionadded:: 3.2
%End

operator QVariant() const;
@@ -106,13 +106,13 @@ def getParameterValues(self):
else:
dest_project = None
if not param.flags() & QgsProcessingParameterDefinition.FlagHidden and \
isinstance(param, (QgsProcessingParameterRasterDestination, QgsProcessingParameterFeatureSink, QgsProcessingParameterVectorDestination)):
isinstance(param, (QgsProcessingParameterRasterDestination,
QgsProcessingParameterFeatureSink,
QgsProcessingParameterVectorDestination)):
if self.mainWidget().checkBoxes[param.name()].isChecked():
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:
@@ -64,27 +64,17 @@ class DestinationSelectionPanel(BASE, WIDGET):

skipOutputChanged = pyqtSignal(bool)

def __init__(self, parameter, alg):
def __init__(self, parameter, alg, default_selection=False):
super(DestinationSelectionPanel, self).__init__(None)
self.setupUi(self)

self.parameter = parameter
self.alg = alg
self.default_selection = default_selection
settings = QgsSettings()
self.encoding = settings.value('/Processing/encoding', 'System')
self.use_temporary = True

if hasattr(self.leText, 'setPlaceholderText'):
if parameter.flags() & QgsProcessingParameterDefinition.FlagOptional and not parameter.createByDefault():
self.leText.setPlaceholderText(self.SKIP_OUTPUT)
self.use_temporary = False
elif isinstance(self.parameter, QgsProcessingParameterFeatureSink) \
and self.parameter.supportsNonFileBasedOutput():
# use memory layers for temporary files if supported
self.leText.setPlaceholderText(self.SAVE_TO_TEMP_LAYER)
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)
@@ -111,22 +101,23 @@ def selectOutput(self):
else:
popupMenu = QMenu()

if self.parameter.flags() & QgsProcessingParameterDefinition.FlagOptional:
actionSkipOutput = QAction(
self.tr('Skip Output'), self.btnSelect)
actionSkipOutput.triggered.connect(self.skipOutput)
popupMenu.addAction(actionSkipOutput)

if isinstance(self.parameter, QgsProcessingParameterFeatureSink) \
and self.parameter.supportsNonFileBasedOutput():
# use memory layers for temporary layers if supported
actionSaveToTemp = QAction(
self.tr('Create Temporary Layer'), self.btnSelect)
else:
actionSaveToTemp = QAction(
self.tr('Save to a Temporary File'), self.btnSelect)
actionSaveToTemp.triggered.connect(self.saveToTemporary)
popupMenu.addAction(actionSaveToTemp)
if not self.default_selection:
if self.parameter.flags() & QgsProcessingParameterDefinition.FlagOptional:
actionSkipOutput = QAction(
self.tr('Skip Output'), self.btnSelect)
actionSkipOutput.triggered.connect(self.skipOutput)
popupMenu.addAction(actionSkipOutput)

if isinstance(self.parameter, QgsProcessingParameterFeatureSink) \
and self.parameter.supportsNonFileBasedOutput():
# use memory layers for temporary layers if supported
actionSaveToTemp = QAction(
self.tr('Create Temporary Layer'), self.btnSelect)
else:
actionSaveToTemp = QAction(
self.tr('Save to a Temporary File'), self.btnSelect)
actionSaveToTemp.triggered.connect(self.saveToTemporary)
popupMenu.addAction(actionSaveToTemp)

actionSaveToFile = QAction(
QCoreApplication.translate('DestinationSelectionPanel', 'Save to File…'), self.btnSelect)
@@ -287,25 +278,33 @@ def selectDirectory(self):
self.skipOutputChanged.emit(False)

def setValue(self, value):
if value == 'memory:' or not value:
self.saveToTemporary()
elif isinstance(value, QgsProcessingOutputLayerDefinition):
if value.sink.staticValue() == 'memory:':
if not value:
if self.parameter.flags() & QgsProcessingParameterDefinition.FlagOptional and \
not self.parameter.createByDefault():
self.skipOutput()
else:
self.saveToTemporary()
else:
if value == 'memory:':
self.saveToTemporary()
elif isinstance(value, QgsProcessingOutputLayerDefinition):
if value.sink.staticValue() in ('memory:', ''):
self.saveToTemporary()
else:
self.leText.setText(value.sink.staticValue())
self.use_temporary = False
self.skipOutputChanged.emit(False)
self.encoding = value.createOptions['fileEncoding']
else:
self.leText.setText(value.sink.staticValue())
self.leText.setText(value)
self.use_temporary = False
self.encoding = value.createOptions['fileEncoding']
else:
self.leText.setText(value)
self.use_temporary = False
self.skipOutputChanged.emit(False)
self.skipOutputChanged.emit(False)

def getValue(self):
key = None
if self.use_temporary and isinstance(self.parameter, QgsProcessingParameterFeatureSink):
key = 'memory:'
elif self.use_temporary:
elif self.use_temporary and not self.default_selection:
key = self.parameter.generateTemporaryDestination()
else:
key = self.leText.text()
@@ -246,8 +246,6 @@ 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):
@@ -301,7 +301,7 @@ def setupUi(self):

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

self.verticalLayout.addSpacing(20)
@@ -312,6 +312,16 @@ def setupUi(self):
self.requiredCheck.setChecked(not self.param.flags() & QgsProcessingParameterDefinition.FlagOptional)
self.verticalLayout.addWidget(self.requiredCheck)

# If child algorithm output is mandatory, disable checkbox
if isinstance(self.param, QgsProcessingDestinationParameter):
provider_name, child_name, output_name = self.param.name().split(':')
child = self.alg.childAlgorithms()['{}:{}'.format(provider_name, child_name)]
model_output = child.modelOutput(output_name)
param_def = child.algorithm().parameterDefinition(model_output.childOutputName())
if not (param_def.flags() & QgsProcessingParameterDefinition.FlagOptional):
self.requiredCheck.setEnabled(False)
self.requiredCheck.setChecked(True)

self.buttonBox = QDialogButtonBox(self)
self.buttonBox.setOrientation(Qt.Horizontal)
self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel |
@@ -449,23 +459,23 @@ def accept(self):
name=name,
description=self.param.description(),
fileFilter=self.param.fileFilter(),
defaultValue=str(self.defaultWidget.getValue()))
defaultValue=self.defaultWidget.getValue())
elif (isinstance(self.param, QgsProcessingParameterFolderDestination)):
self.param = QgsProcessingParameterFolderDestination(
name=name,
description=self.param.description(),
defaultValue=str(self.defaultWidget.getValue()))
defaultValue=self.defaultWidget.getValue())
elif (isinstance(self.param, QgsProcessingParameterRasterDestination)):
self.param = QgsProcessingParameterRasterDestination(
name=name,
description=self.param.description(),
defaultValue=str(self.defaultWidget.getValue()))
defaultValue=self.defaultWidget.getValue())
elif (isinstance(self.param, QgsProcessingParameterVectorDestination)):
self.param = QgsProcessingParameterVectorDestination(
name=name,
description=self.param.description(),
type=self.param.dataType(),
defaultValue=str(self.defaultWidget.getValue()))
defaultValue=self.defaultWidget.getValue())

else:
if self.paramType:
@@ -55,9 +55,9 @@ bool QgsProcessingModelOutput::loadVariant( const QVariantMap &map )
if ( defaultValue.type() == QVariant::Map )
{
QVariantMap defaultMap = defaultValue.toMap();
if ( defaultMap["class"] == "QgsProcessingOutputLayerDefinition" )
if ( defaultMap["class"] == QStringLiteral( "QgsProcessingOutputLayerDefinition" ) )
{
QgsProcessingOutputLayerDefinition value( "" );
QgsProcessingOutputLayerDefinition value;
value.loadVariant( defaultMap );
mDefaultValue = QVariant( value );
}
@@ -34,11 +34,6 @@ 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.
*/
@@ -156,16 +156,16 @@ class CORE_EXPORT QgsProcessingOutputLayerDefinition
/**
* 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()
* \since QGIS 3.2
*/
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()
* \since QGIS 3.2
*/
bool loadVariant( const QVariantMap &map );

@@ -5257,6 +5257,24 @@ void TestQgsProcessing::modelerAlgorithm()
QCOMPARE( testModelOut.childId(), QStringLiteral( "my_id" ) );
testModelOut.setChildOutputName( QStringLiteral( "my_output" ) );
QCOMPARE( testModelOut.childOutputName(), QStringLiteral( "my_output" ) );
testModelOut.setDefaultValue( QStringLiteral( "my_value" ) );
QCOMPARE( testModelOut.defaultValue().toString(), QStringLiteral( "my_value" ) );
testModelOut.setMandatory( true );
QVERIFY( testModelOut.isMandatory() );

QgsProcessingOutputLayerDefinition layerDef( QStringLiteral( "my_path" ) );
layerDef.createOptions["fileEncoding"] = QStringLiteral( "my_encoding" );
testModelOut.setDefaultValue( layerDef );
QCOMPARE( testModelOut.defaultValue().value<QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QStringLiteral( "my_path" ) );
QVariantMap map = testModelOut.toVariant().toMap();
QCOMPARE( map["default_value"].toMap()["sink"].toMap()["val"].toString(), QStringLiteral( "my_path" ) );
QCOMPARE( map["default_value"].toMap()["create_options"].toMap()["fileEncoding"].toString(), QStringLiteral( "my_encoding" ) );
QgsProcessingModelOutput out;
out.loadVariant( map );
QVERIFY( out.defaultValue().canConvert<QgsProcessingOutputLayerDefinition>() );
layerDef = out.defaultValue().value<QgsProcessingOutputLayerDefinition>();
QCOMPARE( layerDef.sink.staticValue().toString(), QStringLiteral( "my_path" ) );
QCOMPARE( layerDef.createOptions["fileEncoding"].toString(), QStringLiteral( "my_encoding" ) );

QMap<QString, QgsProcessingModelOutput> outputs;
QgsProcessingModelOutput out1;
@@ -5272,7 +5290,8 @@ void TestQgsProcessing::modelerAlgorithm()
child.modelOutput( "b" ).setDescription( QStringLiteral( "my output 3" ) );
QCOMPARE( child.modelOutput( "b" ).description(), QStringLiteral( "my output 3" ) );
QCOMPARE( child.modelOutputs().count(), 2 );

child.removeModelOutput( QStringLiteral( "a" ) );
QCOMPARE( child.modelOutputs().count(), 1 );


// model algorithm tests
@@ -5322,6 +5341,7 @@ void TestQgsProcessing::modelerAlgorithm()
alg.setChildAlgorithm( a4a );
QCOMPARE( alg.childAlgorithm( "d" ).description(), QStringLiteral( "new" ) );


// generating child ids
QgsProcessingModelChildAlgorithm c1;
c1.setAlgorithmId( QStringLiteral( "buffer" ) );
@@ -5686,15 +5706,21 @@ void TestQgsProcessing::modelerAlgorithm()
alg7c2out1.setChildId( "cx2" );
alg7c2out1.setChildOutputName( "OUTPUT" );
alg7c2out1.setDescription( QStringLiteral( "my output2" ) );
alg7c2out1.setDefaultValue( QStringLiteral( "my value" ) );
alg7c2out1.setMandatory( true );
alg7c2outputs.insert( QStringLiteral( "my_output2" ), alg7c2out1 );
alg7c2.setModelOutputs( alg7c2outputs );
alg7.addChildAlgorithm( alg7c2 );

QCOMPARE( alg7.destinationParameterDefinitions().count(), 2 );
QCOMPARE( alg7.destinationParameterDefinitions().at( 0 )->name(), QStringLiteral( "cx1:my_output" ) );
QCOMPARE( alg7.destinationParameterDefinitions().at( 0 )->description(), QStringLiteral( "my output" ) );
QVERIFY( alg7.destinationParameterDefinitions().at( 0 )->defaultValue().isNull() );
QVERIFY( !( alg7.destinationParameterDefinitions().at( 0 )->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
QCOMPARE( alg7.destinationParameterDefinitions().at( 1 )->name(), QStringLiteral( "cx2:my_output2" ) );
QCOMPARE( alg7.destinationParameterDefinitions().at( 1 )->description(), QStringLiteral( "my output2" ) );
QCOMPARE( alg7.destinationParameterDefinitions().at( 1 )->defaultValue().toString(), QStringLiteral( "my value" ) );
QVERIFY( !( alg7.destinationParameterDefinitions().at( 1 )->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
QCOMPARE( alg7.outputDefinitions().count(), 2 );
QCOMPARE( alg7.outputDefinitions().at( 0 )->name(), QStringLiteral( "cx1:my_output" ) );
QCOMPARE( alg7.outputDefinitions().at( 0 )->type(), QStringLiteral( "outputVector" ) );
@@ -5711,6 +5737,23 @@ void TestQgsProcessing::modelerAlgorithm()
QCOMPARE( alg7.outputDefinitions().at( 0 )->name(), QStringLiteral( "cx2:my_output2" ) );
QCOMPARE( alg7.outputDefinitions().at( 0 )->type(), QStringLiteral( "outputVector" ) );
QCOMPARE( alg7.outputDefinitions().at( 0 )->description(), QStringLiteral( "my output2" ) );

// mandatory model output with optional child algorithm parameter
QgsProcessingModelChildAlgorithm alg7c3;
alg7c3.setChildId( "cx3" );
alg7c3.setAlgorithmId( "native:extractbyexpression" );
QMap<QString, QgsProcessingModelOutput> alg7c3outputs;
QgsProcessingModelOutput alg7c3out1;
alg7c3out1.setChildId( "cx3" );
alg7c3out1.setChildOutputName( "FAIL_OUTPUT" );
alg7c3out1.setDescription( QStringLiteral( "my_output3" ) );
alg7c3outputs.insert( QStringLiteral( "my_output3" ), alg7c3out1 );
alg7c3.setModelOutputs( alg7c3outputs );
alg7.addChildAlgorithm( alg7c3 );
QVERIFY( alg7.destinationParameterDefinitions().at( 1 )->flags() & QgsProcessingParameterDefinition::FlagOptional );
alg7.childAlgorithm( alg7c3.childId() ).modelOutput( QStringLiteral( "my_output3" ) ).setMandatory( true );
alg7.updateDestinationParameters();
QVERIFY( !( alg7.destinationParameterDefinitions().at( 1 )->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
}

void TestQgsProcessing::modelExecution()

0 comments on commit 81dabd1

Please sign in to comment.
You can’t perform that action at this time.