1 /***************************************************************************
2 testprocesinggui.cpp
3 ---------------------------
4 begin : April 2018
5 copyright : (C) 2018 by Matthias Kuhn
6 email : matthias@opengis.ch
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18 #include <QObject>
19 #include <QLabel>
20 #include <QCheckBox>
21 #include <QComboBox>
22 #include <QStackedWidget>
23 #include <QToolButton>
24 #include <QLineEdit>
25 #include <QPushButton>
26 #include <QPlainTextEdit>
27 #include <QStandardItemModel>
28 #include <QSignalSpy>
29
30 #include "qgstest.h"
31 #include "qgsconfig.h"
32 #include "qgsgui.h"
33 #include "qgsprocessingguiregistry.h"
34 #include "qgsprocessingregistry.h"
35 #include "qgsprocessingalgorithm.h"
36 #include "qgsprocessingalgorithmconfigurationwidget.h"
37 #include "qgsprocessingwidgetwrapper.h"
38 #include "qgsprocessingwidgetwrapperimpl.h"
39 #include "qgsprocessingmodelerparameterwidget.h"
40 #include "qgsprocessingparameters.h"
41 #include "qgsmodelundocommand.h"
42 #include "qgsprocessingmaplayercombobox.h"
43 #include "qgsnativealgorithms.h"
44 #include "processing/models/qgsprocessingmodelalgorithm.h"
45 #include "processing/models/qgsprocessingmodelgroupbox.h"
46 #include "qgsxmlutils.h"
47 #include "qgspropertyoverridebutton.h"
48 #include "qgsprojectionselectionwidget.h"
49 #include "qgsdoublespinbox.h"
50 #include "qgsspinbox.h"
51 #include "qgsmapcanvas.h"
52 #include "qgsauthconfigselect.h"
53 #include "qgsauthmanager.h"
54 #include "qgsprocessingmatrixparameterdialog.h"
55 #include "models/qgsprocessingmodelalgorithm.h"
56 #include "qgsfilewidget.h"
57 #include "qgsexpressionlineedit.h"
58 #include "qgsfieldexpressionwidget.h"
59 #include "qgsprocessingmultipleselectiondialog.h"
60 #include "qgsprintlayout.h"
61 #include "qgslayoutmanager.h"
62 #include "qgslayoutcombobox.h"
63 #include "qgslayoutitemcombobox.h"
64 #include "qgslayoutitemlabel.h"
65 #include "qgsscalewidget.h"
66 #include "mesh/qgsmeshlayer.h"
67 #include "mesh/qgsmeshdataprovider.h"
68 #include "qgscolorbutton.h"
69 #include "qgsprocessingparameterdefinitionwidget.h"
70 #include "qgscoordinateoperationwidget.h"
71 #include "qgsmessagebar.h"
72 #include "qgsfieldcombobox.h"
73 #include "qgsmapthemecollection.h"
74 #include "qgsdatetimeedit.h"
75 #include "qgsproviderregistry.h"
76 #include "qgsprovidermetadata.h"
77 #include "qgsproviderconnectioncombobox.h"
78 #include "qgsdatabaseschemacombobox.h"
79 #include "qgsdatabasetablecombobox.h"
80 #include "qgsprocessingoutputdestinationwidget.h"
81 #include "qgssettings.h"
82 #include "qgsprocessingfeaturesourceoptionswidget.h"
83 #include "qgsextentwidget.h"
84 #include "qgsrasterbandcombobox.h"
85 #include "qgsmeshlayertemporalproperties.h"
86 #include "qgsmodelgraphicsscene.h"
87 #include "qgsmodelgraphicsview.h"
88 #include "qgsmodelcomponentgraphicitem.h"
89 #include "qgsprocessingfieldmapwidgetwrapper.h"
90 #include "qgsprocessingparameterfieldmap.h"
91 #include "qgsprocessingaggregatewidgetwrapper.h"
92 #include "qgsprocessingparameteraggregate.h"
93 #include "qgsprocessingparametertininputlayers.h"
94 #include "qgsprocessingtininputlayerswidget.h"
95 #include "qgsprocessingparameterdxflayers.h"
96 #include "qgsprocessingdxflayerswidgetwrapper.h"
97 #include "qgsprocessingmeshdatasetwidget.h"
98 #include "qgsabstractdatabaseproviderconnection.h"
99 #include "qgspluginlayer.h"
100 #include "qgspointcloudlayer.h"
101 #include "qgsannotationlayer.h"
102
103
104 class TestParamType : public QgsProcessingParameterDefinition
105 {
106 public:
107
TestParamType(const QString & type,const QString & name,const QVariant & defaultValue=QVariant ())108 TestParamType( const QString &type, const QString &name, const QVariant &defaultValue = QVariant() )
109 : QgsProcessingParameterDefinition( name, name, defaultValue )
110 , mType( type )
111 {}
112
113 QString mType;
114
clone() const115 QgsProcessingParameterDefinition *clone() const override
116 {
117 return new TestParamType( mType, name() );
118 }
119
type() const120 QString type() const override { return mType; }
valueAsPythonString(const QVariant &,QgsProcessingContext &) const121 QString valueAsPythonString( const QVariant &, QgsProcessingContext & ) const override { return QString(); }
asScriptCode() const122 QString asScriptCode() const override { return QString(); }
123
124 };
125
126 class TestWidgetWrapper : public QgsAbstractProcessingParameterWidgetWrapper // clazy:exclude=missing-qobject-macro
127 {
128 public:
129
TestWidgetWrapper(const QgsProcessingParameterDefinition * parameter=nullptr,QgsProcessingGui::WidgetType type=QgsProcessingGui::Standard)130 TestWidgetWrapper( const QgsProcessingParameterDefinition *parameter = nullptr,
131 QgsProcessingGui::WidgetType type = QgsProcessingGui::Standard )
132 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type )
133 {}
134
createWidget()135 QWidget *createWidget() override
136 {
137 return nullptr;
138 }
139
createLabel()140 QLabel *createLabel() override
141 {
142 return nullptr;
143 }
144
setWidgetValue(const QVariant &,QgsProcessingContext &)145 void setWidgetValue( const QVariant &, QgsProcessingContext & ) override
146 {
147 }
148
widgetValue() const149 QVariant widgetValue() const override
150 {
151 return QVariant();
152 }
153
154 };
155
156 class TestWidgetFactory : public QgsProcessingParameterWidgetFactoryInterface
157 {
158
159 public:
160
TestWidgetFactory(const QString & type)161 TestWidgetFactory( const QString &type )
162 : type( type )
163 {}
164
165 QString type;
166
parameterType() const167 QString parameterType() const override
168 {
169 return type;
170 }
171
createWidgetWrapper(const QgsProcessingParameterDefinition * parameter,QgsProcessingGui::WidgetType type)172 QgsAbstractProcessingParameterWidgetWrapper *createWidgetWrapper( const QgsProcessingParameterDefinition *parameter,
173 QgsProcessingGui::WidgetType type ) override
174 {
175 return new TestWidgetWrapper( parameter, type );
176 }
177
178
compatibleParameterTypes() const179 QStringList compatibleParameterTypes() const override { return QStringList(); }
180
compatibleOutputTypes() const181 QStringList compatibleOutputTypes() const override { return QStringList(); }
182
183 };
184
185 class DummyPluginLayer: public QgsPluginLayer
186 {
187 public:
188
DummyPluginLayer(const QString & layerType,const QString & layerName)189 DummyPluginLayer( const QString &layerType, const QString &layerName ): QgsPluginLayer( layerType, layerName )
190 {
191 mValid = true;
192 };
193
clone() const194 DummyPluginLayer *clone() const override { return new DummyPluginLayer( "dummylayer", "test" ); };
195
createMapRenderer(QgsRenderContext & rendererContext)196 QgsMapLayerRenderer *createMapRenderer( QgsRenderContext &rendererContext ) override
197 {
198 Q_UNUSED( rendererContext );
199 return nullptr;
200 };
201
writeXml(QDomNode & layerNode,QDomDocument & doc,const QgsReadWriteContext & context) const202 bool writeXml( QDomNode &layerNode, QDomDocument &doc, const QgsReadWriteContext &context ) const override
203 {
204 Q_UNUSED( layerNode );
205 Q_UNUSED( doc );
206 Q_UNUSED( context );
207 return true;
208 };
readSymbology(const QDomNode & node,QString & errorMessage,QgsReadWriteContext & context,StyleCategories categories=AllStyleCategories)209 bool readSymbology( const QDomNode &node, QString &errorMessage,
210 QgsReadWriteContext &context, StyleCategories categories = AllStyleCategories ) override
211 {
212 Q_UNUSED( node );
213 Q_UNUSED( errorMessage );
214 Q_UNUSED( context );
215 Q_UNUSED( categories );
216 return true;
217 };
writeSymbology(QDomNode & node,QDomDocument & doc,QString & errorMessage,const QgsReadWriteContext & context,StyleCategories categories=AllStyleCategories) const218 bool writeSymbology( QDomNode &node, QDomDocument &doc, QString &errorMessage, const QgsReadWriteContext &context,
219 StyleCategories categories = AllStyleCategories ) const override
220 {
221 Q_UNUSED( node );
222 Q_UNUSED( doc );
223 Q_UNUSED( errorMessage );
224 Q_UNUSED( context );
225 Q_UNUSED( categories );
226 return true;
227 };
228
setTransformContext(const QgsCoordinateTransformContext & transformContext)229 void setTransformContext( const QgsCoordinateTransformContext &transformContext ) override { Q_UNUSED( transformContext ); };
230 };
231
232 class TestProcessingGui : public QObject
233 {
234 Q_OBJECT
235 public:
236 TestProcessingGui() = default;
237
238 private slots:
239 void initTestCase();// will be called before the first testfunction is executed.
240 void cleanupTestCase();// will be called after the last testfunction was executed.
241 void init();// will be called before each testfunction is executed.
242 void cleanup();// will be called after every testfunction.
243 void testModelUndo();
244 void testSetGetConfig();
245 void testFilterAlgorithmConfig();
246 void testWrapperFactoryRegistry();
247 void testWrapperGeneral();
248 void testWrapperDynamic();
249 void testModelerWrapper();
250 void testHiddenWrapper();
251 void testBooleanWrapper();
252 void testStringWrapper();
253 void testFileWrapper();
254 void testAuthCfgWrapper();
255 void testCrsWrapper();
256 void testNumericWrapperDouble();
257 void testNumericWrapperInt();
258 void testDistanceWrapper();
259 void testDurationWrapper();
260 void testScaleWrapper();
261 void testRangeWrapper();
262 void testMatrixDialog();
263 void testMatrixWrapper();
264 void testExpressionWrapper();
265 void testFieldSelectionPanel();
266 void testFieldWrapper();
267 void testMultipleSelectionDialog();
268 void testMultipleFileSelectionDialog();
269 void testRasterBandSelectionPanel();
270 void testBandWrapper();
271 void testMultipleInputWrapper();
272 void testEnumSelectionPanel();
273 void testEnumCheckboxPanel();
274 void testEnumWrapper();
275 void testLayoutWrapper();
276 void testLayoutItemWrapper();
277 void testPointPanel();
278 void testPointWrapper();
279 void testGeometryWrapper();
280 void testExtentWrapper();
281 void testColorWrapper();
282 void testCoordinateOperationWrapper();
283 void mapLayerComboBox();
284 void testMapLayerWrapper();
285 void testRasterLayerWrapper();
286 void testVectorLayerWrapper();
287 void testFeatureSourceWrapper();
288 void testMeshLayerWrapper();
289 void paramConfigWidget();
290 void testMapThemeWrapper();
291 void testDateTimeWrapper();
292 void testProviderConnectionWrapper();
293 void testDatabaseSchemaWrapper();
294 void testDatabaseTableWrapper();
295 void testPointCloudLayerWrapper();
296 void testAnnotationLayerWrapper();
297 void testFieldMapWidget();
298 void testFieldMapWrapper();
299 void testAggregateWidget();
300 void testAggregateWrapper();
301 void testOutputDefinitionWidget();
302 void testOutputDefinitionWidgetVectorOut();
303 void testOutputDefinitionWidgetRasterOut();
304 void testOutputDefinitionWidgetFolder();
305 void testOutputDefinitionWidgetFileOut();
306 void testFeatureSourceOptionsWidget();
307 void testVectorOutWrapper();
308 void testSinkWrapper();
309 void testRasterOutWrapper();
310 void testFileOutWrapper();
311 void testFolderOutWrapper();
312 void testTinInputLayerWrapper();
313 void testDxfLayersWrapper();
314 void testMeshDatasetWrapperLayerInProject();
315 void testMeshDatasetWrapperLayerOutsideProject();
316 void testModelGraphicsView();
317
318 private:
319
320 QString mTempDir;
321 const char *mPass = "pass";
322
323 void cleanupTempDir();
324 };
325
326
initTestCase()327 void TestProcessingGui::initTestCase()
328 {
329 mTempDir = QDir::tempPath() + "/auth_proc";
330 // setup a temporary auth db:
331 cleanupTempDir();
332
333 // make QGIS_AUTH_DB_DIR_PATH temp dir for qgis - auth.db and master password file
334 QDir tmpDir = QDir::temp();
335 QVERIFY2( tmpDir.mkpath( mTempDir ), "Couldn't make temp directory" );
336 qputenv( "QGIS_AUTH_DB_DIR_PATH", mTempDir.toLatin1() );
337
338 // init app and auth manager
339 QgsApplication::init();
340 QgsApplication::initQgis();
341 QVERIFY2( !QgsApplication::authManager()->isDisabled(),
342 "Authentication system is DISABLED" );
343
344 // verify QGIS_AUTH_DB_DIR_PATH (temp auth db path) worked
345 QString db1( QFileInfo( QgsApplication::authManager()->authenticationDatabasePath() ).canonicalFilePath() );
346 QString db2( QFileInfo( mTempDir + "/qgis-auth.db" ).canonicalFilePath() );
347 QVERIFY2( db1 == db2, "Auth db temp path does not match db path of manager" );
348
349 // verify master pass can be set manually
350 // (this also creates a fresh password hash in the new temp database)
351 QVERIFY2( QgsApplication::authManager()->setMasterPassword( mPass, true ),
352 "Master password could not be set" );
353 QVERIFY2( QgsApplication::authManager()->masterPasswordIsSet(),
354 "Auth master password not set from passed string" );
355
356 // create QGIS_AUTH_PASSWORD_FILE file
357 QString passfilepath = mTempDir + "/passfile";
358 QFile passfile( passfilepath );
359 if ( passfile.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
360 {
361 QTextStream fout( &passfile );
362 fout << QString( mPass ) << "\r\n";
363 passfile.close();
364 qputenv( "QGIS_AUTH_PASSWORD_FILE", passfilepath.toLatin1() );
365 }
366
367 // re-init app and auth manager
368 QgsApplication::quit();
369 QgsApplication::init();
370 QgsApplication::initQgis();
371 QVERIFY2( !QgsApplication::authManager()->isDisabled(),
372 "Authentication system is DISABLED" );
373
374 // verify QGIS_AUTH_PASSWORD_FILE worked, when compared against hash in db
375 QVERIFY2( QgsApplication::authManager()->masterPasswordIsSet(),
376 "Auth master password not set from QGIS_AUTH_PASSWORD_FILE" );
377
378 QgsApplication::processingRegistry()->addProvider( new QgsNativeAlgorithms( QgsApplication::processingRegistry() ) );
379 }
380
cleanupTestCase()381 void TestProcessingGui::cleanupTestCase()
382 {
383 QgsApplication::exitQgis();
384 }
init()385 void TestProcessingGui::init()
386 {
387
388 }
389
cleanup()390 void TestProcessingGui::cleanup()
391 {
392
393 }
394
testModelUndo()395 void TestProcessingGui::testModelUndo()
396 {
397 // make a little model
398 QgsProcessingModelAlgorithm model( QStringLiteral( "test" ), QStringLiteral( "testGroup" ) );
399 QMap<QString, QgsProcessingModelChildAlgorithm> algs;
400 QgsProcessingModelChildAlgorithm a1( "native:buffer" );
401 a1.setDescription( QStringLiteral( "alg1" ) );
402 a1.setChildId( QStringLiteral( "alg1" ) );
403 QgsProcessingModelChildAlgorithm a2;
404 a2.setDescription( QStringLiteral( "alg2" ) );
405 a2.setChildId( QStringLiteral( "alg2" ) );
406 QgsProcessingModelChildAlgorithm a3( QStringLiteral( "native:buffer" ) );
407 a3.setDescription( QStringLiteral( "alg3" ) );
408 a3.setChildId( QStringLiteral( "alg3" ) );
409 algs.insert( QStringLiteral( "alg1" ), a1 );
410 algs.insert( QStringLiteral( "alg2" ), a2 );
411 algs.insert( QStringLiteral( "alg3" ), a3 );
412 model.setChildAlgorithms( algs );
413
414 QgsModelUndoCommand command( &model, QStringLiteral( "undo" ) );
415 model.childAlgorithm( QStringLiteral( "alg1" ) ).setDescription( QStringLiteral( "new desc" ) );
416 command.saveAfterState();
417
418 QCOMPARE( model.childAlgorithm( QStringLiteral( "alg1" ) ).description(), QStringLiteral( "new desc" ) );
419 command.undo();
420 QCOMPARE( model.childAlgorithm( QStringLiteral( "alg1" ) ).description(), QStringLiteral( "alg1" ) );
421
422 // first redo should have no effect -- we ignore it, since it's automatically triggered when the
423 // command is added to the stack (yet we apply the initial change to the models outside of the undo stack)
424 command.redo();
425 QCOMPARE( model.childAlgorithm( QStringLiteral( "alg1" ) ).description(), QStringLiteral( "alg1" ) );
426 command.redo();
427 QCOMPARE( model.childAlgorithm( QStringLiteral( "alg1" ) ).description(), QStringLiteral( "new desc" ) );
428
429 // the last used parameter values setting should not be affected by undo stack changes
430 QVariantMap params;
431 params.insert( QStringLiteral( "a" ), 1 );
432 model.setDesignerParameterValues( params );
433 command.undo();
434 QCOMPARE( model.designerParameterValues(), params );
435 command.redo();
436 QCOMPARE( model.designerParameterValues(), params );
437 }
438
testSetGetConfig()439 void TestProcessingGui::testSetGetConfig()
440 {
441 const QList< const QgsProcessingAlgorithm * > algorithms = QgsApplication::instance()->processingRegistry()->algorithms();
442
443 // Find all defined widgets for native algorithms
444 // and get the default configuration (that is, we create a widget
445 // and get the configuration it returns without being modified in any way)
446 // We then set and get this configuration and validate that it matches the original one.
447 for ( const QgsProcessingAlgorithm *algorithm : algorithms )
448 {
449 std::unique_ptr<QgsProcessingAlgorithmConfigurationWidget> configWidget( QgsGui::instance()->processingGuiRegistry()->algorithmConfigurationWidget( algorithm ) );
450 if ( configWidget )
451 {
452 QCOMPARE( configWidget->algorithm(), algorithm );
453 const QVariantMap defaultConfig = configWidget->configuration();
454 configWidget->setConfiguration( defaultConfig );
455 const QVariantMap defaultControlConfig = configWidget->configuration();
456 QDomDocument defaultConfigDoc;
457 QDomDocument defaultConfigControlDoc;
458 QgsXmlUtils::writeVariant( defaultConfig, defaultConfigDoc );
459 QgsXmlUtils::writeVariant( defaultControlConfig, defaultConfigControlDoc );
460 QCOMPARE( defaultConfigDoc.toString(), defaultConfigControlDoc.toString() );
461 }
462 }
463 }
464
testFilterAlgorithmConfig()465 void TestProcessingGui::testFilterAlgorithmConfig()
466 {
467 const QgsProcessingAlgorithm *algorithm = QgsApplication::instance()->processingRegistry()->algorithmById( QStringLiteral( "native:filter" ) );
468 std::unique_ptr<QgsProcessingAlgorithmConfigurationWidget> configWidget( QgsGui::instance()->processingGuiRegistry()->algorithmConfigurationWidget( algorithm ) );
469
470 QVariantMap config;
471 QVariantList outputs;
472 QVariantMap output;
473 output.insert( QStringLiteral( "name" ), QStringLiteral( "test" ) );
474 output.insert( QStringLiteral( "expression" ), QStringLiteral( "I am an expression" ) );
475 output.insert( QStringLiteral( "isModelOutput" ), true );
476 outputs.append( output );
477 config.insert( QStringLiteral( "outputs" ), outputs );
478 configWidget->setConfiguration( config );
479
480 QVariantMap configControl = configWidget->configuration();
481
482 QDomDocument configDoc;
483 QDomDocument configControlDoc;
484 QgsXmlUtils::writeVariant( config, configDoc );
485 QgsXmlUtils::writeVariant( configControl, configControlDoc );
486 QCOMPARE( configDoc.toString(), configControlDoc.toString() );
487 }
488
testWrapperFactoryRegistry()489 void TestProcessingGui::testWrapperFactoryRegistry()
490 {
491 QgsProcessingGuiRegistry registry;
492
493 TestParamType numParam( QStringLiteral( "num" ), QStringLiteral( "num" ) );
494 TestParamType stringParam( QStringLiteral( "str" ), QStringLiteral( "str" ) );
495
496 QVERIFY( !registry.createParameterWidgetWrapper( &numParam, QgsProcessingGui::Standard ) );
497
498 TestWidgetFactory *factory = new TestWidgetFactory( QStringLiteral( "str" ) );
499 QVERIFY( registry.addParameterWidgetFactory( factory ) );
500
501 // duplicate type not allowed
502 TestWidgetFactory *factory2 = new TestWidgetFactory( QStringLiteral( "str" ) );
503 QVERIFY( !registry.addParameterWidgetFactory( factory2 ) );
504 delete factory2;
505
506 QgsAbstractProcessingParameterWidgetWrapper *wrapper = registry.createParameterWidgetWrapper( &numParam, QgsProcessingGui::Standard );
507 QVERIFY( !wrapper );
508 wrapper = registry.createParameterWidgetWrapper( &stringParam, QgsProcessingGui::Standard );
509 QVERIFY( wrapper );
510 QCOMPARE( wrapper->parameterDefinition()->type(), QStringLiteral( "str" ) );
511 delete wrapper;
512
513 TestWidgetFactory *factory3 = new TestWidgetFactory( QStringLiteral( "num" ) );
514 QVERIFY( registry.addParameterWidgetFactory( factory3 ) );
515
516 wrapper = registry.createParameterWidgetWrapper( &numParam, QgsProcessingGui::Standard );
517 QVERIFY( wrapper );
518 QCOMPARE( wrapper->parameterDefinition()->type(), QStringLiteral( "num" ) );
519 delete wrapper;
520
521 // removing
522 registry.removeParameterWidgetFactory( nullptr );
523 TestWidgetFactory *factory4 = new TestWidgetFactory( QStringLiteral( "xxxx" ) );
524 registry.removeParameterWidgetFactory( factory4 );
525 registry.removeParameterWidgetFactory( factory );
526 wrapper = registry.createParameterWidgetWrapper( &stringParam, QgsProcessingGui::Standard );
527 QVERIFY( !wrapper );
528
529 wrapper = registry.createParameterWidgetWrapper( &numParam, QgsProcessingGui::Standard );
530 QVERIFY( wrapper );
531 QCOMPARE( wrapper->parameterDefinition()->type(), QStringLiteral( "num" ) );
532 delete wrapper;
533 }
534
testWrapperGeneral()535 void TestProcessingGui::testWrapperGeneral()
536 {
537 TestParamType param( QStringLiteral( "boolean" ), QStringLiteral( "bool" ) );
538 param.setAdditionalExpressionContextVariables( QStringList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) );
539 QgsProcessingBooleanWidgetWrapper wrapper( ¶m );
540 QCOMPARE( wrapper.type(), QgsProcessingGui::Standard );
541
542 QgsExpressionContext expContext = wrapper.createExpressionContext();
543 QVERIFY( expContext.hasVariable( QStringLiteral( "a" ) ) );
544 QVERIFY( expContext.hasVariable( QStringLiteral( "b" ) ) );
545 QCOMPARE( expContext.highlightedVariables(), QStringList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) );
546
547 QgsProcessingBooleanWidgetWrapper wrapper2( ¶m, QgsProcessingGui::Batch );
548 QCOMPARE( wrapper2.type(), QgsProcessingGui::Batch );
549 QCOMPARE( wrapper2.parameterDefinition()->name(), QStringLiteral( "bool" ) );
550
551 QgsProcessingBooleanWidgetWrapper wrapperModeler( ¶m, QgsProcessingGui::Modeler );
552 QCOMPARE( wrapperModeler.type(), QgsProcessingGui::Modeler );
553
554 QgsProcessingContext context;
555 QVERIFY( !wrapper2.wrappedWidget() );
556 QWidget *w = wrapper2.createWrappedWidget( context );
557 QVERIFY( w );
558 QCOMPARE( wrapper2.wrappedWidget(), w );
559 delete w;
560 QVERIFY( !wrapper2.wrappedLabel() );
561 QLabel *l = wrapper2.createWrappedLabel();
562 QCOMPARE( wrapper2.wrappedLabel(), l );
563 delete l;
564 l = wrapperModeler.createWrappedLabel();
565 QVERIFY( l );
566 QCOMPARE( wrapperModeler.wrappedLabel(), l );
567 delete l;
568
569 // check that created widget starts with default value
570 param = TestParamType( QStringLiteral( "boolean" ), QStringLiteral( "bool" ), true );
571 QgsProcessingBooleanWidgetWrapper trueDefault( ¶m );
572 w = trueDefault.createWrappedWidget( context );
573 QVERIFY( trueDefault.widgetValue().toBool() );
574 delete w;
575 param = TestParamType( QStringLiteral( "boolean" ), QStringLiteral( "bool" ), false );
576 QgsProcessingBooleanWidgetWrapper falseDefault( ¶m );
577 w = falseDefault.createWrappedWidget( context );
578 QVERIFY( !falseDefault.widgetValue().toBool() );
579 delete w;
580
581 std::unique_ptr< QgsMapCanvas > mc = std::make_unique< QgsMapCanvas >();
582 QgsProcessingParameterWidgetContext widgetContext;
583 widgetContext.setMapCanvas( mc.get() );
584 QCOMPARE( widgetContext.mapCanvas(), mc.get() );
585
586 std::unique_ptr< QgsMessageBar > mb = std::make_unique< QgsMessageBar >();
587 widgetContext.setMessageBar( mb.get() );
588 QCOMPARE( widgetContext.messageBar(), mb.get() );
589
590 QgsProject p;
591 widgetContext.setProject( &p );
592 QCOMPARE( widgetContext.project(), &p );
593 std::unique_ptr< QgsProcessingModelAlgorithm > model = std::make_unique< QgsProcessingModelAlgorithm >();
594 widgetContext.setModel( model.get() );
595 QCOMPARE( widgetContext.model(), model.get() );
596 widgetContext.setModelChildAlgorithmId( QStringLiteral( "xx" ) );
597 QCOMPARE( widgetContext.modelChildAlgorithmId(), QStringLiteral( "xx" ) );
598
599 wrapper.setWidgetContext( widgetContext );
600 QCOMPARE( wrapper.widgetContext().mapCanvas(), mc.get() );
601 QCOMPARE( wrapper.widgetContext().messageBar(), mb.get() );
602 QCOMPARE( wrapper.widgetContext().model(), model.get() );
603 QCOMPARE( wrapper.widgetContext().modelChildAlgorithmId(), QStringLiteral( "xx" ) );
604 }
605
606 class TestProcessingContextGenerator : public QgsProcessingContextGenerator
607 {
608 public:
609
TestProcessingContextGenerator(QgsProcessingContext & context)610 TestProcessingContextGenerator( QgsProcessingContext &context )
611 : mContext( context )
612 {}
613
processingContext()614 QgsProcessingContext *processingContext() override
615 {
616 return &mContext;
617 }
618
619 QgsProcessingContext &mContext;
620 };
621
622
623 class TestLayerWrapper : public QgsAbstractProcessingParameterWidgetWrapper // clazy:exclude=missing-qobject-macro
624 {
625 public:
TestLayerWrapper(const QgsProcessingParameterDefinition * parameter=nullptr)626 TestLayerWrapper( const QgsProcessingParameterDefinition *parameter = nullptr )
627 : QgsAbstractProcessingParameterWidgetWrapper( parameter )
628 {}
createWidget()629 QWidget *createWidget() override { return nullptr; }
setWidgetValue(const QVariant & val,QgsProcessingContext &)630 void setWidgetValue( const QVariant &val, QgsProcessingContext & ) override { v = val;}
widgetValue() const631 QVariant widgetValue() const override { return v; }
632
633 QVariant v;
634 };
635
testWrapperDynamic()636 void TestProcessingGui::testWrapperDynamic()
637 {
638 const QgsProcessingAlgorithm *centroidAlg = QgsApplication::processingRegistry()->algorithmById( QStringLiteral( "native:centroids" ) );
639 const QgsProcessingParameterDefinition *layerDef = centroidAlg->parameterDefinition( QStringLiteral( "INPUT" ) );
640 const QgsProcessingParameterDefinition *allPartsDef = centroidAlg->parameterDefinition( QStringLiteral( "ALL_PARTS" ) );
641
642 QgsProcessingBooleanWidgetWrapper inputWrapper( layerDef, QgsProcessingGui::Standard );
643 QgsProcessingBooleanWidgetWrapper allPartsWrapper( allPartsDef, QgsProcessingGui::Standard );
644
645 QgsProcessingContext context;
646
647 std::unique_ptr< QWidget > allPartsWidget( allPartsWrapper.createWrappedWidget( context ) );
648 // dynamic parameter, so property button should be created
649 QVERIFY( allPartsWrapper.mPropertyButton.data() != nullptr );
650
651 std::unique_ptr< QWidget > inputWidget( inputWrapper.createWrappedWidget( context ) );
652 // not dynamic parameter, so property button should be NOT created
653 QVERIFY( inputWrapper.mPropertyButton.data() == nullptr );
654
655 // set dynamic parameter to dynamic value
656 allPartsWrapper.setParameterValue( QgsProperty::fromExpression( QStringLiteral( "1+2" ) ), context );
657 QCOMPARE( allPartsWrapper.parameterValue().value< QgsProperty >().expressionString(), QStringLiteral( "1+2" ) );
658 // not dynamic value
659 allPartsWrapper.setParameterValue( true, context );
660 QCOMPARE( allPartsWrapper.parameterValue().toBool(), true );
661 allPartsWrapper.setParameterValue( false, context );
662 QCOMPARE( allPartsWrapper.parameterValue().toBool(), false );
663
664 // project layer
665 QgsProject p;
666 QgsVectorLayer *vl = new QgsVectorLayer( QStringLiteral( "LineString" ), QStringLiteral( "x" ), QStringLiteral( "memory" ) );
667 p.addMapLayer( vl );
668
669 TestLayerWrapper layerWrapper( layerDef );
670
671 QVERIFY( !allPartsWrapper.mPropertyButton->vectorLayer() );
672 layerWrapper.setWidgetValue( QVariant::fromValue( vl ), context );
673 allPartsWrapper.setDynamicParentLayerParameter( &layerWrapper );
674 QCOMPARE( allPartsWrapper.mPropertyButton->vectorLayer(), vl );
675 // should not be owned by wrapper
676 QVERIFY( !allPartsWrapper.mDynamicLayer.get() );
677 layerWrapper.setWidgetValue( QVariant(), context );
678 allPartsWrapper.setDynamicParentLayerParameter( &layerWrapper );
679 QVERIFY( !allPartsWrapper.mPropertyButton->vectorLayer() );
680
681 layerWrapper.setWidgetValue( vl->id(), context );
682 allPartsWrapper.setDynamicParentLayerParameter( &layerWrapper );
683 QVERIFY( !allPartsWrapper.mPropertyButton->vectorLayer() );
684 QVERIFY( !allPartsWrapper.mDynamicLayer.get() );
685
686 // with project layer
687 context.setProject( &p );
688 TestProcessingContextGenerator generator( context );
689 allPartsWrapper.registerProcessingContextGenerator( &generator );
690
691 layerWrapper.setWidgetValue( vl->id(), context );
692 allPartsWrapper.setDynamicParentLayerParameter( &layerWrapper );
693 QCOMPARE( allPartsWrapper.mPropertyButton->vectorLayer(), vl );
694 QVERIFY( !allPartsWrapper.mDynamicLayer.get() );
695
696 // non-project layer
697 QString pointFileName = TEST_DATA_DIR + QStringLiteral( "/points.shp" );
698 layerWrapper.setWidgetValue( pointFileName, context );
699 allPartsWrapper.setDynamicParentLayerParameter( &layerWrapper );
700 QCOMPARE( allPartsWrapper.mPropertyButton->vectorLayer()->publicSource(), pointFileName );
701 // must be owned by wrapper, or layer may be deleted while still required by wrapper
702 QCOMPARE( allPartsWrapper.mDynamicLayer->publicSource(), pointFileName );
703 }
704
testModelerWrapper()705 void TestProcessingGui::testModelerWrapper()
706 {
707 // make a little model
708 QgsProcessingModelAlgorithm model( QStringLiteral( "test" ), QStringLiteral( "testGroup" ) );
709 QMap<QString, QgsProcessingModelChildAlgorithm> algs;
710 QgsProcessingModelChildAlgorithm a1( "native:buffer" );
711 a1.setDescription( QStringLiteral( "alg1" ) );
712 a1.setChildId( QStringLiteral( "alg1" ) );
713 QgsProcessingModelChildAlgorithm a2;
714 a2.setDescription( QStringLiteral( "alg2" ) );
715 a2.setChildId( QStringLiteral( "alg2" ) );
716 QgsProcessingModelChildAlgorithm a3( QStringLiteral( "native:buffer" ) );
717 a3.setDescription( QStringLiteral( "alg3" ) );
718 a3.setChildId( QStringLiteral( "alg3" ) );
719 QgsProcessingModelChildAlgorithm a4( QStringLiteral( "native:package" ) );
720 a4.setDescription( QStringLiteral( "alg4" ) );
721 a4.setChildId( QStringLiteral( "alg4" ) );
722 algs.insert( QStringLiteral( "alg1" ), a1 );
723 algs.insert( QStringLiteral( "alg2" ), a2 );
724 algs.insert( QStringLiteral( "alg3" ), a3 );
725 algs.insert( QStringLiteral( "alg4" ), a4 );
726 model.setChildAlgorithms( algs );
727
728 QMap<QString, QgsProcessingModelParameter> pComponents;
729 QgsProcessingModelParameter pc1;
730 pc1.setParameterName( QStringLiteral( "my_param" ) );
731 pComponents.insert( QStringLiteral( "my_param" ), pc1 );
732 model.setParameterComponents( pComponents );
733
734 QgsProcessingModelParameter bool1( "p1" );
735 model.addModelParameter( new QgsProcessingParameterBoolean( "p1", "desc" ), bool1 );
736 QgsProcessingModelParameter testParam( "p2" );
737 model.addModelParameter( new TestParamType( "test_type", "p2" ), testParam );
738 QgsProcessingModelParameter testDestParam( "p3" );
739 model.addModelParameter( new QgsProcessingParameterFileDestination( "test_dest", "p3" ), testDestParam );
740 // try to create a parameter widget, no factories registered
741 QgsProcessingGuiRegistry registry;
742 QgsProcessingContext context;
743 QVERIFY( !registry.createModelerParameterWidget( &model, QStringLiteral( "a" ), model.parameterDefinition( "p2" ), context ) );
744
745 // register factory
746 TestWidgetFactory *factory = new TestWidgetFactory( QStringLiteral( "test_type" ) );
747 QVERIFY( registry.addParameterWidgetFactory( factory ) );
748 QgsProcessingModelerParameterWidget *w = registry.createModelerParameterWidget( &model, QStringLiteral( "a" ), model.parameterDefinition( "p2" ), context );
749 QVERIFY( w );
750 delete w;
751
752
753 // widget tests
754 w = new QgsProcessingModelerParameterWidget( &model, "alg1", model.parameterDefinition( "p1" ), context );
755 QCOMPARE( w->parameterDefinition()->name(), QStringLiteral( "p1" ) );
756 QLabel *l = w->createLabel();
757 QVERIFY( l );
758 QCOMPARE( l->text(), QStringLiteral( "desc" ) );
759 QCOMPARE( l->toolTip(), w->parameterDefinition()->toolTip() );
760 delete l;
761
762 // static value
763 w->setWidgetValue( QgsProcessingModelChildParameterSource::fromStaticValue( true ) );
764 QCOMPARE( w->value().value< QgsProcessingModelChildParameterSource>().source(), QgsProcessingModelChildParameterSource::StaticValue );
765 QCOMPARE( w->value().value< QgsProcessingModelChildParameterSource>().staticValue().toBool(), true );
766 w->setWidgetValue( QgsProcessingModelChildParameterSource::fromStaticValue( false ) );
767 QCOMPARE( w->value().value< QgsProcessingModelChildParameterSource>().source(), QgsProcessingModelChildParameterSource::StaticValue );
768 QCOMPARE( w->value().value< QgsProcessingModelChildParameterSource>().staticValue().toBool(), false );
769 QCOMPARE( w->mStackedWidget->currentIndex(), 0 );
770 QCOMPARE( w->mSourceButton->toolTip(), QStringLiteral( "Value" ) );
771
772 // expression value
773 w->setWidgetValue( QgsProcessingModelChildParameterSource::fromExpression( QStringLiteral( "1+2" ) ) );
774 QCOMPARE( w->value().value< QgsProcessingModelChildParameterSource>().source(), QgsProcessingModelChildParameterSource::Expression );
775 QCOMPARE( w->value().value< QgsProcessingModelChildParameterSource>().expression(), QStringLiteral( "1+2" ) );
776 QCOMPARE( w->mStackedWidget->currentIndex(), 1 );
777 QCOMPARE( w->mSourceButton->toolTip(), QStringLiteral( "Pre-calculated Value" ) );
778
779 // model input - should fail, because we haven't populated sources yet, and so have no compatible sources
780 w->setWidgetValue( QgsProcessingModelChildParameterSource::fromModelParameter( QStringLiteral( "p1" ) ) );
781 QCOMPARE( w->value().value< QgsProcessingModelChildParameterSource>().source(), QgsProcessingModelChildParameterSource::ModelParameter );
782 QVERIFY( w->value().value< QgsProcessingModelChildParameterSource>().parameterName().isEmpty() );
783 QCOMPARE( w->mStackedWidget->currentIndex(), 2 );
784 QCOMPARE( w->mSourceButton->toolTip(), QStringLiteral( "Model Input" ) );
785
786 // alg output - should fail, because we haven't populated sources yet, and so have no compatible sources
787 w->setWidgetValue( QgsProcessingModelChildParameterSource::fromChildOutput( QStringLiteral( "alg3" ), QStringLiteral( "OUTPUT" ) ) );
788 QCOMPARE( w->value().value< QgsProcessingModelChildParameterSource>().source(), QgsProcessingModelChildParameterSource::ChildOutput );
789 QVERIFY( w->value().value< QgsProcessingModelChildParameterSource>().outputChildId().isEmpty() );
790 QCOMPARE( w->mStackedWidget->currentIndex(), 3 );
791 QCOMPARE( w->mSourceButton->toolTip(), QStringLiteral( "Algorithm Output" ) );
792
793 // populate sources and re-try
794 w->populateSources( QStringList() << QStringLiteral( "boolean" ), QStringList() << QStringLiteral( "outputVector" ), QList<int>() );
795
796 // model input
797 w->setWidgetValue( QgsProcessingModelChildParameterSource::fromModelParameter( QStringLiteral( "p1" ) ) );
798 QCOMPARE( w->value().value< QgsProcessingModelChildParameterSource>().source(), QgsProcessingModelChildParameterSource::ModelParameter );
799 QCOMPARE( w->value().value< QgsProcessingModelChildParameterSource>().parameterName(), QStringLiteral( "p1" ) );
800
801 // alg output
802 w->setWidgetValue( QgsProcessingModelChildParameterSource::fromChildOutput( QStringLiteral( "alg3" ), QStringLiteral( "OUTPUT" ) ) );
803 QCOMPARE( w->value().value< QgsProcessingModelChildParameterSource>().source(), QgsProcessingModelChildParameterSource::ChildOutput );
804 QCOMPARE( w->value().value< QgsProcessingModelChildParameterSource>().outputChildId(), QStringLiteral( "alg3" ) );
805 QCOMPARE( w->value().value< QgsProcessingModelChildParameterSource>().outputName(), QStringLiteral( "OUTPUT" ) );
806
807 // model output
808 delete w;
809 w = new QgsProcessingModelerParameterWidget( &model, "alg1", model.parameterDefinition( "test_dest" ), context );
810 QCOMPARE( w->parameterDefinition()->name(), QStringLiteral( "test_dest" ) );
811 // should default to being a model output for destination parameters, but with no value
812 QVERIFY( w->isModelOutput() );
813 QCOMPARE( w->modelOutputName(), QString() );
814 // set it to something else
815 w->setWidgetValue( QgsProcessingModelChildParameterSource::fromChildOutput( QStringLiteral( "alg3" ), QStringLiteral( "OUTPUT" ) ) );
816 QVERIFY( !w->isModelOutput() );
817 // and back
818 w->setToModelOutput( QStringLiteral( "out" ) );
819 QVERIFY( w->isModelOutput() );
820 QCOMPARE( w->modelOutputName(), QStringLiteral( "out" ) );
821 w->setWidgetValue( QgsProcessingModelChildParameterSource::fromChildOutput( QStringLiteral( "alg3" ), QStringLiteral( "OUTPUT" ) ) );
822 w->setToModelOutput( QString() );
823 QVERIFY( w->isModelOutput() );
824 QCOMPARE( w->modelOutputName(), QString() );
825
826 // multi-source input
827 delete w;
828 const QgsProcessingAlgorithm *packageAlg = QgsApplication::processingRegistry()->algorithmById( QStringLiteral( "native:package" ) );
829 const QgsProcessingParameterDefinition *layerDef = packageAlg->parameterDefinition( QStringLiteral( "LAYERS" ) );
830
831 w = new QgsProcessingModelerParameterWidget( &model, "alg4", layerDef, context );
832
833 w->setWidgetValue( QList< QgsProcessingModelChildParameterSource>()
834 << QgsProcessingModelChildParameterSource::fromChildOutput( QStringLiteral( "alg3" ), QStringLiteral( "OUTPUT" ) )
835 << QgsProcessingModelChildParameterSource::fromModelParameter( QStringLiteral( "p1" ) )
836 << QgsProcessingModelChildParameterSource::fromStaticValue( QStringLiteral( "something" ) ) );
837 QCOMPARE( w->value().toList().count(), 3 );
838
839 QCOMPARE( w->value().toList().at( 0 ).value< QgsProcessingModelChildParameterSource>().source(), QgsProcessingModelChildParameterSource::ChildOutput );
840 QCOMPARE( w->value().toList().at( 0 ).value< QgsProcessingModelChildParameterSource>().source(), QgsProcessingModelChildParameterSource::ChildOutput );
841 QCOMPARE( w->value().toList().at( 0 ).value< QgsProcessingModelChildParameterSource>().outputChildId(), QStringLiteral( "alg3" ) );
842 QCOMPARE( w->value().toList().at( 0 ).value< QgsProcessingModelChildParameterSource>().outputName(), QStringLiteral( "OUTPUT" ) );
843 QCOMPARE( w->value().toList().at( 1 ).value< QgsProcessingModelChildParameterSource>().source(), QgsProcessingModelChildParameterSource::ModelParameter );
844 QCOMPARE( w->value().toList().at( 1 ).value< QgsProcessingModelChildParameterSource>().parameterName(), QStringLiteral( "p1" ) );
845 QCOMPARE( w->value().toList().at( 2 ).value< QgsProcessingModelChildParameterSource>().source(), QgsProcessingModelChildParameterSource::StaticValue );
846 QCOMPARE( w->value().toList().at( 2 ).value< QgsProcessingModelChildParameterSource>().staticValue().toString(), QStringLiteral( "something" ) );
847 delete w;
848
849 }
850
testHiddenWrapper()851 void TestProcessingGui::testHiddenWrapper()
852 {
853 TestParamType param( QStringLiteral( "boolean" ), QStringLiteral( "bool" ) );
854
855 QgsProcessingHiddenWidgetWrapper wrapper( ¶m );
856 QSignalSpy spy( &wrapper, &QgsProcessingHiddenWidgetWrapper::widgetValueHasChanged );
857
858 QgsProcessingContext context;
859 wrapper.setWidgetValue( 1, context );
860 QCOMPARE( spy.count(), 1 );
861 QCOMPARE( wrapper.widgetValue().toInt(), 1 );
862 wrapper.setWidgetValue( 1, context );
863 QCOMPARE( spy.count(), 1 );
864 QCOMPARE( wrapper.widgetValue().toInt(), 1 );
865 wrapper.setWidgetValue( 2, context );
866 QCOMPARE( spy.count(), 2 );
867 QCOMPARE( wrapper.widgetValue().toInt(), 2 );
868
869 QVERIFY( !wrapper.createWrappedWidget( context ) );
870 QVERIFY( !wrapper.createWrappedLabel() );
871
872 std::unique_ptr< QgsVectorLayer > vl = std::make_unique< QgsVectorLayer >( QStringLiteral( "Polygon?crs=epsg:3111&field=pk:int" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) );
873 QVERIFY( !wrapper.linkedVectorLayer() );
874 wrapper.setLinkedVectorLayer( vl.get() );
875 QCOMPARE( wrapper.linkedVectorLayer(), vl.get() );
876 }
877
testBooleanWrapper()878 void TestProcessingGui::testBooleanWrapper()
879 {
880 TestParamType param( QStringLiteral( "boolean" ), QStringLiteral( "bool" ) );
881
882 // standard wrapper
883 QgsProcessingBooleanWidgetWrapper wrapper( ¶m );
884 QSignalSpy spy( &wrapper, &QgsProcessingBooleanWidgetWrapper::widgetValueHasChanged );
885
886 QgsProcessingContext context;
887 QWidget *w = wrapper.createWrappedWidget( context );
888 wrapper.setWidgetValue( true, context );
889 QCOMPARE( spy.count(), 1 );
890 QVERIFY( wrapper.widgetValue().toBool() );
891 QVERIFY( static_cast< QCheckBox * >( wrapper.wrappedWidget() )->isChecked() );
892 wrapper.setWidgetValue( false, context );
893 QCOMPARE( spy.count(), 2 );
894 QVERIFY( !wrapper.widgetValue().toBool() );
895 QVERIFY( !static_cast< QCheckBox * >( wrapper.wrappedWidget() )->isChecked() );
896
897 // should be no label in standard mode
898 QVERIFY( !wrapper.createWrappedLabel() );
899 QCOMPARE( static_cast< QCheckBox * >( wrapper.wrappedWidget() )->text(), QStringLiteral( "bool" ) );
900
901 // check signal
902 static_cast< QCheckBox * >( wrapper.wrappedWidget() )->setChecked( true );
903 QCOMPARE( spy.count(), 3 );
904 static_cast< QCheckBox * >( wrapper.wrappedWidget() )->setChecked( false );
905 QCOMPARE( spy.count(), 4 );
906
907 delete w;
908
909 // batch wrapper
910 QgsProcessingBooleanWidgetWrapper wrapperB( ¶m, QgsProcessingGui::Batch );
911
912 w = wrapperB.createWrappedWidget( context );
913 QSignalSpy spy2( &wrapperB, &QgsProcessingBooleanWidgetWrapper::widgetValueHasChanged );
914 wrapperB.setWidgetValue( true, context );
915 QCOMPARE( spy2.count(), 1 );
916 QVERIFY( wrapperB.widgetValue().toBool() );
917 QVERIFY( static_cast< QComboBox * >( wrapperB.wrappedWidget() )->currentData().toBool() );
918 wrapperB.setWidgetValue( false, context );
919 QCOMPARE( spy2.count(), 2 );
920 QVERIFY( !wrapperB.widgetValue().toBool() );
921 QVERIFY( !static_cast< QComboBox * >( wrapperB.wrappedWidget() )->currentData().toBool() );
922
923 // check signal
924 static_cast< QComboBox * >( w )->setCurrentIndex( 0 );
925 QCOMPARE( spy2.count(), 3 );
926 static_cast< QComboBox * >( w )->setCurrentIndex( 1 );
927 QCOMPARE( spy2.count(), 4 );
928
929 // should be no label in batch mode
930 QVERIFY( !wrapperB.createWrappedLabel() );
931 delete w;
932
933 // modeler wrapper
934 QgsProcessingBooleanWidgetWrapper wrapperM( ¶m, QgsProcessingGui::Modeler );
935
936 w = wrapperM.createWrappedWidget( context );
937 QSignalSpy spy3( &wrapperM, &QgsProcessingBooleanWidgetWrapper::widgetValueHasChanged );
938 wrapperM.setWidgetValue( true, context );
939 QVERIFY( wrapperM.widgetValue().toBool() );
940 QCOMPARE( spy3.count(), 1 );
941 QVERIFY( static_cast< QComboBox * >( wrapperM.wrappedWidget() )->currentData().toBool() );
942 wrapperM.setWidgetValue( false, context );
943 QVERIFY( !wrapperM.widgetValue().toBool() );
944 QCOMPARE( spy3.count(), 2 );
945 QVERIFY( !static_cast< QComboBox * >( wrapperM.wrappedWidget() )->currentData().toBool() );
946
947 // check signal
948 static_cast< QComboBox * >( w )->setCurrentIndex( 0 );
949 QCOMPARE( spy3.count(), 3 );
950 static_cast< QComboBox * >( w )->setCurrentIndex( 1 );
951 QCOMPARE( spy3.count(), 4 );
952
953 // should be a label in modeler mode
954 QLabel *l = wrapperM.createWrappedLabel();
955 QVERIFY( l );
956 QCOMPARE( l->text(), QStringLiteral( "bool" ) );
957 QCOMPARE( l->toolTip(), param.toolTip() );
958 delete w;
959 delete l;
960
961 // config widget
962 QgsProcessingParameterWidgetContext widgetContext;
963 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "boolean" ), context, widgetContext );
964 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
965 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
966 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
967 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
968
969 // using a parameter definition as initial values
970 QgsProcessingParameterBoolean boolParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), true, false );
971 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "boolean" ), context, widgetContext, &boolParam );
972 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
973 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
974 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
975 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
976 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
977 QVERIFY( static_cast< QgsProcessingParameterBoolean * >( def.get() )->defaultValue().toBool() );
978 boolParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
979 boolParam.setDefaultValue( false );
980 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "boolean" ), context, widgetContext, &boolParam );
981 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
982 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
983 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
984 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
985 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
986 QVERIFY( !static_cast< QgsProcessingParameterBoolean * >( def.get() )->defaultValue().toBool() );
987 }
988
testStringWrapper()989 void TestProcessingGui::testStringWrapper()
990 {
991 QgsProcessingParameterString param( QStringLiteral( "string" ), QStringLiteral( "string" ) );
992
993 // standard wrapper
994 QgsProcessingStringWidgetWrapper wrapper( ¶m );
995
996 QgsProcessingContext context;
997 QWidget *w = wrapper.createWrappedWidget( context );
998
999 QSignalSpy spy( &wrapper, &QgsProcessingStringWidgetWrapper::widgetValueHasChanged );
1000 wrapper.setWidgetValue( QStringLiteral( "a" ), context );
1001 QCOMPARE( spy.count(), 1 );
1002 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "a" ) );
1003 QCOMPARE( static_cast< QLineEdit * >( wrapper.wrappedWidget() )->text(), QStringLiteral( "a" ) );
1004 wrapper.setWidgetValue( QString(), context );
1005 QCOMPARE( spy.count(), 2 );
1006 QVERIFY( wrapper.widgetValue().toString().isEmpty() );
1007 QVERIFY( static_cast< QLineEdit * >( wrapper.wrappedWidget() )->text().isEmpty() );
1008
1009 QLabel *l = wrapper.createWrappedLabel();
1010 QVERIFY( l );
1011 QCOMPARE( l->text(), QStringLiteral( "string" ) );
1012 QCOMPARE( l->toolTip(), param.toolTip() );
1013 delete l;
1014
1015 // check signal
1016 static_cast< QLineEdit * >( wrapper.wrappedWidget() )->setText( QStringLiteral( "b" ) );
1017 QCOMPARE( spy.count(), 3 );
1018 static_cast< QLineEdit * >( wrapper.wrappedWidget() )->clear();
1019 QCOMPARE( spy.count(), 4 );
1020
1021 delete w;
1022
1023 // batch wrapper
1024 QgsProcessingStringWidgetWrapper wrapperB( ¶m, QgsProcessingGui::Batch );
1025
1026 w = wrapperB.createWrappedWidget( context );
1027 QSignalSpy spy2( &wrapperB, &QgsProcessingStringWidgetWrapper::widgetValueHasChanged );
1028 wrapperB.setWidgetValue( QStringLiteral( "a" ), context );
1029 QCOMPARE( spy2.count(), 1 );
1030 QCOMPARE( wrapperB.widgetValue().toString(), QStringLiteral( "a" ) );
1031 QCOMPARE( static_cast< QLineEdit * >( wrapperB.wrappedWidget() )->text(), QStringLiteral( "a" ) );
1032 wrapperB.setWidgetValue( QString(), context );
1033 QCOMPARE( spy2.count(), 2 );
1034 QVERIFY( wrapperB.widgetValue().toString().isEmpty() );
1035 QVERIFY( static_cast< QLineEdit * >( wrapperB.wrappedWidget() )->text().isEmpty() );
1036
1037 // check signal
1038 static_cast< QLineEdit * >( w )->setText( QStringLiteral( "x" ) );
1039 QCOMPARE( spy2.count(), 3 );
1040 static_cast< QLineEdit * >( w )->clear();
1041 QCOMPARE( spy2.count(), 4 );
1042
1043 // should be no label in batch mode
1044 QVERIFY( !wrapperB.createWrappedLabel() );
1045 delete w;
1046
1047 // modeler wrapper
1048 QgsProcessingStringWidgetWrapper wrapperM( ¶m, QgsProcessingGui::Modeler );
1049
1050 w = wrapperM.createWrappedWidget( context );
1051 QSignalSpy spy3( &wrapperM, &QgsProcessingStringWidgetWrapper::widgetValueHasChanged );
1052 wrapperM.setWidgetValue( QStringLiteral( "a" ), context );
1053 QCOMPARE( wrapperM.widgetValue().toString(), QStringLiteral( "a" ) );
1054 QCOMPARE( spy3.count(), 1 );
1055 QCOMPARE( static_cast< QLineEdit * >( wrapperM.wrappedWidget() )->text(), QStringLiteral( "a" ) );
1056 wrapperM.setWidgetValue( QString(), context );
1057 QVERIFY( wrapperM.widgetValue().toString().isEmpty() );
1058 QCOMPARE( spy3.count(), 2 );
1059 QVERIFY( static_cast< QLineEdit * >( wrapperM.wrappedWidget() )->text().isEmpty() );
1060
1061 // check signal
1062 static_cast< QLineEdit * >( w )->setText( QStringLiteral( "x" ) );
1063 QCOMPARE( spy3.count(), 3 );
1064 static_cast< QLineEdit * >( w )->clear();
1065 QCOMPARE( spy3.count(), 4 );
1066
1067 // should be a label in modeler mode
1068 l = wrapperM.createWrappedLabel();
1069 QVERIFY( l );
1070 QCOMPARE( l->text(), QStringLiteral( "string" ) );
1071 QCOMPARE( l->toolTip(), param.toolTip() );
1072 delete w;
1073 delete l;
1074
1075 //
1076 // multiline parameter
1077 //
1078 param = QgsProcessingParameterString( QStringLiteral( "string" ), QStringLiteral( "string" ), QVariant(), true );
1079
1080 // standard wrapper
1081 QgsProcessingStringWidgetWrapper wrapperMultiLine( ¶m );
1082
1083 w = wrapperMultiLine.createWrappedWidget( context );
1084
1085 QSignalSpy spy4( &wrapperMultiLine, &QgsProcessingStringWidgetWrapper::widgetValueHasChanged );
1086 wrapperMultiLine.setWidgetValue( QStringLiteral( "a" ), context );
1087 QCOMPARE( spy4.count(), 1 );
1088 QCOMPARE( wrapperMultiLine.widgetValue().toString(), QStringLiteral( "a" ) );
1089 QCOMPARE( static_cast< QPlainTextEdit * >( wrapperMultiLine.wrappedWidget() )->toPlainText(), QStringLiteral( "a" ) );
1090 wrapperMultiLine.setWidgetValue( QString(), context );
1091 QCOMPARE( spy4.count(), 2 );
1092 QVERIFY( wrapperMultiLine.widgetValue().toString().isEmpty() );
1093 QVERIFY( static_cast< QPlainTextEdit * >( wrapperMultiLine.wrappedWidget() )->toPlainText().isEmpty() );
1094
1095 l = wrapper.createWrappedLabel();
1096 QVERIFY( l );
1097 QCOMPARE( l->text(), QStringLiteral( "string" ) );
1098 QCOMPARE( l->toolTip(), param.toolTip() );
1099 delete l;
1100
1101 // check signal
1102 static_cast< QPlainTextEdit * >( wrapperMultiLine.wrappedWidget() )->setPlainText( QStringLiteral( "b" ) );
1103 QCOMPARE( spy4.count(), 3 );
1104 static_cast< QPlainTextEdit * >( wrapperMultiLine.wrappedWidget() )->clear();
1105 QCOMPARE( spy4.count(), 4 );
1106
1107 delete w;
1108
1109 // batch wrapper - should still be a line edit
1110 QgsProcessingStringWidgetWrapper wrapperMultiLineB( ¶m, QgsProcessingGui::Batch );
1111
1112 w = wrapperMultiLineB.createWrappedWidget( context );
1113 QSignalSpy spy5( &wrapperMultiLineB, &QgsProcessingStringWidgetWrapper::widgetValueHasChanged );
1114 wrapperMultiLineB.setWidgetValue( QStringLiteral( "a" ), context );
1115 QCOMPARE( spy5.count(), 1 );
1116 QCOMPARE( wrapperMultiLineB.widgetValue().toString(), QStringLiteral( "a" ) );
1117 QCOMPARE( static_cast< QLineEdit * >( wrapperMultiLineB.wrappedWidget() )->text(), QStringLiteral( "a" ) );
1118 wrapperMultiLineB.setWidgetValue( QString(), context );
1119 QCOMPARE( spy5.count(), 2 );
1120 QVERIFY( wrapperMultiLineB.widgetValue().toString().isEmpty() );
1121 QVERIFY( static_cast< QLineEdit * >( wrapperMultiLineB.wrappedWidget() )->text().isEmpty() );
1122
1123 // check signal
1124 static_cast< QLineEdit * >( w )->setText( QStringLiteral( "x" ) );
1125 QCOMPARE( spy5.count(), 3 );
1126 static_cast< QLineEdit * >( w )->clear();
1127 QCOMPARE( spy5.count(), 4 );
1128
1129 // should be no label in batch mode
1130 QVERIFY( !wrapperB.createWrappedLabel() );
1131 delete w;
1132
1133 // modeler wrapper
1134 QgsProcessingStringWidgetWrapper wrapperMultiLineM( ¶m, QgsProcessingGui::Modeler );
1135
1136 w = wrapperMultiLineM.createWrappedWidget( context );
1137 QSignalSpy spy6( &wrapperMultiLineM, &QgsProcessingStringWidgetWrapper::widgetValueHasChanged );
1138 wrapperMultiLineM.setWidgetValue( QStringLiteral( "a" ), context );
1139 QCOMPARE( wrapperMultiLineM.widgetValue().toString(), QStringLiteral( "a" ) );
1140 QCOMPARE( spy6.count(), 1 );
1141 QCOMPARE( static_cast< QPlainTextEdit * >( wrapperMultiLineM.wrappedWidget() )->toPlainText(), QStringLiteral( "a" ) );
1142 wrapperMultiLineM.setWidgetValue( QString(), context );
1143 QVERIFY( wrapperMultiLineM.widgetValue().toString().isEmpty() );
1144 QCOMPARE( spy6.count(), 2 );
1145 QVERIFY( static_cast< QPlainTextEdit * >( wrapperMultiLineM.wrappedWidget() )->toPlainText().isEmpty() );
1146
1147 // check signal
1148 static_cast< QPlainTextEdit * >( w )->setPlainText( QStringLiteral( "x" ) );
1149 QCOMPARE( spy6.count(), 3 );
1150 static_cast< QPlainTextEdit * >( w )->clear();
1151 QCOMPARE( spy6.count(), 4 );
1152
1153 // should be a label in modeler mode
1154 l = wrapperMultiLineM.createWrappedLabel();
1155 QVERIFY( l );
1156 QCOMPARE( l->text(), QStringLiteral( "string" ) );
1157 QCOMPARE( l->toolTip(), param.toolTip() );
1158 delete w;
1159 delete l;
1160
1161
1162 //
1163 // with value hints
1164 //
1165 param = QgsProcessingParameterString( QStringLiteral( "string" ), QStringLiteral( "string" ), QVariant() );
1166 param.setMetadata( { {
1167 QStringLiteral( "widget_wrapper" ),
1168 QVariantMap(
1169 { {
1170 QStringLiteral( "value_hints" ),
1171 QStringList() << "value 1" << "value 2" << "value 3"
1172 }
1173 }
1174 )
1175 }
1176 } );
1177
1178 QgsProcessingStringWidgetWrapper wrapperHints( ¶m );
1179
1180 w = wrapperHints.createWrappedWidget( context );
1181
1182 QSignalSpy spy7( &wrapperHints, &QgsProcessingStringWidgetWrapper::widgetValueHasChanged );
1183 wrapperHints.setWidgetValue( QStringLiteral( "value 2" ), context );
1184 QCOMPARE( spy7.count(), 1 );
1185 QCOMPARE( wrapperHints.widgetValue().toString(), QStringLiteral( "value 2" ) );
1186 QCOMPARE( qgis::down_cast< QComboBox * >( wrapperHints.wrappedWidget() )->currentText(), QStringLiteral( "value 2" ) );
1187 wrapperHints.setWidgetValue( QStringLiteral( "value 3" ), context );
1188 QCOMPARE( spy7.count(), 2 );
1189 QCOMPARE( wrapperHints.widgetValue().toString(), QStringLiteral( "value 3" ) );
1190 QCOMPARE( qgis::down_cast< QComboBox * >( wrapperHints.wrappedWidget() )->currentText(), QStringLiteral( "value 3" ) );
1191
1192 // set to value which is not present -- should fallback to first value
1193 wrapperHints.setWidgetValue( QStringLiteral( "value 4" ), context );
1194 QCOMPARE( spy7.count(), 3 );
1195 QCOMPARE( wrapperHints.widgetValue().toString(), QStringLiteral( "value 1" ) );
1196 QCOMPARE( qgis::down_cast< QComboBox * >( wrapperHints.wrappedWidget() )->currentText(), QStringLiteral( "value 1" ) );
1197
1198 l = wrapperHints.createWrappedLabel();
1199 QVERIFY( l );
1200 QCOMPARE( l->text(), QStringLiteral( "string" ) );
1201 QCOMPARE( l->toolTip(), param.toolTip() );
1202 delete l;
1203
1204 // check signal
1205 qgis::down_cast< QComboBox * >( wrapperHints.wrappedWidget() )->setCurrentIndex( 1 );
1206 QCOMPARE( spy7.count(), 4 );
1207 qgis::down_cast< QComboBox * >( wrapperHints.wrappedWidget() )->setCurrentIndex( 2 );
1208 QCOMPARE( spy7.count(), 5 );
1209
1210 delete w;
1211
1212 // with value hints, optional param
1213 param = QgsProcessingParameterString( QStringLiteral( "string" ), QStringLiteral( "string" ), QVariant(), false, true );
1214 param.setMetadata( { {
1215 QStringLiteral( "widget_wrapper" ),
1216 QVariantMap(
1217 { {
1218 QStringLiteral( "value_hints" ),
1219 QStringList() << "value 1" << "value 2" << "value 3"
1220 }
1221 }
1222 )
1223 }
1224 } );
1225
1226 QgsProcessingStringWidgetWrapper wrapperHintsOptional( ¶m );
1227
1228 w = wrapperHintsOptional.createWrappedWidget( context );
1229
1230 QSignalSpy spy8( &wrapperHintsOptional, &QgsProcessingStringWidgetWrapper::widgetValueHasChanged );
1231 wrapperHintsOptional.setWidgetValue( QStringLiteral( "value 2" ), context );
1232 QCOMPARE( spy8.count(), 1 );
1233 QCOMPARE( wrapperHintsOptional.widgetValue().toString(), QStringLiteral( "value 2" ) );
1234 QCOMPARE( qgis::down_cast< QComboBox * >( wrapperHintsOptional.wrappedWidget() )->currentText(), QStringLiteral( "value 2" ) );
1235 wrapperHintsOptional.setWidgetValue( QVariant(), context );
1236 QCOMPARE( spy8.count(), 2 );
1237 QVERIFY( !wrapperHintsOptional.widgetValue().isValid() );
1238 QCOMPARE( qgis::down_cast< QComboBox * >( wrapperHintsOptional.wrappedWidget() )->currentText(), QString() );
1239 wrapperHintsOptional.setWidgetValue( QStringLiteral( "value 3" ), context );
1240 QCOMPARE( spy8.count(), 3 );
1241 QCOMPARE( wrapperHintsOptional.widgetValue().toString(), QStringLiteral( "value 3" ) );
1242 QCOMPARE( qgis::down_cast< QComboBox * >( wrapperHintsOptional.wrappedWidget() )->currentText(), QStringLiteral( "value 3" ) );
1243
1244 // set to value which is not present -- should fallback to first value ("not set")
1245 wrapperHintsOptional.setWidgetValue( QStringLiteral( "value 4" ), context );
1246 QCOMPARE( spy8.count(), 4 );
1247 QVERIFY( !wrapperHintsOptional.widgetValue().isValid() );
1248 QCOMPARE( qgis::down_cast< QComboBox * >( wrapperHintsOptional.wrappedWidget() )->currentText(), QString() );
1249
1250 l = wrapperHintsOptional.createWrappedLabel();
1251 QVERIFY( l );
1252 QCOMPARE( l->text(), QStringLiteral( "string [optional]" ) );
1253 QCOMPARE( l->toolTip(), param.toolTip() );
1254 delete l;
1255
1256 // check signal
1257 qgis::down_cast< QComboBox * >( wrapperHintsOptional.wrappedWidget() )->setCurrentIndex( 1 );
1258 QCOMPARE( spy8.count(), 5 );
1259 qgis::down_cast< QComboBox * >( wrapperHintsOptional.wrappedWidget() )->setCurrentIndex( 2 );
1260 QCOMPARE( spy8.count(), 6 );
1261
1262 delete w;
1263
1264
1265 // config widget
1266 QgsProcessingParameterWidgetContext widgetContext;
1267 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "string" ), context, widgetContext );
1268 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
1269 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
1270 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
1271 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
1272 QVERIFY( !static_cast< QgsProcessingParameterString * >( def.get() )->multiLine() );
1273
1274 // using a parameter definition as initial values
1275 QgsProcessingParameterString stringParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), QStringLiteral( "aaa" ), true );
1276 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "string" ), context, widgetContext, &stringParam );
1277 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
1278 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
1279 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
1280 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
1281 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
1282 QVERIFY( static_cast< QgsProcessingParameterString * >( def.get() )->multiLine() );
1283 QCOMPARE( static_cast< QgsProcessingParameterString * >( def.get() )->defaultValue().toString(), QStringLiteral( "aaa" ) );
1284 stringParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
1285 stringParam.setMultiLine( false );
1286 stringParam.setDefaultValue( QString() );
1287 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "string" ), context, widgetContext, &stringParam );
1288 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
1289 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
1290 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
1291 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
1292 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
1293 QVERIFY( static_cast< QgsProcessingParameterString * >( def.get() )->defaultValue().toString().isEmpty() );
1294 QVERIFY( !static_cast< QgsProcessingParameterString * >( def.get() )->multiLine() );
1295 }
1296
testFileWrapper()1297 void TestProcessingGui::testFileWrapper()
1298 {
1299 auto testWrapper = []( QgsProcessingGui::WidgetType type )
1300 {
1301 QgsProcessingParameterFile param( QStringLiteral( "file" ), QStringLiteral( "file" ) );
1302
1303 QgsProcessingFileWidgetWrapper wrapper( ¶m, type );
1304
1305 QgsProcessingContext context;
1306 QWidget *w = wrapper.createWrappedWidget( context );
1307
1308 QSignalSpy spy( &wrapper, &QgsProcessingFileWidgetWrapper::widgetValueHasChanged );
1309 wrapper.setWidgetValue( QString( TEST_DATA_DIR + QStringLiteral( "/points.shp" ) ), context );
1310 QCOMPARE( spy.count(), 1 );
1311 QCOMPARE( wrapper.widgetValue().toString(), QString( TEST_DATA_DIR + QStringLiteral( "/points.shp" ) ) );
1312 QCOMPARE( static_cast< QgsFileWidget * >( wrapper.wrappedWidget() )->filePath(), QString( TEST_DATA_DIR + QStringLiteral( "/points.shp" ) ) );
1313 QCOMPARE( static_cast< QgsFileWidget * >( wrapper.wrappedWidget() )->filter(), QStringLiteral( "All files (*.*)" ) );
1314 QCOMPARE( static_cast< QgsFileWidget * >( wrapper.wrappedWidget() )->storageMode(), QgsFileWidget::GetFile );
1315 wrapper.setWidgetValue( QString(), context );
1316 QCOMPARE( spy.count(), 2 );
1317 QVERIFY( wrapper.widgetValue().toString().isEmpty() );
1318 QVERIFY( static_cast< QgsFileWidget * >( wrapper.wrappedWidget() )->filePath().isEmpty() );
1319
1320 QLabel *l = wrapper.createWrappedLabel();
1321 if ( wrapper.type() != QgsProcessingGui::Batch )
1322 {
1323 QVERIFY( l );
1324 QCOMPARE( l->text(), QStringLiteral( "file" ) );
1325 QCOMPARE( l->toolTip(), param.toolTip() );
1326 delete l;
1327 }
1328 else
1329 {
1330 QVERIFY( !l );
1331 }
1332
1333 // check signal
1334 static_cast< QgsFileWidget * >( wrapper.wrappedWidget() )->setFilePath( TEST_DATA_DIR + QStringLiteral( "/polys.shp" ) );
1335 QCOMPARE( spy.count(), 3 );
1336
1337 delete w;
1338
1339 // with extension
1340 QgsProcessingParameterFile param2( QStringLiteral( "file" ), QStringLiteral( "file" ), QgsProcessingParameterFile::File, QStringLiteral( "qml" ) );
1341
1342 QgsProcessingFileWidgetWrapper wrapper2( ¶m2, type );
1343 w = wrapper2.createWrappedWidget( context );
1344 QCOMPARE( static_cast< QgsFileWidget * >( wrapper2.wrappedWidget() )->filter(), QStringLiteral( "QML files (*.qml)" ) );
1345 QCOMPARE( static_cast< QgsFileWidget * >( wrapper2.wrappedWidget() )->storageMode(), QgsFileWidget::GetFile );
1346
1347 // with filter
1348 QgsProcessingParameterFile param3( QStringLiteral( "file" ), QStringLiteral( "file" ), QgsProcessingParameterFile::File, QString(), QVariant(), false, QStringLiteral( "Project files (*.qgs *.qgz)" ) );
1349
1350 QgsProcessingFileWidgetWrapper wrapper3( & param3, type );
1351 w = wrapper3.createWrappedWidget( context );
1352 QCOMPARE( static_cast< QgsFileWidget * >( wrapper3.wrappedWidget() )->filter(), QStringLiteral( "Project files (*.qgs *.qgz)" ) );
1353 QCOMPARE( static_cast< QgsFileWidget * >( wrapper3.wrappedWidget() )->storageMode(), QgsFileWidget::GetFile );
1354
1355 // folder mode
1356 QgsProcessingParameterFile param4( QStringLiteral( "folder" ), QStringLiteral( "folder" ), QgsProcessingParameterFile::Folder );
1357
1358 QgsProcessingFileWidgetWrapper wrapper4( ¶m4, type );
1359 w = wrapper4.createWrappedWidget( context );
1360 QCOMPARE( static_cast< QgsFileWidget * >( wrapper4.wrappedWidget() )->storageMode(), QgsFileWidget::GetDirectory );
1361 };
1362
1363 // standard wrapper
1364 testWrapper( QgsProcessingGui::Standard );
1365
1366 // batch wrapper
1367 testWrapper( QgsProcessingGui::Batch );
1368
1369 // modeler wrapper
1370 testWrapper( QgsProcessingGui::Modeler );
1371
1372
1373 // config widget
1374 QgsProcessingParameterWidgetContext widgetContext;
1375 QgsProcessingContext context;
1376 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "file" ), context, widgetContext );
1377 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
1378 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
1379 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
1380 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
1381
1382 // using a parameter definition as initial values
1383 QgsProcessingParameterFile fileParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), QgsProcessingParameterFile::File );
1384 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "file" ), context, widgetContext, &fileParam );
1385 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
1386 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
1387 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
1388 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
1389 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
1390 QCOMPARE( static_cast< QgsProcessingParameterFile * >( def.get() )->behavior(), QgsProcessingParameterFile::File );
1391 QVERIFY( !static_cast< QgsProcessingParameterFile * >( def.get() )->defaultValue().isValid() );
1392 QCOMPARE( static_cast< QgsProcessingParameterFile * >( def.get() )->fileFilter(), QStringLiteral( "All files (*.*)" ) );
1393 fileParam.setFileFilter( QStringLiteral( "TAB files (*.tab)" ) );
1394 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "file" ), context, widgetContext, &fileParam );
1395 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
1396 QCOMPARE( static_cast< QgsProcessingParameterFile * >( def.get() )->fileFilter(), QStringLiteral( "TAB files (*.tab)" ) );
1397
1398 fileParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
1399 fileParam.setBehavior( QgsProcessingParameterFile::Folder );
1400 fileParam.setDefaultValue( QStringLiteral( "my path" ) );
1401 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "file" ), context, widgetContext, &fileParam );
1402 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
1403 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
1404 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
1405 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
1406 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
1407 QCOMPARE( static_cast< QgsProcessingParameterFile * >( def.get() )->behavior(), QgsProcessingParameterFile::Folder );
1408 QCOMPARE( static_cast< QgsProcessingParameterFile * >( def.get() )->defaultValue().toString(), QStringLiteral( "my path" ) );
1409 }
1410
testAuthCfgWrapper()1411 void TestProcessingGui::testAuthCfgWrapper()
1412 {
1413 QList<QgsAuthMethodConfig> configs;
1414
1415 // Basic
1416 QgsAuthMethodConfig b_config;
1417 b_config.setId( QStringLiteral( "aaaaaaa" ) );
1418 b_config.setName( QStringLiteral( "Basic" ) );
1419 b_config.setMethod( QStringLiteral( "Basic" ) );
1420 b_config.setUri( QStringLiteral( "http://example.com" ) );
1421 b_config.setConfig( QStringLiteral( "username" ), QStringLiteral( "username" ) );
1422 b_config.setConfig( QStringLiteral( "password" ), QStringLiteral( "password" ) );
1423 b_config.setConfig( QStringLiteral( "realm" ), QStringLiteral( "Realm" ) );
1424 configs << b_config;
1425
1426 QgsAuthMethodConfig b_config2;
1427 b_config2.setId( QStringLiteral( "bbbbbbb" ) );
1428 b_config2.setName( QStringLiteral( "Basic2" ) );
1429 b_config2.setMethod( QStringLiteral( "Basic" ) );
1430 b_config2.setUri( QStringLiteral( "http://example.com" ) );
1431 b_config2.setConfig( QStringLiteral( "username" ), QStringLiteral( "username" ) );
1432 b_config2.setConfig( QStringLiteral( "password" ), QStringLiteral( "password" ) );
1433 b_config2.setConfig( QStringLiteral( "realm" ), QStringLiteral( "Realm" ) );
1434 configs << b_config2;
1435
1436 QgsAuthManager *authm = QgsApplication::authManager();
1437 QStringList authIds;
1438 for ( QgsAuthMethodConfig config : std::as_const( configs ) )
1439 {
1440 QVERIFY( config.isValid() );
1441
1442 QVERIFY( authm->storeAuthenticationConfig( config ) );
1443
1444 // config should now have a valid, unique ID
1445 authIds << config.id();
1446 }
1447
1448 QCOMPARE( authIds.count(), 2 );
1449
1450 QgsProcessingParameterAuthConfig param( QStringLiteral( "authcfg" ), QStringLiteral( "authcfg" ) );
1451
1452 // standard wrapper
1453 QgsProcessingAuthConfigWidgetWrapper wrapper( ¶m );
1454
1455 QgsProcessingContext context;
1456 QWidget *w = wrapper.createWrappedWidget( context );
1457
1458 QSignalSpy spy( &wrapper, &QgsProcessingAuthConfigWidgetWrapper::widgetValueHasChanged );
1459 wrapper.setWidgetValue( authIds.at( 0 ), context );
1460 QCOMPARE( spy.count(), 1 );
1461 QCOMPARE( wrapper.widgetValue().toString(), authIds.at( 0 ) );
1462 QCOMPARE( static_cast< QgsAuthConfigSelect * >( wrapper.wrappedWidget() )->configId(), authIds.at( 0 ) );
1463 wrapper.setWidgetValue( authIds.at( 1 ), context );
1464 QCOMPARE( spy.count(), 2 );
1465 QCOMPARE( wrapper.widgetValue().toString(), authIds.at( 1 ) );
1466 QCOMPARE( static_cast< QgsAuthConfigSelect * >( wrapper.wrappedWidget() )->configId(), authIds.at( 1 ) );
1467 wrapper.setWidgetValue( QString(), context );
1468 QCOMPARE( spy.count(), 3 );
1469 QVERIFY( wrapper.widgetValue().toString().isEmpty() );
1470 QVERIFY( static_cast< QgsAuthConfigSelect * >( wrapper.wrappedWidget() )->configId().isEmpty() );
1471
1472 QLabel *l = wrapper.createWrappedLabel();
1473 QVERIFY( l );
1474 QCOMPARE( l->text(), QStringLiteral( "authcfg" ) );
1475 QCOMPARE( l->toolTip(), param.toolTip() );
1476 delete l;
1477
1478 // check signal
1479 static_cast< QgsAuthConfigSelect * >( wrapper.wrappedWidget() )->setConfigId( authIds.at( 0 ) );
1480 QCOMPARE( spy.count(), 4 );
1481
1482 delete w;
1483
1484 // batch wrapper
1485 QgsProcessingAuthConfigWidgetWrapper wrapperB( ¶m, QgsProcessingGui::Batch );
1486
1487 w = wrapperB.createWrappedWidget( context );
1488 QSignalSpy spy2( &wrapperB, &QgsProcessingAuthConfigWidgetWrapper::widgetValueHasChanged );
1489 wrapperB.setWidgetValue( authIds.at( 0 ), context );
1490 QCOMPARE( spy2.count(), 1 );
1491 QCOMPARE( wrapperB.widgetValue().toString(), authIds.at( 0 ) );
1492 QCOMPARE( static_cast< QgsAuthConfigSelect * >( wrapperB.wrappedWidget() )->configId(), authIds.at( 0 ) );
1493 wrapperB.setWidgetValue( QString(), context );
1494 QCOMPARE( spy2.count(), 2 );
1495 QVERIFY( wrapperB.widgetValue().toString().isEmpty() );
1496 QVERIFY( static_cast< QgsAuthConfigSelect * >( wrapperB.wrappedWidget() )->configId().isEmpty() );
1497
1498 // check signal
1499 static_cast< QgsAuthConfigSelect * >( w )->setConfigId( authIds.at( 0 ) );
1500 QCOMPARE( spy2.count(), 3 );
1501
1502 // should be no label in batch mode
1503 QVERIFY( !wrapperB.createWrappedLabel() );
1504 delete w;
1505
1506 // modeler wrapper
1507 QgsProcessingAuthConfigWidgetWrapper wrapperM( ¶m, QgsProcessingGui::Modeler );
1508
1509 w = wrapperM.createWrappedWidget( context );
1510 QSignalSpy spy3( &wrapperM, &QgsProcessingAuthConfigWidgetWrapper::widgetValueHasChanged );
1511 wrapperM.setWidgetValue( authIds.at( 0 ), context );
1512 QCOMPARE( wrapperM.widgetValue().toString(), authIds.at( 0 ) );
1513 QCOMPARE( spy3.count(), 1 );
1514 QCOMPARE( static_cast< QgsAuthConfigSelect * >( wrapperM.wrappedWidget() )->configId(), authIds.at( 0 ) );
1515 wrapperM.setWidgetValue( QString(), context );
1516 QVERIFY( wrapperM.widgetValue().toString().isEmpty() );
1517 QCOMPARE( spy3.count(), 2 );
1518 QVERIFY( static_cast< QgsAuthConfigSelect * >( wrapperM.wrappedWidget() )->configId().isEmpty() );
1519
1520 // check signal
1521 static_cast< QgsAuthConfigSelect * >( w )->setConfigId( authIds.at( 0 ) );
1522 QCOMPARE( spy3.count(), 3 );
1523
1524 // should be a label in modeler mode
1525 l = wrapperM.createWrappedLabel();
1526 QVERIFY( l );
1527 QCOMPARE( l->text(), QStringLiteral( "authcfg" ) );
1528 QCOMPARE( l->toolTip(), param.toolTip() );
1529 delete w;
1530 delete l;
1531 }
1532
testCrsWrapper()1533 void TestProcessingGui::testCrsWrapper()
1534 {
1535 QgsProcessingParameterCrs param( QStringLiteral( "crs" ), QStringLiteral( "crs" ) );
1536
1537 // standard wrapper
1538 QgsProcessingCrsWidgetWrapper wrapper( ¶m );
1539
1540 QgsProcessingContext context;
1541 QWidget *w = wrapper.createWrappedWidget( context );
1542
1543 QSignalSpy spy( &wrapper, &QgsProcessingCrsWidgetWrapper::widgetValueHasChanged );
1544 wrapper.setWidgetValue( QStringLiteral( "epsg:3111" ), context );
1545 QCOMPARE( spy.count(), 1 );
1546 QCOMPARE( wrapper.widgetValue().value< QgsCoordinateReferenceSystem >().authid(), QStringLiteral( "EPSG:3111" ) );
1547 QCOMPARE( static_cast< QgsProjectionSelectionWidget * >( wrapper.wrappedWidget() )->crs().authid(), QStringLiteral( "EPSG:3111" ) );
1548 wrapper.setWidgetValue( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:28356" ) ), context );
1549 QCOMPARE( spy.count(), 2 );
1550 QCOMPARE( wrapper.widgetValue().value< QgsCoordinateReferenceSystem >().authid(), QStringLiteral( "EPSG:28356" ) );
1551 QCOMPARE( static_cast< QgsProjectionSelectionWidget * >( wrapper.wrappedWidget() )->crs().authid(), QStringLiteral( "EPSG:28356" ) );
1552 wrapper.setWidgetValue( QString(), context );
1553 QCOMPARE( spy.count(), 3 );
1554 QVERIFY( !wrapper.widgetValue().value< QgsCoordinateReferenceSystem >().isValid() );
1555 QVERIFY( !static_cast< QgsProjectionSelectionWidget * >( wrapper.wrappedWidget() )->crs().isValid() );
1556
1557 QLabel *l = wrapper.createWrappedLabel();
1558 QVERIFY( l );
1559 QCOMPARE( l->text(), QStringLiteral( "crs" ) );
1560 QCOMPARE( l->toolTip(), param.toolTip() );
1561 delete l;
1562
1563 // check signal
1564 static_cast< QgsProjectionSelectionWidget * >( wrapper.wrappedWidget() )->setCrs( QgsCoordinateReferenceSystem( "EPSG:3857" ) );
1565 QCOMPARE( spy.count(), 4 );
1566 static_cast< QgsProjectionSelectionWidget * >( wrapper.wrappedWidget() )->setCrs( QgsCoordinateReferenceSystem() );
1567 QCOMPARE( spy.count(), 5 );
1568
1569 delete w;
1570
1571 // batch wrapper
1572 QgsProcessingCrsWidgetWrapper wrapperB( ¶m, QgsProcessingGui::Batch );
1573
1574 w = wrapperB.createWrappedWidget( context );
1575 QSignalSpy spy2( &wrapperB, &QgsProcessingCrsWidgetWrapper::widgetValueHasChanged );
1576 wrapperB.setWidgetValue( QStringLiteral( "epsg:3111" ), context );
1577 QCOMPARE( spy2.count(), 1 );
1578 QCOMPARE( wrapperB.widgetValue().value< QgsCoordinateReferenceSystem >().authid(), QStringLiteral( "EPSG:3111" ) );
1579 QCOMPARE( static_cast< QgsProjectionSelectionWidget * >( wrapperB.wrappedWidget() )->crs().authid(), QStringLiteral( "EPSG:3111" ) );
1580 wrapperB.setWidgetValue( QgsCoordinateReferenceSystem(), context );
1581 QCOMPARE( spy2.count(), 2 );
1582 QVERIFY( !wrapperB.widgetValue().value< QgsCoordinateReferenceSystem >().isValid() );
1583 QVERIFY( !static_cast< QgsProjectionSelectionWidget * >( wrapperB.wrappedWidget() )->crs().isValid() );
1584
1585 // check signal
1586 static_cast< QgsProjectionSelectionWidget * >( w )->setCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:28356" ) ) );
1587 QCOMPARE( spy2.count(), 3 );
1588 static_cast< QgsProjectionSelectionWidget * >( w )->setCrs( QgsCoordinateReferenceSystem() );
1589 QCOMPARE( spy2.count(), 4 );
1590
1591 // should be no label in batch mode
1592 QVERIFY( !wrapperB.createWrappedLabel() );
1593 delete w;
1594
1595 // modeler wrapper
1596 QgsProcessingCrsWidgetWrapper wrapperM( ¶m, QgsProcessingGui::Modeler );
1597
1598 w = wrapperM.createWrappedWidget( context );
1599 QSignalSpy spy3( &wrapperM, &QgsProcessingCrsWidgetWrapper::widgetValueHasChanged );
1600 wrapperM.setWidgetValue( QStringLiteral( "epsg:3111" ), context );
1601 QCOMPARE( wrapperM.widgetValue().value< QgsCoordinateReferenceSystem >().authid(), QStringLiteral( "EPSG:3111" ) );
1602 QCOMPARE( spy3.count(), 1 );
1603 QCOMPARE( wrapperM.mProjectionSelectionWidget->crs().authid(), QStringLiteral( "EPSG:3111" ) );
1604 QVERIFY( !wrapperM.mUseProjectCrsCheckBox->isChecked() );
1605 wrapperM.setWidgetValue( QgsCoordinateReferenceSystem(), context );
1606 QVERIFY( !wrapperM.widgetValue().value< QgsCoordinateReferenceSystem >().isValid() );
1607 QCOMPARE( spy3.count(), 2 );
1608 QVERIFY( !wrapperM.mProjectionSelectionWidget->crs().isValid() );
1609 QVERIFY( !wrapperM.mUseProjectCrsCheckBox->isChecked() );
1610 wrapperM.setWidgetValue( QStringLiteral( "ProjectCrs" ), context );
1611 QCOMPARE( wrapperM.widgetValue().toString(), QStringLiteral( "ProjectCrs" ) );
1612 QCOMPARE( spy3.count(), 3 );
1613 QVERIFY( wrapperM.mUseProjectCrsCheckBox->isChecked() );
1614
1615 // check signal
1616 wrapperM.mUseProjectCrsCheckBox->setChecked( false );
1617 QCOMPARE( spy3.count(), 4 );
1618 wrapperM.mProjectionSelectionWidget->setCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:28355" ) ) );
1619 QCOMPARE( spy3.count(), 5 );
1620 wrapperM.mProjectionSelectionWidget->setCrs( QgsCoordinateReferenceSystem() );
1621 QCOMPARE( spy3.count(), 6 );
1622
1623 // should be a label in modeler mode
1624 l = wrapperM.createWrappedLabel();
1625 QVERIFY( l );
1626 QCOMPARE( l->text(), QStringLiteral( "crs" ) );
1627 QCOMPARE( l->toolTip(), param.toolTip() );
1628 delete w;
1629 delete l;
1630
1631 // config widget
1632 QgsProcessingParameterWidgetContext widgetContext;
1633 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "crs" ), context, widgetContext );
1634 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
1635 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
1636 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
1637 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
1638
1639 // using a parameter definition as initial values
1640 QgsProcessingParameterCrs crsParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), QStringLiteral( "EPSG:4326" ) );
1641 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "crs" ), context, widgetContext, &crsParam );
1642 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
1643 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
1644 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
1645 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
1646 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
1647 QCOMPARE( static_cast< QgsProcessingParameterCrs * >( def.get() )->defaultValue().toString(), QStringLiteral( "EPSG:4326" ) );
1648 crsParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
1649 crsParam.setDefaultValue( QStringLiteral( "EPSG:3111" ) );
1650 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "crs" ), context, widgetContext, &crsParam );
1651 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
1652 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
1653 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
1654 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
1655 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
1656 QCOMPARE( static_cast< QgsProcessingParameterCrs * >( def.get() )->defaultValue().toString(), QStringLiteral( "EPSG:3111" ) );
1657 }
1658
testNumericWrapperDouble()1659 void TestProcessingGui::testNumericWrapperDouble()
1660 {
1661 auto testWrapper = []( QgsProcessingGui::WidgetType type )
1662 {
1663 QgsProcessingContext context;
1664
1665 QgsProcessingParameterNumber param( QStringLiteral( "num" ), QStringLiteral( "num" ), QgsProcessingParameterNumber::Double );
1666 QgsProcessingNumericWidgetWrapper wrapper( ¶m, type );
1667
1668 QWidget *w = wrapper.createWrappedWidget( context );
1669 QVERIFY( static_cast< QgsDoubleSpinBox * >( wrapper.wrappedWidget() )->expressionsEnabled() );
1670 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapper.wrappedWidget() )->decimals(), 6 ); // you can change this, if it's an intentional change!
1671 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapper.wrappedWidget() )->singleStep(), 1.0 );
1672 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapper.wrappedWidget() )->minimum(), -999999999.0 );
1673 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapper.wrappedWidget() )->maximum(), 999999999.0 );
1674 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapper.wrappedWidget() )->clearValue(), 0.0 );
1675
1676 QSignalSpy spy( &wrapper, &QgsProcessingNumericWidgetWrapper::widgetValueHasChanged );
1677 wrapper.setWidgetValue( 5, context );
1678 QCOMPARE( spy.count(), 1 );
1679 QCOMPARE( wrapper.widgetValue().toDouble(), 5.0 );
1680 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapper.wrappedWidget() )->value(), 5.0 );
1681 wrapper.setWidgetValue( QStringLiteral( "28356" ), context );
1682 QCOMPARE( spy.count(), 2 );
1683 QCOMPARE( wrapper.widgetValue().toDouble(), 28356.0 );
1684 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapper.wrappedWidget() )->value(), 28356.0 );
1685 wrapper.setWidgetValue( QVariant(), context ); // not optional, so shouldn't work
1686 QCOMPARE( spy.count(), 3 );
1687 QCOMPARE( wrapper.widgetValue().toDouble(), 0.0 );
1688 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapper.wrappedWidget() )->value(), 0.0 );
1689
1690 QLabel *l = wrapper.createWrappedLabel();
1691 if ( wrapper.type() != QgsProcessingGui::Batch )
1692 {
1693 QVERIFY( l );
1694 QCOMPARE( l->text(), QStringLiteral( "num" ) );
1695 QCOMPARE( l->toolTip(), param.toolTip() );
1696 delete l;
1697 }
1698 else
1699 {
1700 QVERIFY( !l );
1701 }
1702
1703 // check signal
1704 static_cast< QgsDoubleSpinBox * >( wrapper.wrappedWidget() )->setValue( 37.0 );
1705 QCOMPARE( spy.count(), 4 );
1706 static_cast< QgsDoubleSpinBox * >( wrapper.wrappedWidget() )->clear();
1707 QCOMPARE( spy.count(), 5 );
1708 QCOMPARE( wrapper.widgetValue().toDouble(), 0.0 );
1709 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapper.wrappedWidget() )->value(), 0.0 );
1710
1711 delete w;
1712
1713 // with min value
1714 QgsProcessingParameterNumber paramMin( QStringLiteral( "num" ), QStringLiteral( "num" ), QgsProcessingParameterNumber::Double );
1715 paramMin.setMinimum( -5 );
1716
1717 QgsProcessingNumericWidgetWrapper wrapperMin( ¶mMin, type );
1718
1719 w = wrapperMin.createWrappedWidget( context );
1720 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapperMin.wrappedWidget() )->singleStep(), 1.0 );
1721 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapperMin.wrappedWidget() )->minimum(), -5.0 );
1722 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapperMin.wrappedWidget() )->maximum(), 999999999.0 );
1723 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapperMin.wrappedWidget() )->clearValue(), -5.0 );
1724 QCOMPARE( wrapperMin.parameterValue().toDouble(), 0.0 );
1725 delete w;
1726
1727 // with max value
1728 QgsProcessingParameterNumber paramMax( QStringLiteral( "num" ), QStringLiteral( "num" ), QgsProcessingParameterNumber::Double );
1729 paramMax.setMaximum( 5 );
1730
1731 QgsProcessingNumericWidgetWrapper wrapperMax( ¶mMax, type );
1732
1733 w = wrapperMax.createWrappedWidget( context );
1734 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapperMax.wrappedWidget() )->singleStep(), 1.0 );
1735 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapperMax.wrappedWidget() )->minimum(), -999999999.0 );
1736 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapperMax.wrappedWidget() )->maximum(), 5.0 );
1737 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapperMax.wrappedWidget() )->clearValue(), 0.0 );
1738 QCOMPARE( wrapperMax.parameterValue().toDouble(), 0.0 );
1739 delete w;
1740
1741 // with min and max value
1742 QgsProcessingParameterNumber paramMinMax( QStringLiteral( "num" ), QStringLiteral( "num" ), QgsProcessingParameterNumber::Double );
1743 paramMinMax.setMinimum( -.1 );
1744 paramMinMax.setMaximum( .1 );
1745
1746 QgsProcessingNumericWidgetWrapper wrapperMinMax( ¶mMinMax, type );
1747
1748 w = wrapperMinMax.createWrappedWidget( context );
1749 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapperMinMax.wrappedWidget() )->singleStep(), 0.02 );
1750 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapperMinMax.wrappedWidget() )->minimum(), -.1 );
1751 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapperMinMax.wrappedWidget() )->maximum(), .1 );
1752 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapperMinMax.wrappedWidget() )->clearValue(), -.1 );
1753 QCOMPARE( wrapperMinMax.parameterValue().toDouble(), 0.0 );
1754 delete w;
1755
1756 // with default value
1757 QgsProcessingParameterNumber paramDefault( QStringLiteral( "num" ), QStringLiteral( "num" ), QgsProcessingParameterNumber::Double );
1758 paramDefault.setDefaultValue( 55 );
1759
1760 QgsProcessingNumericWidgetWrapper wrapperDefault( ¶mDefault, type );
1761
1762 w = wrapperDefault.createWrappedWidget( context );
1763 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapperDefault.wrappedWidget() )->clearValue(), 55.0 );
1764 QCOMPARE( wrapperDefault.parameterValue().toDouble(), 55.0 );
1765 delete w;
1766
1767 // optional, no default
1768 QgsProcessingParameterNumber paramOptional( QStringLiteral( "num" ), QStringLiteral( "num" ), QgsProcessingParameterNumber::Double, QVariant(), true );
1769
1770 QgsProcessingNumericWidgetWrapper wrapperOptional( ¶mOptional, type );
1771
1772 w = wrapperOptional.createWrappedWidget( context );
1773 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapperOptional.wrappedWidget() )->clearValue(), -1000000000.0 );
1774 QVERIFY( !wrapperOptional.parameterValue().isValid() );
1775 wrapperOptional.setParameterValue( 5, context );
1776 QCOMPARE( wrapperOptional.parameterValue().toDouble(), 5.0 );
1777 wrapperOptional.setParameterValue( QVariant(), context );
1778 QVERIFY( !wrapperOptional.parameterValue().isValid() );
1779 wrapperOptional.setParameterValue( 5, context );
1780 static_cast< QgsDoubleSpinBox * >( wrapperOptional.wrappedWidget() )->clear();
1781 QVERIFY( !wrapperOptional.parameterValue().isValid() );
1782
1783 // optional, with default
1784 paramOptional.setDefaultValue( 3 );
1785 QgsProcessingNumericWidgetWrapper wrapperOptionalDefault( ¶mOptional, type );
1786
1787 w = wrapperOptionalDefault.createWrappedWidget( context );
1788 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapperOptionalDefault.wrappedWidget() )->clearValue(), -1000000000.0 );
1789 QCOMPARE( wrapperOptionalDefault.parameterValue().toDouble(), 3.0 );
1790 wrapperOptionalDefault.setParameterValue( 5, context );
1791 QCOMPARE( wrapperOptionalDefault.parameterValue().toDouble(), 5.0 );
1792 wrapperOptionalDefault.setParameterValue( QVariant(), context );
1793 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapperOptionalDefault.wrappedWidget() )->value(), -1000000000.0 );
1794 QVERIFY( !wrapperOptionalDefault.parameterValue().isValid() );
1795 wrapperOptionalDefault.setParameterValue( 5, context );
1796 QCOMPARE( wrapperOptionalDefault.parameterValue().toDouble(), 5.0 );
1797 static_cast< QgsDoubleSpinBox * >( wrapperOptionalDefault.wrappedWidget() )->clear();
1798 QVERIFY( !wrapperOptionalDefault.parameterValue().isValid() );
1799 wrapperOptionalDefault.setParameterValue( 5, context );
1800 QCOMPARE( wrapperOptionalDefault.parameterValue().toDouble(), 5.0 );
1801
1802 delete w;
1803
1804 // with decimals
1805 QgsProcessingParameterNumber paramDecimals( QStringLiteral( "num" ), QStringLiteral( "num" ), QgsProcessingParameterNumber::Double, QVariant(), true, 1, 1.02 );
1806 QVariantMap metadata;
1807 QVariantMap wrapperMetadata;
1808 wrapperMetadata.insert( QStringLiteral( "decimals" ), 2 );
1809 metadata.insert( QStringLiteral( "widget_wrapper" ), wrapperMetadata );
1810 paramDecimals.setMetadata( metadata );
1811 QgsProcessingNumericWidgetWrapper wrapperDecimals( ¶mDecimals, type );
1812 w = wrapperDecimals.createWrappedWidget( context );
1813 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapperDecimals.wrappedWidget() )->decimals(), 2 );
1814 QCOMPARE( static_cast< QgsDoubleSpinBox * >( wrapperDecimals.wrappedWidget() )->singleStep(), 0.01 ); // single step should never be less than set number of decimals
1815 delete w;
1816 };
1817
1818 // standard wrapper
1819 testWrapper( QgsProcessingGui::Standard );
1820
1821 // batch wrapper
1822 testWrapper( QgsProcessingGui::Batch );
1823
1824 // modeler wrapper
1825 testWrapper( QgsProcessingGui::Modeler );
1826
1827 // config widget
1828 QgsProcessingParameterWidgetContext widgetContext;
1829 QgsProcessingContext context;
1830 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "number" ), context, widgetContext );
1831 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
1832 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
1833 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
1834 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
1835
1836 // using a parameter definition as initial values
1837 QgsProcessingParameterNumber numParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), QgsProcessingParameterNumber::Double, 1.0 );
1838 numParam.setMinimum( 0 );
1839 numParam.setMaximum( 10 );
1840 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "number" ), context, widgetContext, &numParam );
1841 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
1842 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
1843 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
1844 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
1845 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
1846 QCOMPARE( static_cast< QgsProcessingParameterNumber * >( def.get() )->defaultValue().toDouble(), 1.0 );
1847 QCOMPARE( static_cast< QgsProcessingParameterNumber * >( def.get() )->dataType(), QgsProcessingParameterNumber::Double );
1848 QCOMPARE( static_cast< QgsProcessingParameterNumber * >( def.get() )->minimum(), 0.0 );
1849 QCOMPARE( static_cast< QgsProcessingParameterNumber * >( def.get() )->maximum(), 10.0 );
1850 numParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
1851 numParam.setDataType( QgsProcessingParameterNumber::Integer );
1852 numParam.setMinimum( -1 );
1853 numParam.setMaximum( 1 );
1854 numParam.setDefaultValue( 0 );
1855 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "number" ), context, widgetContext, &numParam );
1856 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
1857 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
1858 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
1859 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
1860 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
1861 QCOMPARE( static_cast< QgsProcessingParameterNumber * >( def.get() )->defaultValue().toInt(), 0 );
1862 QCOMPARE( static_cast< QgsProcessingParameterNumber * >( def.get() )->dataType(), QgsProcessingParameterNumber::Integer );
1863 QCOMPARE( static_cast< QgsProcessingParameterNumber * >( def.get() )->minimum(), -1.0 );
1864 QCOMPARE( static_cast< QgsProcessingParameterNumber * >( def.get() )->maximum(), 1.0 );
1865 }
1866
testNumericWrapperInt()1867 void TestProcessingGui::testNumericWrapperInt()
1868 {
1869 auto testWrapper = []( QgsProcessingGui::WidgetType type )
1870 {
1871 QgsProcessingContext context;
1872
1873 QgsProcessingParameterNumber param( QStringLiteral( "num" ), QStringLiteral( "num" ), QgsProcessingParameterNumber::Integer );
1874 QgsProcessingNumericWidgetWrapper wrapper( ¶m, type );
1875
1876 QWidget *w = wrapper.createWrappedWidget( context );
1877 QVERIFY( static_cast< QgsSpinBox * >( wrapper.wrappedWidget() )->expressionsEnabled() );
1878 QCOMPARE( static_cast< QgsSpinBox * >( wrapper.wrappedWidget() )->minimum(), -999999999 );
1879 QCOMPARE( static_cast< QgsSpinBox * >( wrapper.wrappedWidget() )->maximum(), 999999999 );
1880 QCOMPARE( static_cast< QgsSpinBox * >( wrapper.wrappedWidget() )->clearValue(), 0 );
1881
1882 QSignalSpy spy( &wrapper, &QgsProcessingNumericWidgetWrapper::widgetValueHasChanged );
1883 wrapper.setWidgetValue( 5, context );
1884 QCOMPARE( spy.count(), 1 );
1885 QCOMPARE( wrapper.widgetValue().toInt(), 5 );
1886 QCOMPARE( static_cast< QgsSpinBox * >( wrapper.wrappedWidget() )->value(), 5 );
1887 wrapper.setWidgetValue( QStringLiteral( "28356" ), context );
1888 QCOMPARE( spy.count(), 2 );
1889 QCOMPARE( wrapper.widgetValue().toInt(), 28356 );
1890 QCOMPARE( static_cast< QgsSpinBox * >( wrapper.wrappedWidget() )->value(), 28356 );
1891 wrapper.setWidgetValue( QVariant(), context ); // not optional, so shouldn't work
1892 QCOMPARE( spy.count(), 3 );
1893 QCOMPARE( wrapper.widgetValue().toInt(), 0 );
1894 QCOMPARE( static_cast< QgsSpinBox * >( wrapper.wrappedWidget() )->value(), 0 );
1895
1896 QLabel *l = wrapper.createWrappedLabel();
1897 if ( wrapper.type() != QgsProcessingGui::Batch )
1898 {
1899 QVERIFY( l );
1900 QCOMPARE( l->text(), QStringLiteral( "num" ) );
1901 QCOMPARE( l->toolTip(), param.toolTip() );
1902 delete l;
1903 }
1904 else
1905 {
1906 QVERIFY( !l );
1907 }
1908
1909 // check signal
1910 static_cast< QgsSpinBox * >( wrapper.wrappedWidget() )->setValue( 37 );
1911 QCOMPARE( spy.count(), 4 );
1912 static_cast< QgsSpinBox * >( wrapper.wrappedWidget() )->clear();
1913 QCOMPARE( spy.count(), 5 );
1914 QCOMPARE( wrapper.widgetValue().toInt(), 0 );
1915 QCOMPARE( static_cast< QgsSpinBox * >( wrapper.wrappedWidget() )->value(), 0 );
1916
1917 delete w;
1918
1919 // with min value
1920 QgsProcessingParameterNumber paramMin( QStringLiteral( "num" ), QStringLiteral( "num" ), QgsProcessingParameterNumber::Integer );
1921 paramMin.setMinimum( -5 );
1922
1923 QgsProcessingNumericWidgetWrapper wrapperMin( ¶mMin, type );
1924
1925 w = wrapperMin.createWrappedWidget( context );
1926 QCOMPARE( static_cast< QgsSpinBox * >( wrapperMin.wrappedWidget() )->minimum(), -5 );
1927 QCOMPARE( static_cast< QgsSpinBox * >( wrapperMin.wrappedWidget() )->maximum(), 999999999 );
1928 QCOMPARE( static_cast< QgsSpinBox * >( wrapperMin.wrappedWidget() )->clearValue(), -5 );
1929 QCOMPARE( wrapperMin.parameterValue().toInt(), 0 );
1930 delete w;
1931
1932 // with max value
1933 QgsProcessingParameterNumber paramMax( QStringLiteral( "num" ), QStringLiteral( "num" ), QgsProcessingParameterNumber::Integer );
1934 paramMax.setMaximum( 5 );
1935
1936 QgsProcessingNumericWidgetWrapper wrapperMax( ¶mMax, type );
1937
1938 w = wrapperMax.createWrappedWidget( context );
1939 QCOMPARE( static_cast< QgsSpinBox * >( wrapperMax.wrappedWidget() )->minimum(), -999999999 );
1940 QCOMPARE( static_cast< QgsSpinBox * >( wrapperMax.wrappedWidget() )->maximum(), 5 );
1941 QCOMPARE( static_cast< QgsSpinBox * >( wrapperMax.wrappedWidget() )->clearValue(), 0 );
1942 QCOMPARE( wrapperMax.parameterValue().toInt(), 0 );
1943 delete w;
1944
1945 // with min and max value
1946 QgsProcessingParameterNumber paramMinMax( QStringLiteral( "num" ), QStringLiteral( "num" ), QgsProcessingParameterNumber::Integer );
1947 paramMinMax.setMinimum( -1 );
1948 paramMinMax.setMaximum( 1 );
1949
1950 QgsProcessingNumericWidgetWrapper wrapperMinMax( ¶mMinMax, type );
1951
1952 w = wrapperMinMax.createWrappedWidget( context );
1953 QCOMPARE( static_cast< QgsSpinBox * >( wrapperMinMax.wrappedWidget() )->minimum(), -1 );
1954 QCOMPARE( static_cast< QgsSpinBox * >( wrapperMinMax.wrappedWidget() )->maximum(), 1 );
1955 QCOMPARE( static_cast< QgsSpinBox * >( wrapperMinMax.wrappedWidget() )->clearValue(), -1 );
1956 QCOMPARE( wrapperMinMax.parameterValue().toInt(), 0 );
1957 delete w;
1958
1959 // with default value
1960 QgsProcessingParameterNumber paramDefault( QStringLiteral( "num" ), QStringLiteral( "num" ), QgsProcessingParameterNumber::Integer );
1961 paramDefault.setDefaultValue( 55 );
1962
1963 QgsProcessingNumericWidgetWrapper wrapperDefault( ¶mDefault, type );
1964
1965 w = wrapperDefault.createWrappedWidget( context );
1966 QCOMPARE( static_cast< QgsSpinBox * >( wrapperDefault.wrappedWidget() )->clearValue(), 55 );
1967 QCOMPARE( wrapperDefault.parameterValue().toInt(), 55 );
1968 delete w;
1969
1970 // optional, no default
1971 QgsProcessingParameterNumber paramOptional( QStringLiteral( "num" ), QStringLiteral( "num" ), QgsProcessingParameterNumber::Integer, QVariant(), true );
1972
1973 QgsProcessingNumericWidgetWrapper wrapperOptional( ¶mOptional, type );
1974
1975 w = wrapperOptional.createWrappedWidget( context );
1976 QCOMPARE( static_cast< QgsSpinBox * >( wrapperOptional.wrappedWidget() )->clearValue(), -1000000000 );
1977 QVERIFY( !wrapperOptional.parameterValue().isValid() );
1978 wrapperOptional.setParameterValue( 5, context );
1979 QCOMPARE( wrapperOptional.parameterValue().toInt(), 5 );
1980 wrapperOptional.setParameterValue( QVariant(), context );
1981 QVERIFY( !wrapperOptional.parameterValue().isValid() );
1982 wrapperOptional.setParameterValue( 5, context );
1983 static_cast< QgsSpinBox * >( wrapperOptional.wrappedWidget() )->clear();
1984 QVERIFY( !wrapperOptional.parameterValue().isValid() );
1985
1986 // optional, with default
1987 paramOptional.setDefaultValue( 3 );
1988 QgsProcessingNumericWidgetWrapper wrapperOptionalDefault( ¶mOptional, type );
1989
1990 w = wrapperOptionalDefault.createWrappedWidget( context );
1991 QCOMPARE( static_cast< QgsSpinBox * >( wrapperOptionalDefault.wrappedWidget() )->clearValue(), -1000000000 );
1992 QCOMPARE( wrapperOptionalDefault.parameterValue().toInt(), 3 );
1993 wrapperOptionalDefault.setParameterValue( 5, context );
1994 QCOMPARE( wrapperOptionalDefault.parameterValue().toInt(), 5 );
1995 wrapperOptionalDefault.setParameterValue( QVariant(), context );
1996 QCOMPARE( static_cast< QgsSpinBox * >( wrapperOptionalDefault.wrappedWidget() )->value(), -1000000000 );
1997 QVERIFY( !wrapperOptionalDefault.parameterValue().isValid() );
1998 wrapperOptionalDefault.setParameterValue( 5, context );
1999 QCOMPARE( wrapperOptionalDefault.parameterValue().toInt(), 5 );
2000 static_cast< QgsSpinBox * >( wrapperOptionalDefault.wrappedWidget() )->clear();
2001 QVERIFY( !wrapperOptionalDefault.parameterValue().isValid() );
2002 wrapperOptionalDefault.setParameterValue( 5, context );
2003 QCOMPARE( wrapperOptionalDefault.parameterValue().toInt(), 5 );
2004
2005 delete w;
2006 };
2007
2008 // standard wrapper
2009 testWrapper( QgsProcessingGui::Standard );
2010
2011 // batch wrapper
2012 testWrapper( QgsProcessingGui::Batch );
2013
2014 // modeler wrapper
2015 testWrapper( QgsProcessingGui::Modeler );
2016
2017 // config widget
2018 QgsProcessingParameterWidgetContext widgetContext;
2019 QgsProcessingContext context;
2020 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "number" ), context, widgetContext );
2021 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
2022 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
2023 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
2024 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
2025
2026 // using a parameter definition as initial values
2027 QgsProcessingParameterNumber numParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), QgsProcessingParameterNumber::Integer, 1 );
2028 numParam.setMinimum( 0 );
2029 numParam.setMaximum( 10 );
2030 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "number" ), context, widgetContext, &numParam );
2031 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
2032 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
2033 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
2034 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
2035 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
2036 QCOMPARE( static_cast< QgsProcessingParameterNumber * >( def.get() )->defaultValue().toDouble(), 1.0 );
2037 QCOMPARE( static_cast< QgsProcessingParameterNumber * >( def.get() )->dataType(), QgsProcessingParameterNumber::Integer );
2038 QCOMPARE( static_cast< QgsProcessingParameterNumber * >( def.get() )->minimum(), 0.0 );
2039 QCOMPARE( static_cast< QgsProcessingParameterNumber * >( def.get() )->maximum(), 10.0 );
2040 numParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
2041 numParam.setDataType( QgsProcessingParameterNumber::Double );
2042 numParam.setMinimum( -2.5 );
2043 numParam.setMaximum( 2.5 );
2044 numParam.setDefaultValue( 0.5 );
2045 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "number" ), context, widgetContext, &numParam );
2046 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
2047 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
2048 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
2049 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
2050 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
2051 QCOMPARE( static_cast< QgsProcessingParameterNumber * >( def.get() )->defaultValue().toDouble(), 0.5 );
2052 QCOMPARE( static_cast< QgsProcessingParameterNumber * >( def.get() )->dataType(), QgsProcessingParameterNumber::Double );
2053 QCOMPARE( static_cast< QgsProcessingParameterNumber * >( def.get() )->minimum(), -2.5 );
2054 QCOMPARE( static_cast< QgsProcessingParameterNumber * >( def.get() )->maximum(), 2.5 );
2055 }
2056
testDistanceWrapper()2057 void TestProcessingGui::testDistanceWrapper()
2058 {
2059 QgsProcessingParameterDistance param( QStringLiteral( "distance" ), QStringLiteral( "distance" ) );
2060
2061 // standard wrapper
2062 QgsProcessingDistanceWidgetWrapper wrapper( ¶m );
2063
2064 QgsProcessingContext context;
2065 QWidget *w = wrapper.createWrappedWidget( context );
2066
2067 QSignalSpy spy( &wrapper, &QgsProcessingDistanceWidgetWrapper::widgetValueHasChanged );
2068 wrapper.setWidgetValue( 55.5, context );
2069 QCOMPARE( spy.count(), 1 );
2070 QCOMPARE( wrapper.widgetValue().toDouble(), 55.5 );
2071 QCOMPARE( wrapper.mDoubleSpinBox->value(), 55.5 );
2072 wrapper.setWidgetValue( -34.0, context );
2073 QCOMPARE( spy.count(), 2 );
2074 QCOMPARE( wrapper.widgetValue().toDouble(), -34.0 );
2075 QCOMPARE( wrapper.mDoubleSpinBox->value(), -34.0 );
2076
2077 QLabel *l = wrapper.createWrappedLabel();
2078 QVERIFY( l );
2079 QCOMPARE( l->text(), QStringLiteral( "distance" ) );
2080 QCOMPARE( l->toolTip(), param.toolTip() );
2081 delete l;
2082
2083 // check signal
2084 wrapper.mDoubleSpinBox->setValue( 43.0 );
2085 QCOMPARE( spy.count(), 3 );
2086
2087 // test unit handling
2088 w->show();
2089
2090 QCOMPARE( wrapper.mLabel->text(), QStringLiteral( "<unknown>" ) );
2091
2092 // crs values
2093 wrapper.setUnitParameterValue( QStringLiteral( "EPSG:3111" ) );
2094 QCOMPARE( wrapper.mLabel->text(), QStringLiteral( "meters" ) );
2095 QVERIFY( !wrapper.mWarningLabel->isVisible() );
2096 QVERIFY( wrapper.mUnitsCombo->isVisible() );
2097 QVERIFY( !wrapper.mLabel->isVisible() );
2098 QCOMPARE( wrapper.mUnitsCombo->currentData().toInt(), static_cast< int >( QgsUnitTypes::DistanceMeters ) );
2099
2100 wrapper.setUnitParameterValue( QStringLiteral( "EPSG:4326" ) );
2101 QCOMPARE( wrapper.mLabel->text(), QStringLiteral( "degrees" ) );
2102 QVERIFY( wrapper.mWarningLabel->isVisible() );
2103 QVERIFY( !wrapper.mUnitsCombo->isVisible() );
2104 QVERIFY( wrapper.mLabel->isVisible() );
2105
2106 wrapper.setUnitParameterValue( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3111" ) ) );
2107 QCOMPARE( wrapper.mLabel->text(), QStringLiteral( "meters" ) );
2108 QVERIFY( !wrapper.mWarningLabel->isVisible() );
2109 QVERIFY( wrapper.mUnitsCombo->isVisible() );
2110 QVERIFY( !wrapper.mLabel->isVisible() );
2111 QCOMPARE( wrapper.mUnitsCombo->currentData().toInt(), static_cast< int >( QgsUnitTypes::DistanceMeters ) );
2112
2113 wrapper.setUnitParameterValue( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) );
2114 QCOMPARE( wrapper.mLabel->text(), QStringLiteral( "degrees" ) );
2115 QVERIFY( wrapper.mWarningLabel->isVisible() );
2116 QVERIFY( !wrapper.mUnitsCombo->isVisible() );
2117 QVERIFY( wrapper.mLabel->isVisible() );
2118
2119 // layer values
2120 std::unique_ptr< QgsVectorLayer > vl = std::make_unique< QgsVectorLayer >( QStringLiteral( "Polygon?crs=epsg:3111&field=pk:int" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) );
2121 wrapper.setUnitParameterValue( QVariant::fromValue( vl.get() ) );
2122 QCOMPARE( wrapper.mLabel->text(), QStringLiteral( "meters" ) );
2123 QVERIFY( !wrapper.mWarningLabel->isVisible() );
2124 QVERIFY( wrapper.mUnitsCombo->isVisible() );
2125 QVERIFY( !wrapper.mLabel->isVisible() );
2126 QCOMPARE( wrapper.mUnitsCombo->currentData().toInt(), static_cast< int >( QgsUnitTypes::DistanceMeters ) );
2127
2128 std::unique_ptr< QgsVectorLayer > vl2 = std::make_unique< QgsVectorLayer >( QStringLiteral( "Polygon?crs=epsg:4326&field=pk:int" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) );
2129 wrapper.setUnitParameterValue( QVariant::fromValue( vl2.get() ) );
2130 QCOMPARE( wrapper.mLabel->text(), QStringLiteral( "degrees" ) );
2131 QVERIFY( wrapper.mWarningLabel->isVisible() );
2132 QVERIFY( !wrapper.mUnitsCombo->isVisible() );
2133 QVERIFY( wrapper.mLabel->isVisible() );
2134
2135 // unresolvable values
2136 wrapper.setUnitParameterValue( QStringLiteral( "blah" ) );
2137 QCOMPARE( wrapper.mLabel->text(), QStringLiteral( "<unknown>" ) );
2138 QVERIFY( !wrapper.mWarningLabel->isVisible() );
2139 QVERIFY( !wrapper.mUnitsCombo->isVisible() );
2140 QVERIFY( wrapper.mLabel->isVisible() );
2141
2142 // resolvable text value
2143 const QString id = vl->id();
2144 QgsProject::instance()->addMapLayer( vl.release() );
2145 context.setProject( QgsProject::instance() );
2146
2147 TestProcessingContextGenerator generator( context );
2148 wrapper.registerProcessingContextGenerator( &generator );
2149 wrapper.setUnitParameterValue( id );
2150 QCOMPARE( wrapper.mLabel->text(), QStringLiteral( "meters" ) );
2151 QVERIFY( !wrapper.mWarningLabel->isVisible() );
2152 QVERIFY( wrapper.mUnitsCombo->isVisible() );
2153 QVERIFY( !wrapper.mLabel->isVisible() );
2154 QCOMPARE( wrapper.mUnitsCombo->currentData().toInt(), static_cast< int >( QgsUnitTypes::DistanceMeters ) );
2155
2156 // using unit choice
2157 wrapper.setParameterValue( 5, context );
2158 QCOMPARE( wrapper.parameterValue().toDouble(), 5.0 );
2159 wrapper.mUnitsCombo->setCurrentIndex( wrapper.mUnitsCombo->findData( QgsUnitTypes::DistanceKilometers ) );
2160 QCOMPARE( wrapper.parameterValue().toDouble(), 5000.0 );
2161 wrapper.setParameterValue( 2, context );
2162 QCOMPARE( wrapper.parameterValue().toDouble(), 2000.0 );
2163
2164 wrapper.setUnitParameterValue( id );
2165 QCOMPARE( wrapper.parameterValue().toDouble(), 2.0 );
2166 wrapper.setParameterValue( 5, context );
2167 QCOMPARE( wrapper.parameterValue().toDouble(), 5.0 );
2168
2169 delete w;
2170
2171 // with default unit
2172 QgsProcessingParameterDistance paramDefaultUnit( QStringLiteral( "num" ), QStringLiteral( "num" ) );
2173 paramDefaultUnit.setDefaultUnit( QgsUnitTypes::DistanceFeet );
2174 QgsProcessingDistanceWidgetWrapper wrapperDefaultUnit( ¶mDefaultUnit, QgsProcessingGui::Standard );
2175 w = wrapperDefaultUnit.createWrappedWidget( context );
2176 w->show();
2177 QCOMPARE( wrapperDefaultUnit.mLabel->text(), QStringLiteral( "feet" ) );
2178 delete w;
2179
2180 // with decimals
2181 QgsProcessingParameterDistance paramDecimals( QStringLiteral( "num" ), QStringLiteral( "num" ), QVariant(), QString(), true, 1, 1.02 );
2182 QVariantMap metadata;
2183 QVariantMap wrapperMetadata;
2184 wrapperMetadata.insert( QStringLiteral( "decimals" ), 2 );
2185 metadata.insert( QStringLiteral( "widget_wrapper" ), wrapperMetadata );
2186 paramDecimals.setMetadata( metadata );
2187 QgsProcessingDistanceWidgetWrapper wrapperDecimals( ¶mDecimals, QgsProcessingGui::Standard );
2188 w = wrapperDecimals.createWrappedWidget( context );
2189 QCOMPARE( wrapperDecimals.mDoubleSpinBox->decimals(), 2 );
2190 QCOMPARE( wrapperDecimals.mDoubleSpinBox->singleStep(), 0.01 ); // single step should never be less than set number of decimals
2191 delete w;
2192
2193 // batch wrapper
2194 QgsProcessingDistanceWidgetWrapper wrapperB( ¶m, QgsProcessingGui::Batch );
2195
2196 w = wrapperB.createWrappedWidget( context );
2197 QSignalSpy spy2( &wrapperB, &QgsProcessingDistanceWidgetWrapper::widgetValueHasChanged );
2198 wrapperB.setWidgetValue( 34, context );
2199 QCOMPARE( spy2.count(), 1 );
2200 QCOMPARE( wrapperB.widgetValue().toDouble(), 34.0 );
2201 QCOMPARE( wrapperB.mDoubleSpinBox->value(), 34.0 );
2202 wrapperB.setWidgetValue( -57, context );
2203 QCOMPARE( spy2.count(), 2 );
2204 QCOMPARE( wrapperB.widgetValue().toDouble(), -57.0 );
2205 QCOMPARE( wrapperB.mDoubleSpinBox->value(), -57.0 );
2206
2207 // check signal
2208 static_cast< QgsDoubleSpinBox * >( w )->setValue( 29 );
2209 QCOMPARE( spy2.count(), 3 );
2210
2211 // should be no label in batch mode
2212 QVERIFY( !wrapperB.createWrappedLabel() );
2213 delete w;
2214
2215 // modeler wrapper
2216 QgsProcessingDistanceWidgetWrapper wrapperM( ¶m, QgsProcessingGui::Modeler );
2217
2218 w = wrapperM.createWrappedWidget( context );
2219 QSignalSpy spy3( &wrapperM, &QgsProcessingDistanceWidgetWrapper::widgetValueHasChanged );
2220 wrapperM.setWidgetValue( 29, context );
2221 QCOMPARE( wrapperM.widgetValue().toDouble(), 29.0 );
2222 QCOMPARE( spy3.count(), 1 );
2223 QCOMPARE( wrapperM.mDoubleSpinBox->value(), 29.0 );
2224 wrapperM.setWidgetValue( -29, context );
2225 QCOMPARE( wrapperM.widgetValue().toDouble(), -29.0 );
2226 QCOMPARE( spy3.count(), 2 );
2227 QCOMPARE( wrapperM.mDoubleSpinBox->value(), -29.0 );
2228
2229 // check signal
2230 wrapperM.mDoubleSpinBox->setValue( 33 );
2231 QCOMPARE( spy3.count(), 3 );
2232
2233 // should be a label in modeler mode
2234 l = wrapperM.createWrappedLabel();
2235 QVERIFY( l );
2236 QCOMPARE( l->text(), QStringLiteral( "distance" ) );
2237 QCOMPARE( l->toolTip(), param.toolTip() );
2238 delete w;
2239 delete l;
2240
2241 // config widget
2242 QgsProcessingParameterWidgetContext widgetContext;
2243 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "distance" ), context, widgetContext );
2244 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
2245 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
2246 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
2247 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
2248
2249 // using a parameter definition as initial values
2250 QgsProcessingParameterDistance distParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), 1, QStringLiteral( "parent" ) );
2251 distParam.setMinimum( 1 );
2252 distParam.setMaximum( 100 );
2253 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "distance" ), context, widgetContext, &distParam );
2254 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
2255 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
2256 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
2257 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
2258 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
2259 QCOMPARE( static_cast< QgsProcessingParameterDistance * >( def.get() )->defaultValue().toDouble(), 1.0 );
2260 QCOMPARE( static_cast< QgsProcessingParameterDistance * >( def.get() )->minimum(), 1.0 );
2261 QCOMPARE( static_cast< QgsProcessingParameterDistance * >( def.get() )->maximum(), 100.0 );
2262 QCOMPARE( static_cast< QgsProcessingParameterDistance * >( def.get() )->parentParameterName(), QStringLiteral( "parent" ) );
2263 distParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
2264 distParam.setParentParameterName( QString() );
2265 distParam.setMinimum( 10 );
2266 distParam.setMaximum( 12 );
2267 distParam.setDefaultValue( 11.5 );
2268 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "distance" ), context, widgetContext, &distParam );
2269 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
2270 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
2271 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
2272 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
2273 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
2274 QCOMPARE( static_cast< QgsProcessingParameterDistance * >( def.get() )->defaultValue().toDouble(), 11.5 );
2275 QCOMPARE( static_cast< QgsProcessingParameterDistance * >( def.get() )->minimum(), 10.0 );
2276 QCOMPARE( static_cast< QgsProcessingParameterDistance * >( def.get() )->maximum(), 12.0 );
2277 QVERIFY( static_cast< QgsProcessingParameterDistance * >( def.get() )->parentParameterName().isEmpty() );
2278 }
2279
testDurationWrapper()2280 void TestProcessingGui::testDurationWrapper()
2281 {
2282 QgsProcessingParameterDuration param( QStringLiteral( "duration" ), QStringLiteral( "duration" ) );
2283
2284 // standard wrapper
2285 QgsProcessingDurationWidgetWrapper wrapper( ¶m );
2286
2287 QgsProcessingContext context;
2288 QWidget *w = wrapper.createWrappedWidget( context );
2289
2290 QSignalSpy spy( &wrapper, &QgsProcessingDurationWidgetWrapper::widgetValueHasChanged );
2291 wrapper.setWidgetValue( 55.5, context );
2292 QCOMPARE( spy.count(), 1 );
2293 QCOMPARE( wrapper.widgetValue().toDouble(), 55.5 );
2294 QCOMPARE( wrapper.mDoubleSpinBox->value(), 55.5 );
2295 wrapper.setWidgetValue( -34.0, context );
2296 QCOMPARE( spy.count(), 2 );
2297 QCOMPARE( wrapper.widgetValue().toDouble(), -34.0 );
2298 QCOMPARE( wrapper.mDoubleSpinBox->value(), -34.0 );
2299
2300 QLabel *l = wrapper.createWrappedLabel();
2301 QVERIFY( l );
2302 QCOMPARE( l->text(), QStringLiteral( "duration" ) );
2303 QCOMPARE( l->toolTip(), param.toolTip() );
2304 delete l;
2305
2306 // check signal
2307 wrapper.mDoubleSpinBox->setValue( 43.0 );
2308 QCOMPARE( spy.count(), 3 );
2309
2310 // with default unit
2311 QgsProcessingParameterDuration paramDefaultUnit( QStringLiteral( "dur" ), QStringLiteral( "dur" ) );
2312 paramDefaultUnit.setDefaultUnit( QgsUnitTypes::TemporalDays );
2313 QgsProcessingDurationWidgetWrapper wrapperDefaultUnit( ¶mDefaultUnit, QgsProcessingGui::Standard );
2314 w = wrapperDefaultUnit.createWrappedWidget( context );
2315 w->show();
2316 QCOMPARE( wrapperDefaultUnit.mUnitsCombo->currentText(), QgsUnitTypes::toString( QgsUnitTypes::TemporalDays ) );
2317 delete w;
2318
2319 // with decimals
2320 QgsProcessingParameterDuration paramDecimals( QStringLiteral( "num" ), QStringLiteral( "num" ), QVariant(), true, 1, 1.02 );
2321 QVariantMap metadata;
2322 QVariantMap wrapperMetadata;
2323 wrapperMetadata.insert( QStringLiteral( "decimals" ), 2 );
2324 metadata.insert( QStringLiteral( "widget_wrapper" ), wrapperMetadata );
2325 paramDecimals.setMetadata( metadata );
2326 QgsProcessingDurationWidgetWrapper wrapperDecimals( ¶mDecimals, QgsProcessingGui::Standard );
2327 w = wrapperDecimals.createWrappedWidget( context );
2328 QCOMPARE( wrapperDecimals.mDoubleSpinBox->decimals(), 2 );
2329 QCOMPARE( wrapperDecimals.mDoubleSpinBox->singleStep(), 0.01 ); // single step should never be less than set number of decimals
2330 delete w;
2331
2332 // batch wrapper
2333 QgsProcessingDurationWidgetWrapper wrapperB( ¶m, QgsProcessingGui::Batch );
2334
2335 w = wrapperB.createWrappedWidget( context );
2336 QSignalSpy spy2( &wrapperB, &QgsProcessingDurationWidgetWrapper::widgetValueHasChanged );
2337 wrapperB.setWidgetValue( 34, context );
2338 QCOMPARE( spy2.count(), 1 );
2339 QCOMPARE( wrapperB.widgetValue().toDouble(), 34.0 );
2340 QCOMPARE( wrapperB.mDoubleSpinBox->value(), 34.0 );
2341 wrapperB.setWidgetValue( -57, context );
2342 QCOMPARE( spy2.count(), 2 );
2343 QCOMPARE( wrapperB.widgetValue().toDouble(), -57.0 );
2344 QCOMPARE( wrapperB.mDoubleSpinBox->value(), -57.0 );
2345
2346 // check signal
2347 static_cast< QgsDoubleSpinBox * >( w )->setValue( 29 );
2348 QCOMPARE( spy2.count(), 3 );
2349
2350 // should be no label in batch mode
2351 QVERIFY( !wrapperB.createWrappedLabel() );
2352 delete w;
2353
2354 // modeler wrapper
2355 QgsProcessingDurationWidgetWrapper wrapperM( ¶m, QgsProcessingGui::Modeler );
2356
2357 w = wrapperM.createWrappedWidget( context );
2358 QSignalSpy spy3( &wrapperM, &QgsProcessingDurationWidgetWrapper::widgetValueHasChanged );
2359 wrapperM.setWidgetValue( 29, context );
2360 QCOMPARE( wrapperM.widgetValue().toDouble(), 29.0 );
2361 QCOMPARE( spy3.count(), 1 );
2362 QCOMPARE( wrapperM.mDoubleSpinBox->value(), 29.0 );
2363 wrapperM.setWidgetValue( -29, context );
2364 QCOMPARE( wrapperM.widgetValue().toDouble(), -29.0 );
2365 QCOMPARE( spy3.count(), 2 );
2366 QCOMPARE( wrapperM.mDoubleSpinBox->value(), -29.0 );
2367
2368 // check signal
2369 wrapperM.mDoubleSpinBox->setValue( 33 );
2370 QCOMPARE( spy3.count(), 3 );
2371
2372 // should be a label in modeler mode which includes a unit type string
2373 l = wrapperM.createWrappedLabel();
2374 QVERIFY( l );
2375 QCOMPARE( l->text(), QStringLiteral( "duration [milliseconds]" ) );
2376 QCOMPARE( l->toolTip(), param.toolTip() );
2377 delete w;
2378 delete l;
2379
2380 // config widget
2381 QgsProcessingParameterWidgetContext widgetContext;
2382 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "duration" ), context, widgetContext );
2383 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
2384 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
2385 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
2386 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
2387
2388 // using a parameter definition as initial values
2389 QgsProcessingParameterDuration durParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), 1 );
2390 durParam.setMinimum( 1 );
2391 durParam.setMaximum( 100 );
2392 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "duration" ), context, widgetContext, &durParam );
2393 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
2394 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
2395 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
2396 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
2397 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
2398 QCOMPARE( static_cast< QgsProcessingParameterDuration * >( def.get() )->defaultValue().toDouble(), 1.0 );
2399 QCOMPARE( static_cast< QgsProcessingParameterDuration * >( def.get() )->minimum(), 1.0 );
2400 QCOMPARE( static_cast< QgsProcessingParameterDuration * >( def.get() )->maximum(), 100.0 );
2401 durParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
2402 durParam.setMinimum( 10 );
2403 durParam.setMaximum( 12 );
2404 durParam.setDefaultValue( 11.5 );
2405 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "duration" ), context, widgetContext, &durParam );
2406 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
2407 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
2408 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
2409 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
2410 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
2411 QCOMPARE( static_cast< QgsProcessingParameterDuration * >( def.get() )->defaultValue().toDouble(), 11.5 );
2412 QCOMPARE( static_cast< QgsProcessingParameterDuration * >( def.get() )->minimum(), 10.0 );
2413 QCOMPARE( static_cast< QgsProcessingParameterDuration * >( def.get() )->maximum(), 12.0 );
2414 }
2415
testScaleWrapper()2416 void TestProcessingGui::testScaleWrapper()
2417 {
2418 auto testWrapper = []( QgsProcessingGui::WidgetType type )
2419 {
2420 QgsProcessingContext context;
2421
2422 QgsProcessingParameterScale param( QStringLiteral( "num" ), QStringLiteral( "num" ) );
2423 QgsProcessingScaleWidgetWrapper wrapper( ¶m, type );
2424
2425 QWidget *w = wrapper.createWrappedWidget( context );
2426 QSignalSpy spy( &wrapper, &QgsProcessingNumericWidgetWrapper::widgetValueHasChanged );
2427 wrapper.setWidgetValue( 5, context );
2428 QCOMPARE( spy.count(), 1 );
2429 QCOMPARE( wrapper.widgetValue().toDouble(), 5.0 );
2430 QCOMPARE( static_cast< QgsScaleWidget * >( wrapper.wrappedWidget() )->scale(), 5.0 );
2431 wrapper.setWidgetValue( QStringLiteral( "28356" ), context );
2432 QCOMPARE( spy.count(), 2 );
2433 QCOMPARE( wrapper.widgetValue().toDouble(), 28356.0 );
2434 QCOMPARE( static_cast< QgsScaleWidget * >( wrapper.wrappedWidget() )->scale(), 28356.0 );
2435 wrapper.setWidgetValue( QVariant(), context ); // not optional, so shouldn't work
2436 QCOMPARE( spy.count(), 3 );
2437 QCOMPARE( wrapper.widgetValue().toDouble(), 0.0 );
2438 QCOMPARE( static_cast< QgsScaleWidget * >( wrapper.wrappedWidget() )->scale(), 0.0 );
2439
2440 QLabel *l = wrapper.createWrappedLabel();
2441 if ( wrapper.type() != QgsProcessingGui::Batch )
2442 {
2443 QVERIFY( l );
2444 QCOMPARE( l->text(), QStringLiteral( "num" ) );
2445 QCOMPARE( l->toolTip(), param.toolTip() );
2446 delete l;
2447 }
2448 else
2449 {
2450 QVERIFY( !l );
2451 }
2452
2453 // check signal
2454 static_cast< QgsScaleWidget * >( wrapper.wrappedWidget() )->setScale( 37.0 );
2455 QCOMPARE( spy.count(), 4 );
2456
2457 delete w;
2458
2459 // optional, no default
2460 QgsProcessingParameterScale paramOptional( QStringLiteral( "num" ), QStringLiteral( "num" ), QVariant(), true );
2461
2462 QgsProcessingScaleWidgetWrapper wrapperOptional( ¶mOptional, type );
2463
2464 w = wrapperOptional.createWrappedWidget( context );
2465 QVERIFY( !wrapperOptional.parameterValue().isValid() );
2466 wrapperOptional.setParameterValue( 5, context );
2467 QCOMPARE( wrapperOptional.parameterValue().toDouble(), 5.0 );
2468 wrapperOptional.setParameterValue( QVariant(), context );
2469 QVERIFY( !wrapperOptional.parameterValue().isValid() );
2470 wrapperOptional.setParameterValue( 5, context );
2471 static_cast< QgsScaleWidget * >( wrapperOptional.wrappedWidget() )->setScale( std::numeric_limits< double >::quiet_NaN() );
2472 QVERIFY( !wrapperOptional.parameterValue().isValid() );
2473
2474 // optional, with default
2475 paramOptional.setDefaultValue( 3 );
2476 QgsProcessingScaleWidgetWrapper wrapperOptionalDefault( ¶mOptional, type );
2477
2478 w = wrapperOptionalDefault.createWrappedWidget( context );
2479 QCOMPARE( wrapperOptionalDefault.parameterValue().toDouble(), 3.0 );
2480 wrapperOptionalDefault.setParameterValue( 5, context );
2481 QCOMPARE( wrapperOptionalDefault.parameterValue().toDouble(), 5.0 );
2482 wrapperOptionalDefault.setParameterValue( QVariant(), context );
2483 QVERIFY( std::isnan( static_cast< QgsScaleWidget * >( wrapperOptionalDefault.wrappedWidget() )->scale() ) );
2484 QVERIFY( !wrapperOptionalDefault.parameterValue().isValid() );
2485 wrapperOptionalDefault.setParameterValue( 5, context );
2486 QCOMPARE( wrapperOptionalDefault.parameterValue().toDouble(), 5.0 );
2487 static_cast< QgsScaleWidget * >( wrapperOptionalDefault.wrappedWidget() )->setScale( std::numeric_limits< double >::quiet_NaN() );
2488 QVERIFY( !wrapperOptionalDefault.parameterValue().isValid() );
2489 wrapperOptionalDefault.setParameterValue( 5, context );
2490 QCOMPARE( wrapperOptionalDefault.parameterValue().toDouble(), 5.0 );
2491
2492 delete w;
2493 };
2494
2495 // standard wrapper
2496 testWrapper( QgsProcessingGui::Standard );
2497
2498 // batch wrapper
2499 testWrapper( QgsProcessingGui::Batch );
2500
2501 // modeler wrapper
2502 testWrapper( QgsProcessingGui::Modeler );
2503
2504 // config widget
2505 QgsProcessingParameterWidgetContext widgetContext;
2506 QgsProcessingContext context;
2507 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "scale" ), context, widgetContext );
2508 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
2509 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
2510 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
2511 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
2512
2513 // using a parameter definition as initial values
2514 QgsProcessingParameterScale scaleParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), 1000 );
2515 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "scale" ), context, widgetContext, &scaleParam );
2516 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
2517 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
2518 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
2519 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
2520 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
2521 QCOMPARE( static_cast< QgsProcessingParameterScale * >( def.get() )->defaultValue().toDouble(), 1000.0 );
2522 scaleParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
2523 scaleParam.setDefaultValue( 28356 );
2524 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "scale" ), context, widgetContext, &scaleParam );
2525 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
2526 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
2527 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
2528 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
2529 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
2530 QCOMPARE( static_cast< QgsProcessingParameterScale * >( def.get() )->defaultValue().toDouble(), 28356.0 );
2531 }
2532
testRangeWrapper()2533 void TestProcessingGui::testRangeWrapper()
2534 {
2535 auto testWrapper = []( QgsProcessingGui::WidgetType type )
2536 {
2537 QgsProcessingContext context;
2538
2539 QgsProcessingParameterRange param( QStringLiteral( "range" ), QStringLiteral( "range" ), QgsProcessingParameterNumber::Double );
2540 param.setDefaultValue( QStringLiteral( "0.0,100.0" ) );
2541 QgsProcessingRangeWidgetWrapper wrapper( ¶m, type );
2542
2543 QWidget *w = wrapper.createWrappedWidget( context );
2544 QVERIFY( w );
2545
2546 // initial value
2547 QCOMPARE( wrapper.parameterValue().toString(), QStringLiteral( "0,100" ) );
2548
2549 QVERIFY( wrapper.mMinSpinBox->expressionsEnabled() );
2550 QVERIFY( wrapper.mMaxSpinBox->expressionsEnabled() );
2551 QCOMPARE( wrapper.mMinSpinBox->decimals(), 6 ); // you can change this, if it's an intentional change!
2552 QCOMPARE( wrapper.mMaxSpinBox->decimals(), 6 ); // you can change this, if it's an intentional change!
2553 QGSCOMPARENEAR( wrapper.mMinSpinBox->minimum(), -99999999.999999, 1 );
2554 QGSCOMPARENEAR( wrapper.mMaxSpinBox->minimum(), -99999999.999999, 1 );
2555 QGSCOMPARENEAR( wrapper.mMinSpinBox->maximum(), 99999999.999999, 1 );
2556 QGSCOMPARENEAR( wrapper.mMaxSpinBox->maximum(), 99999999.999999, 1 );
2557
2558 QSignalSpy spy( &wrapper, &QgsProcessingRangeWidgetWrapper::widgetValueHasChanged );
2559 wrapper.setWidgetValue( QVariantList() << 5 << 7, context );
2560 QCOMPARE( spy.count(), 1 );
2561 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "5,7" ) );
2562 QCOMPARE( wrapper.mMinSpinBox->value(), 5.0 );
2563 QCOMPARE( wrapper.mMaxSpinBox->value(), 7.0 );
2564 wrapper.setWidgetValue( QStringLiteral( "28.1,36.5" ), context );
2565 QCOMPARE( spy.count(), 2 );
2566 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "28.1,36.5" ) );
2567 QCOMPARE( wrapper.mMinSpinBox->value(), 28.1 );
2568 QCOMPARE( wrapper.mMaxSpinBox->value(), 36.5 );
2569
2570 QLabel *l = wrapper.createWrappedLabel();
2571 if ( wrapper.type() != QgsProcessingGui::Batch )
2572 {
2573 QVERIFY( l );
2574 QCOMPARE( l->text(), QStringLiteral( "range" ) );
2575 QCOMPARE( l->toolTip(), param.toolTip() );
2576 delete l;
2577 }
2578 else
2579 {
2580 QVERIFY( !l );
2581 }
2582
2583 // check signal
2584 wrapper.mMinSpinBox->setValue( 7.0 );
2585 QCOMPARE( spy.count(), 3 );
2586 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "7,36.5" ) );
2587 wrapper.mMaxSpinBox->setValue( 9.0 );
2588 QCOMPARE( spy.count(), 4 );
2589 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "7,9" ) );
2590
2591 // check that min/max are mutually adapted
2592 wrapper.setParameterValue( QStringLiteral( "200.0,100.0" ), context );
2593 QCOMPARE( wrapper.parameterValue().toString(), QStringLiteral( "100,100" ) );
2594
2595 wrapper.mMaxSpinBox->setValue( 50 );
2596 QCOMPARE( wrapper.parameterValue().toString(), QStringLiteral( "50,50" ) );
2597 wrapper.mMinSpinBox->setValue( 100 );
2598 QCOMPARE( wrapper.parameterValue().toString(), QStringLiteral( "100,100" ) );
2599
2600 delete w;
2601
2602 // ints
2603 QgsProcessingParameterRange param2( QStringLiteral( "range" ), QStringLiteral( "range" ), QgsProcessingParameterNumber::Integer );
2604 param2.setDefaultValue( QStringLiteral( "0.1,100.1" ) );
2605
2606 QgsProcessingRangeWidgetWrapper wrapper2( ¶m2, type );
2607
2608 w = wrapper2.createWrappedWidget( context );
2609 QVERIFY( w );
2610 QCOMPARE( wrapper2.mMinSpinBox->decimals(), 0 );
2611 QCOMPARE( wrapper2.mMaxSpinBox->decimals(), 0 ); // you can't change this, vampire worms will bite you at night if you do
2612
2613 // check initial value
2614 QCOMPARE( wrapper2.parameterValue().toString(), QStringLiteral( "0,100" ) );
2615 // check rounding
2616 wrapper2.setParameterValue( QStringLiteral( "100.1,200.1" ), context );
2617 QCOMPARE( wrapper2.parameterValue().toString(), QStringLiteral( "100,200" ) );
2618 wrapper2.setParameterValue( QStringLiteral( "100.6,200.6" ), context );
2619 QCOMPARE( wrapper2.parameterValue().toString(), QStringLiteral( "101,201" ) );
2620 // check set/get
2621 wrapper2.setParameterValue( QStringLiteral( "100.1,200.1" ), context );
2622 QCOMPARE( wrapper2.parameterValue().toString(), QStringLiteral( "100,200" ) );
2623 // check that min/max are mutually adapted
2624 wrapper2.setParameterValue( QStringLiteral( "200.1,100.1" ), context );
2625 QCOMPARE( wrapper2.parameterValue().toString(), QStringLiteral( "100,100" ) );
2626 wrapper2.mMaxSpinBox->setValue( 50.1 );
2627 QCOMPARE( wrapper2.parameterValue().toString(), QStringLiteral( "50,50" ) );
2628 wrapper2.mMinSpinBox->setValue( 100.1 );
2629 QCOMPARE( wrapper2.parameterValue().toString(), QStringLiteral( "100,100" ) );
2630
2631 delete w;
2632
2633 // optional
2634 QgsProcessingParameterRange paramOptional( QStringLiteral( "range" ), QStringLiteral( "range" ), QgsProcessingParameterNumber::Double, QVariant(), true );
2635
2636 QgsProcessingRangeWidgetWrapper wrapperOptional( ¶mOptional, type );
2637
2638 w = wrapperOptional.createWrappedWidget( context );
2639 QCOMPARE( wrapperOptional.parameterValue().toString(), QStringLiteral( "None,None" ) );
2640 wrapperOptional.setParameterValue( QStringLiteral( "1,100" ), context );
2641 QCOMPARE( wrapperOptional.parameterValue().toString(), QStringLiteral( "1,100" ) );
2642 wrapperOptional.setParameterValue( QStringLiteral( "None,100" ), context );
2643 QCOMPARE( wrapperOptional.parameterValue().toString(), QStringLiteral( "None,100" ) );
2644 wrapperOptional.setParameterValue( QStringLiteral( "1,None" ), context );
2645 QCOMPARE( wrapperOptional.parameterValue().toString(), QStringLiteral( "1,None" ) );
2646 wrapperOptional.setParameterValue( QStringLiteral( "None,None" ), context );
2647 QCOMPARE( wrapperOptional.parameterValue().toString(), QStringLiteral( "None,None" ) );
2648 wrapperOptional.setParameterValue( QStringLiteral( "None" ), context );
2649 QCOMPARE( wrapperOptional.parameterValue().toString(), QStringLiteral( "None,None" ) );
2650 wrapperOptional.setParameterValue( QVariant(), context );
2651 QCOMPARE( wrapperOptional.parameterValue().toString(), QStringLiteral( "None,None" ) );
2652
2653 delete w;
2654 };
2655
2656 // standard wrapper
2657 testWrapper( QgsProcessingGui::Standard );
2658
2659 // batch wrapper
2660 testWrapper( QgsProcessingGui::Batch );
2661
2662 // modeler wrapper
2663 testWrapper( QgsProcessingGui::Modeler );
2664
2665 // config widget
2666 QgsProcessingParameterWidgetContext widgetContext;
2667 QgsProcessingContext context;
2668 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "range" ), context, widgetContext );
2669 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
2670 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
2671 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
2672 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
2673
2674 // using a parameter definition as initial values
2675 QgsProcessingParameterRange rangeParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), QgsProcessingParameterNumber::Integer, QStringLiteral( "0,255" ) );
2676 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "range" ), context, widgetContext, &rangeParam );
2677 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
2678 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
2679 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
2680 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
2681 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
2682 QCOMPARE( static_cast< QgsProcessingParameterRange * >( def.get() )->defaultValue().toString(), QStringLiteral( "0,255" ) );
2683 QCOMPARE( static_cast< QgsProcessingParameterRange * >( def.get() )->dataType(), QgsProcessingParameterNumber::Integer );
2684 rangeParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
2685 rangeParam.setDataType( QgsProcessingParameterNumber::Double );
2686 rangeParam.setDefaultValue( QStringLiteral( "0,1" ) );
2687 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "range" ), context, widgetContext, &rangeParam );
2688 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
2689 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
2690 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
2691 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
2692 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
2693 QCOMPARE( static_cast< QgsProcessingParameterRange * >( def.get() )->defaultValue().toString(), QStringLiteral( "0,1" ) );
2694 QCOMPARE( static_cast< QgsProcessingParameterRange * >( def.get() )->dataType(), QgsProcessingParameterNumber::Double );
2695 }
2696
testMatrixDialog()2697 void TestProcessingGui::testMatrixDialog()
2698 {
2699 QgsProcessingParameterMatrix matrixParam( QString(), QString(), 3, false, QStringList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) );
2700 std::unique_ptr< QgsProcessingMatrixParameterPanelWidget > dlg = std::make_unique< QgsProcessingMatrixParameterPanelWidget>( nullptr, &matrixParam );
2701 // variable length table
2702 QVERIFY( dlg->mButtonAdd->isEnabled() );
2703 QVERIFY( dlg->mButtonRemove->isEnabled() );
2704 QVERIFY( dlg->mButtonRemoveAll->isEnabled() );
2705
2706 QCOMPARE( dlg->table(), QVariantList() );
2707
2708 dlg = std::make_unique< QgsProcessingMatrixParameterPanelWidget >( nullptr, &matrixParam, QVariantList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) << QStringLiteral( "c" ) << QStringLiteral( "d" ) << QStringLiteral( "e" ) << QStringLiteral( "f" ) );
2709 QCOMPARE( dlg->table(), QVariantList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) << QStringLiteral( "c" ) << QStringLiteral( "d" ) << QStringLiteral( "e" ) << QStringLiteral( "f" ) );
2710 dlg->addRow();
2711 QCOMPARE( dlg->table(), QVariantList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) << QStringLiteral( "c" ) << QStringLiteral( "d" ) << QStringLiteral( "e" ) << QStringLiteral( "f" ) << QString() << QString() );
2712 dlg->deleteAllRows();
2713 QCOMPARE( dlg->table(), QVariantList() );
2714
2715 QgsProcessingParameterMatrix matrixParam2( QString(), QString(), 3, true, QStringList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) );
2716 dlg = std::make_unique< QgsProcessingMatrixParameterPanelWidget >( nullptr, &matrixParam2, QVariantList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) << QStringLiteral( "c" ) << QStringLiteral( "d" ) << QStringLiteral( "e" ) << QStringLiteral( "f" ) );
2717 QVERIFY( !dlg->mButtonAdd->isEnabled() );
2718 QVERIFY( !dlg->mButtonRemove->isEnabled() );
2719 QVERIFY( !dlg->mButtonRemoveAll->isEnabled() );
2720 }
2721
testMatrixWrapper()2722 void TestProcessingGui::testMatrixWrapper()
2723 {
2724 auto testWrapper = []( QgsProcessingGui::WidgetType type )
2725 {
2726 QgsProcessingContext context;
2727
2728 QgsProcessingParameterMatrix param( QStringLiteral( "matrix" ), QStringLiteral( "matrix" ), 3, false, QStringList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) );
2729 param.setDefaultValue( QStringLiteral( "0.0,100.0,150.0,250.0" ) );
2730 QgsProcessingMatrixWidgetWrapper wrapper( ¶m, type );
2731
2732 QWidget *w = wrapper.createWrappedWidget( context );
2733 QVERIFY( w );
2734
2735 // initial value
2736 QCOMPARE( wrapper.parameterValue().toList(), QVariantList() << QStringLiteral( "0.0" ) << QStringLiteral( "100.0" ) << QStringLiteral( "150.0" ) << QStringLiteral( "250.0" ) );
2737
2738 QSignalSpy spy( &wrapper, &QgsProcessingMatrixWidgetWrapper::widgetValueHasChanged );
2739 wrapper.setWidgetValue( QVariantList() << 5 << 7, context );
2740 QCOMPARE( spy.count(), 1 );
2741 QCOMPARE( wrapper.widgetValue().toList(), QVariantList() << QStringLiteral( "5" ) << QStringLiteral( "7" ) );
2742 QCOMPARE( wrapper.mMatrixWidget->value(), QVariantList() << QStringLiteral( "5" ) << QStringLiteral( "7" ) );
2743 wrapper.setWidgetValue( QStringLiteral( "28.1,36.5,5.5,8.9" ), context );
2744 QCOMPARE( spy.count(), 2 );
2745 QCOMPARE( wrapper.widgetValue().toList(), QVariantList() << QStringLiteral( "28.1" ) << QStringLiteral( "36.5" ) << QStringLiteral( "5.5" ) << QStringLiteral( "8.9" ) );
2746 QCOMPARE( wrapper.mMatrixWidget->value(), QVariantList() << QStringLiteral( "28.1" ) << QStringLiteral( "36.5" ) << QStringLiteral( "5.5" ) << QStringLiteral( "8.9" ) );
2747
2748 QLabel *l = wrapper.createWrappedLabel();
2749 if ( wrapper.type() != QgsProcessingGui::Batch )
2750 {
2751 QVERIFY( l );
2752 QCOMPARE( l->text(), QStringLiteral( "matrix" ) );
2753 QCOMPARE( l->toolTip(), param.toolTip() );
2754 delete l;
2755 }
2756 else
2757 {
2758 QVERIFY( !l );
2759 }
2760
2761 // check signal
2762 wrapper.mMatrixWidget->setValue( QVariantList() << QStringLiteral( "7" ) << QStringLiteral( "9" ) );
2763 QCOMPARE( spy.count(), 3 );
2764 QCOMPARE( wrapper.widgetValue().toList(), QVariantList() << QStringLiteral( "7" ) << QStringLiteral( "9" ) );
2765
2766 delete w;
2767 };
2768
2769 // standard wrapper
2770 testWrapper( QgsProcessingGui::Standard );
2771
2772 // batch wrapper
2773 testWrapper( QgsProcessingGui::Batch );
2774
2775 // modeler wrapper
2776 testWrapper( QgsProcessingGui::Modeler );
2777
2778 // config widget
2779 QgsProcessingParameterWidgetContext widgetContext;
2780 QgsProcessingContext context;
2781 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "matrix" ), context, widgetContext );
2782 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
2783 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
2784 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
2785 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
2786
2787 // using a parameter definition as initial values
2788 QgsProcessingParameterMatrix matrixParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), 1, false, QStringList() << "A" << "B" << "C", QVariantList() << 0 << 0 << 0 );
2789 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "matrix" ), context, widgetContext, &matrixParam );
2790 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
2791 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
2792 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
2793 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
2794 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
2795 QCOMPARE( static_cast< QgsProcessingParameterMatrix * >( def.get() )->headers(), QStringList() << "A" << "B" << "C" );
2796 QCOMPARE( static_cast< QgsProcessingParameterMatrix * >( def.get() )->defaultValue().toStringList(), QStringList() << "0" << "0" << "0" );
2797 QVERIFY( !static_cast< QgsProcessingParameterMatrix * >( def.get() )->hasFixedNumberRows() );
2798 matrixParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
2799 matrixParam.setHasFixedNumberRows( true );
2800 matrixParam.setDefaultValue( QVariantList() << 1 << 2 << 3 );
2801 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "matrix" ), context, widgetContext, &matrixParam );
2802 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
2803 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
2804 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
2805 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
2806 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
2807 QCOMPARE( static_cast< QgsProcessingParameterMatrix * >( def.get() )->headers(), QStringList() << "A" << "B" << "C" );
2808 QCOMPARE( static_cast< QgsProcessingParameterMatrix * >( def.get() )->defaultValue().toStringList(), QStringList() << "1" << "2" << "3" );
2809 QVERIFY( static_cast< QgsProcessingParameterMatrix * >( def.get() )->hasFixedNumberRows() );
2810 }
2811
testExpressionWrapper()2812 void TestProcessingGui::testExpressionWrapper()
2813 {
2814 const QgsProcessingAlgorithm *centroidAlg = QgsApplication::processingRegistry()->algorithmById( QStringLiteral( "native:centroids" ) );
2815 const QgsProcessingParameterDefinition *layerDef = centroidAlg->parameterDefinition( QStringLiteral( "INPUT" ) );
2816
2817 auto testWrapper = [layerDef]( QgsProcessingGui::WidgetType type )
2818 {
2819 QgsProcessingParameterExpression param( QStringLiteral( "expression" ), QStringLiteral( "expression" ) );
2820
2821 QgsProcessingExpressionWidgetWrapper wrapper( ¶m, type );
2822
2823 QgsProcessingContext context;
2824 QWidget *w = wrapper.createWrappedWidget( context );
2825
2826 QSignalSpy spy( &wrapper, &QgsProcessingExpressionWidgetWrapper::widgetValueHasChanged );
2827 wrapper.setWidgetValue( QStringLiteral( "1+2" ), context );
2828 QCOMPARE( spy.count(), 1 );
2829 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "1+2" ) );
2830 QCOMPARE( static_cast< QgsExpressionLineEdit * >( wrapper.wrappedWidget() )->expression(), QStringLiteral( "1+2" ) );
2831 wrapper.setWidgetValue( QString(), context );
2832 QCOMPARE( spy.count(), 2 );
2833 QVERIFY( wrapper.widgetValue().toString().isEmpty() );
2834 QVERIFY( static_cast< QgsExpressionLineEdit * >( wrapper.wrappedWidget() )->expression().isEmpty() );
2835
2836 QLabel *l = wrapper.createWrappedLabel();
2837 if ( wrapper.type() != QgsProcessingGui::Batch )
2838 {
2839 QVERIFY( l );
2840 QCOMPARE( l->text(), QStringLiteral( "expression" ) );
2841 QCOMPARE( l->toolTip(), param.toolTip() );
2842 delete l;
2843 }
2844 else
2845 {
2846 QVERIFY( !l );
2847 }
2848
2849 // check signal
2850 static_cast< QgsExpressionLineEdit * >( wrapper.wrappedWidget() )->setExpression( QStringLiteral( "3+4" ) );
2851 QCOMPARE( spy.count(), 3 );
2852
2853 delete w;
2854
2855 // with layer
2856 param.setParentLayerParameterName( QStringLiteral( "other" ) );
2857 QgsProcessingExpressionWidgetWrapper wrapper2( ¶m, type );
2858 w = wrapper2.createWrappedWidget( context );
2859
2860 QSignalSpy spy2( &wrapper2, &QgsProcessingExpressionWidgetWrapper::widgetValueHasChanged );
2861 wrapper2.setWidgetValue( QStringLiteral( "11+12" ), context );
2862 QCOMPARE( spy2.count(), 1 );
2863 QCOMPARE( wrapper2.widgetValue().toString(), QStringLiteral( "11+12" ) );
2864 QCOMPARE( static_cast< QgsFieldExpressionWidget * >( wrapper2.wrappedWidget() )->expression(), QStringLiteral( "11+12" ) );
2865
2866 wrapper2.setWidgetValue( QString(), context );
2867 QCOMPARE( spy2.count(), 2 );
2868 QVERIFY( wrapper2.widgetValue().toString().isEmpty() );
2869 QVERIFY( static_cast< QgsFieldExpressionWidget * >( wrapper2.wrappedWidget() )->expression().isEmpty() );
2870
2871 static_cast< QgsFieldExpressionWidget * >( wrapper2.wrappedWidget() )->setExpression( QStringLiteral( "3+4" ) );
2872 QCOMPARE( spy2.count(), 3 );
2873
2874 TestLayerWrapper layerWrapper( layerDef );
2875 QgsProject p;
2876 QgsVectorLayer *vl = new QgsVectorLayer( QStringLiteral( "LineString" ), QStringLiteral( "x" ), QStringLiteral( "memory" ) );
2877 p.addMapLayer( vl );
2878
2879 QVERIFY( !wrapper2.mFieldExpWidget->layer() );
2880 layerWrapper.setWidgetValue( QVariant::fromValue( vl ), context );
2881 wrapper2.setParentLayerWrapperValue( &layerWrapper );
2882 QCOMPARE( wrapper2.mFieldExpWidget->layer(), vl );
2883
2884 // should not be owned by wrapper
2885 QVERIFY( !wrapper2.mParentLayer.get() );
2886 layerWrapper.setWidgetValue( QVariant(), context );
2887 wrapper2.setParentLayerWrapperValue( &layerWrapper );
2888 QVERIFY( !wrapper2.mFieldExpWidget->layer() );
2889
2890 layerWrapper.setWidgetValue( vl->id(), context );
2891 wrapper2.setParentLayerWrapperValue( &layerWrapper );
2892 QVERIFY( !wrapper2.mFieldExpWidget->layer() );
2893 QVERIFY( !wrapper2.mParentLayer.get() );
2894
2895 // with project layer
2896 context.setProject( &p );
2897 TestProcessingContextGenerator generator( context );
2898 wrapper2.registerProcessingContextGenerator( &generator );
2899
2900 layerWrapper.setWidgetValue( vl->id(), context );
2901 wrapper2.setParentLayerWrapperValue( &layerWrapper );
2902 QCOMPARE( wrapper2.mFieldExpWidget->layer(), vl );
2903 QVERIFY( !wrapper2.mParentLayer.get() );
2904
2905 // non-project layer
2906 QString pointFileName = TEST_DATA_DIR + QStringLiteral( "/points.shp" );
2907 layerWrapper.setWidgetValue( pointFileName, context );
2908 wrapper2.setParentLayerWrapperValue( &layerWrapper );
2909 QCOMPARE( wrapper2.mFieldExpWidget->layer()->publicSource(), pointFileName );
2910 // must be owned by wrapper, or layer may be deleted while still required by wrapper
2911 QCOMPARE( wrapper2.mParentLayer->publicSource(), pointFileName );
2912 };
2913
2914 // standard wrapper
2915 testWrapper( QgsProcessingGui::Standard );
2916
2917 // batch wrapper
2918 testWrapper( QgsProcessingGui::Batch );
2919
2920 // modeler wrapper
2921 testWrapper( QgsProcessingGui::Modeler );
2922
2923 // config widget
2924 QgsProcessingParameterWidgetContext widgetContext;
2925 QgsProcessingContext context;
2926 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "expression" ), context, widgetContext );
2927 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
2928 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
2929 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
2930 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
2931
2932 // using a parameter definition as initial values
2933 QgsProcessingParameterExpression exprParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), QVariant(), QStringLiteral( "parent" ) );
2934 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "expression" ), context, widgetContext, &exprParam );
2935 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
2936 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
2937 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
2938 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
2939 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
2940 QCOMPARE( static_cast< QgsProcessingParameterExpression * >( def.get() )->parentLayerParameterName(), QStringLiteral( "parent" ) );
2941 exprParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
2942 exprParam.setParentLayerParameterName( QString() );
2943 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "expression" ), context, widgetContext, &exprParam );
2944 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
2945 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
2946 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
2947 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
2948 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
2949 QVERIFY( static_cast< QgsProcessingParameterExpression * >( def.get() )->parentLayerParameterName().isEmpty() );
2950 }
2951
testFieldSelectionPanel()2952 void TestProcessingGui::testFieldSelectionPanel()
2953 {
2954 QgsProcessingParameterField fieldParam( QString(), QString(), QVariant(), QStringLiteral( "INPUT" ), QgsProcessingParameterField::Any, true );
2955 QgsProcessingFieldPanelWidget w( nullptr, &fieldParam );
2956 QSignalSpy spy( &w, &QgsProcessingFieldPanelWidget::changed );
2957
2958 QCOMPARE( w.mLineEdit->text(), QStringLiteral( "0 options selected" ) );
2959 w.setValue( QStringLiteral( "aa" ) );
2960 QCOMPARE( spy.count(), 1 );
2961 QCOMPARE( w.value().toList(), QVariantList() << QStringLiteral( "aa" ) );
2962 QCOMPARE( w.mLineEdit->text(), QStringLiteral( "1 options selected" ) );
2963
2964 w.setValue( QVariantList() << QStringLiteral( "bb" ) << QStringLiteral( "aa" ) );
2965 QCOMPARE( spy.count(), 2 );
2966 QCOMPARE( w.value().toList(), QVariantList() << QStringLiteral( "bb" ) << QStringLiteral( "aa" ) );
2967 QCOMPARE( w.mLineEdit->text(), QStringLiteral( "2 options selected" ) );
2968
2969 w.setValue( QVariant() );
2970 QCOMPARE( spy.count(), 3 );
2971 QCOMPARE( w.value().toList(), QVariantList() );
2972 QCOMPARE( w.mLineEdit->text(), QStringLiteral( "0 options selected" ) );
2973
2974 }
2975
testFieldWrapper()2976 void TestProcessingGui::testFieldWrapper()
2977 {
2978 const QgsProcessingAlgorithm *centroidAlg = QgsApplication::processingRegistry()->algorithmById( QStringLiteral( "native:centroids" ) );
2979 const QgsProcessingParameterDefinition *layerDef = centroidAlg->parameterDefinition( QStringLiteral( "INPUT" ) );
2980
2981 auto testWrapper = [layerDef]( QgsProcessingGui::WidgetType type )
2982 {
2983 TestLayerWrapper layerWrapper( layerDef );
2984 QgsProject p;
2985 QgsVectorLayer *vl = new QgsVectorLayer( QStringLiteral( "LineString?field=aaa:int&field=bbb:string" ), QStringLiteral( "x" ), QStringLiteral( "memory" ) );
2986 p.addMapLayer( vl );
2987
2988 QgsProcessingParameterField param( QStringLiteral( "field" ), QStringLiteral( "field" ), QVariant(), QStringLiteral( "INPUT" ) );
2989
2990 QgsProcessingFieldWidgetWrapper wrapper( ¶m, type );
2991
2992 QgsProcessingContext context;
2993
2994 QWidget *w = wrapper.createWrappedWidget( context );
2995 ( void )w;
2996 layerWrapper.setWidgetValue( QVariant::fromValue( vl ), context );
2997 wrapper.setParentLayerWrapperValue( &layerWrapper );
2998
2999 QSignalSpy spy( &wrapper, &QgsProcessingFieldWidgetWrapper::widgetValueHasChanged );
3000 wrapper.setWidgetValue( QStringLiteral( "bbb" ), context );
3001 QCOMPARE( spy.count(), 1 );
3002 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "bbb" ) );
3003
3004 switch ( type )
3005 {
3006 case QgsProcessingGui::Standard:
3007 case QgsProcessingGui::Batch:
3008 QCOMPARE( static_cast< QgsFieldComboBox * >( wrapper.wrappedWidget() )->currentField(), QStringLiteral( "bbb" ) );
3009 break;
3010
3011 case QgsProcessingGui::Modeler:
3012 QCOMPARE( static_cast< QLineEdit * >( wrapper.wrappedWidget() )->text(), QStringLiteral( "bbb" ) );
3013 break;
3014 }
3015
3016 wrapper.setWidgetValue( QString(), context );
3017 QCOMPARE( spy.count(), 2 );
3018 QVERIFY( wrapper.widgetValue().toString().isEmpty() );
3019
3020 delete w;
3021
3022 // optional
3023 param = QgsProcessingParameterField( QStringLiteral( "field" ), QStringLiteral( "field" ), QVariant(), QStringLiteral( "INPUT" ), QgsProcessingParameterField::Any, false, true );
3024
3025 QgsProcessingFieldWidgetWrapper wrapper2( ¶m, type );
3026
3027 w = wrapper2.createWrappedWidget( context );
3028 layerWrapper.setWidgetValue( QVariant::fromValue( vl ), context );
3029 wrapper2.setParentLayerWrapperValue( &layerWrapper );
3030 QSignalSpy spy2( &wrapper2, &QgsProcessingFieldWidgetWrapper::widgetValueHasChanged );
3031 wrapper2.setWidgetValue( QStringLiteral( "aaa" ), context );
3032 QCOMPARE( spy2.count(), 1 );
3033 QCOMPARE( wrapper2.widgetValue().toString(), QStringLiteral( "aaa" ) );
3034
3035 wrapper2.setWidgetValue( QString(), context );
3036 QCOMPARE( spy2.count(), 2 );
3037 QVERIFY( wrapper2.widgetValue().toString().isEmpty() );
3038
3039 switch ( type )
3040 {
3041 case QgsProcessingGui::Standard:
3042 case QgsProcessingGui::Batch:
3043 QCOMPARE( static_cast< QgsFieldComboBox * >( wrapper2.wrappedWidget() )->currentField(), QString() );
3044 break;
3045
3046 case QgsProcessingGui::Modeler:
3047 QCOMPARE( static_cast< QLineEdit * >( wrapper2.wrappedWidget() )->text(), QString() );
3048 break;
3049 }
3050
3051 QLabel *l = wrapper.createWrappedLabel();
3052 if ( wrapper.type() != QgsProcessingGui::Batch )
3053 {
3054 QVERIFY( l );
3055 QCOMPARE( l->text(), QStringLiteral( "field [optional]" ) );
3056 QCOMPARE( l->toolTip(), param.toolTip() );
3057 delete l;
3058 }
3059 else
3060 {
3061 QVERIFY( !l );
3062 }
3063
3064 // check signal
3065 switch ( type )
3066 {
3067 case QgsProcessingGui::Standard:
3068 case QgsProcessingGui::Batch:
3069 static_cast< QgsFieldComboBox * >( wrapper2.wrappedWidget() )->setField( QStringLiteral( "bbb" ) );
3070 break;
3071
3072 case QgsProcessingGui::Modeler:
3073 static_cast< QLineEdit * >( wrapper2.wrappedWidget() )->setText( QStringLiteral( "bbb" ) );
3074 break;
3075 }
3076
3077 QCOMPARE( spy2.count(), 3 );
3078
3079 switch ( type )
3080 {
3081 case QgsProcessingGui::Standard:
3082 case QgsProcessingGui::Batch:
3083 QCOMPARE( wrapper2.mComboBox->layer(), vl );
3084 break;
3085
3086 case QgsProcessingGui::Modeler:
3087 break;
3088 }
3089
3090 // should not be owned by wrapper
3091 QVERIFY( !wrapper2.mParentLayer.get() );
3092 layerWrapper.setWidgetValue( QVariant(), context );
3093 wrapper2.setParentLayerWrapperValue( &layerWrapper );
3094
3095 switch ( type )
3096 {
3097 case QgsProcessingGui::Standard:
3098 case QgsProcessingGui::Batch:
3099 QVERIFY( !wrapper2.mComboBox->layer() );
3100 break;
3101
3102 case QgsProcessingGui::Modeler:
3103 break;
3104 }
3105
3106 layerWrapper.setWidgetValue( vl->id(), context );
3107 wrapper2.setParentLayerWrapperValue( &layerWrapper );
3108 switch ( type )
3109 {
3110 case QgsProcessingGui::Standard:
3111 case QgsProcessingGui::Batch:
3112 QVERIFY( !wrapper2.mComboBox->layer() );
3113 break;
3114
3115 case QgsProcessingGui::Modeler:
3116 break;
3117 }
3118 QVERIFY( !wrapper2.mParentLayer.get() );
3119
3120 // with project layer
3121 context.setProject( &p );
3122 TestProcessingContextGenerator generator( context );
3123 wrapper2.registerProcessingContextGenerator( &generator );
3124
3125 layerWrapper.setWidgetValue( vl->id(), context );
3126 wrapper2.setParentLayerWrapperValue( &layerWrapper );
3127 switch ( type )
3128 {
3129 case QgsProcessingGui::Standard:
3130 case QgsProcessingGui::Batch:
3131 QCOMPARE( wrapper2.mComboBox->layer(), vl );
3132 break;
3133
3134 case QgsProcessingGui::Modeler:
3135 break;
3136 }
3137 QVERIFY( !wrapper2.mParentLayer.get() );
3138
3139 // non-project layer
3140 QString pointFileName = TEST_DATA_DIR + QStringLiteral( "/points.shp" );
3141 layerWrapper.setWidgetValue( pointFileName, context );
3142 wrapper2.setParentLayerWrapperValue( &layerWrapper );
3143 switch ( type )
3144 {
3145 case QgsProcessingGui::Standard:
3146 case QgsProcessingGui::Batch:
3147 QCOMPARE( wrapper2.mComboBox->layer()->publicSource(), pointFileName );
3148 break;
3149
3150 case QgsProcessingGui::Modeler:
3151 break;
3152 }
3153
3154 // must be owned by wrapper, or layer may be deleted while still required by wrapper
3155 QCOMPARE( wrapper2.mParentLayer->publicSource(), pointFileName );
3156
3157 delete w;
3158
3159 // multiple
3160 param = QgsProcessingParameterField( QStringLiteral( "field" ), QStringLiteral( "field" ), QVariant(), QStringLiteral( "INPUT" ), QgsProcessingParameterField::Any, true, true );
3161
3162 QgsProcessingFieldWidgetWrapper wrapper3( ¶m, type );
3163
3164 w = wrapper3.createWrappedWidget( context );
3165 layerWrapper.setWidgetValue( QVariant::fromValue( vl ), context );
3166 wrapper3.setParentLayerWrapperValue( &layerWrapper );
3167 QSignalSpy spy3( &wrapper3, &QgsProcessingFieldWidgetWrapper::widgetValueHasChanged );
3168 wrapper3.setWidgetValue( QStringLiteral( "aaa" ), context );
3169 QCOMPARE( spy3.count(), 1 );
3170 QCOMPARE( wrapper3.widgetValue().toStringList(), QStringList() << QStringLiteral( "aaa" ) );
3171
3172 wrapper3.setWidgetValue( QString(), context );
3173 QCOMPARE( spy3.count(), 2 );
3174 QVERIFY( wrapper3.widgetValue().toString().isEmpty() );
3175
3176 wrapper3.setWidgetValue( QStringLiteral( "aaa;bbb" ), context );
3177 QCOMPARE( spy3.count(), 3 );
3178 QCOMPARE( wrapper3.widgetValue().toStringList(), QStringList() << QStringLiteral( "aaa" ) << QStringLiteral( "bbb" ) );
3179
3180 delete w;
3181
3182 // filtering fields
3183 QgsFields f;
3184 f.append( QgsField( QStringLiteral( "string" ), QVariant::String ) );
3185 f.append( QgsField( QStringLiteral( "double" ), QVariant::Double ) );
3186 f.append( QgsField( QStringLiteral( "int" ), QVariant::Int ) );
3187 f.append( QgsField( QStringLiteral( "date" ), QVariant::Date ) );
3188 f.append( QgsField( QStringLiteral( "time" ), QVariant::Time ) );
3189 f.append( QgsField( QStringLiteral( "datetime" ), QVariant::DateTime ) );
3190
3191 QgsFields f2 = wrapper3.filterFields( f );
3192 QCOMPARE( f2, f );
3193
3194 // string fields
3195 param = QgsProcessingParameterField( QStringLiteral( "field" ), QStringLiteral( "field" ), QVariant(), QStringLiteral( "INPUT" ), QgsProcessingParameterField::String, false, true );
3196 QgsProcessingFieldWidgetWrapper wrapper4( ¶m, type );
3197 w = wrapper4.createWrappedWidget( context );
3198 switch ( type )
3199 {
3200 case QgsProcessingGui::Standard:
3201 case QgsProcessingGui::Batch:
3202 QCOMPARE( static_cast< QgsFieldComboBox * >( wrapper4.wrappedWidget() )->filters(), QgsFieldProxyModel::String );
3203 break;
3204
3205 case QgsProcessingGui::Modeler:
3206 break;
3207 }
3208 f2 = wrapper4.filterFields( f );
3209 QCOMPARE( f2.size(), 1 );
3210 QCOMPARE( f2.at( 0 ).name(), QStringLiteral( "string" ) );
3211 delete w;
3212
3213 // string, multiple
3214 param = QgsProcessingParameterField( QStringLiteral( "field" ), QStringLiteral( "field" ), QVariant(), QStringLiteral( "INPUT" ), QgsProcessingParameterField::String, true, true );
3215 QgsProcessingFieldWidgetWrapper wrapper4a( ¶m, type );
3216 w = wrapper4a.createWrappedWidget( context );
3217 wrapper4a.setParentLayerWrapperValue( &layerWrapper );
3218 switch ( type )
3219 {
3220 case QgsProcessingGui::Standard:
3221 case QgsProcessingGui::Batch:
3222 QCOMPARE( wrapper4a.mPanel->fields().count(), 1 );
3223 QCOMPARE( wrapper4a.mPanel->fields().at( 0 ).name(), QStringLiteral( "bbb" ) );
3224 break;
3225
3226 case QgsProcessingGui::Modeler:
3227 break;
3228 }
3229 delete w;
3230
3231 // numeric fields
3232 param = QgsProcessingParameterField( QStringLiteral( "field" ), QStringLiteral( "field" ), QVariant(), QStringLiteral( "INPUT" ), QgsProcessingParameterField::Numeric, false, true );
3233 QgsProcessingFieldWidgetWrapper wrapper5( ¶m, type );
3234 w = wrapper5.createWrappedWidget( context );
3235 switch ( type )
3236 {
3237 case QgsProcessingGui::Standard:
3238 case QgsProcessingGui::Batch:
3239 QCOMPARE( static_cast< QgsFieldComboBox * >( wrapper5.wrappedWidget() )->filters(), QgsFieldProxyModel::Numeric );
3240 break;
3241
3242 case QgsProcessingGui::Modeler:
3243 break;
3244 }
3245 f2 = wrapper5.filterFields( f );
3246 QCOMPARE( f2.size(), 2 );
3247 QCOMPARE( f2.at( 0 ).name(), QStringLiteral( "double" ) );
3248 QCOMPARE( f2.at( 1 ).name(), QStringLiteral( "int" ) );
3249
3250 delete w;
3251
3252 // numeric, multiple
3253 param = QgsProcessingParameterField( QStringLiteral( "field" ), QStringLiteral( "field" ), QVariant(), QStringLiteral( "INPUT" ), QgsProcessingParameterField::Numeric, true, true );
3254 QgsProcessingFieldWidgetWrapper wrapper5a( ¶m, type );
3255 w = wrapper5a.createWrappedWidget( context );
3256 wrapper5a.setParentLayerWrapperValue( &layerWrapper );
3257 switch ( type )
3258 {
3259 case QgsProcessingGui::Standard:
3260 case QgsProcessingGui::Batch:
3261 QCOMPARE( wrapper5a.mPanel->fields().count(), 1 );
3262 QCOMPARE( wrapper5a.mPanel->fields().at( 0 ).name(), QStringLiteral( "aaa" ) );
3263 break;
3264
3265 case QgsProcessingGui::Modeler:
3266 break;
3267 }
3268 delete w;
3269
3270 // datetime fields
3271 param = QgsProcessingParameterField( QStringLiteral( "field" ), QStringLiteral( "field" ), QVariant(), QStringLiteral( "INPUT" ), QgsProcessingParameterField::DateTime, false, true );
3272 QgsProcessingFieldWidgetWrapper wrapper6( ¶m, type );
3273 w = wrapper6.createWrappedWidget( context );
3274 switch ( type )
3275 {
3276 case QgsProcessingGui::Standard:
3277 case QgsProcessingGui::Batch:
3278 QCOMPARE( static_cast< QgsFieldComboBox * >( wrapper6.wrappedWidget() )->filters(), QgsFieldProxyModel::Date | QgsFieldProxyModel::Time | QgsFieldProxyModel::DateTime );
3279 break;
3280
3281 case QgsProcessingGui::Modeler:
3282 break;
3283 }
3284 f2 = wrapper6.filterFields( f );
3285 QCOMPARE( f2.size(), 3 );
3286 QCOMPARE( f2.at( 0 ).name(), QStringLiteral( "date" ) );
3287 QCOMPARE( f2.at( 1 ).name(), QStringLiteral( "time" ) );
3288 QCOMPARE( f2.at( 2 ).name(), QStringLiteral( "datetime" ) );
3289
3290
3291 // default to all fields
3292 param = QgsProcessingParameterField( QStringLiteral( "field" ), QStringLiteral( "field" ), QVariant(), QStringLiteral( "INPUT" ), QgsProcessingParameterField::Any, true, true );
3293 param.setDefaultToAllFields( true );
3294 QgsProcessingFieldWidgetWrapper wrapper7( ¶m, type );
3295 w = wrapper7.createWrappedWidget( context );
3296 wrapper7.setParentLayerWrapperValue( &layerWrapper );
3297 switch ( type )
3298 {
3299 case QgsProcessingGui::Standard:
3300 case QgsProcessingGui::Batch:
3301 QCOMPARE( wrapper7.widgetValue().toList(), QVariantList() << QStringLiteral( "aaa" ) << QStringLiteral( "bbb" ) );
3302 break;
3303
3304 case QgsProcessingGui::Modeler:
3305 break;
3306 }
3307 delete w;
3308
3309 // MultipleLayers as parent layer
3310 QgsVectorLayer *vl2 = new QgsVectorLayer( QStringLiteral( "LineString?field=bbb:string" ), QStringLiteral( "y" ), QStringLiteral( "memory" ) );
3311 p.addMapLayer( vl2 );
3312
3313 QgsProcessingFieldWidgetWrapper wrapper8( ¶m, type );
3314 wrapper8.registerProcessingContextGenerator( &generator );
3315 w = wrapper8.createWrappedWidget( context );
3316 layerWrapper.setWidgetValue( QVariantList() << vl->id() << vl2->id(), context );
3317 wrapper8.setParentLayerWrapperValue( &layerWrapper );
3318
3319 switch ( type )
3320 {
3321 case QgsProcessingGui::Standard:
3322 case QgsProcessingGui::Batch:
3323 QCOMPARE( wrapper8.widgetValue().toList(), QVariantList() << QStringLiteral( "bbb" ) );
3324 break;
3325
3326 case QgsProcessingGui::Modeler:
3327 break;
3328 }
3329 delete w;
3330 };
3331
3332 // standard wrapper
3333 testWrapper( QgsProcessingGui::Standard );
3334
3335 // batch wrapper
3336 testWrapper( QgsProcessingGui::Batch );
3337
3338 // modeler wrapper
3339 testWrapper( QgsProcessingGui::Modeler );
3340
3341 // config widget
3342 QgsProcessingParameterWidgetContext widgetContext;
3343 QgsProcessingContext context;
3344 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "field" ), context, widgetContext );
3345 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
3346 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
3347 QVERIFY( !def->defaultValue().isValid() );
3348 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
3349 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
3350
3351 // using a parameter definition as initial values
3352 QgsProcessingParameterField fieldParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), QStringLiteral( "field_name" ), QStringLiteral( "parent" ) );
3353 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "field" ), context, widgetContext, &fieldParam );
3354 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
3355 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
3356 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
3357 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
3358 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
3359 QCOMPARE( static_cast< QgsProcessingParameterField * >( def.get() )->defaultValue().toString(), QStringLiteral( "field_name" ) );
3360 QCOMPARE( static_cast< QgsProcessingParameterField * >( def.get() )->parentLayerParameterName(), QStringLiteral( "parent" ) );
3361 QCOMPARE( static_cast< QgsProcessingParameterField * >( def.get() )->dataType(), QgsProcessingParameterField::Any );
3362 QCOMPARE( static_cast< QgsProcessingParameterField * >( def.get() )->allowMultiple(), false );
3363 QCOMPARE( static_cast< QgsProcessingParameterField * >( def.get() )->defaultToAllFields(), false );
3364 fieldParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
3365 fieldParam.setParentLayerParameterName( QString() );
3366 fieldParam.setAllowMultiple( true );
3367 fieldParam.setDefaultToAllFields( true );
3368 fieldParam.setDataType( QgsProcessingParameterField::String );
3369 fieldParam.setDefaultValue( QStringLiteral( "field_1;field_2" ) );
3370 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "field" ), context, widgetContext, &fieldParam );
3371 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
3372 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
3373 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
3374 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
3375 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
3376 QCOMPARE( static_cast< QgsProcessingParameterField * >( def.get() )->defaultValue().toString(), QStringLiteral( "field_1;field_2" ) );
3377 QVERIFY( static_cast< QgsProcessingParameterBand * >( def.get() )->parentLayerParameterName().isEmpty() );
3378 QCOMPARE( static_cast< QgsProcessingParameterField * >( def.get() )->dataType(), QgsProcessingParameterField::String );
3379 QCOMPARE( static_cast< QgsProcessingParameterField * >( def.get() )->allowMultiple(), true );
3380 QCOMPARE( static_cast< QgsProcessingParameterField * >( def.get() )->defaultToAllFields(), true );
3381 }
3382
testMultipleSelectionDialog()3383 void TestProcessingGui::testMultipleSelectionDialog()
3384 {
3385 QVariantList availableOptions;
3386 QVariantList selectedOptions;
3387 std::unique_ptr< QgsProcessingMultipleSelectionPanelWidget > dlg = std::make_unique< QgsProcessingMultipleSelectionPanelWidget >( availableOptions, selectedOptions );
3388 QVERIFY( dlg->selectedOptions().isEmpty() );
3389 QCOMPARE( dlg->mModel->rowCount(), 0 );
3390
3391 std::unique_ptr< QgsVectorLayer > vl = std::make_unique< QgsVectorLayer >( QStringLiteral( "LineString" ), QStringLiteral( "x" ), QStringLiteral( "memory" ) );
3392 availableOptions << QVariant( "aa" ) << QVariant( 15 ) << QVariant::fromValue( vl.get() );
3393 dlg = std::make_unique< QgsProcessingMultipleSelectionPanelWidget >( availableOptions, selectedOptions );
3394 QVERIFY( dlg->selectedOptions().isEmpty() );
3395 QCOMPARE( dlg->mModel->rowCount(), 3 );
3396 dlg->selectAll( true );
3397 QCOMPARE( dlg->selectedOptions(), availableOptions );
3398 dlg->mModel->item( 1 )->setCheckState( Qt::Unchecked );
3399 QCOMPARE( dlg->selectedOptions(), QVariantList() << "aa" << QVariant::fromValue( vl.get() ) );
3400
3401 // reorder rows
3402 QList<QStandardItem *> itemList = dlg->mModel->takeRow( 2 );
3403 dlg->mModel->insertRow( 0, itemList );
3404 QCOMPARE( dlg->selectedOptions(), QVariantList() << QVariant::fromValue( vl.get() ) << "aa" );
3405
3406 // additional options
3407 availableOptions.clear();
3408 selectedOptions << QVariant( "bb" ) << QVariant( 6.6 );
3409 dlg = std::make_unique< QgsProcessingMultipleSelectionPanelWidget >( availableOptions, selectedOptions );
3410 QCOMPARE( dlg->mModel->rowCount(), 2 );
3411 QCOMPARE( dlg->selectedOptions(), selectedOptions );
3412 dlg->mModel->item( 1 )->setCheckState( Qt::Unchecked );
3413 QCOMPARE( dlg->selectedOptions(), QVariantList() << "bb" );
3414
3415 // mix of standard and additional options
3416 availableOptions << QVariant( 6.6 ) << QVariant( "aa" );
3417 dlg = std::make_unique< QgsProcessingMultipleSelectionPanelWidget >( availableOptions, selectedOptions );
3418 QCOMPARE( dlg->mModel->rowCount(), 3 );
3419 QCOMPARE( dlg->selectedOptions(), selectedOptions ); // order must be maintained!
3420 dlg->mModel->item( 2 )->setCheckState( Qt::Checked );
3421 QCOMPARE( dlg->selectedOptions(), QVariantList() << "bb" << QVariant( 6.6 ) << QVariant( "aa" ) );
3422
3423 // selection buttons
3424 selectedOptions.clear();
3425 availableOptions = QVariantList() << QVariant( "a" ) << QVariant( "b" ) << QVariant( "c" );
3426 dlg = std::make_unique< QgsProcessingMultipleSelectionPanelWidget >( availableOptions, selectedOptions );
3427 QVERIFY( dlg->selectedOptions().isEmpty() );
3428 dlg->mSelectionList->selectionModel()->select( dlg->mModel->index( 1, 0 ), QItemSelectionModel::ClearAndSelect );
3429 // without a multi-selection, select all/toggle options should affect all items
3430 dlg->selectAll( true );
3431 QCOMPARE( dlg->selectedOptions(), availableOptions );
3432 dlg->selectAll( false );
3433 QVERIFY( dlg->selectedOptions().isEmpty() );
3434 dlg->toggleSelection();
3435 QCOMPARE( dlg->selectedOptions(), availableOptions );
3436 dlg->toggleSelection();
3437 QVERIFY( dlg->selectedOptions().isEmpty() );
3438 // with multi-selection, actions should only affected selected rows
3439 dlg->mSelectionList->selectionModel()->select( dlg->mModel->index( 2, 0 ), QItemSelectionModel::Select );
3440 dlg->selectAll( true );
3441 QCOMPARE( dlg->selectedOptions(), QVariantList() << "b" << "c" );
3442 dlg->selectAll( false );
3443 QVERIFY( dlg->selectedOptions().isEmpty() );
3444 dlg->selectAll( true );
3445 QCOMPARE( dlg->selectedOptions(), QVariantList() << "b" << "c" );
3446 dlg->mModel->item( 0 )->setCheckState( Qt::Checked );
3447 dlg->selectAll( false );
3448 QCOMPARE( dlg->selectedOptions(), QVariantList() << "a" );
3449 dlg->toggleSelection();
3450 QCOMPARE( dlg->selectedOptions(), QVariantList() << "a" << "b" << "c" );
3451 dlg->toggleSelection();
3452 QCOMPARE( dlg->selectedOptions(), QVariantList() << "a" );
3453
3454 // text format
3455 availableOptions = QVariantList() << QVariant( "a" ) << 6 << 6.2;
3456 dlg = std::make_unique< QgsProcessingMultipleSelectionPanelWidget >( availableOptions, selectedOptions );
3457 QCOMPARE( dlg->mModel->item( 0 )->text(), QStringLiteral( "a" ) );
3458 QCOMPARE( dlg->mModel->item( 1 )->text(), QStringLiteral( "6" ) );
3459 QCOMPARE( dlg->mModel->item( 2 )->text(), QStringLiteral( "6.2" ) );
3460 dlg->setValueFormatter( []( const QVariant & v )-> QString
3461 {
3462 return v.toString() + '_';
3463 } );
3464 QCOMPARE( dlg->mModel->item( 0 )->text(), QStringLiteral( "a_" ) );
3465 QCOMPARE( dlg->mModel->item( 1 )->text(), QStringLiteral( "6_" ) );
3466 QCOMPARE( dlg->mModel->item( 2 )->text(), QStringLiteral( "6.2_" ) );
3467
3468 // mix of fixed + model choices
3469 availableOptions = QVariantList() << QVariant( "a" ) << 6 << 6.2
3470 << QVariant::fromValue( QgsProcessingModelChildParameterSource::fromChildOutput( QStringLiteral( "alg" ), QStringLiteral( "out" ) ) )
3471 << QVariant::fromValue( QgsProcessingModelChildParameterSource::fromModelParameter( QStringLiteral( "input" ) ) );
3472 dlg = std::make_unique< QgsProcessingMultipleSelectionPanelWidget >( availableOptions, QVariantList() << 6
3473 << QVariant::fromValue( QgsProcessingModelChildParameterSource::fromChildOutput( QStringLiteral( "alg" ), QStringLiteral( "out" ) ) )
3474 << QVariant::fromValue( QgsProcessingModelChildParameterSource::fromModelParameter( QStringLiteral( "input" ) ) ) );
3475
3476 // when any selected option is a model child parameter source, then we require that all options are upgraded in place to model child parameter sources
3477 QVariantList res = dlg->selectedOptions();
3478 QCOMPARE( res.size(), 3 );
3479 QCOMPARE( res.at( 0 ).value< QgsProcessingModelChildParameterSource >(), QgsProcessingModelChildParameterSource::fromStaticValue( 6 ) );
3480 QCOMPARE( res.at( 1 ).value< QgsProcessingModelChildParameterSource >(), QgsProcessingModelChildParameterSource::fromChildOutput( QStringLiteral( "alg" ), QStringLiteral( "out" ) ) );
3481 QCOMPARE( res.at( 2 ).value< QgsProcessingModelChildParameterSource >(), QgsProcessingModelChildParameterSource::fromModelParameter( QStringLiteral( "input" ) ) );
3482 dlg->selectAll( true );
3483 res = dlg->selectedOptions();
3484 QCOMPARE( res.size(), 5 );
3485 QCOMPARE( res.at( 0 ).value< QgsProcessingModelChildParameterSource >(), QgsProcessingModelChildParameterSource::fromStaticValue( 6 ) );
3486 QCOMPARE( res.at( 1 ).value< QgsProcessingModelChildParameterSource >(), QgsProcessingModelChildParameterSource::fromChildOutput( QStringLiteral( "alg" ), QStringLiteral( "out" ) ) );
3487 QCOMPARE( res.at( 2 ).value< QgsProcessingModelChildParameterSource >(), QgsProcessingModelChildParameterSource::fromModelParameter( QStringLiteral( "input" ) ) );
3488 QCOMPARE( res.at( 3 ).value< QgsProcessingModelChildParameterSource >(), QgsProcessingModelChildParameterSource::fromStaticValue( QStringLiteral( "a" ) ) );
3489 QCOMPARE( res.at( 4 ).value< QgsProcessingModelChildParameterSource >(), QgsProcessingModelChildParameterSource::fromStaticValue( 6.2 ) );
3490 }
3491
testMultipleFileSelectionDialog()3492 void TestProcessingGui::testMultipleFileSelectionDialog()
3493 {
3494 std::unique_ptr< QgsProcessingParameterMultipleLayers > param = std::make_unique< QgsProcessingParameterMultipleLayers >( QString(), QString(), QgsProcessing::TypeRaster );
3495 QVariantList selectedOptions;
3496 std::unique_ptr< QgsProcessingMultipleInputPanelWidget > dlg = std::make_unique< QgsProcessingMultipleInputPanelWidget >( param.get(), selectedOptions, QList<QgsProcessingModelChildParameterSource >() );
3497 QVERIFY( dlg->selectedOptions().isEmpty() );
3498 QCOMPARE( dlg->mModel->rowCount(), 0 );
3499
3500 QgsProject::instance()->removeAllMapLayers();
3501 QgsVectorLayer *point = new QgsVectorLayer( QStringLiteral( "Point" ), QStringLiteral( "point" ), QStringLiteral( "memory" ) );
3502 QgsProject::instance()->addMapLayer( point );
3503 QgsVectorLayer *line = new QgsVectorLayer( QStringLiteral( "LineString" ), QStringLiteral( "line" ), QStringLiteral( "memory" ) );
3504 QgsProject::instance()->addMapLayer( line );
3505 QgsVectorLayer *polygon = new QgsVectorLayer( QStringLiteral( "Polygon" ), QStringLiteral( "polygon" ), QStringLiteral( "memory" ) );
3506 QgsProject::instance()->addMapLayer( polygon );
3507 QgsVectorLayer *noGeom = new QgsVectorLayer( QStringLiteral( "None" ), QStringLiteral( "nogeom" ), QStringLiteral( "memory" ) );
3508 QgsProject::instance()->addMapLayer( noGeom );
3509 QgsMeshLayer *mesh = new QgsMeshLayer( QStringLiteral( TEST_DATA_DIR ) + "/mesh/quad_and_triangle.2dm", QStringLiteral( "mesh" ), QStringLiteral( "mdal" ) );
3510 mesh->dataProvider()->addDataset( QStringLiteral( TEST_DATA_DIR ) + "/mesh/quad_and_triangle_vertex_scalar_with_inactive_face.dat" );
3511 QVERIFY( mesh->isValid() );
3512 QgsProject::instance()->addMapLayer( mesh );
3513 QgsRasterLayer *raster = new QgsRasterLayer( QStringLiteral( TEST_DATA_DIR ) + "/raster/band1_byte_ct_epsg4326.tif", QStringLiteral( "raster" ) );
3514 QgsProject::instance()->addMapLayer( raster );
3515 DummyPluginLayer *plugin = new DummyPluginLayer( "dummylayer", "plugin" );
3516 QgsProject::instance()->addMapLayer( plugin );
3517
3518 #ifdef HAVE_EPT
3519 QgsPointCloudLayer *pointCloud = new QgsPointCloudLayer( QStringLiteral( TEST_DATA_DIR ) + "/point_clouds/ept/sunshine-coast/ept.json", QStringLiteral( "pointcloud" ), QStringLiteral( "ept" ) );
3520 QgsProject::instance()->addMapLayer( pointCloud );
3521 #endif
3522
3523 QgsAnnotationLayer *annotationLayer = new QgsAnnotationLayer( QStringLiteral( "secondary annotations" ), QgsAnnotationLayer::LayerOptions( QgsProject::instance()->transformContext() ) );
3524 QgsProject::instance()->addMapLayer( annotationLayer );
3525
3526 dlg->setProject( QgsProject::instance() );
3527 // should be filtered to raster layers only
3528 QCOMPARE( dlg->mModel->rowCount(), 1 );
3529 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 0, 0 ) ).toString(), QStringLiteral( "raster [EPSG:4326]" ) );
3530 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 0, 0 ), Qt::UserRole ).toString(), raster->id() );
3531 QVERIFY( dlg->selectedOptions().isEmpty() );
3532 // existing value using layer id should match to project layer
3533 dlg = std::make_unique< QgsProcessingMultipleInputPanelWidget >( param.get(), QVariantList() << raster->id(), QList<QgsProcessingModelChildParameterSource >() );
3534 dlg->setProject( QgsProject::instance() );
3535 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 0, 0 ) ).toString(), QStringLiteral( "raster [EPSG:4326]" ) );
3536 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 0, 0 ), Qt::UserRole ).toString(), raster->id() );
3537 QCOMPARE( dlg->selectedOptions().size(), 1 );
3538 QCOMPARE( dlg->selectedOptions().at( 0 ).toString(), raster->id() );
3539 // existing value using layer source should also match to project layer
3540 dlg = std::make_unique< QgsProcessingMultipleInputPanelWidget >( param.get(), QVariantList() << raster->source(), QList<QgsProcessingModelChildParameterSource >() );
3541 dlg->setProject( QgsProject::instance() );
3542 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 0, 0 ) ).toString(), QStringLiteral( "raster [EPSG:4326]" ) );
3543 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 0, 0 ), Qt::UserRole ).toString(), raster->source() );
3544 QCOMPARE( dlg->selectedOptions().size(), 1 );
3545 QCOMPARE( dlg->selectedOptions().at( 0 ).toString(), raster->source() );
3546 // existing value using full layer path not matching a project layer should work
3547 dlg = std::make_unique< QgsProcessingMultipleInputPanelWidget >( param.get(), QVariantList() << raster->source() << QString( QStringLiteral( TEST_DATA_DIR ) + "/landsat.tif" ), QList<QgsProcessingModelChildParameterSource >() );
3548 dlg->setProject( QgsProject::instance() );
3549 QCOMPARE( dlg->mModel->rowCount(), 2 );
3550 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 0, 0 ) ).toString(), QStringLiteral( "raster [EPSG:4326]" ) );
3551 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 0, 0 ), Qt::UserRole ).toString(), raster->source() );
3552 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 1, 0 ) ).toString(), QString( QStringLiteral( TEST_DATA_DIR ) + "/landsat.tif" ) );
3553 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 1, 0 ), Qt::UserRole ).toString(), QString( QStringLiteral( TEST_DATA_DIR ) + "/landsat.tif" ) );
3554 QCOMPARE( dlg->selectedOptions().size(), 2 );
3555 QCOMPARE( dlg->selectedOptions().at( 0 ).toString(), raster->source() );
3556 QCOMPARE( dlg->selectedOptions().at( 1 ).toString(), QString( QStringLiteral( TEST_DATA_DIR ) + "/landsat.tif" ) );
3557
3558 // should remember layer order
3559 dlg = std::make_unique< QgsProcessingMultipleInputPanelWidget >( param.get(), QVariantList() << QString( QStringLiteral( TEST_DATA_DIR ) + "/landsat.tif" ) << raster->source(), QList<QgsProcessingModelChildParameterSource >() );
3560 dlg->setProject( QgsProject::instance() );
3561 QCOMPARE( dlg->mModel->rowCount(), 2 );
3562 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 0, 0 ) ).toString(), QString( QStringLiteral( TEST_DATA_DIR ) + "/landsat.tif" ) );
3563 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 0, 0 ), Qt::UserRole ).toString(), QString( QStringLiteral( TEST_DATA_DIR ) + "/landsat.tif" ) );
3564 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 1, 0 ) ).toString(), QStringLiteral( "raster [EPSG:4326]" ) );
3565 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 1, 0 ), Qt::UserRole ).toString(), raster->source() );
3566 QCOMPARE( dlg->selectedOptions().size(), 2 );
3567 QCOMPARE( dlg->selectedOptions().at( 0 ).toString(), QString( QStringLiteral( TEST_DATA_DIR ) + "/landsat.tif" ) );
3568 QCOMPARE( dlg->selectedOptions().at( 1 ).toString(), raster->source() );
3569
3570 // mesh
3571 param = std::make_unique< QgsProcessingParameterMultipleLayers >( QString(), QString(), QgsProcessing::TypeMesh );
3572 dlg = std::make_unique< QgsProcessingMultipleInputPanelWidget >( param.get(), QVariantList(), QList<QgsProcessingModelChildParameterSource >() );
3573 dlg->setProject( QgsProject::instance() );
3574 QCOMPARE( dlg->mModel->rowCount(), 1 );
3575 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 0, 0 ) ).toString(), QStringLiteral( "mesh" ) );
3576 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 0, 0 ), Qt::UserRole ).toString(), mesh->id() );
3577
3578 // plugin
3579 param = std::make_unique< QgsProcessingParameterMultipleLayers >( QString(), QString(), QgsProcessing::TypePlugin );
3580 dlg = std::make_unique< QgsProcessingMultipleInputPanelWidget >( param.get(), QVariantList(), QList<QgsProcessingModelChildParameterSource >() );
3581 dlg->setProject( QgsProject::instance() );
3582 QCOMPARE( dlg->mModel->rowCount(), 1 );
3583 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 0, 0 ) ).toString(), QStringLiteral( "plugin" ) );
3584 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 0, 0 ), Qt::UserRole ).toString(), plugin->id() );
3585
3586 #ifdef HAVE_EPT
3587 // point cloud
3588 param = std::make_unique< QgsProcessingParameterMultipleLayers >( QString(), QString(), QgsProcessing::TypePointCloud );
3589 dlg = std::make_unique< QgsProcessingMultipleInputPanelWidget >( param.get(), QVariantList(), QList<QgsProcessingModelChildParameterSource >() );
3590 dlg->setProject( QgsProject::instance() );
3591 QCOMPARE( dlg->mModel->rowCount(), 1 );
3592 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 0, 0 ) ).toString(), QStringLiteral( "pointcloud [EPSG:28356]" ) );
3593 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 0, 0 ), Qt::UserRole ).toString(), pointCloud->id() );
3594 #endif
3595
3596 // annotation
3597 param = std::make_unique< QgsProcessingParameterMultipleLayers >( QString(), QString(), QgsProcessing::TypeAnnotation );
3598 dlg = std::make_unique< QgsProcessingMultipleInputPanelWidget >( param.get(), QVariantList(), QList<QgsProcessingModelChildParameterSource >() );
3599 dlg->setProject( QgsProject::instance() );
3600 QCOMPARE( dlg->mModel->rowCount(), 2 );
3601 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 0, 0 ) ).toString(), QStringLiteral( "secondary annotations" ) );
3602 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 0, 0 ), Qt::UserRole ).toString(), annotationLayer->id() );
3603 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 1, 0 ) ).toString(), QStringLiteral( "Annotations" ) );
3604 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 1, 0 ), Qt::UserRole ).toString(), QStringLiteral( "main" ) );
3605
3606 // vector points
3607 param = std::make_unique< QgsProcessingParameterMultipleLayers >( QString(), QString(), QgsProcessing::TypeVectorPoint );
3608 dlg = std::make_unique< QgsProcessingMultipleInputPanelWidget >( param.get(), QVariantList(), QList<QgsProcessingModelChildParameterSource >() );
3609 dlg->setProject( QgsProject::instance() );
3610 QCOMPARE( dlg->mModel->rowCount(), 1 );
3611 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 0, 0 ) ).toString(), QStringLiteral( "point [EPSG:4326]" ) );
3612 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 0, 0 ), Qt::UserRole ).toString(), point->id() );
3613
3614 // vector lines
3615 param = std::make_unique< QgsProcessingParameterMultipleLayers >( QString(), QString(), QgsProcessing::TypeVectorLine );
3616 dlg = std::make_unique< QgsProcessingMultipleInputPanelWidget >( param.get(), QVariantList(), QList<QgsProcessingModelChildParameterSource >() );
3617 dlg->setProject( QgsProject::instance() );
3618 QCOMPARE( dlg->mModel->rowCount(), 1 );
3619 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 0, 0 ) ).toString(), QStringLiteral( "line [EPSG:4326]" ) );
3620 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 0, 0 ), Qt::UserRole ).toString(), line->id() );
3621
3622 // vector polygons
3623 param = std::make_unique< QgsProcessingParameterMultipleLayers >( QString(), QString(), QgsProcessing::TypeVectorPolygon );
3624 dlg = std::make_unique< QgsProcessingMultipleInputPanelWidget >( param.get(), QVariantList(), QList<QgsProcessingModelChildParameterSource >() );
3625 dlg->setProject( QgsProject::instance() );
3626 QCOMPARE( dlg->mModel->rowCount(), 1 );
3627 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 0, 0 ) ).toString(), QStringLiteral( "polygon [EPSG:4326]" ) );
3628 QCOMPARE( dlg->mModel->data( dlg->mModel->index( 0, 0 ), Qt::UserRole ).toString(), polygon->id() );
3629
3630 // vector any type
3631 param = std::make_unique< QgsProcessingParameterMultipleLayers >( QString(), QString(), QgsProcessing::TypeVector );
3632 dlg = std::make_unique< QgsProcessingMultipleInputPanelWidget >( param.get(), QVariantList(), QList<QgsProcessingModelChildParameterSource >() );
3633 dlg->setProject( QgsProject::instance() );
3634 QCOMPARE( dlg->mModel->rowCount(), 4 );
3635 QSet< QString > titles;
3636 for ( int i = 0; i < dlg->mModel->rowCount(); ++i )
3637 titles << dlg->mModel->data( dlg->mModel->index( i, 0 ) ).toString();
3638 QCOMPARE( titles, QSet<QString>() << QStringLiteral( "polygon [EPSG:4326]" ) << QStringLiteral( "point [EPSG:4326]" ) << QStringLiteral( "line [EPSG:4326]" ) << QStringLiteral( "nogeom" ) );
3639
3640 // any type
3641 param = std::make_unique< QgsProcessingParameterMultipleLayers >( QString(), QString(), QgsProcessing::TypeMapLayer );
3642 dlg = std::make_unique< QgsProcessingMultipleInputPanelWidget >( param.get(), QVariantList(), QList<QgsProcessingModelChildParameterSource >() );
3643 dlg->setProject( QgsProject::instance() );
3644 #ifdef HAVE_EPT
3645 QCOMPARE( dlg->mModel->rowCount(), 10 );
3646 #else
3647 QCOMPARE( dlg->mModel->rowCount(), 9 );
3648 #endif
3649
3650 titles.clear();
3651 for ( int i = 0; i < dlg->mModel->rowCount(); ++i )
3652 titles << dlg->mModel->data( dlg->mModel->index( i, 0 ) ).toString();
3653 #ifdef HAVE_EPT
3654 QCOMPARE( titles, QSet<QString>() << QStringLiteral( "polygon [EPSG:4326]" ) << QStringLiteral( "point [EPSG:4326]" ) << QStringLiteral( "line [EPSG:4326]" )
3655 << QStringLiteral( "nogeom" ) << QStringLiteral( "raster [EPSG:4326]" ) << QStringLiteral( "mesh" ) << QStringLiteral( "plugin" )
3656 << QStringLiteral( "pointcloud [EPSG:28356]" ) << QStringLiteral( "secondary annotations" ) << QStringLiteral( "Annotations" ) );
3657 #else
3658 QCOMPARE( titles, QSet<QString>() << QStringLiteral( "polygon [EPSG:4326]" ) << QStringLiteral( "point [EPSG:4326]" ) << QStringLiteral( "line [EPSG:4326]" )
3659 << QStringLiteral( "nogeom" ) << QStringLiteral( "raster [EPSG:4326]" ) << QStringLiteral( "mesh" ) << QStringLiteral( "plugin" )
3660 << QStringLiteral( "secondary annotations" ) << QStringLiteral( "Annotations" ) );
3661 #endif
3662
3663 // files
3664 param = std::make_unique< QgsProcessingParameterMultipleLayers >( QString(), QString(), QgsProcessing::TypeFile );
3665 dlg = std::make_unique< QgsProcessingMultipleInputPanelWidget >( param.get(), QVariantList(), QList<QgsProcessingModelChildParameterSource >() );
3666 dlg->setProject( QgsProject::instance() );
3667 QCOMPARE( dlg->mModel->rowCount(), 0 );
3668 }
3669
testRasterBandSelectionPanel()3670 void TestProcessingGui::testRasterBandSelectionPanel()
3671 {
3672 QgsProcessingParameterBand bandParam( QString(), QString(), QVariant(), QStringLiteral( "INPUT" ), false, true );
3673 QgsProcessingRasterBandPanelWidget w( nullptr, &bandParam );
3674 QSignalSpy spy( &w, &QgsProcessingRasterBandPanelWidget::changed );
3675
3676 QCOMPARE( w.mLineEdit->text(), QStringLiteral( "0 bands selected" ) );
3677 w.setValue( QStringLiteral( "1" ) );
3678 QCOMPARE( spy.count(), 1 );
3679 QCOMPARE( w.value().toList(), QVariantList() << QStringLiteral( "1" ) );
3680 QCOMPARE( w.mLineEdit->text(), QStringLiteral( "1 bands selected" ) );
3681
3682 w.setValue( QVariantList() << QStringLiteral( "2" ) << QStringLiteral( "1" ) );
3683 QCOMPARE( spy.count(), 2 );
3684 QCOMPARE( w.value().toList(), QVariantList() << QStringLiteral( "2" ) << QStringLiteral( "1" ) );
3685 QCOMPARE( w.mLineEdit->text(), QStringLiteral( "2 bands selected" ) );
3686
3687 w.setValue( QVariantList() << 3 << 5 << 1 );
3688 QCOMPARE( spy.count(), 3 );
3689 QCOMPARE( w.value().toList(), QVariantList() << 3 << 5 << 1 );
3690 QCOMPARE( w.mLineEdit->text(), QStringLiteral( "3 bands selected" ) );
3691
3692 w.setValue( QVariant() );
3693 QCOMPARE( spy.count(), 4 );
3694 QCOMPARE( w.value().toList(), QVariantList() );
3695 QCOMPARE( w.mLineEdit->text(), QStringLiteral( "0 bands selected" ) );
3696 }
3697
testBandWrapper()3698 void TestProcessingGui::testBandWrapper()
3699 {
3700 const QgsProcessingAlgorithm *statsAlg = QgsApplication::processingRegistry()->algorithmById( QStringLiteral( "native:rasterlayerstatistics" ) );
3701 const QgsProcessingParameterDefinition *layerDef = statsAlg->parameterDefinition( QStringLiteral( "INPUT" ) );
3702
3703 auto testWrapper = [layerDef]( QgsProcessingGui::WidgetType type )
3704 {
3705 TestLayerWrapper layerWrapper( layerDef );
3706 QgsProject p;
3707 QgsRasterLayer *rl = new QgsRasterLayer( TEST_DATA_DIR + QStringLiteral( "/landsat.tif" ), QStringLiteral( "x" ), QStringLiteral( "gdal" ) );
3708 p.addMapLayer( rl );
3709
3710 QgsProcessingParameterBand param( QStringLiteral( "band" ), QStringLiteral( "band" ), QVariant(), QStringLiteral( "INPUT" ) );
3711
3712 QgsProcessingBandWidgetWrapper wrapper( ¶m, type );
3713
3714 QgsProcessingContext context;
3715
3716 QWidget *w = wrapper.createWrappedWidget( context );
3717 ( void )w;
3718 layerWrapper.setWidgetValue( QVariant::fromValue( rl ), context );
3719 wrapper.setParentLayerWrapperValue( &layerWrapper );
3720
3721 QSignalSpy spy( &wrapper, &QgsProcessingBandWidgetWrapper::widgetValueHasChanged );
3722 wrapper.setWidgetValue( 3, context );
3723 QCOMPARE( spy.count(), 1 );
3724 QCOMPARE( wrapper.widgetValue().toInt(), 3 );
3725
3726 switch ( type )
3727 {
3728 case QgsProcessingGui::Standard:
3729 case QgsProcessingGui::Batch:
3730 QCOMPARE( static_cast< QgsRasterBandComboBox * >( wrapper.wrappedWidget() )->currentBand(), 3 );
3731 break;
3732
3733 case QgsProcessingGui::Modeler:
3734 QCOMPARE( static_cast< QLineEdit * >( wrapper.wrappedWidget() )->text(), QStringLiteral( "3" ) );
3735 break;
3736 }
3737
3738 wrapper.setWidgetValue( QStringLiteral( "1" ), context );
3739 QCOMPARE( spy.count(), 2 );
3740 QCOMPARE( wrapper.widgetValue().toInt(), 1 );
3741
3742 switch ( type )
3743 {
3744 case QgsProcessingGui::Standard:
3745 case QgsProcessingGui::Batch:
3746 QCOMPARE( static_cast< QgsRasterBandComboBox * >( wrapper.wrappedWidget() )->currentBand(), 1 );
3747 break;
3748
3749 case QgsProcessingGui::Modeler:
3750 QCOMPARE( static_cast< QLineEdit * >( wrapper.wrappedWidget() )->text(), QStringLiteral( "1" ) );
3751 break;
3752 }
3753
3754 delete w;
3755
3756 // optional
3757 param = QgsProcessingParameterBand( QStringLiteral( "band" ), QStringLiteral( "band" ), QVariant(), QStringLiteral( "INPUT" ), true, false );
3758
3759 QgsProcessingBandWidgetWrapper wrapper2( ¶m, type );
3760
3761 w = wrapper2.createWrappedWidget( context );
3762 layerWrapper.setWidgetValue( QVariant::fromValue( rl ), context );
3763 wrapper2.setParentLayerWrapperValue( &layerWrapper );
3764 QSignalSpy spy2( &wrapper2, &QgsProcessingBandWidgetWrapper::widgetValueHasChanged );
3765 wrapper2.setWidgetValue( QStringLiteral( "4" ), context );
3766 QCOMPARE( spy2.count(), 1 );
3767 QCOMPARE( wrapper2.widgetValue().toInt(), 4 );
3768
3769 wrapper2.setWidgetValue( QVariant(), context );
3770 QCOMPARE( spy2.count(), 2 );
3771 QVERIFY( !wrapper2.widgetValue().isValid() );
3772
3773 switch ( type )
3774 {
3775 case QgsProcessingGui::Standard:
3776 case QgsProcessingGui::Batch:
3777 QCOMPARE( static_cast< QgsRasterBandComboBox * >( wrapper2.wrappedWidget() )->currentBand(), -1 );
3778 break;
3779
3780 case QgsProcessingGui::Modeler:
3781 QCOMPARE( static_cast< QLineEdit * >( wrapper2.wrappedWidget() )->text(), QString() );
3782 break;
3783 }
3784
3785 QLabel *l = wrapper.createWrappedLabel();
3786 if ( wrapper.type() != QgsProcessingGui::Batch )
3787 {
3788 QVERIFY( l );
3789 QCOMPARE( l->text(), QStringLiteral( "band [optional]" ) );
3790 QCOMPARE( l->toolTip(), param.toolTip() );
3791 delete l;
3792 }
3793 else
3794 {
3795 QVERIFY( !l );
3796 }
3797
3798 // check signal
3799 switch ( type )
3800 {
3801 case QgsProcessingGui::Standard:
3802 case QgsProcessingGui::Batch:
3803 static_cast< QgsRasterBandComboBox * >( wrapper2.wrappedWidget() )->setBand( 6 );
3804 break;
3805
3806 case QgsProcessingGui::Modeler:
3807 static_cast< QLineEdit * >( wrapper2.wrappedWidget() )->setText( QStringLiteral( "6" ) );
3808 break;
3809 }
3810
3811 QCOMPARE( spy2.count(), 3 );
3812
3813 switch ( type )
3814 {
3815 case QgsProcessingGui::Standard:
3816 case QgsProcessingGui::Batch:
3817 QCOMPARE( wrapper2.mComboBox->layer(), rl );
3818 break;
3819
3820 case QgsProcessingGui::Modeler:
3821 break;
3822 }
3823
3824 // should not be owned by wrapper
3825 QVERIFY( !wrapper2.mParentLayer.get() );
3826 layerWrapper.setWidgetValue( QVariant(), context );
3827 wrapper2.setParentLayerWrapperValue( &layerWrapper );
3828
3829 switch ( type )
3830 {
3831 case QgsProcessingGui::Standard:
3832 case QgsProcessingGui::Batch:
3833 QVERIFY( !wrapper2.mComboBox->layer() );
3834 break;
3835
3836 case QgsProcessingGui::Modeler:
3837 break;
3838 }
3839
3840 layerWrapper.setWidgetValue( rl->id(), context );
3841 wrapper2.setParentLayerWrapperValue( &layerWrapper );
3842 switch ( type )
3843 {
3844 case QgsProcessingGui::Standard:
3845 case QgsProcessingGui::Batch:
3846 QVERIFY( !wrapper2.mComboBox->layer() );
3847 break;
3848
3849 case QgsProcessingGui::Modeler:
3850 break;
3851 }
3852 QVERIFY( !wrapper2.mParentLayer.get() );
3853
3854 // with project layer
3855 context.setProject( &p );
3856 TestProcessingContextGenerator generator( context );
3857 wrapper2.registerProcessingContextGenerator( &generator );
3858
3859 layerWrapper.setWidgetValue( rl->id(), context );
3860 wrapper2.setParentLayerWrapperValue( &layerWrapper );
3861 switch ( type )
3862 {
3863 case QgsProcessingGui::Standard:
3864 case QgsProcessingGui::Batch:
3865 QCOMPARE( wrapper2.mComboBox->layer(), rl );
3866 break;
3867
3868 case QgsProcessingGui::Modeler:
3869 break;
3870 }
3871 QVERIFY( !wrapper2.mParentLayer.get() );
3872
3873 // non-project layer
3874 QString rasterFileName = TEST_DATA_DIR + QStringLiteral( "/landsat-f32-b1.tif" );
3875 layerWrapper.setWidgetValue( rasterFileName, context );
3876 wrapper2.setParentLayerWrapperValue( &layerWrapper );
3877 switch ( type )
3878 {
3879 case QgsProcessingGui::Standard:
3880 case QgsProcessingGui::Batch:
3881 QCOMPARE( wrapper2.mComboBox->layer()->publicSource(), rasterFileName );
3882 break;
3883
3884 case QgsProcessingGui::Modeler:
3885 break;
3886 }
3887
3888 // must be owned by wrapper, or layer may be deleted while still required by wrapper
3889 QCOMPARE( wrapper2.mParentLayer->publicSource(), rasterFileName );
3890
3891 delete w;
3892
3893 // multiple
3894 param = QgsProcessingParameterBand( QStringLiteral( "band" ), QStringLiteral( "band" ), QVariant(), QStringLiteral( "INPUT" ), true, true );
3895
3896 QgsProcessingBandWidgetWrapper wrapper3( ¶m, type );
3897
3898 w = wrapper3.createWrappedWidget( context );
3899 layerWrapper.setWidgetValue( QVariant::fromValue( rl ), context );
3900 wrapper3.setParentLayerWrapperValue( &layerWrapper );
3901 QSignalSpy spy3( &wrapper3, &QgsProcessingBandWidgetWrapper::widgetValueHasChanged );
3902 wrapper3.setWidgetValue( QStringLiteral( "5" ), context );
3903 QCOMPARE( spy3.count(), 1 );
3904 QCOMPARE( wrapper3.widgetValue().toList(), QVariantList() << 5 );
3905
3906 wrapper3.setWidgetValue( QString(), context );
3907 QCOMPARE( spy3.count(), 2 );
3908 QVERIFY( wrapper3.widgetValue().toString().isEmpty() );
3909
3910 wrapper3.setWidgetValue( QStringLiteral( "3;4" ), context );
3911 QCOMPARE( spy3.count(), 3 );
3912 QCOMPARE( wrapper3.widgetValue().toStringList(), QStringList() << QStringLiteral( "3" ) << QStringLiteral( "4" ) );
3913
3914 wrapper3.setWidgetValue( QVariantList() << 5 << 6 << 7, context );
3915 QCOMPARE( spy3.count(), 4 );
3916 QCOMPARE( wrapper3.widgetValue().toList(), QVariantList() << 5 << 6 << 7 );
3917
3918 wrapper3.setWidgetValue( QVariant(), context );
3919 QCOMPARE( spy3.count(), 5 );
3920 QVERIFY( !wrapper3.widgetValue().isValid() );
3921
3922
3923 // multiple non-optional
3924 param = QgsProcessingParameterBand( QStringLiteral( "band" ), QStringLiteral( "band" ), QVariant(), QStringLiteral( "INPUT" ), false, true );
3925
3926 QgsProcessingBandWidgetWrapper wrapper4( ¶m, type );
3927
3928 w = wrapper4.createWrappedWidget( context );
3929 layerWrapper.setWidgetValue( QVariant::fromValue( rl ), context );
3930 wrapper4.setParentLayerWrapperValue( &layerWrapper );
3931 QSignalSpy spy4( &wrapper4, &QgsProcessingBandWidgetWrapper::widgetValueHasChanged );
3932 wrapper4.setWidgetValue( QStringLiteral( "5" ), context );
3933 QCOMPARE( spy4.count(), 1 );
3934 QCOMPARE( wrapper4.widgetValue().toList(), QVariantList() << 5 );
3935
3936 wrapper4.setWidgetValue( QString(), context );
3937 QCOMPARE( spy4.count(), 2 );
3938 QVERIFY( wrapper4.widgetValue().toString().isEmpty() );
3939
3940 wrapper4.setWidgetValue( QStringLiteral( "3;4" ), context );
3941 QCOMPARE( spy4.count(), 3 );
3942 QCOMPARE( wrapper4.widgetValue().toStringList(), QStringList() << QStringLiteral( "3" ) << QStringLiteral( "4" ) );
3943
3944 wrapper4.setWidgetValue( QVariantList() << 5 << 6 << 7, context );
3945 QCOMPARE( spy4.count(), 4 );
3946 QCOMPARE( wrapper4.widgetValue().toList(), QVariantList() << 5 << 6 << 7 );
3947
3948 delete w;
3949 };
3950
3951 // standard wrapper
3952 testWrapper( QgsProcessingGui::Standard );
3953
3954 // batch wrapper
3955 testWrapper( QgsProcessingGui::Batch );
3956
3957 // modeler wrapper
3958 testWrapper( QgsProcessingGui::Modeler );
3959
3960 // config widget
3961 QgsProcessingParameterWidgetContext widgetContext;
3962 QgsProcessingContext context;
3963 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "band" ), context, widgetContext );
3964 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
3965 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
3966 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
3967 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
3968
3969 // using a parameter definition as initial values
3970 QgsProcessingParameterBand bandParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), 1, QStringLiteral( "parent" ) );
3971 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "band" ), context, widgetContext, &bandParam );
3972 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
3973 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
3974 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
3975 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
3976 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
3977 QCOMPARE( static_cast< QgsProcessingParameterBand * >( def.get() )->defaultValue().toString(), QStringLiteral( "1" ) );
3978 QCOMPARE( static_cast< QgsProcessingParameterBand * >( def.get() )->allowMultiple(), false );
3979 QCOMPARE( static_cast< QgsProcessingParameterBand * >( def.get() )->parentLayerParameterName(), QStringLiteral( "parent" ) );
3980 bandParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
3981 bandParam.setParentLayerParameterName( QString() );
3982 bandParam.setAllowMultiple( true );
3983 bandParam.setDefaultValue( QVariantList() << 2 << 3 );
3984 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "band" ), context, widgetContext, &bandParam );
3985 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
3986 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
3987 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
3988 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
3989 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
3990 QCOMPARE( static_cast< QgsProcessingParameterBand * >( def.get() )->defaultValue().toStringList(), QStringList() << "2" << "3" );
3991 QCOMPARE( static_cast< QgsProcessingParameterBand * >( def.get() )->allowMultiple(), true );
3992 QVERIFY( static_cast< QgsProcessingParameterBand * >( def.get() )->parentLayerParameterName().isEmpty() );
3993 }
3994
testMultipleInputWrapper()3995 void TestProcessingGui::testMultipleInputWrapper()
3996 {
3997 QString path1 = TEST_DATA_DIR + QStringLiteral( "/landsat-f32-b1.tif" );
3998 QString path2 = TEST_DATA_DIR + QStringLiteral( "/landsat.tif" );
3999
4000 auto testWrapper = [ = ]( QgsProcessingGui::WidgetType type )
4001 {
4002 QgsProcessingParameterMultipleLayers param( QStringLiteral( "multi" ), QStringLiteral( "multi" ), QgsProcessing::TypeVector, QVariant(), false );
4003
4004 QgsProcessingMultipleLayerWidgetWrapper wrapper( ¶m, type );
4005
4006 QgsProcessingContext context;
4007
4008 QWidget *w = wrapper.createWrappedWidget( context );
4009 ( void )w;
4010
4011 QSignalSpy spy( &wrapper, &QgsProcessingMultipleLayerWidgetWrapper::widgetValueHasChanged );
4012 wrapper.setWidgetValue( QVariantList() << path1 << path2, context );
4013 QCOMPARE( spy.count(), 1 );
4014 QCOMPARE( wrapper.widgetValue().toList(), QVariantList() << path1 << path2 );
4015 QCOMPARE( static_cast< QgsProcessingMultipleLayerPanelWidget * >( wrapper.wrappedWidget() )->value().toList(), QVariantList() << path1 << path2 );
4016
4017 wrapper.setWidgetValue( path1, context );
4018 QCOMPARE( spy.count(), 2 );
4019 QCOMPARE( wrapper.widgetValue().toStringList(), QStringList() << path1 );
4020 QCOMPARE( static_cast< QgsProcessingMultipleLayerPanelWidget * >( wrapper.wrappedWidget() )->value().toList(), QVariantList() << path1 );
4021 delete w;
4022
4023 // optional
4024 param = QgsProcessingParameterMultipleLayers( QStringLiteral( "multi" ), QStringLiteral( "multi" ), QgsProcessing::TypeVector, QVariant(), true );
4025
4026 QgsProcessingMultipleLayerWidgetWrapper wrapper2( ¶m, type );
4027
4028 w = wrapper2.createWrappedWidget( context );
4029 QSignalSpy spy2( &wrapper2, &QgsProcessingMultipleLayerWidgetWrapper::widgetValueHasChanged );
4030 wrapper2.setWidgetValue( path2, context );
4031 QCOMPARE( spy2.count(), 1 );
4032 QCOMPARE( wrapper2.widgetValue().toList(), QVariantList() << path2 );
4033
4034 wrapper2.setWidgetValue( QVariant(), context );
4035 QCOMPARE( spy2.count(), 2 );
4036 QVERIFY( !wrapper2.widgetValue().isValid() );
4037 QVERIFY( static_cast< QgsProcessingMultipleLayerPanelWidget * >( wrapper2.wrappedWidget() )->value().toList().isEmpty() );
4038
4039 QLabel *l = wrapper.createWrappedLabel();
4040 if ( wrapper.type() != QgsProcessingGui::Batch )
4041 {
4042 QVERIFY( l );
4043 QCOMPARE( l->text(), QStringLiteral( "multi [optional]" ) );
4044 QCOMPARE( l->toolTip(), param.toolTip() );
4045 delete l;
4046 }
4047 else
4048 {
4049 QVERIFY( !l );
4050 }
4051
4052 // check signal
4053 static_cast< QgsProcessingMultipleLayerPanelWidget * >( wrapper2.wrappedWidget() )->setValue( QVariantList() << path1 );
4054 QCOMPARE( spy2.count(), 3 );
4055
4056
4057 if ( wrapper.type() == QgsProcessingGui::Modeler )
4058 {
4059 // different mix of sources
4060
4061 wrapper2.setWidgetValue( QVariantList()
4062 << QVariant::fromValue( QgsProcessingModelChildParameterSource::fromChildOutput( QStringLiteral( "alg3" ), QStringLiteral( "OUTPUT" ) ) )
4063 << QVariant::fromValue( QgsProcessingModelChildParameterSource::fromModelParameter( QStringLiteral( "p1" ) ) )
4064 << QVariant::fromValue( QgsProcessingModelChildParameterSource::fromStaticValue( QStringLiteral( "something" ) ) ), context ) ;
4065 QCOMPARE( wrapper2.widgetValue().toList().count(), 3 );
4066
4067 QCOMPARE( wrapper2.widgetValue().toList().at( 0 ).value< QgsProcessingModelChildParameterSource>().source(), QgsProcessingModelChildParameterSource::ChildOutput );
4068 QCOMPARE( wrapper2.widgetValue().toList().at( 0 ).value< QgsProcessingModelChildParameterSource>().source(), QgsProcessingModelChildParameterSource::ChildOutput );
4069 QCOMPARE( wrapper2.widgetValue().toList().at( 0 ).value< QgsProcessingModelChildParameterSource>().outputChildId(), QStringLiteral( "alg3" ) );
4070 QCOMPARE( wrapper2.widgetValue().toList().at( 0 ).value< QgsProcessingModelChildParameterSource>().outputName(), QStringLiteral( "OUTPUT" ) );
4071 QCOMPARE( wrapper2.widgetValue().toList().at( 1 ).value< QgsProcessingModelChildParameterSource>().source(), QgsProcessingModelChildParameterSource::ModelParameter );
4072 QCOMPARE( wrapper2.widgetValue().toList().at( 1 ).value< QgsProcessingModelChildParameterSource>().parameterName(), QStringLiteral( "p1" ) );
4073 QCOMPARE( wrapper2.widgetValue().toList().at( 2 ).value< QgsProcessingModelChildParameterSource>().source(), QgsProcessingModelChildParameterSource::StaticValue );
4074 QCOMPARE( wrapper2.widgetValue().toList().at( 2 ).value< QgsProcessingModelChildParameterSource>().staticValue().toString(), QStringLiteral( "something" ) );
4075 delete w;
4076 }
4077 };
4078
4079 // standard wrapper
4080 testWrapper( QgsProcessingGui::Standard );
4081
4082 // batch wrapper
4083 testWrapper( QgsProcessingGui::Batch );
4084
4085 // modeler wrapper
4086 testWrapper( QgsProcessingGui::Modeler );
4087
4088 // config widget
4089 QgsProcessingParameterWidgetContext widgetContext;
4090 QgsProcessingContext context;
4091 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "multilayer" ), context, widgetContext );
4092 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
4093 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
4094 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
4095 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
4096
4097 // using a parameter definition as initial values
4098 QgsProcessingParameterMultipleLayers layersParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ) );
4099 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "multilayer" ), context, widgetContext, &layersParam );
4100 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
4101 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
4102 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
4103 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
4104 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
4105 QCOMPARE( static_cast< QgsProcessingParameterMultipleLayers * >( def.get() )->layerType(), QgsProcessing::TypeVectorAnyGeometry );
4106 layersParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
4107 layersParam.setLayerType( QgsProcessing::TypeRaster );
4108 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "multilayer" ), context, widgetContext, &layersParam );
4109 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
4110 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
4111 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
4112 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
4113 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
4114 QCOMPARE( static_cast< QgsProcessingParameterMultipleLayers * >( def.get() )->layerType(), QgsProcessing::TypeRaster );
4115 }
4116
testEnumSelectionPanel()4117 void TestProcessingGui::testEnumSelectionPanel()
4118 {
4119 QgsProcessingParameterEnum enumParam( QString(), QString(), QStringList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) << QStringLiteral( "c" ), true );
4120 QgsProcessingEnumPanelWidget w( nullptr, &enumParam );
4121 QSignalSpy spy( &w, &QgsProcessingEnumPanelWidget::changed );
4122
4123 QCOMPARE( w.mLineEdit->text(), QStringLiteral( "0 options selected" ) );
4124 w.setValue( 1 );
4125 QCOMPARE( spy.count(), 1 );
4126 QCOMPARE( w.value().toList(), QVariantList() << 1 );
4127 QCOMPARE( w.mLineEdit->text(), QStringLiteral( "1 options selected" ) );
4128
4129 w.setValue( QVariantList() << 2 << 0 );
4130 QCOMPARE( spy.count(), 2 );
4131 QCOMPARE( w.value().toList(), QVariantList() << 2 << 0 );
4132 QCOMPARE( w.mLineEdit->text(), QStringLiteral( "2 options selected" ) );
4133
4134 w.setValue( QVariant() );
4135 QCOMPARE( spy.count(), 3 );
4136 QCOMPARE( w.value().toList(), QVariantList() );
4137 QCOMPARE( w.mLineEdit->text(), QStringLiteral( "0 options selected" ) );
4138
4139 // static strings
4140 QgsProcessingParameterEnum enumParam2( QString(), QString(), QStringList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) << QStringLiteral( "c" ), true, QVariant(), false, true );
4141 QgsProcessingEnumPanelWidget w2( nullptr, &enumParam2 );
4142 QSignalSpy spy2( &w2, &QgsProcessingEnumPanelWidget::changed );
4143
4144 QCOMPARE( w2.mLineEdit->text(), QStringLiteral( "0 options selected" ) );
4145 w2.setValue( QStringLiteral( "a" ) );
4146 QCOMPARE( spy2.count(), 1 );
4147 QCOMPARE( w2.value().toList(), QVariantList() << QStringLiteral( "a" ) );
4148 QCOMPARE( w2.mLineEdit->text(), QStringLiteral( "1 options selected" ) );
4149
4150 w2.setValue( QVariantList() << QStringLiteral( "c" ) << QStringLiteral( "a" ) );
4151 QCOMPARE( spy2.count(), 2 );
4152 QCOMPARE( w2.value().toList(), QVariantList() << QStringLiteral( "c" ) << QStringLiteral( "a" ) );
4153 QCOMPARE( w2.mLineEdit->text(), QStringLiteral( "2 options selected" ) );
4154
4155 w2.setValue( QVariant() );
4156 QCOMPARE( spy2.count(), 3 );
4157 QCOMPARE( w2.value().toList(), QVariantList() );
4158 QCOMPARE( w2.mLineEdit->text(), QStringLiteral( "0 options selected" ) );
4159 }
4160
testEnumCheckboxPanel()4161 void TestProcessingGui::testEnumCheckboxPanel()
4162 {
4163 //single value
4164 QgsProcessingParameterEnum param( QStringLiteral( "enum" ), QStringLiteral( "enum" ), QStringList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) << QStringLiteral( "c" ), false );
4165 QgsProcessingEnumCheckboxPanelWidget panel( nullptr, ¶m );
4166 QSignalSpy spy( &panel, &QgsProcessingEnumCheckboxPanelWidget::changed );
4167
4168 QCOMPARE( panel.value(), QVariant() );
4169 panel.setValue( 2 );
4170 QCOMPARE( spy.count(), 1 );
4171 QCOMPARE( panel.value().toInt(), 2 );
4172 QVERIFY( !panel.mButtons[ 0 ]->isChecked() );
4173 QVERIFY( !panel.mButtons[ 1 ]->isChecked() );
4174 QVERIFY( panel.mButtons[ 2 ]->isChecked() );
4175 panel.setValue( 0 );
4176 QCOMPARE( spy.count(), 2 );
4177 QCOMPARE( panel.value().toInt(), 0 );
4178 QVERIFY( panel.mButtons[ 0 ]->isChecked() );
4179 QVERIFY( !panel.mButtons[ 1 ]->isChecked() );
4180 QVERIFY( !panel.mButtons[ 2 ]->isChecked() );
4181 panel.mButtons[1]->setChecked( true );
4182 QCOMPARE( spy.count(), 4 );
4183 QCOMPARE( panel.value().toInt(), 1 );
4184 panel.setValue( QVariantList() << 2 );
4185 QCOMPARE( spy.count(), 5 );
4186 QCOMPARE( panel.value().toInt(), 2 );
4187 QVERIFY( !panel.mButtons[ 0 ]->isChecked() );
4188 QVERIFY( !panel.mButtons[ 1 ]->isChecked() );
4189 QVERIFY( panel.mButtons[ 2 ]->isChecked() );
4190
4191 // multiple value
4192 QgsProcessingParameterEnum param2( QStringLiteral( "enum" ), QStringLiteral( "enum" ), QStringList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) << QStringLiteral( "c" ), true );
4193 QgsProcessingEnumCheckboxPanelWidget panel2( nullptr, ¶m2 );
4194 QSignalSpy spy2( &panel2, &QgsProcessingEnumCheckboxPanelWidget::changed );
4195
4196 QCOMPARE( panel2.value().toList(), QVariantList() );
4197 panel2.setValue( 2 );
4198 QCOMPARE( spy2.count(), 1 );
4199 QCOMPARE( panel2.value().toList(), QVariantList() << 2 );
4200 QVERIFY( !panel2.mButtons[ 0 ]->isChecked() );
4201 QVERIFY( !panel2.mButtons[ 1 ]->isChecked() );
4202 QVERIFY( panel2.mButtons[ 2 ]->isChecked() );
4203 panel2.setValue( QVariantList() << 0 << 1 );
4204 QCOMPARE( spy2.count(), 2 );
4205 QCOMPARE( panel2.value().toList(), QVariantList() << 0 << 1 );
4206 QVERIFY( panel2.mButtons[ 0 ]->isChecked() );
4207 QVERIFY( panel2.mButtons[ 1 ]->isChecked() );
4208 QVERIFY( !panel2.mButtons[ 2 ]->isChecked() );
4209 panel2.mButtons[0]->setChecked( false );
4210 QCOMPARE( spy2.count(), 3 );
4211 QCOMPARE( panel2.value().toList(), QVariantList() << 1 );
4212 panel2.mButtons[2]->setChecked( true );
4213 QCOMPARE( spy2.count(), 4 );
4214 QCOMPARE( panel2.value().toList(), QVariantList() << 1 << 2 );
4215 panel2.deselectAll();
4216 QCOMPARE( spy2.count(), 5 );
4217 QCOMPARE( panel2.value().toList(), QVariantList() );
4218 panel2.selectAll();
4219 QCOMPARE( spy2.count(), 6 );
4220 QCOMPARE( panel2.value().toList(), QVariantList() << 0 << 1 << 2 );
4221
4222 // multiple value optional
4223 QgsProcessingParameterEnum param3( QStringLiteral( "enum" ), QStringLiteral( "enum" ), QStringList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) << QStringLiteral( "c" ), true, QVariant(), true );
4224 QgsProcessingEnumCheckboxPanelWidget panel3( nullptr, ¶m3 );
4225 QSignalSpy spy3( &panel3, &QgsProcessingEnumCheckboxPanelWidget::changed );
4226
4227 QCOMPARE( panel3.value().toList(), QVariantList() );
4228 panel3.setValue( 2 );
4229 QCOMPARE( spy3.count(), 1 );
4230 QCOMPARE( panel3.value().toList(), QVariantList() << 2 );
4231 QVERIFY( !panel3.mButtons[ 0 ]->isChecked() );
4232 QVERIFY( !panel3.mButtons[ 1 ]->isChecked() );
4233 QVERIFY( panel3.mButtons[ 2 ]->isChecked() );
4234 panel3.setValue( QVariantList() << 0 << 1 );
4235 QCOMPARE( spy3.count(), 2 );
4236 QCOMPARE( panel3.value().toList(), QVariantList() << 0 << 1 );
4237 QVERIFY( panel3.mButtons[ 0 ]->isChecked() );
4238 QVERIFY( panel3.mButtons[ 1 ]->isChecked() );
4239 QVERIFY( !panel3.mButtons[ 2 ]->isChecked() );
4240 panel3.mButtons[0]->setChecked( false );
4241 QCOMPARE( spy3.count(), 3 );
4242 QCOMPARE( panel3.value().toList(), QVariantList() << 1 );
4243 panel3.mButtons[2]->setChecked( true );
4244 QCOMPARE( spy3.count(), 4 );
4245 QCOMPARE( panel3.value().toList(), QVariantList() << 1 << 2 );
4246 panel3.deselectAll();
4247 QCOMPARE( spy3.count(), 5 );
4248 QCOMPARE( panel3.value().toList(), QVariantList() );
4249 panel3.selectAll();
4250 QCOMPARE( spy3.count(), 6 );
4251 QCOMPARE( panel3.value().toList(), QVariantList() << 0 << 1 << 2 );
4252 panel3.setValue( QVariantList() );
4253 QCOMPARE( panel3.value().toList(), QVariantList() );
4254 QVERIFY( !panel3.mButtons[ 0 ]->isChecked() );
4255 QVERIFY( !panel3.mButtons[ 1 ]->isChecked() );
4256 QVERIFY( !panel3.mButtons[ 2 ]->isChecked() );
4257 QCOMPARE( spy3.count(), 7 );
4258 panel3.selectAll();
4259 QCOMPARE( spy3.count(), 8 );
4260 panel3.setValue( QVariant() );
4261 QCOMPARE( panel3.value().toList(), QVariantList() );
4262 QVERIFY( !panel3.mButtons[ 0 ]->isChecked() );
4263 QVERIFY( !panel3.mButtons[ 1 ]->isChecked() );
4264 QVERIFY( !panel3.mButtons[ 2 ]->isChecked() );
4265 QCOMPARE( spy3.count(), 9 );
4266
4267 //single value using static strings
4268 QgsProcessingParameterEnum param4( QStringLiteral( "enum" ), QStringLiteral( "enum" ), QStringList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) << QStringLiteral( "c" ), false, QVariant(), false, true );
4269 QgsProcessingEnumCheckboxPanelWidget panel4( nullptr, ¶m4 );
4270 QSignalSpy spy4( &panel4, &QgsProcessingEnumCheckboxPanelWidget::changed );
4271
4272 QCOMPARE( panel4.value(), QVariant() );
4273 panel4.setValue( QStringLiteral( "c" ) );
4274 QCOMPARE( spy4.count(), 1 );
4275 QCOMPARE( panel4.value().toString(), QStringLiteral( "c" ) );
4276 QVERIFY( !panel4.mButtons[ 0 ]->isChecked() );
4277 QVERIFY( !panel4.mButtons[ 1 ]->isChecked() );
4278 QVERIFY( panel4.mButtons[ 2 ]->isChecked() );
4279 panel4.setValue( QStringLiteral( "a" ) );
4280 QCOMPARE( spy4.count(), 2 );
4281 QCOMPARE( panel4.value().toString(), QStringLiteral( "a" ) );
4282 QVERIFY( panel4.mButtons[ 0 ]->isChecked() );
4283 QVERIFY( !panel4.mButtons[ 1 ]->isChecked() );
4284 QVERIFY( !panel4.mButtons[ 2 ]->isChecked() );
4285 panel4.mButtons[1]->setChecked( true );
4286 QCOMPARE( spy4.count(), 4 );
4287 QCOMPARE( panel4.value().toString(), QStringLiteral( "b" ) );
4288 panel4.setValue( QVariantList() << QStringLiteral( "c" ) );
4289 QCOMPARE( spy4.count(), 5 );
4290 QCOMPARE( panel4.value().toString(), QStringLiteral( "c" ) );
4291 QVERIFY( !panel4.mButtons[ 0 ]->isChecked() );
4292 QVERIFY( !panel4.mButtons[ 1 ]->isChecked() );
4293 QVERIFY( panel4.mButtons[ 2 ]->isChecked() );
4294
4295 // multiple value with static strings
4296 QgsProcessingParameterEnum param5( QStringLiteral( "enum" ), QStringLiteral( "enum" ), QStringList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) << QStringLiteral( "c" ), true, QVariant(), false, true );
4297 QgsProcessingEnumCheckboxPanelWidget panel5( nullptr, ¶m5 );
4298 QSignalSpy spy5( &panel5, &QgsProcessingEnumCheckboxPanelWidget::changed );
4299
4300 QCOMPARE( panel5.value().toList(), QVariantList() );
4301 panel5.setValue( QStringLiteral( "c" ) );
4302 QCOMPARE( spy5.count(), 1 );
4303 QCOMPARE( panel5.value().toList(), QVariantList() << QStringLiteral( "c" ) );
4304 QVERIFY( !panel5.mButtons[ 0 ]->isChecked() );
4305 QVERIFY( !panel5.mButtons[ 1 ]->isChecked() );
4306 QVERIFY( panel5.mButtons[ 2 ]->isChecked() );
4307 panel5.setValue( QVariantList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) );
4308 QCOMPARE( spy5.count(), 2 );
4309 QCOMPARE( panel5.value().toList(), QVariantList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) );
4310 QVERIFY( panel5.mButtons[ 0 ]->isChecked() );
4311 QVERIFY( panel5.mButtons[ 1 ]->isChecked() );
4312 QVERIFY( !panel5.mButtons[ 2 ]->isChecked() );
4313 panel5.mButtons[0]->setChecked( false );
4314 QCOMPARE( spy5.count(), 3 );
4315 QCOMPARE( panel5.value().toList(), QVariantList() << QStringLiteral( "b" ) );
4316 panel5.mButtons[2]->setChecked( true );
4317 QCOMPARE( spy5.count(), 4 );
4318 QCOMPARE( panel5.value().toList(), QVariantList() << QStringLiteral( "b" ) << QStringLiteral( "c" ) );
4319 panel5.deselectAll();
4320 QCOMPARE( spy5.count(), 5 );
4321 QCOMPARE( panel5.value().toList(), QVariantList() );
4322 panel5.selectAll();
4323 QCOMPARE( spy5.count(), 6 );
4324 QCOMPARE( panel5.value().toList(), QVariantList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) << QStringLiteral( "c" ) );
4325
4326 // multiple value optional with statis strings
4327 QgsProcessingParameterEnum param6( QStringLiteral( "enum" ), QStringLiteral( "enum" ), QStringList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) << QStringLiteral( "c" ), true, QVariant(), true, true );
4328 QgsProcessingEnumCheckboxPanelWidget panel6( nullptr, ¶m6 );
4329 QSignalSpy spy6( &panel6, &QgsProcessingEnumCheckboxPanelWidget::changed );
4330
4331 QCOMPARE( panel6.value().toList(), QVariantList() );
4332 panel6.setValue( QStringLiteral( "c" ) );
4333 QCOMPARE( spy6.count(), 1 );
4334 QCOMPARE( panel6.value().toList(), QVariantList() << QStringLiteral( "c" ) );
4335 QVERIFY( !panel6.mButtons[ 0 ]->isChecked() );
4336 QVERIFY( !panel6.mButtons[ 1 ]->isChecked() );
4337 QVERIFY( panel6.mButtons[ 2 ]->isChecked() );
4338 panel6.setValue( QVariantList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) );
4339 QCOMPARE( spy6.count(), 2 );
4340 QCOMPARE( panel6.value().toList(), QVariantList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) );
4341 QVERIFY( panel6.mButtons[ 0 ]->isChecked() );
4342 QVERIFY( panel6.mButtons[ 1 ]->isChecked() );
4343 QVERIFY( !panel6.mButtons[ 2 ]->isChecked() );
4344 panel6.mButtons[0]->setChecked( false );
4345 QCOMPARE( spy6.count(), 3 );
4346 QCOMPARE( panel6.value().toList(), QVariantList() << QStringLiteral( "b" ) );
4347 panel6.mButtons[2]->setChecked( true );
4348 QCOMPARE( spy6.count(), 4 );
4349 QCOMPARE( panel6.value().toList(), QVariantList() << QStringLiteral( "b" ) << QStringLiteral( "c" ) );
4350 panel6.deselectAll();
4351 QCOMPARE( spy6.count(), 5 );
4352 QCOMPARE( panel6.value().toList(), QVariantList() );
4353 panel6.selectAll();
4354 QCOMPARE( spy6.count(), 6 );
4355 QCOMPARE( panel6.value().toList(), QVariantList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) << QStringLiteral( "c" ) );
4356 panel6.setValue( QVariantList() );
4357 QCOMPARE( panel6.value().toList(), QVariantList() );
4358 QVERIFY( !panel6.mButtons[ 0 ]->isChecked() );
4359 QVERIFY( !panel6.mButtons[ 1 ]->isChecked() );
4360 QVERIFY( !panel6.mButtons[ 2 ]->isChecked() );
4361 QCOMPARE( spy6.count(), 7 );
4362 panel6.selectAll();
4363 QCOMPARE( spy6.count(), 8 );
4364 panel6.setValue( QVariant() );
4365 QCOMPARE( panel6.value().toList(), QVariantList() );
4366 QVERIFY( !panel6.mButtons[ 0 ]->isChecked() );
4367 QVERIFY( !panel6.mButtons[ 1 ]->isChecked() );
4368 QVERIFY( !panel6.mButtons[ 2 ]->isChecked() );
4369 QCOMPARE( spy6.count(), 9 );
4370 }
4371
testEnumWrapper()4372 void TestProcessingGui::testEnumWrapper()
4373 {
4374 auto testWrapper = []( QgsProcessingGui::WidgetType type, bool checkboxStyle = false )
4375 {
4376 // non optional, single value
4377 QgsProcessingParameterEnum param( QStringLiteral( "enum" ), QStringLiteral( "enum" ), QStringList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) << QStringLiteral( "c" ), false );
4378 QVariantMap metadata;
4379 QVariantMap wrapperMetadata;
4380 wrapperMetadata.insert( QStringLiteral( "useCheckBoxes" ), true );
4381 metadata.insert( QStringLiteral( "widget_wrapper" ), wrapperMetadata );
4382 if ( checkboxStyle )
4383 param.setMetadata( metadata );
4384
4385 QgsProcessingEnumWidgetWrapper wrapper( ¶m, type );
4386
4387 QgsProcessingContext context;
4388 QWidget *w = wrapper.createWrappedWidget( context );
4389
4390 QSignalSpy spy( &wrapper, &QgsProcessingEnumWidgetWrapper::widgetValueHasChanged );
4391 wrapper.setWidgetValue( 1, context );
4392 QCOMPARE( spy.count(), 1 );
4393 QCOMPARE( wrapper.widgetValue().toInt(), 1 );
4394 if ( !checkboxStyle )
4395 {
4396 QCOMPARE( static_cast< QComboBox * >( wrapper.wrappedWidget() )->currentIndex(), 1 );
4397 QCOMPARE( static_cast< QComboBox * >( wrapper.wrappedWidget() )->currentText(), QStringLiteral( "b" ) );
4398 }
4399 else
4400 {
4401 QCOMPARE( static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper.wrappedWidget() )->value().toInt(), 1 );
4402 }
4403 wrapper.setWidgetValue( 0, context );
4404 QCOMPARE( spy.count(), 2 );
4405 QCOMPARE( wrapper.widgetValue().toInt(), 0 );
4406 if ( !checkboxStyle )
4407 {
4408 QCOMPARE( static_cast< QComboBox * >( wrapper.wrappedWidget() )->currentIndex(), 0 );
4409 QCOMPARE( static_cast< QComboBox * >( wrapper.wrappedWidget() )->currentText(), QStringLiteral( "a" ) );
4410 }
4411 else
4412 {
4413 QCOMPARE( static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper.wrappedWidget() )->value().toInt(), 0 );
4414 }
4415
4416 QLabel *l = wrapper.createWrappedLabel();
4417 if ( wrapper.type() != QgsProcessingGui::Batch )
4418 {
4419 QVERIFY( l );
4420 QCOMPARE( l->text(), QStringLiteral( "enum" ) );
4421 QCOMPARE( l->toolTip(), param.toolTip() );
4422 delete l;
4423 }
4424 else
4425 {
4426 QVERIFY( !l );
4427 }
4428
4429 // check signal
4430 if ( !checkboxStyle )
4431 static_cast< QComboBox * >( wrapper.wrappedWidget() )->setCurrentIndex( 2 );
4432 else
4433 static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper.wrappedWidget() )->setValue( 2 );
4434 QCOMPARE( spy.count(), 3 );
4435
4436 delete w;
4437
4438 // optional
4439 QgsProcessingParameterEnum param2( QStringLiteral( "enum" ), QStringLiteral( "enum" ), QStringList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) << QStringLiteral( "c" ), false, QVariant(), true );
4440 if ( checkboxStyle )
4441 param2.setMetadata( metadata );
4442
4443 QgsProcessingEnumWidgetWrapper wrapper2( ¶m2, type );
4444
4445 w = wrapper2.createWrappedWidget( context );
4446
4447 QSignalSpy spy2( &wrapper2, &QgsProcessingEnumWidgetWrapper::widgetValueHasChanged );
4448 wrapper2.setWidgetValue( 1, context );
4449 QCOMPARE( spy2.count(), 1 );
4450 QCOMPARE( wrapper2.widgetValue().toInt(), 1 );
4451 if ( !checkboxStyle )
4452 {
4453 QCOMPARE( static_cast< QComboBox * >( wrapper2.wrappedWidget() )->currentIndex(), 2 );
4454 QCOMPARE( static_cast< QComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "b" ) );
4455 }
4456 else
4457 {
4458 QCOMPARE( static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper2.wrappedWidget() )->value().toInt(), 1 );
4459 }
4460 wrapper2.setWidgetValue( 0, context );
4461 QCOMPARE( spy2.count(), 2 );
4462 QCOMPARE( wrapper2.widgetValue().toInt(), 0 );
4463 if ( !checkboxStyle )
4464 {
4465 QCOMPARE( static_cast< QComboBox * >( wrapper2.wrappedWidget() )->currentIndex(), 1 );
4466 QCOMPARE( static_cast< QComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "a" ) );
4467 }
4468 else
4469 {
4470 QCOMPARE( static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper2.wrappedWidget() )->value().toInt(), 0 );
4471 }
4472 wrapper2.setWidgetValue( QVariant(), context );
4473 QCOMPARE( spy2.count(), 3 );
4474 if ( !checkboxStyle )
4475 {
4476 QVERIFY( !wrapper2.widgetValue().isValid() );
4477 QCOMPARE( static_cast< QComboBox * >( wrapper2.wrappedWidget() )->currentIndex(), 0 );
4478 QCOMPARE( static_cast< QComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "[Not selected]" ) );
4479 }
4480
4481 // check signal
4482 if ( !checkboxStyle )
4483 static_cast< QComboBox * >( wrapper2.wrappedWidget() )->setCurrentIndex( 2 );
4484 else
4485 static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper2.wrappedWidget() )->setValue( 1 );
4486 QCOMPARE( spy2.count(), 4 );
4487
4488 delete w;
4489
4490 // allow multiple, non optional
4491 QgsProcessingParameterEnum param3( QStringLiteral( "enum" ), QStringLiteral( "enum" ), QStringList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) << QStringLiteral( "c" ), true, QVariant(), false );
4492 if ( checkboxStyle )
4493 param3.setMetadata( metadata );
4494
4495 QgsProcessingEnumWidgetWrapper wrapper3( ¶m3, type );
4496
4497 w = wrapper3.createWrappedWidget( context );
4498
4499 QSignalSpy spy3( &wrapper3, &QgsProcessingEnumWidgetWrapper::widgetValueHasChanged );
4500 wrapper3.setWidgetValue( 1, context );
4501 QCOMPARE( spy3.count(), 1 );
4502 QCOMPARE( wrapper3.widgetValue().toList(), QVariantList() << 1 );
4503 if ( !checkboxStyle )
4504 QCOMPARE( static_cast< QgsProcessingEnumPanelWidget * >( wrapper3.wrappedWidget() )->value().toList(), QVariantList() << 1 );
4505 else
4506 QCOMPARE( static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper3.wrappedWidget() )->value().toList(), QVariantList() << 1 );
4507 wrapper3.setWidgetValue( 0, context );
4508 QCOMPARE( spy3.count(), 2 );
4509 QCOMPARE( wrapper3.widgetValue().toList(), QVariantList() << 0 );
4510 if ( !checkboxStyle )
4511 QCOMPARE( static_cast< QgsProcessingEnumPanelWidget * >( wrapper3.wrappedWidget() )->value().toList(), QVariantList() << 0 );
4512 else
4513 QCOMPARE( static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper3.wrappedWidget() )->value().toList(), QVariantList() << 0 );
4514 wrapper3.setWidgetValue( QVariantList() << 2 << 1, context );
4515 QCOMPARE( spy3.count(), 3 );
4516 if ( !checkboxStyle )
4517 {
4518 QCOMPARE( wrapper3.widgetValue().toList(), QVariantList() << 2 << 1 );
4519 QCOMPARE( static_cast< QgsProcessingEnumPanelWidget * >( wrapper3.wrappedWidget() )->value().toList(), QVariantList() << 2 << 1 );
4520 }
4521 else
4522 {
4523 // checkbox style isn't ordered
4524 QCOMPARE( wrapper3.widgetValue().toList(), QVariantList() << 1 << 2 );
4525 QCOMPARE( static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper3.wrappedWidget() )->value().toList(), QVariantList() << 1 << 2 );
4526 }
4527 // check signal
4528 if ( !checkboxStyle )
4529 static_cast< QgsProcessingEnumPanelWidget * >( wrapper3.wrappedWidget() )->setValue( QVariantList() << 0 << 1 );
4530 else
4531 static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper3.wrappedWidget() )->setValue( QVariantList() << 0 << 1 );
4532
4533 QCOMPARE( spy3.count(), 4 );
4534
4535 delete w;
4536
4537 // allow multiple, optional
4538 QgsProcessingParameterEnum param4( QStringLiteral( "enum" ), QStringLiteral( "enum" ), QStringList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) << QStringLiteral( "c" ), true, QVariant(), true );
4539 if ( checkboxStyle )
4540 param4.setMetadata( metadata );
4541
4542 QgsProcessingEnumWidgetWrapper wrapper4( ¶m4, type );
4543
4544 w = wrapper4.createWrappedWidget( context );
4545
4546 QSignalSpy spy4( &wrapper4, &QgsProcessingEnumWidgetWrapper::widgetValueHasChanged );
4547 wrapper4.setWidgetValue( 1, context );
4548 QCOMPARE( spy4.count(), 1 );
4549 QCOMPARE( wrapper4.widgetValue().toList(), QVariantList() << 1 );
4550 if ( !checkboxStyle )
4551 QCOMPARE( static_cast< QgsProcessingEnumPanelWidget * >( wrapper4.wrappedWidget() )->value().toList(), QVariantList() << 1 );
4552 else
4553 QCOMPARE( static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper4.wrappedWidget() )->value().toList(), QVariantList() << 1 );
4554 wrapper4.setWidgetValue( 0, context );
4555 QCOMPARE( spy4.count(), 2 );
4556 QCOMPARE( wrapper4.widgetValue().toList(), QVariantList() << 0 );
4557 if ( !checkboxStyle )
4558 QCOMPARE( static_cast< QgsProcessingEnumPanelWidget * >( wrapper4.wrappedWidget() )->value().toList(), QVariantList() << 0 );
4559 else
4560 QCOMPARE( static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper4.wrappedWidget() )->value().toList(), QVariantList() << 0 );
4561 wrapper4.setWidgetValue( QVariantList() << 2 << 1, context );
4562 QCOMPARE( spy4.count(), 3 );
4563 if ( !checkboxStyle )
4564 {
4565 QCOMPARE( wrapper4.widgetValue().toList(), QVariantList() << 2 << 1 );
4566 QCOMPARE( static_cast< QgsProcessingEnumPanelWidget * >( wrapper4.wrappedWidget() )->value().toList(), QVariantList() << 2 << 1 );
4567 }
4568 else
4569 {
4570 // checkbox style isn't ordered
4571 QCOMPARE( wrapper4.widgetValue().toList(), QVariantList() << 1 << 2 );
4572 QCOMPARE( static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper4.wrappedWidget() )->value().toList(), QVariantList() << 1 << 2 );
4573 }
4574 wrapper4.setWidgetValue( QVariantList(), context );
4575 QCOMPARE( spy4.count(), 4 );
4576 QCOMPARE( wrapper4.widgetValue().toList(), QVariantList() );
4577 if ( !checkboxStyle )
4578 QCOMPARE( static_cast< QgsProcessingEnumPanelWidget * >( wrapper4.wrappedWidget() )->value().toList(), QVariantList() );
4579 else
4580 QCOMPARE( static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper4.wrappedWidget() )->value().toList(), QVariantList() );
4581
4582 wrapper4.setWidgetValue( QVariant(), context );
4583 QCOMPARE( spy4.count(), 5 );
4584 QCOMPARE( wrapper4.widgetValue().toList(), QVariantList() );
4585 if ( !checkboxStyle )
4586 QCOMPARE( static_cast< QgsProcessingEnumPanelWidget * >( wrapper4.wrappedWidget() )->value().toList(), QVariantList() );
4587 else
4588 QCOMPARE( static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper4.wrappedWidget() )->value().toList(), QVariantList() );
4589
4590 // check signal
4591 if ( !checkboxStyle )
4592 {
4593 static_cast< QgsProcessingEnumPanelWidget * >( wrapper4.wrappedWidget() )->setValue( QVariantList() << 0 << 1 );
4594 QCOMPARE( spy4.count(), 6 );
4595 static_cast< QgsProcessingEnumPanelWidget * >( wrapper4.wrappedWidget() )->setValue( QVariant() );
4596 QCOMPARE( spy4.count(), 7 );
4597 }
4598 else
4599 {
4600 static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper4.wrappedWidget() )->setValue( QVariantList() << 0 << 1 );
4601 QCOMPARE( spy4.count(), 6 );
4602 static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper4.wrappedWidget() )->setValue( QVariant() );
4603 QCOMPARE( spy4.count(), 7 );
4604 }
4605
4606 delete w;
4607
4608 // non optional, single with static strings
4609 QgsProcessingParameterEnum param5( QStringLiteral( "enum" ), QStringLiteral( "enum" ), QStringList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) << QStringLiteral( "c" ), false, QVariant(), false, true );
4610 if ( checkboxStyle )
4611 param5.setMetadata( metadata );
4612
4613 QgsProcessingEnumWidgetWrapper wrapper5( ¶m5, type );
4614
4615 w = wrapper5.createWrappedWidget( context );
4616
4617 QSignalSpy spy5( &wrapper5, &QgsProcessingEnumWidgetWrapper::widgetValueHasChanged );
4618 wrapper5.setWidgetValue( QStringLiteral( "b" ), context );
4619 QCOMPARE( spy5.count(), 1 );
4620 QCOMPARE( wrapper5.widgetValue().toString(), QStringLiteral( "b" ) );
4621 if ( !checkboxStyle )
4622 {
4623 QCOMPARE( static_cast< QComboBox * >( wrapper5.wrappedWidget() )->currentIndex(), 1 );
4624 QCOMPARE( static_cast< QComboBox * >( wrapper5.wrappedWidget() )->currentText(), QStringLiteral( "b" ) );
4625 }
4626 else
4627 {
4628 QCOMPARE( static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper5.wrappedWidget() )->value().toString(), QStringLiteral( "b" ) );
4629 }
4630 wrapper5.setWidgetValue( QStringLiteral( "a" ), context );
4631 QCOMPARE( spy5.count(), 2 );
4632 QCOMPARE( wrapper5.widgetValue().toString(), QStringLiteral( "a" ) );
4633 if ( !checkboxStyle )
4634 {
4635 QCOMPARE( static_cast< QComboBox * >( wrapper5.wrappedWidget() )->currentIndex(), 0 );
4636 QCOMPARE( static_cast< QComboBox * >( wrapper5.wrappedWidget() )->currentText(), QStringLiteral( "a" ) );
4637 }
4638 else
4639 {
4640 QCOMPARE( static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper5.wrappedWidget() )->value().toString(), QStringLiteral( "a" ) );
4641 }
4642
4643 // check signal
4644 if ( !checkboxStyle )
4645 static_cast< QComboBox * >( wrapper5.wrappedWidget() )->setCurrentIndex( 2 );
4646 else
4647 static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper5.wrappedWidget() )->setValue( QStringLiteral( "c" ) );
4648 QCOMPARE( spy5.count(), 3 );
4649
4650 delete w;
4651
4652 // single, optional with static strings
4653 QgsProcessingParameterEnum param6( QStringLiteral( "enum" ), QStringLiteral( "enum" ), QStringList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) << QStringLiteral( "c" ), false, QVariant(), true, true );
4654 if ( checkboxStyle )
4655 param6.setMetadata( metadata );
4656
4657 QgsProcessingEnumWidgetWrapper wrapper6( ¶m6, type );
4658
4659 w = wrapper6.createWrappedWidget( context );
4660
4661 QSignalSpy spy6( &wrapper6, &QgsProcessingEnumWidgetWrapper::widgetValueHasChanged );
4662 wrapper6.setWidgetValue( QStringLiteral( "b" ), context );
4663 QCOMPARE( spy6.count(), 1 );
4664 QCOMPARE( wrapper6.widgetValue().toString(), QStringLiteral( "b" ) );
4665 if ( !checkboxStyle )
4666 {
4667 QCOMPARE( static_cast< QComboBox * >( wrapper6.wrappedWidget() )->currentIndex(), 2 );
4668 QCOMPARE( static_cast< QComboBox * >( wrapper6.wrappedWidget() )->currentText(), QStringLiteral( "b" ) );
4669 }
4670 else
4671 {
4672 QCOMPARE( static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper6.wrappedWidget() )->value().toString(), QStringLiteral( "b" ) );
4673 }
4674 wrapper6.setWidgetValue( QStringLiteral( "a" ), context );
4675 QCOMPARE( spy6.count(), 2 );
4676 QCOMPARE( wrapper6.widgetValue().toString(), QStringLiteral( "a" ) );
4677 if ( !checkboxStyle )
4678 {
4679 QCOMPARE( static_cast< QComboBox * >( wrapper6.wrappedWidget() )->currentIndex(), 1 );
4680 QCOMPARE( static_cast< QComboBox * >( wrapper6.wrappedWidget() )->currentText(), QStringLiteral( "a" ) );
4681 }
4682 else
4683 {
4684 QCOMPARE( static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper6.wrappedWidget() )->value().toString(), QStringLiteral( "a" ) );
4685 }
4686 wrapper6.setWidgetValue( QVariant(), context );
4687 QCOMPARE( spy6.count(), 3 );
4688 if ( !checkboxStyle )
4689 {
4690 QVERIFY( !wrapper6.widgetValue().isValid() );
4691 QCOMPARE( static_cast< QComboBox * >( wrapper6.wrappedWidget() )->currentIndex(), 0 );
4692 QCOMPARE( static_cast< QComboBox * >( wrapper6.wrappedWidget() )->currentText(), QStringLiteral( "[Not selected]" ) );
4693 }
4694
4695 // check signal
4696 if ( !checkboxStyle )
4697 static_cast< QComboBox * >( wrapper6.wrappedWidget() )->setCurrentIndex( 2 );
4698 else
4699 static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper6.wrappedWidget() )->setValue( QStringLiteral( "a" ) );
4700 QCOMPARE( spy6.count(), 4 );
4701
4702 delete w;
4703
4704 // multiple, non optional with static strings
4705 QgsProcessingParameterEnum param7( QStringLiteral( "enum" ), QStringLiteral( "enum" ), QStringList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) << QStringLiteral( "c" ), true, QVariant(), false, true );
4706 if ( checkboxStyle )
4707 param7.setMetadata( metadata );
4708
4709 QgsProcessingEnumWidgetWrapper wrapper7( ¶m7, type );
4710
4711 w = wrapper7.createWrappedWidget( context );
4712
4713 QSignalSpy spy7( &wrapper7, &QgsProcessingEnumWidgetWrapper::widgetValueHasChanged );
4714 wrapper7.setWidgetValue( QStringLiteral( "b" ), context );
4715 QCOMPARE( spy7.count(), 1 );
4716 QCOMPARE( wrapper7.widgetValue().toList(), QVariantList() << QStringLiteral( "b" ) );
4717 if ( !checkboxStyle )
4718 QCOMPARE( static_cast< QgsProcessingEnumPanelWidget * >( wrapper7.wrappedWidget() )->value().toList(), QVariantList() << QStringLiteral( "b" ) );
4719 else
4720 QCOMPARE( static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper7.wrappedWidget() )->value().toList(), QVariantList() << QStringLiteral( "b" ) );
4721 wrapper7.setWidgetValue( QStringLiteral( "a" ), context );
4722 QCOMPARE( spy7.count(), 2 );
4723 QCOMPARE( wrapper7.widgetValue().toList(), QVariantList() << QStringLiteral( "a" ) );
4724 if ( !checkboxStyle )
4725 QCOMPARE( static_cast< QgsProcessingEnumPanelWidget * >( wrapper7.wrappedWidget() )->value().toList(), QVariantList() << QStringLiteral( "a" ) );
4726 else
4727 QCOMPARE( static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper7.wrappedWidget() )->value().toList(), QVariantList() << QStringLiteral( "a" ) );
4728 wrapper7.setWidgetValue( QVariantList() << QStringLiteral( "c" ) << QStringLiteral( "b" ), context );
4729 QCOMPARE( spy7.count(), 3 );
4730 if ( !checkboxStyle )
4731 {
4732 QCOMPARE( wrapper7.widgetValue().toList(), QVariantList() << QStringLiteral( "c" ) << QStringLiteral( "b" ) );
4733 QCOMPARE( static_cast< QgsProcessingEnumPanelWidget * >( wrapper7.wrappedWidget() )->value().toList(), QVariantList() << QStringLiteral( "c" ) << QStringLiteral( "b" ) );
4734 }
4735 else
4736 {
4737 // checkbox style isn't ordered
4738 QCOMPARE( wrapper7.widgetValue().toList(), QVariantList() << QStringLiteral( "b" ) << QStringLiteral( "c" ) );
4739 QCOMPARE( static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper7.wrappedWidget() )->value().toList(), QVariantList() << QStringLiteral( "b" ) << QStringLiteral( "c" ) );
4740 }
4741 // check signal
4742 if ( !checkboxStyle )
4743 static_cast< QgsProcessingEnumPanelWidget * >( wrapper7.wrappedWidget() )->setValue( QVariantList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) );
4744 else
4745 static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper7.wrappedWidget() )->setValue( QVariantList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) );
4746
4747 QCOMPARE( spy7.count(), 4 );
4748
4749 delete w;
4750
4751 // multiple, optional with static strings
4752 QgsProcessingParameterEnum param8( QStringLiteral( "enum" ), QStringLiteral( "enum" ), QStringList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) << QStringLiteral( "c" ), true, QVariant(), true, true );
4753 if ( checkboxStyle )
4754 param8.setMetadata( metadata );
4755
4756 QgsProcessingEnumWidgetWrapper wrapper8( ¶m8, type );
4757
4758 w = wrapper8.createWrappedWidget( context );
4759
4760 QSignalSpy spy8( &wrapper8, &QgsProcessingEnumWidgetWrapper::widgetValueHasChanged );
4761 wrapper8.setWidgetValue( QStringLiteral( "b" ), context );
4762 QCOMPARE( spy8.count(), 1 );
4763 QCOMPARE( wrapper8.widgetValue().toList(), QVariantList() << QStringLiteral( "b" ) );
4764 if ( !checkboxStyle )
4765 QCOMPARE( static_cast< QgsProcessingEnumPanelWidget * >( wrapper8.wrappedWidget() )->value().toList(), QVariantList() << QStringLiteral( "b" ) );
4766 else
4767 QCOMPARE( static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper8.wrappedWidget() )->value().toList(), QVariantList() << QStringLiteral( "b" ) );
4768 wrapper8.setWidgetValue( QStringLiteral( "a" ), context );
4769 QCOMPARE( spy8.count(), 2 );
4770 QCOMPARE( wrapper8.widgetValue().toList(), QVariantList() << QStringLiteral( "a" ) );
4771 if ( !checkboxStyle )
4772 QCOMPARE( static_cast< QgsProcessingEnumPanelWidget * >( wrapper8.wrappedWidget() )->value().toList(), QVariantList() << QStringLiteral( "a" ) );
4773 else
4774 QCOMPARE( static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper8.wrappedWidget() )->value().toList(), QVariantList() << QStringLiteral( "a" ) );
4775 wrapper8.setWidgetValue( QVariantList() << QStringLiteral( "c" ) << QStringLiteral( "b" ), context );
4776 QCOMPARE( spy8.count(), 3 );
4777 if ( !checkboxStyle )
4778 {
4779 QCOMPARE( wrapper8.widgetValue().toList(), QVariantList() << QStringLiteral( "c" ) << QStringLiteral( "b" ) );
4780 QCOMPARE( static_cast< QgsProcessingEnumPanelWidget * >( wrapper8.wrappedWidget() )->value().toList(), QVariantList() << QStringLiteral( "c" ) << QStringLiteral( "b" ) );
4781 }
4782 else
4783 {
4784 // checkbox style isn't ordered
4785 QCOMPARE( wrapper8.widgetValue().toList(), QVariantList() << QStringLiteral( "b" ) << QStringLiteral( "c" ) );
4786 QCOMPARE( static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper8.wrappedWidget() )->value().toList(), QVariantList() << QStringLiteral( "b" ) << QStringLiteral( "c" ) );
4787 }
4788 wrapper8.setWidgetValue( QVariantList(), context );
4789 QCOMPARE( spy8.count(), 4 );
4790 QCOMPARE( wrapper8.widgetValue().toList(), QVariantList() );
4791 if ( !checkboxStyle )
4792 QCOMPARE( static_cast< QgsProcessingEnumPanelWidget * >( wrapper8.wrappedWidget() )->value().toList(), QVariantList() );
4793 else
4794 QCOMPARE( static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper8.wrappedWidget() )->value().toList(), QVariantList() );
4795
4796 wrapper8.setWidgetValue( QVariant(), context );
4797 QCOMPARE( spy8.count(), 5 );
4798 QCOMPARE( wrapper8.widgetValue().toList(), QVariantList() );
4799 if ( !checkboxStyle )
4800 QCOMPARE( static_cast< QgsProcessingEnumPanelWidget * >( wrapper8.wrappedWidget() )->value().toList(), QVariantList() );
4801 else
4802 QCOMPARE( static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper8.wrappedWidget() )->value().toList(), QVariantList() );
4803
4804 // check signal
4805 if ( !checkboxStyle )
4806 {
4807 static_cast< QgsProcessingEnumPanelWidget * >( wrapper8.wrappedWidget() )->setValue( QVariantList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) );
4808 QCOMPARE( spy8.count(), 6 );
4809 static_cast< QgsProcessingEnumPanelWidget * >( wrapper8.wrappedWidget() )->setValue( QVariant() );
4810 QCOMPARE( spy8.count(), 7 );
4811 }
4812 else
4813 {
4814 static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper8.wrappedWidget() )->setValue( QVariantList() << QStringLiteral( "a" ) << QStringLiteral( "b" ) );
4815 QCOMPARE( spy8.count(), 6 );
4816 static_cast< QgsProcessingEnumCheckboxPanelWidget * >( wrapper8.wrappedWidget() )->setValue( QVariant() );
4817 QCOMPARE( spy8.count(), 7 );
4818 }
4819
4820 delete w;
4821 };
4822
4823 // standard wrapper
4824 testWrapper( QgsProcessingGui::Standard );
4825
4826 // batch wrapper
4827 testWrapper( QgsProcessingGui::Batch );
4828
4829 // modeler wrapper
4830 testWrapper( QgsProcessingGui::Modeler );
4831
4832 // checkbox style (not for batch or model mode!)
4833 testWrapper( QgsProcessingGui::Standard, true );
4834
4835 // config widget
4836 QgsProcessingParameterWidgetContext widgetContext;
4837 QgsProcessingContext context;
4838 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "enum" ), context, widgetContext );
4839 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
4840 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
4841 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
4842 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
4843
4844 // using a parameter definition as initial values
4845 QgsProcessingParameterEnum enumParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), QStringList() << "A" << "B" << "C", false, 2 );
4846 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "enum" ), context, widgetContext, &enumParam );
4847 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
4848 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
4849 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
4850 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
4851 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
4852 QCOMPARE( static_cast< QgsProcessingParameterEnum * >( def.get() )->options(), QStringList() << "A" << "B" << "C" );
4853 QCOMPARE( static_cast< QgsProcessingParameterEnum * >( def.get() )->defaultValue().toStringList(), QStringList() << "2" );
4854 QVERIFY( !static_cast< QgsProcessingParameterEnum * >( def.get() )->allowMultiple() );
4855 enumParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
4856 enumParam.setAllowMultiple( true );
4857 enumParam.setDefaultValue( QVariantList() << 0 << 1 );
4858 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "enum" ), context, widgetContext, &enumParam );
4859 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
4860 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
4861 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
4862 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
4863 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
4864 QCOMPARE( static_cast< QgsProcessingParameterEnum * >( def.get() )->options(), QStringList() << "A" << "B" << "C" );
4865 QCOMPARE( static_cast< QgsProcessingParameterEnum * >( def.get() )->defaultValue().toStringList(), QStringList() << "0" << "1" );
4866 QVERIFY( static_cast< QgsProcessingParameterEnum * >( def.get() )->allowMultiple() );
4867 }
4868
testLayoutWrapper()4869 void TestProcessingGui::testLayoutWrapper()
4870 {
4871 QgsProject p;
4872 QgsPrintLayout *l1 = new QgsPrintLayout( &p );
4873 l1->setName( "l1" );
4874 p.layoutManager()->addLayout( l1 );
4875 QgsPrintLayout *l2 = new QgsPrintLayout( &p );
4876 l2->setName( "l2" );
4877 p.layoutManager()->addLayout( l2 );
4878
4879 auto testWrapper = [&p]( QgsProcessingGui::WidgetType type )
4880 {
4881 // non optional
4882 QgsProcessingParameterLayout param( QStringLiteral( "layout" ), QStringLiteral( "layout" ), false );
4883
4884 QgsProcessingLayoutWidgetWrapper wrapper( ¶m, type );
4885
4886 QgsProcessingContext context;
4887 context.setProject( &p );
4888 QgsProcessingParameterWidgetContext widgetContext;
4889 widgetContext.setProject( &p );
4890 wrapper.setWidgetContext( widgetContext );
4891 QWidget *w = wrapper.createWrappedWidget( context );
4892
4893 QSignalSpy spy( &wrapper, &QgsProcessingLayoutWidgetWrapper::widgetValueHasChanged );
4894 wrapper.setWidgetValue( "l2", context );
4895 QCOMPARE( spy.count(), 1 );
4896 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "l2" ) );
4897 if ( type != QgsProcessingGui::Modeler )
4898 {
4899 QCOMPARE( static_cast< QgsLayoutComboBox * >( wrapper.wrappedWidget() )->currentIndex(), 1 );
4900 QCOMPARE( static_cast< QgsLayoutComboBox * >( wrapper.wrappedWidget() )->currentText(), QStringLiteral( "l2" ) );
4901 }
4902 else
4903 {
4904 QCOMPARE( static_cast< QComboBox * >( wrapper.wrappedWidget() )->currentText(), QStringLiteral( "l2" ) );
4905 }
4906 wrapper.setWidgetValue( "l1", context );
4907 QCOMPARE( spy.count(), 2 );
4908 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "l1" ) );
4909 if ( type != QgsProcessingGui::Modeler )
4910 {
4911 QCOMPARE( static_cast< QgsLayoutComboBox * >( wrapper.wrappedWidget() )->currentIndex(), 0 );
4912 QCOMPARE( static_cast< QgsLayoutComboBox * >( wrapper.wrappedWidget() )->currentText(), QStringLiteral( "l1" ) );
4913 }
4914 else
4915 {
4916 QCOMPARE( static_cast< QComboBox * >( wrapper.wrappedWidget() )->currentText(), QStringLiteral( "l1" ) );
4917 }
4918
4919 QLabel *l = wrapper.createWrappedLabel();
4920 if ( wrapper.type() != QgsProcessingGui::Batch )
4921 {
4922 QVERIFY( l );
4923 QCOMPARE( l->text(), QStringLiteral( "layout" ) );
4924 QCOMPARE( l->toolTip(), param.toolTip() );
4925 delete l;
4926 }
4927 else
4928 {
4929 QVERIFY( !l );
4930 }
4931
4932 // check signal
4933 if ( type != QgsProcessingGui::Modeler )
4934 {
4935 static_cast< QComboBox * >( wrapper.wrappedWidget() )->setCurrentIndex( 1 );
4936 }
4937 else
4938 {
4939 static_cast< QComboBox * >( wrapper.wrappedWidget() )->setCurrentText( QStringLiteral( "aaaa" ) );
4940 }
4941 QCOMPARE( spy.count(), 3 );
4942
4943 delete w;
4944
4945 // optional
4946
4947 QgsProcessingParameterLayout param2( QStringLiteral( "layout" ), QStringLiteral( "layout" ), QVariant(), true );
4948
4949 QgsProcessingLayoutWidgetWrapper wrapper2( ¶m2, type );
4950 wrapper2.setWidgetContext( widgetContext );
4951 w = wrapper2.createWrappedWidget( context );
4952
4953 QSignalSpy spy2( &wrapper2, &QgsProcessingLayoutWidgetWrapper::widgetValueHasChanged );
4954 wrapper2.setWidgetValue( "l2", context );
4955 QCOMPARE( spy2.count(), 1 );
4956 QCOMPARE( wrapper2.widgetValue().toString(), QStringLiteral( "l2" ) );
4957 if ( type != QgsProcessingGui::Modeler )
4958 {
4959 QCOMPARE( static_cast< QgsLayoutComboBox * >( wrapper2.wrappedWidget() )->currentIndex(), 2 );
4960 QCOMPARE( static_cast< QgsLayoutComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "l2" ) );
4961 }
4962 else
4963 {
4964 QCOMPARE( static_cast< QComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "l2" ) );
4965 }
4966 wrapper2.setWidgetValue( "l1", context );
4967 QCOMPARE( spy2.count(), 2 );
4968 QCOMPARE( wrapper2.widgetValue().toString(), QStringLiteral( "l1" ) );
4969 if ( type != QgsProcessingGui::Modeler )
4970 {
4971 QCOMPARE( static_cast< QgsLayoutComboBox * >( wrapper2.wrappedWidget() )->currentIndex(), 1 );
4972 QCOMPARE( static_cast< QgsLayoutComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "l1" ) );
4973 }
4974 else
4975 {
4976 QCOMPARE( static_cast< QComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "l1" ) );
4977 }
4978 wrapper2.setWidgetValue( QVariant(), context );
4979 QCOMPARE( spy2.count(), 3 );
4980 QVERIFY( !wrapper2.widgetValue().isValid() );
4981 if ( type != QgsProcessingGui::Modeler )
4982 {
4983 QCOMPARE( static_cast< QgsLayoutComboBox * >( wrapper2.wrappedWidget() )->currentIndex(), 0 );
4984 QVERIFY( static_cast< QgsLayoutComboBox * >( wrapper2.wrappedWidget() )->currentText().isEmpty() );
4985 }
4986 else
4987 {
4988 QVERIFY( static_cast< QComboBox * >( wrapper2.wrappedWidget() )->currentText().isEmpty() );
4989 }
4990
4991 // check signal
4992 if ( type != QgsProcessingGui::Modeler )
4993 static_cast< QComboBox * >( wrapper2.wrappedWidget() )->setCurrentIndex( 2 );
4994 else
4995 static_cast< QComboBox * >( wrapper2.wrappedWidget() )->setCurrentText( QStringLiteral( "aaa" ) );
4996 QCOMPARE( spy2.count(), 4 );
4997
4998 delete w;
4999 };
5000
5001 // standard wrapper
5002 testWrapper( QgsProcessingGui::Standard );
5003
5004 // batch wrapper
5005 testWrapper( QgsProcessingGui::Batch );
5006
5007 // modeler wrapper
5008 testWrapper( QgsProcessingGui::Modeler );
5009
5010 }
5011
testLayoutItemWrapper()5012 void TestProcessingGui::testLayoutItemWrapper()
5013 {
5014 QgsProject p;
5015 QgsPrintLayout *l1 = new QgsPrintLayout( &p );
5016 l1->setName( "l1" );
5017 p.layoutManager()->addLayout( l1 );
5018 QgsLayoutItemLabel *label1 = new QgsLayoutItemLabel( l1 );
5019 label1->setId( "a" );
5020 l1->addLayoutItem( label1 );
5021 QgsLayoutItemLabel *label2 = new QgsLayoutItemLabel( l1 );
5022 label2->setId( "b" );
5023 l1->addLayoutItem( label2 );
5024
5025 auto testWrapper = [&p, l1, label1, label2]( QgsProcessingGui::WidgetType type )
5026 {
5027 // non optional
5028 QgsProcessingParameterLayoutItem param( QStringLiteral( "layout" ), QStringLiteral( "layout" ), false );
5029
5030 QgsProcessingLayoutItemWidgetWrapper wrapper( ¶m, type );
5031
5032 QgsProcessingContext context;
5033 context.setProject( &p );
5034 QgsProcessingParameterWidgetContext widgetContext;
5035 widgetContext.setProject( &p );
5036 wrapper.setWidgetContext( widgetContext );
5037 QWidget *w = wrapper.createWrappedWidget( context );
5038
5039 wrapper.setLayout( l1 );
5040
5041 QSignalSpy spy( &wrapper, &QgsProcessingLayoutItemWidgetWrapper::widgetValueHasChanged );
5042 wrapper.setWidgetValue( "b", context );
5043 QCOMPARE( spy.count(), 1 );
5044 if ( type != QgsProcessingGui::Modeler )
5045 {
5046 QCOMPARE( wrapper.widgetValue().toString(), label2->uuid() );
5047 QCOMPARE( static_cast< QgsLayoutItemComboBox * >( wrapper.wrappedWidget() )->currentText(), QStringLiteral( "b" ) );
5048 }
5049 else
5050 {
5051 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "b" ) );
5052 QCOMPARE( static_cast< QLineEdit * >( wrapper.wrappedWidget() )->text(), QStringLiteral( "b" ) );
5053 }
5054 wrapper.setWidgetValue( "a", context );
5055 QCOMPARE( spy.count(), 2 );
5056 if ( type != QgsProcessingGui::Modeler )
5057 {
5058 QCOMPARE( wrapper.widgetValue().toString(), label1->uuid() );
5059 QCOMPARE( static_cast< QgsLayoutItemComboBox * >( wrapper.wrappedWidget() )->currentText(), QStringLiteral( "a" ) );
5060 }
5061 else
5062 {
5063 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "a" ) );
5064 QCOMPARE( static_cast< QLineEdit * >( wrapper.wrappedWidget() )->text(), QStringLiteral( "a" ) );
5065 }
5066
5067 QLabel *l = wrapper.createWrappedLabel();
5068 if ( wrapper.type() != QgsProcessingGui::Batch )
5069 {
5070 QVERIFY( l );
5071 QCOMPARE( l->text(), QStringLiteral( "layout" ) );
5072 QCOMPARE( l->toolTip(), param.toolTip() );
5073 delete l;
5074 }
5075 else
5076 {
5077 QVERIFY( !l );
5078 }
5079
5080 // check signal
5081 if ( type != QgsProcessingGui::Modeler )
5082 {
5083 static_cast< QComboBox * >( wrapper.wrappedWidget() )->setCurrentIndex( 1 );
5084 }
5085 else
5086 {
5087 static_cast< QLineEdit * >( wrapper.wrappedWidget() )->setText( QStringLiteral( "aaaa" ) );
5088 }
5089 QCOMPARE( spy.count(), 3 );
5090
5091 delete w;
5092
5093 // optional
5094
5095 QgsProcessingParameterLayoutItem param2( QStringLiteral( "layout" ), QStringLiteral( "layout" ), QVariant(), QString(), -1, true );
5096
5097 QgsProcessingLayoutItemWidgetWrapper wrapper2( ¶m2, type );
5098 wrapper2.setWidgetContext( widgetContext );
5099 w = wrapper2.createWrappedWidget( context );
5100 wrapper2.setLayout( l1 );
5101
5102 QSignalSpy spy2( &wrapper2, &QgsProcessingLayoutItemWidgetWrapper::widgetValueHasChanged );
5103 wrapper2.setWidgetValue( "b", context );
5104 QCOMPARE( spy2.count(), 1 );
5105 if ( type != QgsProcessingGui::Modeler )
5106 {
5107 QCOMPARE( wrapper2.widgetValue().toString(), label2->uuid() );
5108 QCOMPARE( static_cast< QgsLayoutItemComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "b" ) );
5109 }
5110 else
5111 {
5112 QCOMPARE( wrapper2.widgetValue().toString(), QStringLiteral( "b" ) );
5113 QCOMPARE( static_cast< QLineEdit * >( wrapper2.wrappedWidget() )->text(), QStringLiteral( "b" ) );
5114 }
5115 wrapper2.setWidgetValue( "a", context );
5116 QCOMPARE( spy2.count(), 2 );
5117 if ( type != QgsProcessingGui::Modeler )
5118 {
5119 QCOMPARE( wrapper2.widgetValue().toString(), label1->uuid() );
5120 QCOMPARE( static_cast< QgsLayoutItemComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "a" ) );
5121 }
5122 else
5123 {
5124 QCOMPARE( wrapper2.widgetValue().toString(), QStringLiteral( "a" ) );
5125 QCOMPARE( static_cast< QLineEdit * >( wrapper2.wrappedWidget() )->text(), QStringLiteral( "a" ) );
5126 }
5127 wrapper2.setWidgetValue( QVariant(), context );
5128 QCOMPARE( spy2.count(), 3 );
5129 QVERIFY( !wrapper2.widgetValue().isValid() );
5130 if ( type != QgsProcessingGui::Modeler )
5131 {
5132 QVERIFY( static_cast< QgsLayoutItemComboBox * >( wrapper2.wrappedWidget() )->currentText().isEmpty() );
5133 }
5134 else
5135 {
5136 QVERIFY( static_cast< QLineEdit * >( wrapper2.wrappedWidget() )->text().isEmpty() );
5137 }
5138
5139 // check signal
5140 if ( type != QgsProcessingGui::Modeler )
5141 static_cast< QgsLayoutItemComboBox * >( wrapper2.wrappedWidget() )->setCurrentIndex( 1 );
5142 else
5143 static_cast< QLineEdit * >( wrapper2.wrappedWidget() )->setText( QStringLiteral( "aaa" ) );
5144 QCOMPARE( spy2.count(), 4 );
5145
5146 delete w;
5147 };
5148
5149 // standard wrapper
5150 testWrapper( QgsProcessingGui::Standard );
5151
5152 // batch wrapper
5153 testWrapper( QgsProcessingGui::Batch );
5154
5155 // modeler wrapper
5156 testWrapper( QgsProcessingGui::Modeler );
5157
5158
5159 // config widget
5160 QgsProcessingParameterWidgetContext widgetContext;
5161 QgsProcessingContext context;
5162 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "layoutitem" ), context, widgetContext );
5163 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
5164 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
5165 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
5166 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
5167
5168 // using a parameter definition as initial values
5169 QgsProcessingParameterLayoutItem itemParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), QVariant(), QStringLiteral( "parent" ) );
5170 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "layoutitem" ), context, widgetContext, &itemParam );
5171 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
5172 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
5173 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
5174 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
5175 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
5176 QCOMPARE( static_cast< QgsProcessingParameterLayoutItem * >( def.get() )->parentLayoutParameterName(), QStringLiteral( "parent" ) );
5177 itemParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
5178 itemParam.setParentLayoutParameterName( QString() );
5179 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "layoutitem" ), context, widgetContext, &itemParam );
5180 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
5181 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
5182 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
5183 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
5184 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
5185 QVERIFY( static_cast< QgsProcessingParameterLayoutItem * >( def.get() )->parentLayoutParameterName().isEmpty() );
5186 }
5187
testPointPanel()5188 void TestProcessingGui::testPointPanel()
5189 {
5190 std::unique_ptr< QgsProcessingPointPanel > panel = std::make_unique< QgsProcessingPointPanel >( nullptr );
5191 QSignalSpy spy( panel.get(), &QgsProcessingPointPanel::changed );
5192
5193 panel->setValue( QgsPointXY( 100, 150 ), QgsCoordinateReferenceSystem() );
5194 QCOMPARE( panel->value().toString(), QStringLiteral( "100.000000,150.000000" ) );
5195 QCOMPARE( spy.count(), 1 );
5196
5197 panel->setValue( QgsPointXY( 200, 250 ), QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3111" ) ) );
5198 QCOMPARE( panel->value().toString(), QStringLiteral( "200.000000,250.000000 [EPSG:3111]" ) );
5199 QCOMPARE( spy.count(), 2 );
5200
5201 panel->setValue( QgsPointXY( 123456.123456789, 654321.987654321 ), QgsCoordinateReferenceSystem() );
5202 QCOMPARE( panel->value().toString(), QStringLiteral( "123456.123457,654321.987654" ) );
5203 QCOMPARE( spy.count(), 3 );
5204
5205 QVERIFY( !panel->mLineEdit->showClearButton() );
5206 panel->setAllowNull( true );
5207 QVERIFY( panel->mLineEdit->showClearButton() );
5208 panel->clear();
5209 QVERIFY( !panel->value().isValid() );
5210 QCOMPARE( spy.count(), 4 );
5211
5212 QgsMapCanvas canvas;
5213 canvas.setDestinationCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:28356" ) ) );
5214 panel->setMapCanvas( &canvas );
5215 panel->updatePoint( QgsPointXY( 1.5, -3.5 ) );
5216 QCOMPARE( panel->value().toString(), QStringLiteral( "1.500000,-3.500000 [EPSG:28356]" ) );
5217 QCOMPARE( spy.count(), 5 );
5218
5219 panel.reset();
5220 }
5221
5222
testPointWrapper()5223 void TestProcessingGui::testPointWrapper()
5224 {
5225 auto testWrapper = []( QgsProcessingGui::WidgetType type )
5226 {
5227 // non optional
5228 QgsProcessingParameterPoint param( QStringLiteral( "point" ), QStringLiteral( "point" ), false );
5229
5230 QgsProcessingPointWidgetWrapper wrapper( ¶m, type );
5231
5232 QgsProcessingContext context;
5233 QWidget *w = wrapper.createWrappedWidget( context );
5234
5235 QSignalSpy spy( &wrapper, &QgsProcessingLayoutItemWidgetWrapper::widgetValueHasChanged );
5236 wrapper.setWidgetValue( "1,2", context );
5237 QCOMPARE( spy.count(), 1 );
5238 if ( type != QgsProcessingGui::Modeler )
5239 {
5240 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "1.000000,2.000000" ) );
5241 QCOMPARE( static_cast< QgsProcessingPointPanel * >( wrapper.wrappedWidget() )->mLineEdit->text(), QStringLiteral( "1.000000,2.000000" ) );
5242 }
5243 else
5244 {
5245 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "1,2" ) );
5246 QCOMPARE( static_cast< QLineEdit * >( wrapper.wrappedWidget() )->text(), QStringLiteral( "1,2" ) );
5247 }
5248 wrapper.setWidgetValue( "1,2 [EPSG:3111]", context );
5249 QCOMPARE( spy.count(), 2 );
5250 if ( type != QgsProcessingGui::Modeler )
5251 {
5252 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "1.000000,2.000000 [EPSG:3111]" ) );
5253 QCOMPARE( static_cast< QgsProcessingPointPanel * >( wrapper.wrappedWidget() )->mLineEdit->text(), QStringLiteral( "1.000000,2.000000 [EPSG:3111]" ) );
5254 }
5255 else
5256 {
5257 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "1,2 [EPSG:3111]" ) );
5258 QCOMPARE( static_cast< QLineEdit * >( wrapper.wrappedWidget() )->text(), QStringLiteral( "1,2 [EPSG:3111]" ) );
5259 }
5260
5261 // check signal
5262 if ( type != QgsProcessingGui::Modeler )
5263 {
5264 static_cast< QgsProcessingPointPanel * >( wrapper.wrappedWidget() )->mLineEdit->setText( QStringLiteral( "b" ) );
5265 }
5266 else
5267 {
5268 static_cast< QLineEdit * >( wrapper.wrappedWidget() )->setText( QStringLiteral( "aaaa" ) );
5269 }
5270 QCOMPARE( spy.count(), 3 );
5271
5272
5273 QLabel *l = wrapper.createWrappedLabel();
5274 if ( wrapper.type() != QgsProcessingGui::Batch )
5275 {
5276 QVERIFY( l );
5277 QCOMPARE( l->text(), QStringLiteral( "point" ) );
5278 QCOMPARE( l->toolTip(), param.toolTip() );
5279 delete l;
5280 }
5281 else
5282 {
5283 QVERIFY( !l );
5284 }
5285
5286 delete w;
5287
5288 // optional
5289
5290 QgsProcessingParameterPoint param2( QStringLiteral( "point" ), QStringLiteral( "point" ), QVariant(), true );
5291
5292 QgsProcessingPointWidgetWrapper wrapper2( ¶m2, type );
5293 w = wrapper2.createWrappedWidget( context );
5294
5295 QSignalSpy spy2( &wrapper2, &QgsProcessingLayoutItemWidgetWrapper::widgetValueHasChanged );
5296 wrapper2.setWidgetValue( "1,2", context );
5297 QCOMPARE( spy2.count(), 1 );
5298 if ( type != QgsProcessingGui::Modeler )
5299 {
5300 QCOMPARE( static_cast< QgsProcessingPointPanel * >( wrapper2.wrappedWidget() )->mLineEdit->text(), QStringLiteral( "1.000000,2.000000" ) );
5301 QCOMPARE( wrapper2.widgetValue().toString(), QStringLiteral( "1.000000,2.000000" ) );
5302 }
5303 else
5304 {
5305 QCOMPARE( wrapper2.widgetValue().toString(), QStringLiteral( "1,2" ) );
5306 QCOMPARE( static_cast< QLineEdit * >( wrapper2.wrappedWidget() )->text(), QStringLiteral( "1,2" ) );
5307 }
5308
5309 wrapper2.setWidgetValue( "1,2 [EPSG:3111]", context );
5310 QCOMPARE( spy2.count(), 2 );
5311 if ( type != QgsProcessingGui::Modeler )
5312 {
5313 QCOMPARE( wrapper2.widgetValue().toString(), QStringLiteral( "1.000000,2.000000 [EPSG:3111]" ) );
5314 QCOMPARE( static_cast< QgsProcessingPointPanel * >( wrapper2.wrappedWidget() )->mLineEdit->text(), QStringLiteral( "1.000000,2.000000 [EPSG:3111]" ) );
5315 }
5316 else
5317 {
5318 QCOMPARE( wrapper2.widgetValue().toString(), QStringLiteral( "1,2 [EPSG:3111]" ) );
5319 QCOMPARE( static_cast< QLineEdit * >( wrapper2.wrappedWidget() )->text(), QStringLiteral( "1,2 [EPSG:3111]" ) );
5320 }
5321 wrapper2.setWidgetValue( QVariant(), context );
5322 QCOMPARE( spy2.count(), 3 );
5323 QVERIFY( !wrapper2.widgetValue().isValid() );
5324 if ( type == QgsProcessingGui::Modeler )
5325 {
5326 QVERIFY( static_cast< QLineEdit * >( wrapper2.wrappedWidget() )->text().isEmpty() );
5327 }
5328 else
5329 {
5330 QVERIFY( static_cast< QgsProcessingPointPanel * >( wrapper2.wrappedWidget() )->mLineEdit->text().isEmpty() );
5331 }
5332 wrapper2.setWidgetValue( "1,3", context );
5333 QCOMPARE( spy2.count(), 4 );
5334 wrapper2.setWidgetValue( "", context );
5335 QCOMPARE( spy2.count(), 5 );
5336 QVERIFY( !wrapper2.widgetValue().isValid() );
5337 if ( type == QgsProcessingGui::Modeler )
5338 {
5339 QVERIFY( static_cast< QLineEdit * >( wrapper2.wrappedWidget() )->text().isEmpty() );
5340 }
5341 else
5342 {
5343 QVERIFY( static_cast< QgsProcessingPointPanel * >( wrapper2.wrappedWidget() )->mLineEdit->text().isEmpty() );
5344 }
5345
5346 // check signals
5347 wrapper2.setWidgetValue( "1,3", context );
5348 QCOMPARE( spy2.count(), 6 );
5349 if ( type == QgsProcessingGui::Modeler )
5350 {
5351 static_cast< QLineEdit * >( wrapper2.wrappedWidget() )->clear();
5352 }
5353 else
5354 {
5355 static_cast< QgsProcessingPointPanel * >( wrapper2.wrappedWidget() )->mLineEdit->clear();
5356 }
5357 QCOMPARE( spy2.count(), 7 );
5358
5359 delete w;
5360 };
5361
5362 // standard wrapper
5363 testWrapper( QgsProcessingGui::Standard );
5364
5365 // batch wrapper
5366 testWrapper( QgsProcessingGui::Batch );
5367
5368 // modeler wrapper
5369 testWrapper( QgsProcessingGui::Modeler );
5370
5371 // config widget
5372 QgsProcessingContext context;
5373 QgsProcessingParameterWidgetContext widgetContext;
5374 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "point" ), context, widgetContext );
5375 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
5376 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
5377 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
5378 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
5379
5380 // using a parameter definition as initial values
5381 QgsProcessingParameterPoint pointParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), QStringLiteral( "1,2" ) );
5382 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "point" ), context, widgetContext, &pointParam );
5383 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
5384 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
5385 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
5386 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
5387 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
5388 QCOMPARE( static_cast< QgsProcessingParameterPoint * >( def.get() )->defaultValue().toString(), QStringLiteral( "1.000000,2.000000" ) );
5389 pointParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
5390 pointParam.setDefaultValue( QStringLiteral( "4,7" ) );
5391 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "point" ), context, widgetContext, &pointParam );
5392 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
5393 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
5394 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
5395 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
5396 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
5397 QCOMPARE( static_cast< QgsProcessingParameterPoint * >( def.get() )->defaultValue().toString(), QStringLiteral( "4.000000,7.000000" ) );
5398
5399 }
5400
5401
testGeometryWrapper()5402 void TestProcessingGui::testGeometryWrapper()
5403 {
5404 auto testWrapper = []( QgsProcessingGui::WidgetType type )
5405 {
5406 // non optional
5407 QgsProcessingParameterGeometry param( QStringLiteral( "geometry" ), QStringLiteral( "geometry" ), false );
5408
5409 QgsProcessingGeometryWidgetWrapper wrapper( ¶m, type );
5410
5411 QgsProcessingContext context;
5412 QWidget *w = wrapper.createWrappedWidget( context );
5413
5414 QSignalSpy spy( &wrapper, &QgsProcessingLayoutItemWidgetWrapper::widgetValueHasChanged );
5415 wrapper.setWidgetValue( QStringLiteral( "POINT (1 2)" ), context );
5416 QCOMPARE( spy.count(), 1 );
5417 QCOMPARE( wrapper.widgetValue().toString().toLower(), QStringLiteral( "point (1 2)" ) );
5418 QCOMPARE( static_cast< QLineEdit * >( wrapper.wrappedWidget() )->text().toLower(), QStringLiteral( "point (1 2)" ).toLower() );
5419 wrapper.setWidgetValue( QString(), context );
5420 QCOMPARE( spy.count(), 2 );
5421 QVERIFY( wrapper.widgetValue().toString().isEmpty() );
5422 QVERIFY( static_cast< QLineEdit * >( wrapper.wrappedWidget() )->text().isEmpty() );
5423
5424 QLabel *l = wrapper.createWrappedLabel();
5425 if ( wrapper.type() != QgsProcessingGui::Batch )
5426 {
5427 QVERIFY( l );
5428 QCOMPARE( l->text(), QStringLiteral( "geometry" ) );
5429 QCOMPARE( l->toolTip(), param.toolTip() );
5430 delete l;
5431 }
5432 else
5433 {
5434 QVERIFY( !l );
5435 }
5436
5437 // check signal
5438 static_cast< QLineEdit * >( wrapper.wrappedWidget() )->setText( QStringLiteral( "b" ) );
5439 QCOMPARE( spy.count(), 3 );
5440 static_cast< QLineEdit * >( wrapper.wrappedWidget() )->clear();
5441 QCOMPARE( spy.count(), 4 );
5442
5443 delete w;
5444
5445 // optional
5446
5447 QgsProcessingParameterGeometry param2( QStringLiteral( "geometry" ), QStringLiteral( "geometry" ), QVariant(), true );
5448
5449 QgsProcessingGeometryWidgetWrapper wrapper2( ¶m2, type );
5450
5451 w = wrapper2.createWrappedWidget( context );
5452
5453 QSignalSpy spy2( &wrapper2, &QgsProcessingLayoutItemWidgetWrapper::widgetValueHasChanged );
5454 wrapper2.setWidgetValue( "POINT (1 2)", context );
5455 QCOMPARE( spy2.count(), 1 );
5456 QCOMPARE( wrapper2.widgetValue().toString().toLower(), QStringLiteral( "point (1 2)" ) );
5457 QCOMPARE( static_cast< QLineEdit * >( wrapper2.wrappedWidget() )->text().toLower(), QStringLiteral( "point (1 2)" ) );
5458
5459 wrapper2.setWidgetValue( QVariant(), context );
5460 QCOMPARE( spy2.count(), 2 );
5461 QVERIFY( !wrapper2.widgetValue().isValid() );
5462 QVERIFY( static_cast< QLineEdit * >( wrapper2.wrappedWidget() )->text().isEmpty() );
5463
5464 wrapper2.setWidgetValue( "POINT (1 3)", context );
5465 QCOMPARE( spy2.count(), 3 );
5466 wrapper2.setWidgetValue( "", context );
5467 QCOMPARE( spy2.count(), 4 );
5468 QVERIFY( !wrapper2.widgetValue().isValid() );
5469 QVERIFY( static_cast< QLineEdit * >( wrapper2.wrappedWidget() )->text().isEmpty() );
5470
5471 delete w;
5472 };
5473
5474 // standard wrapper
5475 testWrapper( QgsProcessingGui::Standard );
5476
5477
5478 // batch wrapper
5479 testWrapper( QgsProcessingGui::Batch );
5480
5481 // modeler wrapper
5482 testWrapper( QgsProcessingGui::Modeler );
5483
5484
5485 // config widget
5486 QgsProcessingContext context;
5487 QgsProcessingParameterWidgetContext widgetContext;
5488 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "geometry" ), context, widgetContext );
5489 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
5490 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
5491 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
5492 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
5493
5494 // using a parameter definition as initial values
5495 QgsProcessingParameterGeometry geometryParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), QStringLiteral( "POINT (1 2)" ) );
5496
5497 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "geometry" ), context, widgetContext, &geometryParam );
5498
5499 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
5500 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
5501 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
5502 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
5503 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
5504 QCOMPARE( static_cast< QgsProcessingParameterGeometry * >( def.get() )->defaultValue().toString().toLower(), QStringLiteral( "point (1 2)" ) );
5505 geometryParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
5506 geometryParam.setDefaultValue( QStringLiteral( "POINT (4 7)" ) );
5507 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "geometry" ), context, widgetContext, &geometryParam );
5508 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
5509 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
5510 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
5511 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
5512 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
5513 QCOMPARE( static_cast< QgsProcessingParameterGeometry * >( def.get() )->defaultValue().toString().toLower(), QStringLiteral( "point (4 7)" ) );
5514
5515 }
5516
5517
5518
5519
testExtentWrapper()5520 void TestProcessingGui::testExtentWrapper()
5521 {
5522 auto testWrapper = []( QgsProcessingGui::WidgetType type )
5523 {
5524 // non optional
5525 QgsProcessingParameterExtent param( QStringLiteral( "extent" ), QStringLiteral( "extent" ), false );
5526
5527 QgsProcessingExtentWidgetWrapper wrapper( ¶m, type );
5528
5529 QgsProcessingContext context;
5530 QWidget *w = wrapper.createWrappedWidget( context );
5531
5532 QSignalSpy spy( &wrapper, &QgsProcessingExtentWidgetWrapper::widgetValueHasChanged );
5533 wrapper.setWidgetValue( "1,2,3,4", context );
5534 QCOMPARE( spy.count(), 1 );
5535 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "1.000000000,2.000000000,3.000000000,4.000000000" ) );
5536 QCOMPARE( static_cast< QgsExtentWidget * >( wrapper.wrappedWidget() )->outputExtent(), QgsRectangle( 1, 3, 2, 4 ) );
5537
5538 wrapper.setWidgetValue( "1,2,3,4 [EPSG:3111]", context );
5539 QCOMPARE( spy.count(), 2 );
5540 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "1.000000000,2.000000000,3.000000000,4.000000000 [EPSG:3111]" ) );
5541 QCOMPARE( static_cast< QgsExtentWidget * >( wrapper.wrappedWidget() )->outputExtent(), QgsRectangle( 1, 3, 2, 4 ) );
5542 QCOMPARE( static_cast< QgsExtentWidget * >( wrapper.wrappedWidget() )->outputCrs().authid(), QStringLiteral( "EPSG:3111" ) );
5543
5544 // check signal
5545 static_cast< QgsExtentWidget * >( wrapper.wrappedWidget() )->setOutputExtentFromUser( QgsRectangle( 11, 22, 33, 44 ), QgsCoordinateReferenceSystem() );
5546 QCOMPARE( spy.count(), 3 );
5547
5548 QLabel *l = wrapper.createWrappedLabel();
5549 if ( wrapper.type() != QgsProcessingGui::Batch )
5550 {
5551 QVERIFY( l );
5552 QCOMPARE( l->text(), QStringLiteral( "extent" ) );
5553 QCOMPARE( l->toolTip(), param.toolTip() );
5554 delete l;
5555 }
5556 else
5557 {
5558 QVERIFY( !l );
5559 }
5560
5561 delete w;
5562
5563 // optional
5564
5565 QgsProcessingParameterExtent param2( QStringLiteral( "extent" ), QStringLiteral( "extent" ), QVariant(), true );
5566
5567 QgsProcessingExtentWidgetWrapper wrapper2( ¶m2, type );
5568 w = wrapper2.createWrappedWidget( context );
5569
5570 QSignalSpy spy2( &wrapper2, &QgsProcessingExtentWidgetWrapper::widgetValueHasChanged );
5571 wrapper2.setWidgetValue( "1,2,3,4", context );
5572 QCOMPARE( spy2.count(), 1 );
5573 QCOMPARE( static_cast< QgsExtentWidget * >( wrapper2.wrappedWidget() )->outputExtent(), QgsRectangle( 1, 3, 2, 4 ) );
5574 QCOMPARE( wrapper2.widgetValue().toString(), QStringLiteral( "1.000000000,2.000000000,3.000000000,4.000000000" ) );
5575
5576 wrapper2.setWidgetValue( "1,2,3,4 [EPSG:3111]", context );
5577 QCOMPARE( spy2.count(), 2 );
5578 QCOMPARE( wrapper2.widgetValue().toString(), QStringLiteral( "1.000000000,2.000000000,3.000000000,4.000000000 [EPSG:3111]" ) );
5579 QCOMPARE( static_cast< QgsExtentWidget * >( wrapper2.wrappedWidget() )->outputExtent(), QgsRectangle( 1, 3, 2, 4 ) );
5580 QCOMPARE( static_cast< QgsExtentWidget * >( wrapper2.wrappedWidget() )->outputCrs().authid(), QStringLiteral( "EPSG:3111" ) );
5581 wrapper2.setWidgetValue( QVariant(), context );
5582 QCOMPARE( spy2.count(), 3 );
5583 QVERIFY( !wrapper2.widgetValue().isValid() );
5584 QVERIFY( !static_cast< QgsExtentWidget * >( wrapper2.wrappedWidget() )->isValid() );
5585
5586 wrapper2.setWidgetValue( "1,3,4,7", context );
5587 QCOMPARE( spy2.count(), 4 );
5588 wrapper2.setWidgetValue( "", context );
5589 QCOMPARE( spy2.count(), 5 );
5590 QVERIFY( !wrapper2.widgetValue().isValid() );
5591 QVERIFY( !static_cast< QgsExtentWidget * >( wrapper2.wrappedWidget() )->isValid() );
5592
5593 // check signals
5594 wrapper2.setWidgetValue( "1,3,9,8", context );
5595 QCOMPARE( spy2.count(), 6 );
5596 static_cast< QgsExtentWidget * >( wrapper2.wrappedWidget() )->clear();
5597 QCOMPARE( spy2.count(), 7 );
5598
5599 delete w;
5600
5601 };
5602
5603 // standard wrapper
5604 testWrapper( QgsProcessingGui::Standard );
5605
5606 // batch wrapper
5607 testWrapper( QgsProcessingGui::Batch );
5608
5609 // modeler wrapper
5610 testWrapper( QgsProcessingGui::Modeler );
5611
5612 // config widget
5613 QgsProcessingContext context;
5614 QgsProcessingParameterWidgetContext widgetContext;
5615 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "extent" ), context, widgetContext );
5616 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
5617 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
5618 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
5619 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
5620
5621 // using a parameter definition as initial values
5622 QgsProcessingParameterExtent extentParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), QStringLiteral( "1,2,3,4" ) );
5623 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "extent" ), context, widgetContext, &extentParam );
5624 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
5625 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
5626 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
5627 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
5628 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
5629 QCOMPARE( static_cast< QgsProcessingParameterExtent * >( def.get() )->defaultValue().toString(), QStringLiteral( "1.000000000,2.000000000,3.000000000,4.000000000" ) );
5630 extentParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
5631 extentParam.setDefaultValue( QStringLiteral( "4,7,8,9" ) );
5632 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "extent" ), context, widgetContext, &extentParam );
5633 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
5634 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
5635 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
5636 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
5637 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
5638 QCOMPARE( static_cast< QgsProcessingParameterExtent * >( def.get() )->defaultValue().toString(), QStringLiteral( "4.000000000,7.000000000,8.000000000,9.000000000" ) );
5639 }
5640
testColorWrapper()5641 void TestProcessingGui::testColorWrapper()
5642 {
5643 auto testWrapper = []( QgsProcessingGui::WidgetType type )
5644 {
5645 QgsProcessingParameterColor param( QStringLiteral( "color" ), QStringLiteral( "color" ) );
5646
5647 QgsProcessingColorWidgetWrapper wrapper( ¶m, type );
5648
5649 QgsProcessingContext context;
5650 QWidget *w = wrapper.createWrappedWidget( context );
5651
5652 QSignalSpy spy( &wrapper, &QgsProcessingColorWidgetWrapper::widgetValueHasChanged );
5653 wrapper.setWidgetValue( QColor( 255, 0, 0 ), context );
5654 QCOMPARE( spy.count(), 1 );
5655 QCOMPARE( wrapper.widgetValue().value< QColor >().name(), QStringLiteral( "#ff0000" ) );
5656 QCOMPARE( static_cast< QgsColorButton * >( wrapper.wrappedWidget() )->color(), QColor( 255, 0, 0 ) );
5657 QVERIFY( !static_cast< QgsColorButton * >( wrapper.wrappedWidget() )->showNull() );
5658 QVERIFY( static_cast< QgsColorButton * >( wrapper.wrappedWidget() )->allowOpacity() );
5659 wrapper.setWidgetValue( QColor(), context );
5660 QCOMPARE( spy.count(), 2 );
5661 QVERIFY( !wrapper.widgetValue().value< QColor >().isValid() );
5662 QVERIFY( !static_cast< QgsColorButton * >( wrapper.wrappedWidget() )->color().isValid() );
5663
5664 QLabel *l = wrapper.createWrappedLabel();
5665 if ( wrapper.type() != QgsProcessingGui::Batch )
5666 {
5667 QVERIFY( l );
5668 QCOMPARE( l->text(), QStringLiteral( "color" ) );
5669 QCOMPARE( l->toolTip(), param.toolTip() );
5670 delete l;
5671 }
5672 else
5673 {
5674 QVERIFY( !l );
5675 }
5676
5677 // check signal
5678 static_cast< QgsColorButton * >( wrapper.wrappedWidget() )->setColor( QColor( 0, 255, 0 ) );
5679 QCOMPARE( spy.count(), 3 );
5680
5681 // with opacity
5682 wrapper.setWidgetValue( QColor( 255, 0, 0, 100 ), context );
5683 QCOMPARE( wrapper.widgetValue().value< QColor >(), QColor( 255, 0, 0, 100 ) );
5684
5685 delete w;
5686
5687 // with null
5688 QgsProcessingParameterColor param2( QStringLiteral( "c2" ), QStringLiteral( "c2" ), QColor( 10, 20, 30 ), true, true );
5689
5690 QgsProcessingColorWidgetWrapper wrapper2( ¶m2, type );
5691 w = wrapper2.createWrappedWidget( context );
5692 QVERIFY( static_cast< QgsColorButton * >( wrapper2.wrappedWidget() )->showNull() );
5693 QCOMPARE( static_cast< QgsColorButton * >( wrapper2.wrappedWidget() )->color().name(), QStringLiteral( "#0a141e" ) );
5694 wrapper2.setWidgetValue( QVariant(), context );
5695 QVERIFY( !wrapper2.widgetValue().isValid() );
5696 wrapper2.setWidgetValue( QColor( 255, 0, 255 ), context );
5697 QCOMPARE( wrapper2.widgetValue().value< QColor >().name(), QStringLiteral( "#ff00ff" ) );
5698
5699 // no opacity
5700 QgsProcessingParameterColor param3( QStringLiteral( "c2" ), QStringLiteral( "c2" ), QColor( 10, 20, 30 ), false, true );
5701
5702 QgsProcessingColorWidgetWrapper wrapper3( ¶m3, type );
5703 w = wrapper3.createWrappedWidget( context );
5704 wrapper3.setWidgetValue( QColor( 255, 0, 0, 100 ), context );
5705 QCOMPARE( wrapper3.widgetValue().value< QColor >(), QColor( 255, 0, 0 ) );
5706 };
5707
5708 // standard wrapper
5709 testWrapper( QgsProcessingGui::Standard );
5710
5711 // batch wrapper
5712 testWrapper( QgsProcessingGui::Batch );
5713
5714 // modeler wrapper
5715 testWrapper( QgsProcessingGui::Modeler );
5716
5717 // config widget
5718 QgsProcessingParameterWidgetContext widgetContext;
5719 QgsProcessingContext context;
5720 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "color" ), context, widgetContext );
5721 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
5722 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
5723 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
5724 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
5725 QVERIFY( static_cast< QgsProcessingParameterColor * >( def.get() )->opacityEnabled() ); // should default to true
5726
5727 // using a parameter definition as initial values
5728 QgsProcessingParameterColor colorParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), QColor( 255, 0, 0, 100 ), true );
5729 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "color" ), context, widgetContext, &colorParam );
5730 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
5731 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
5732 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
5733 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
5734 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
5735 QCOMPARE( static_cast< QgsProcessingParameterColor * >( def.get() )->defaultValue().value< QColor >(), QColor( 255, 0, 0, 100 ) );
5736 QVERIFY( static_cast< QgsProcessingParameterColor * >( def.get() )->opacityEnabled() );
5737 colorParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
5738 colorParam.setOpacityEnabled( false );
5739 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "color" ), context, widgetContext, &colorParam );
5740 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
5741 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
5742 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
5743 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
5744 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
5745 QCOMPARE( static_cast< QgsProcessingParameterColor * >( def.get() )->defaultValue().value< QColor >(), QColor( 255, 0, 0 ) ); // (no opacity!)
5746 QVERIFY( !static_cast< QgsProcessingParameterColor * >( def.get() )->opacityEnabled() );
5747 }
5748
testCoordinateOperationWrapper()5749 void TestProcessingGui::testCoordinateOperationWrapper()
5750 {
5751 auto testWrapper = []( QgsProcessingGui::WidgetType type )
5752 {
5753 QgsProcessingParameterCoordinateOperation param( QStringLiteral( "op" ), QStringLiteral( "op" ) );
5754
5755 QgsProcessingCoordinateOperationWidgetWrapper wrapper( ¶m, type );
5756
5757 QgsProcessingContext context;
5758 QWidget *w = wrapper.createWrappedWidget( context );
5759 wrapper.setSourceCrsParameterValue( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:26745" ) ) );
5760 wrapper.setDestinationCrsParameterValue( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3857" ) ) );
5761
5762 QSignalSpy spy( &wrapper, &QgsProcessingCoordinateOperationWidgetWrapper::widgetValueHasChanged );
5763 wrapper.setWidgetValue( QStringLiteral( "+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84" ), context );
5764 QCOMPARE( spy.count(), 1 );
5765 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84" ) );
5766 switch ( type )
5767 {
5768 case QgsProcessingGui::Standard:
5769 {
5770 QCOMPARE( static_cast< QgsCoordinateOperationWidget * >( wrapper.wrappedWidget() )->selectedOperation().proj, QStringLiteral( "+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84" ) );
5771 wrapper.setWidgetValue( QStringLiteral( "+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=159 +z=175 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84" ), context );
5772 QCOMPARE( spy.count(), 2 );
5773 QCOMPARE( static_cast< QgsCoordinateOperationWidget * >( wrapper.wrappedWidget() )->selectedOperation().proj, QStringLiteral( "+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=159 +z=175 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84" ) );
5774
5775 // check signal
5776 QgsCoordinateOperationWidget::OperationDetails deets;
5777 deets.proj = QStringLiteral( "+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84" );
5778 static_cast< QgsCoordinateOperationWidget * >( wrapper.wrappedWidget() )->setSelectedOperation( deets );
5779 QCOMPARE( spy.count(), 3 );
5780 break;
5781 }
5782
5783 case QgsProcessingGui::Modeler:
5784 case QgsProcessingGui::Batch:
5785 {
5786 QCOMPARE( wrapper.mLineEdit->text(), QStringLiteral( "+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84" ) );
5787 wrapper.setWidgetValue( QStringLiteral( "+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=159 +z=175 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84" ), context );
5788 QCOMPARE( spy.count(), 2 );
5789 QCOMPARE( wrapper.mLineEdit->text(), QStringLiteral( "+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=159 +z=175 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84" ) );
5790
5791 // check signal
5792 wrapper.mLineEdit->setText( QStringLiteral( "+proj=pipeline +step +proj=unitconvert +xy_in=us-ft +xy_out=m +step +inv +proj=lcc +lat_0=33.5 +lon_0=-118 +lat_1=35.4666666666667 +lat_2=34.0333333333333 +x_0=609601.219202438 +y_0=0 +ellps=clrk66 +step +proj=push +v_3 +step +proj=cart +ellps=clrk66 +step +proj=helmert +x=-8 +y=160 +z=176 +step +inv +proj=cart +ellps=WGS84 +step +proj=pop +v_3 +step +proj=webmerc +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84" ) );
5793 QCOMPARE( spy.count(), 3 );
5794 break;
5795 }
5796 }
5797
5798 QLabel *l = wrapper.createWrappedLabel();
5799 if ( wrapper.type() != QgsProcessingGui::Batch )
5800 {
5801 QVERIFY( l );
5802 QCOMPARE( l->text(), QStringLiteral( "op" ) );
5803 QCOMPARE( l->toolTip(), param.toolTip() );
5804 delete l;
5805 }
5806 else
5807 {
5808 QVERIFY( !l );
5809 }
5810
5811 delete w;
5812 };
5813
5814 // standard wrapper
5815 testWrapper( QgsProcessingGui::Standard );
5816
5817 // batch wrapper
5818 testWrapper( QgsProcessingGui::Batch );
5819
5820 // modeler wrapper
5821 testWrapper( QgsProcessingGui::Modeler );
5822
5823 // config widget
5824 QgsProcessingParameterWidgetContext widgetContext;
5825 QgsProcessingContext context;
5826 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "coordinateoperation" ), context, widgetContext );
5827 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
5828 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
5829 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
5830 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
5831
5832 QVERIFY( !static_cast< QgsProcessingParameterCoordinateOperation * >( def.get() )->sourceCrs().isValid() ); // should default to not set
5833 QVERIFY( !static_cast< QgsProcessingParameterCoordinateOperation * >( def.get() )->destinationCrs().isValid() ); // should default to not set
5834 QVERIFY( static_cast< QgsProcessingParameterCoordinateOperation * >( def.get() )->sourceCrsParameterName().isEmpty() ); // should default to not set
5835 QVERIFY( static_cast< QgsProcessingParameterCoordinateOperation * >( def.get() )->destinationCrsParameterName().isEmpty() ); // should default to not set
5836
5837 // using a parameter definition as initial values
5838 QgsProcessingParameterCoordinateOperation coordParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), QStringLiteral( "+proj" ), QStringLiteral( "a" ), QStringLiteral( "b" ), QStringLiteral( "EPSG:26745" ), QStringLiteral( "EPSG:4326" ), false );
5839 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "coordinateoperation" ), context, widgetContext, &coordParam );
5840 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
5841 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
5842 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
5843 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
5844 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
5845 QCOMPARE( static_cast< QgsProcessingParameterCoordinateOperation * >( def.get() )->defaultValue().toString(), QStringLiteral( "+proj" ) );
5846 QCOMPARE( static_cast< QgsProcessingParameterCoordinateOperation * >( def.get() )->sourceCrsParameterName(), QStringLiteral( "a" ) );
5847 QCOMPARE( static_cast< QgsProcessingParameterCoordinateOperation * >( def.get() )->destinationCrsParameterName(), QStringLiteral( "b" ) );
5848 QCOMPARE( static_cast< QgsProcessingParameterCoordinateOperation * >( def.get() )->sourceCrs().value< QgsCoordinateReferenceSystem >( ).authid(), QStringLiteral( "EPSG:26745" ) );
5849 QCOMPARE( static_cast< QgsProcessingParameterCoordinateOperation * >( def.get() )->destinationCrs().value< QgsCoordinateReferenceSystem >( ).authid(), QStringLiteral( "EPSG:4326" ) );
5850 coordParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
5851 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "coordinateoperation" ), context, widgetContext, &coordParam );
5852 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
5853 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
5854 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
5855 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
5856 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
5857 }
5858
mapLayerComboBox()5859 void TestProcessingGui::mapLayerComboBox()
5860 {
5861 QgsProject::instance()->removeAllMapLayers();
5862 QgsProcessingContext context;
5863 context.setProject( QgsProject::instance() );
5864
5865 // feature source param
5866 std::unique_ptr< QgsProcessingParameterDefinition > param( new QgsProcessingParameterFeatureSource( QStringLiteral( "param" ), QString() ) );
5867 std::unique_ptr< QgsProcessingMapLayerComboBox> combo = std::make_unique< QgsProcessingMapLayerComboBox >( param.get() );
5868
5869 QSignalSpy spy( combo.get(), &QgsProcessingMapLayerComboBox::valueChanged );
5870 QVERIFY( !combo->value().isValid() );
5871 combo->setValue( QStringLiteral( "file path" ), context );
5872 QCOMPARE( spy.count(), 1 );
5873 QCOMPARE( combo->value().toString(), QStringLiteral( "file path" ) );
5874 QVERIFY( !combo->currentLayer() );
5875 QCOMPARE( spy.count(), 1 );
5876 combo->setValue( QVariant(), context ); // not possible, it's not an optional param
5877 QCOMPARE( combo->value().toString(), QStringLiteral( "file path" ) );
5878 QVERIFY( !combo->currentLayer() );
5879 QCOMPARE( spy.count(), 1 );
5880 combo->setValue( QStringLiteral( "file path 2" ), context );
5881 QCOMPARE( combo->value().toString(), QStringLiteral( "file path 2" ) );
5882 QVERIFY( !combo->currentLayer() );
5883 QCOMPARE( spy.count(), 2 );
5884 combo->setValue( QStringLiteral( "file path" ), context );
5885 QCOMPARE( combo->value().toString(), QStringLiteral( "file path" ) );
5886 QVERIFY( !combo->currentLayer() );
5887 QCOMPARE( spy.count(), 3 );
5888 combo->setLayer( nullptr ); // not possible, not optional
5889 QCOMPARE( combo->value().toString(), QStringLiteral( "file path" ) );
5890 QVERIFY( !combo->currentLayer() );
5891 QCOMPARE( spy.count(), 3 );
5892
5893 // project layers
5894 QgsVectorLayer *vl = new QgsVectorLayer( QStringLiteral( "LineString" ), QStringLiteral( "l1" ), QStringLiteral( "memory" ) );
5895 QgsFeature f;
5896 vl->dataProvider()->addFeature( f );
5897 QgsProject::instance()->addMapLayer( vl );
5898 QVERIFY( vl->isValid() );
5899 QgsVectorLayer *vl2 = new QgsVectorLayer( QStringLiteral( "LineString" ), QStringLiteral( "l2" ), QStringLiteral( "memory" ) );
5900 vl2->dataProvider()->addFeature( f );
5901 QgsProject::instance()->addMapLayer( vl2 );
5902 QVERIFY( vl2->isValid() );
5903
5904 QCOMPARE( combo->value().toString(), QStringLiteral( "file path" ) );
5905 QVERIFY( !combo->currentLayer() );
5906 QCOMPARE( spy.count(), 3 );
5907
5908 combo->setLayer( vl );
5909 QCOMPARE( combo->currentLayer(), vl );
5910 QCOMPARE( combo->value().toString(), vl->id() );
5911 QVERIFY( combo->currentText().startsWith( vl->name() ) );
5912 QCOMPARE( spy.count(), 4 );
5913 combo->setLayer( vl );
5914 QCOMPARE( spy.count(), 4 );
5915
5916 combo->setLayer( vl2 );
5917 QCOMPARE( combo->value().toString(), vl2->id() );
5918 QVERIFY( combo->currentText().startsWith( vl2->name() ) );
5919 QCOMPARE( spy.count(), 5 );
5920
5921 combo->setValue( QStringLiteral( "file path" ), context );
5922 QCOMPARE( combo->value().toString(), QStringLiteral( "file path" ) );
5923 QVERIFY( !combo->currentLayer() );
5924 QCOMPARE( spy.count(), 6 );
5925
5926 // setting feature source def, i.e. with selection
5927 QgsProcessingFeatureSourceDefinition sourceDef( vl2->id(), false );
5928 combo->setValue( sourceDef, context );
5929 QCOMPARE( combo->value().toString(), vl2->id() );
5930 QVERIFY( combo->currentText().startsWith( vl2->name() ) );
5931 QCOMPARE( spy.count(), 7 );
5932 // asking for selected features only, but no selection in layer, won't be allowed
5933 sourceDef = QgsProcessingFeatureSourceDefinition( vl2->id(), true );
5934 combo->setValue( sourceDef, context );
5935 QCOMPARE( combo->value().toString(), vl2->id() );
5936 QVERIFY( combo->currentText().startsWith( vl2->name() ) );
5937 QCOMPARE( spy.count(), 7 ); // no change
5938
5939 // now make a selection in the layer, and repeat
5940 vl2->selectAll();
5941 combo->setValue( sourceDef, context );
5942 QVERIFY( combo->value().canConvert< QgsProcessingFeatureSourceDefinition >() );
5943 QCOMPARE( combo->value().value< QgsProcessingFeatureSourceDefinition >().source.staticValue().toString(), vl2->id() );
5944 QVERIFY( combo->value().value< QgsProcessingFeatureSourceDefinition >().selectedFeaturesOnly );
5945 QVERIFY( combo->currentText().startsWith( vl2->name() ) );
5946 QCOMPARE( spy.count(), 8 );
5947
5948 // remove layer selection, and check result...
5949 vl2->removeSelection();
5950 QCOMPARE( combo->value().toString(), vl2->id() );
5951 QVERIFY( combo->currentText().startsWith( vl2->name() ) );
5952 QCOMPARE( spy.count(), 9 );
5953
5954 // phew, nearly there. Let's check another variation
5955 vl2->selectAll();
5956 combo->setValue( sourceDef, context );
5957 QVERIFY( combo->value().canConvert< QgsProcessingFeatureSourceDefinition >() );
5958 QCOMPARE( spy.count(), 10 );
5959 combo->setValue( QVariant::fromValue( vl ), context );
5960 QCOMPARE( combo->value().toString(), vl->id() );
5961 QVERIFY( combo->currentText().startsWith( vl->name() ) );
5962 QCOMPARE( spy.count(), 11 );
5963
5964 // one last variation - selection to selection
5965 combo->setValue( sourceDef, context );
5966 QCOMPARE( spy.count(), 12 );
5967 QVERIFY( combo->value().value< QgsProcessingFeatureSourceDefinition >().selectedFeaturesOnly );
5968 vl->selectAll();
5969 sourceDef = QgsProcessingFeatureSourceDefinition( vl->id(), true );
5970 combo->setValue( sourceDef, context );
5971 // expect "selected only" state to remain
5972 QVERIFY( combo->value().canConvert< QgsProcessingFeatureSourceDefinition >() );
5973 QCOMPARE( combo->value().value< QgsProcessingFeatureSourceDefinition >().source.staticValue().toString(), vl->id() );
5974 QVERIFY( combo->value().value< QgsProcessingFeatureSourceDefinition >().selectedFeaturesOnly );
5975 QVERIFY( combo->currentText().startsWith( vl->name() ) );
5976 QCOMPARE( spy.count(), 13 );
5977
5978 // iterate over features
5979 QVERIFY( !( combo->value().value< QgsProcessingFeatureSourceDefinition >().flags & QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature ) );
5980 sourceDef.flags |= QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature;
5981 combo->setValue( sourceDef, context );
5982 QVERIFY( combo->value().value< QgsProcessingFeatureSourceDefinition >().flags & QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature );
5983 sourceDef.flags = QgsProcessingFeatureSourceDefinition::Flags();
5984 combo->setValue( sourceDef, context );
5985 QVERIFY( !( combo->value().value< QgsProcessingFeatureSourceDefinition >().flags & QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature ) );
5986
5987 // advanced settings
5988 sourceDef.featureLimit = 67;
5989 combo->setValue( sourceDef, context );
5990 QCOMPARE( combo->value().value< QgsProcessingFeatureSourceDefinition >().featureLimit, 67LL );
5991 sourceDef.featureLimit = -1;
5992 combo->setValue( sourceDef, context );
5993 QCOMPARE( combo->value().value< QgsProcessingFeatureSourceDefinition >().featureLimit, -1LL );
5994 sourceDef.flags |= QgsProcessingFeatureSourceDefinition::Flag::FlagOverrideDefaultGeometryCheck;
5995 sourceDef.geometryCheck = QgsFeatureRequest::GeometrySkipInvalid;
5996 combo->setValue( sourceDef, context );
5997 QVERIFY( combo->value().value< QgsProcessingFeatureSourceDefinition >().flags & QgsProcessingFeatureSourceDefinition::Flag::FlagOverrideDefaultGeometryCheck );
5998 QCOMPARE( combo->value().value< QgsProcessingFeatureSourceDefinition >().geometryCheck, QgsFeatureRequest::GeometrySkipInvalid );
5999 sourceDef.flags = QgsProcessingFeatureSourceDefinition::Flags();
6000 combo->setValue( sourceDef, context );
6001 QVERIFY( !( combo->value().value< QgsProcessingFeatureSourceDefinition >().flags & QgsProcessingFeatureSourceDefinition::Flag::FlagOverrideDefaultGeometryCheck ) );
6002
6003 combo.reset();
6004 param.reset();
6005
6006 // setup a project with a range of layer types
6007 QgsProject::instance()->removeAllMapLayers();
6008 QgsVectorLayer *point = new QgsVectorLayer( QStringLiteral( "Point" ), QStringLiteral( "l1" ), QStringLiteral( "memory" ) );
6009 QgsProject::instance()->addMapLayer( point );
6010 QgsVectorLayer *line = new QgsVectorLayer( QStringLiteral( "LineString" ), QStringLiteral( "l1" ), QStringLiteral( "memory" ) );
6011 QgsProject::instance()->addMapLayer( line );
6012 QgsVectorLayer *polygon = new QgsVectorLayer( QStringLiteral( "Polygon" ), QStringLiteral( "l1" ), QStringLiteral( "memory" ) );
6013 QgsProject::instance()->addMapLayer( polygon );
6014 QgsVectorLayer *noGeom = new QgsVectorLayer( QStringLiteral( "None" ), QStringLiteral( "l1" ), QStringLiteral( "memory" ) );
6015 QgsProject::instance()->addMapLayer( noGeom );
6016 QgsMeshLayer *mesh = new QgsMeshLayer( QStringLiteral( TEST_DATA_DIR ) + "/mesh/quad_and_triangle.2dm", QStringLiteral( "Triangle and Quad Mdal" ), QStringLiteral( "mdal" ) );
6017 mesh->dataProvider()->addDataset( QStringLiteral( TEST_DATA_DIR ) + "/mesh/quad_and_triangle_vertex_scalar_with_inactive_face.dat" );
6018 QVERIFY( mesh->isValid() );
6019 QgsProject::instance()->addMapLayer( mesh );
6020 QgsRasterLayer *raster = new QgsRasterLayer( QStringLiteral( TEST_DATA_DIR ) + "/raster/band1_byte_ct_epsg4326.tif", QStringLiteral( "band1_byte" ) );
6021 QgsProject::instance()->addMapLayer( raster );
6022
6023 // map layer param, all types are acceptable
6024 param = std::make_unique< QgsProcessingParameterMapLayer> ( QStringLiteral( "param" ), QString() );
6025 combo = std::make_unique< QgsProcessingMapLayerComboBox >( param.get() );
6026 combo->setLayer( point );
6027 QCOMPARE( combo->currentLayer(), point );
6028 combo->setLayer( line );
6029 QCOMPARE( combo->currentLayer(), line );
6030 combo->setLayer( polygon );
6031 QCOMPARE( combo->currentLayer(), polygon );
6032 combo->setLayer( noGeom );
6033 QCOMPARE( combo->currentLayer(), noGeom );
6034 combo->setLayer( mesh );
6035 QCOMPARE( combo->currentLayer(), mesh );
6036 combo->setLayer( raster );
6037 QCOMPARE( combo->currentLayer(), raster );
6038 combo.reset();
6039 param.reset();
6040
6041 // map layer param, only point vector and raster types are acceptable
6042 param = std::make_unique< QgsProcessingParameterMapLayer> ( QStringLiteral( "param" ), QString(), QVariant(), false, QList< int >() << QgsProcessing::TypeVectorPoint << QgsProcessing::TypeRaster );
6043 combo = std::make_unique< QgsProcessingMapLayerComboBox >( param.get() );
6044 combo->setLayer( point );
6045 QCOMPARE( combo->currentLayer(), point );
6046 combo->setLayer( line );
6047 QVERIFY( !combo->currentLayer() );
6048 combo->setLayer( polygon );
6049 QVERIFY( !combo->currentLayer() );
6050 combo->setLayer( noGeom );
6051 QVERIFY( !combo->currentLayer() );
6052 combo->setLayer( mesh );
6053 QVERIFY( !combo->currentLayer() );
6054 combo->setLayer( raster );
6055 QCOMPARE( combo->currentLayer(), raster );
6056 combo.reset();
6057 param.reset();
6058
6059 // raster layer param, only raster types are acceptable
6060 param = std::make_unique< QgsProcessingParameterRasterLayer> ( QStringLiteral( "param" ), QString() );
6061 combo = std::make_unique< QgsProcessingMapLayerComboBox >( param.get() );
6062 combo->setLayer( point );
6063 QVERIFY( !combo->currentLayer() );
6064 combo->setLayer( line );
6065 QVERIFY( !combo->currentLayer() );
6066 combo->setLayer( polygon );
6067 QVERIFY( !combo->currentLayer() );
6068 combo->setLayer( noGeom );
6069 QVERIFY( !combo->currentLayer() );
6070 combo->setLayer( mesh );
6071 QVERIFY( !combo->currentLayer() );
6072 combo->setLayer( raster );
6073 QCOMPARE( combo->currentLayer(), raster );
6074 combo.reset();
6075 param.reset();
6076
6077 // mesh layer parm, only mesh types are acceptable
6078 param = std::make_unique< QgsProcessingParameterMeshLayer> ( QStringLiteral( "param" ), QString() );
6079 combo = std::make_unique< QgsProcessingMapLayerComboBox >( param.get() );
6080 combo->setLayer( point );
6081 QVERIFY( !combo->currentLayer() );
6082 combo->setLayer( line );
6083 QVERIFY( !combo->currentLayer() );
6084 combo->setLayer( polygon );
6085 QVERIFY( !combo->currentLayer() );
6086 combo->setLayer( noGeom );
6087 QVERIFY( !combo->currentLayer() );
6088 combo->setLayer( mesh );
6089 QCOMPARE( combo->currentLayer(), mesh );
6090 combo->setLayer( raster );
6091 QVERIFY( !combo->currentLayer() );
6092 combo.reset();
6093 param.reset();
6094
6095 // feature source and vector layer params
6096 // if not specified, the default is any vector layer with geometry
6097 param = std::make_unique< QgsProcessingParameterVectorLayer> ( QStringLiteral( "param" ) );
6098 combo = std::make_unique< QgsProcessingMapLayerComboBox >( param.get() );
6099 auto param2 = std::make_unique< QgsProcessingParameterFeatureSource> ( QStringLiteral( "param" ) );
6100 auto combo2 = std::make_unique< QgsProcessingMapLayerComboBox >( param2.get() );
6101 combo->setLayer( point );
6102 QCOMPARE( combo->currentLayer(), point );
6103 combo2->setLayer( point );
6104 QCOMPARE( combo2->currentLayer(), point );
6105 combo->setLayer( line );
6106 QCOMPARE( combo->currentLayer(), line );
6107 combo2->setLayer( line );
6108 QCOMPARE( combo2->currentLayer(), line );
6109 combo->setLayer( polygon );
6110 QCOMPARE( combo->currentLayer(), polygon );
6111 combo2->setLayer( polygon );
6112 QCOMPARE( combo2->currentLayer(), polygon );
6113 combo->setLayer( noGeom );
6114 QVERIFY( !combo->currentLayer() );
6115 combo2->setLayer( noGeom );
6116 QVERIFY( !combo2->currentLayer() );
6117 combo->setLayer( mesh );
6118 QVERIFY( !combo->currentLayer() );
6119 combo2->setLayer( mesh );
6120 QVERIFY( !combo2->currentLayer() );
6121 combo->setLayer( raster );
6122 QVERIFY( !combo->currentLayer() );
6123 combo2->setLayer( raster );
6124 QVERIFY( !combo2->currentLayer() );
6125 combo2.reset();
6126 param2.reset();
6127 combo.reset();
6128 param.reset();
6129
6130 // point layer
6131 param = std::make_unique< QgsProcessingParameterVectorLayer> ( QStringLiteral( "param" ), QString(), QList< int>() << QgsProcessing::TypeVectorPoint );
6132 combo = std::make_unique< QgsProcessingMapLayerComboBox >( param.get() );
6133 param2 = std::make_unique< QgsProcessingParameterFeatureSource> ( QStringLiteral( "param" ), QString(), QList< int>() << QgsProcessing::TypeVectorPoint );
6134 combo2 = std::make_unique< QgsProcessingMapLayerComboBox >( param2.get() );
6135 combo->setLayer( point );
6136 QCOMPARE( combo->currentLayer(), point );
6137 combo2->setLayer( point );
6138 QCOMPARE( combo2->currentLayer(), point );
6139 combo->setLayer( line );
6140 QVERIFY( !combo->currentLayer() );
6141 combo2->setLayer( line );
6142 QVERIFY( !combo2->currentLayer() );
6143 combo->setLayer( polygon );
6144 QVERIFY( !combo->currentLayer() );
6145 combo2->setLayer( polygon );
6146 QVERIFY( !combo2->currentLayer() );
6147 combo->setLayer( noGeom );
6148 QVERIFY( !combo->currentLayer() );
6149 combo2->setLayer( noGeom );
6150 QVERIFY( !combo2->currentLayer() );
6151 combo->setLayer( mesh );
6152 QVERIFY( !combo->currentLayer() );
6153 combo2->setLayer( mesh );
6154 QVERIFY( !combo2->currentLayer() );
6155 combo->setLayer( raster );
6156 QVERIFY( !combo->currentLayer() );
6157 combo2->setLayer( raster );
6158 QVERIFY( !combo2->currentLayer() );
6159 combo2.reset();
6160 param2.reset();
6161 combo.reset();
6162 param.reset();
6163
6164 // line layer
6165 param = std::make_unique< QgsProcessingParameterVectorLayer> ( QStringLiteral( "param" ), QString(), QList< int>() << QgsProcessing::TypeVectorLine );
6166 combo = std::make_unique< QgsProcessingMapLayerComboBox >( param.get() );
6167 param2 = std::make_unique< QgsProcessingParameterFeatureSource> ( QStringLiteral( "param" ), QString(), QList< int>() << QgsProcessing::TypeVectorLine );
6168 combo2 = std::make_unique< QgsProcessingMapLayerComboBox >( param2.get() );
6169 combo->setLayer( point );
6170 QVERIFY( !combo->currentLayer() );
6171 combo2->setLayer( point );
6172 QVERIFY( !combo2->currentLayer() );
6173 combo->setLayer( line );
6174 QCOMPARE( combo->currentLayer(), line );
6175 combo2->setLayer( line );
6176 QCOMPARE( combo2->currentLayer(), line );
6177 combo->setLayer( polygon );
6178 QVERIFY( !combo->currentLayer() );
6179 combo2->setLayer( polygon );
6180 QVERIFY( !combo2->currentLayer() );
6181 combo->setLayer( noGeom );
6182 QVERIFY( !combo->currentLayer() );
6183 combo2->setLayer( noGeom );
6184 QVERIFY( !combo2->currentLayer() );
6185 combo->setLayer( mesh );
6186 QVERIFY( !combo->currentLayer() );
6187 combo2->setLayer( mesh );
6188 QVERIFY( !combo2->currentLayer() );
6189 combo->setLayer( raster );
6190 QVERIFY( !combo->currentLayer() );
6191 combo2->setLayer( raster );
6192 QVERIFY( !combo2->currentLayer() );
6193 combo2.reset();
6194 param2.reset();
6195 combo.reset();
6196 param.reset();
6197
6198 // polygon
6199 param = std::make_unique< QgsProcessingParameterVectorLayer> ( QStringLiteral( "param" ), QString(), QList< int>() << QgsProcessing::TypeVectorPolygon );
6200 combo = std::make_unique< QgsProcessingMapLayerComboBox >( param.get() );
6201 param2 = std::make_unique< QgsProcessingParameterFeatureSource> ( QStringLiteral( "param" ), QString(), QList< int>() << QgsProcessing::TypeVectorPolygon );
6202 combo2 = std::make_unique< QgsProcessingMapLayerComboBox >( param2.get() );
6203 combo->setLayer( point );
6204 QVERIFY( !combo->currentLayer() );
6205 combo2->setLayer( point );
6206 QVERIFY( !combo2->currentLayer() );
6207 combo->setLayer( line );
6208 QVERIFY( !combo->currentLayer() );
6209 combo2->setLayer( line );
6210 QVERIFY( !combo2->currentLayer() );
6211 combo->setLayer( polygon );
6212 QCOMPARE( combo->currentLayer(), polygon );
6213 combo2->setLayer( polygon );
6214 QCOMPARE( combo2->currentLayer(), polygon );
6215 combo->setLayer( noGeom );
6216 QVERIFY( !combo->currentLayer() );
6217 combo2->setLayer( noGeom );
6218 QVERIFY( !combo2->currentLayer() );
6219 combo->setLayer( mesh );
6220 QVERIFY( !combo->currentLayer() );
6221 combo2->setLayer( mesh );
6222 QVERIFY( !combo2->currentLayer() );
6223 combo->setLayer( raster );
6224 QVERIFY( !combo->currentLayer() );
6225 combo2->setLayer( raster );
6226 QVERIFY( !combo2->currentLayer() );
6227 combo2.reset();
6228 param2.reset();
6229 combo.reset();
6230 param.reset();
6231
6232 // no geom
6233 param = std::make_unique< QgsProcessingParameterVectorLayer> ( QStringLiteral( "param" ), QString(), QList< int>() << QgsProcessing::TypeVector );
6234 combo = std::make_unique< QgsProcessingMapLayerComboBox >( param.get() );
6235 param2 = std::make_unique< QgsProcessingParameterFeatureSource> ( QStringLiteral( "param" ), QString(), QList< int>() << QgsProcessing::TypeVector );
6236 combo2 = std::make_unique< QgsProcessingMapLayerComboBox >( param2.get() );
6237 combo->setLayer( point );
6238 QCOMPARE( combo->currentLayer(), point );
6239 combo2->setLayer( point );
6240 QCOMPARE( combo2->currentLayer(), point );
6241 combo->setLayer( line );
6242 QCOMPARE( combo->currentLayer(), line );
6243 combo2->setLayer( line );
6244 QCOMPARE( combo2->currentLayer(), line );
6245 combo->setLayer( polygon );
6246 QCOMPARE( combo->currentLayer(), polygon );
6247 combo2->setLayer( polygon );
6248 QCOMPARE( combo2->currentLayer(), polygon );
6249 combo->setLayer( noGeom );
6250 QCOMPARE( combo->currentLayer(), noGeom );
6251 combo2->setLayer( noGeom );
6252 QCOMPARE( combo2->currentLayer(), noGeom );
6253 combo->setLayer( mesh );
6254 QVERIFY( !combo->currentLayer() );
6255 combo2->setLayer( mesh );
6256 QVERIFY( !combo2->currentLayer() );
6257 combo->setLayer( raster );
6258 QVERIFY( !combo->currentLayer() );
6259 combo2->setLayer( raster );
6260 QVERIFY( !combo2->currentLayer() );
6261 combo2.reset();
6262 param2.reset();
6263 combo.reset();
6264 param.reset();
6265
6266 // any geom
6267 param = std::make_unique< QgsProcessingParameterVectorLayer> ( QStringLiteral( "param" ), QString(), QList< int>() << QgsProcessing::TypeVectorAnyGeometry );
6268 combo = std::make_unique< QgsProcessingMapLayerComboBox >( param.get() );
6269 param2 = std::make_unique< QgsProcessingParameterFeatureSource> ( QStringLiteral( "param" ), QString(), QList< int>() << QgsProcessing::TypeVectorAnyGeometry );
6270 combo2 = std::make_unique< QgsProcessingMapLayerComboBox >( param2.get() );
6271 combo->setLayer( point );
6272 QCOMPARE( combo->currentLayer(), point );
6273 combo2->setLayer( point );
6274 QCOMPARE( combo2->currentLayer(), point );
6275 combo->setLayer( line );
6276 QCOMPARE( combo->currentLayer(), line );
6277 combo2->setLayer( line );
6278 QCOMPARE( combo2->currentLayer(), line );
6279 combo->setLayer( polygon );
6280 QCOMPARE( combo->currentLayer(), polygon );
6281 combo2->setLayer( polygon );
6282 QCOMPARE( combo2->currentLayer(), polygon );
6283 combo->setLayer( noGeom );
6284 QVERIFY( !combo->currentLayer() );
6285 combo2->setLayer( noGeom );
6286 QVERIFY( !combo2->currentLayer() );
6287 combo->setLayer( mesh );
6288 QVERIFY( !combo->currentLayer() );
6289 combo2->setLayer( mesh );
6290 QVERIFY( !combo2->currentLayer() );
6291 combo->setLayer( raster );
6292 QVERIFY( !combo->currentLayer() );
6293 combo2->setLayer( raster );
6294 QVERIFY( !combo2->currentLayer() );
6295 combo2.reset();
6296 param2.reset();
6297 combo.reset();
6298 param.reset();
6299
6300 // combination point and line only
6301 param = std::make_unique< QgsProcessingParameterVectorLayer> ( QStringLiteral( "param" ), QString(), QList< int>() << QgsProcessing::TypeVectorPoint << QgsProcessing::TypeVectorLine );
6302 combo = std::make_unique< QgsProcessingMapLayerComboBox >( param.get() );
6303 param2 = std::make_unique< QgsProcessingParameterFeatureSource> ( QStringLiteral( "param" ), QString(), QList< int>() << QgsProcessing::TypeVectorPoint << QgsProcessing::TypeVectorLine );
6304 combo2 = std::make_unique< QgsProcessingMapLayerComboBox >( param2.get() );
6305 combo->setLayer( point );
6306 QCOMPARE( combo->currentLayer(), point );
6307 combo2->setLayer( point );
6308 QCOMPARE( combo2->currentLayer(), point );
6309 combo->setLayer( line );
6310 QCOMPARE( combo->currentLayer(), line );
6311 combo2->setLayer( line );
6312 QCOMPARE( combo2->currentLayer(), line );
6313 combo->setLayer( polygon );
6314 QVERIFY( !combo->currentLayer() );
6315 combo2->setLayer( polygon );
6316 QVERIFY( !combo2->currentLayer() );
6317 combo->setLayer( noGeom );
6318 QVERIFY( !combo->currentLayer() );
6319 combo2->setLayer( noGeom );
6320 QVERIFY( !combo2->currentLayer() );
6321 combo->setLayer( mesh );
6322 QVERIFY( !combo->currentLayer() );
6323 combo2->setLayer( mesh );
6324 QVERIFY( !combo2->currentLayer() );
6325 combo->setLayer( raster );
6326 QVERIFY( !combo->currentLayer() );
6327 combo2->setLayer( raster );
6328 QVERIFY( !combo2->currentLayer() );
6329 combo2.reset();
6330 param2.reset();
6331 combo.reset();
6332 param.reset();
6333
6334 // optional
6335 param = std::make_unique< QgsProcessingParameterVectorLayer> ( QStringLiteral( "param" ), QString(), QList< int>(), QVariant(), true );
6336 combo = std::make_unique< QgsProcessingMapLayerComboBox >( param.get() );
6337 combo->setLayer( point );
6338 QCOMPARE( combo->currentLayer(), point );
6339 combo->setLayer( nullptr );
6340 QVERIFY( !combo->currentLayer() );
6341 QVERIFY( !combo->value().isValid() );
6342 combo->setLayer( point );
6343 QCOMPARE( combo->currentLayer(), point );
6344 combo->setValue( QVariant(), context );
6345 QVERIFY( !combo->currentLayer() );
6346 QVERIFY( !combo->value().isValid() );
6347
6348 combo2.reset();
6349 param2.reset();
6350 combo.reset();
6351 param.reset();
6352 QgsProject::instance()->removeAllMapLayers();
6353 }
6354
testMapLayerWrapper()6355 void TestProcessingGui::testMapLayerWrapper()
6356 {
6357 // setup a project with a range of layer types
6358 QgsProject::instance()->removeAllMapLayers();
6359 QgsVectorLayer *point = new QgsVectorLayer( QStringLiteral( "Point" ), QStringLiteral( "l1" ), QStringLiteral( "memory" ) );
6360 QgsProject::instance()->addMapLayer( point );
6361 QgsVectorLayer *line = new QgsVectorLayer( QStringLiteral( "LineString" ), QStringLiteral( "l1" ), QStringLiteral( "memory" ) );
6362 QgsProject::instance()->addMapLayer( line );
6363 QgsVectorLayer *polygon = new QgsVectorLayer( QStringLiteral( "Polygon" ), QStringLiteral( "l1" ), QStringLiteral( "memory" ) );
6364 QgsProject::instance()->addMapLayer( polygon );
6365 QgsVectorLayer *noGeom = new QgsVectorLayer( QStringLiteral( "None" ), QStringLiteral( "l1" ), QStringLiteral( "memory" ) );
6366 QgsProject::instance()->addMapLayer( noGeom );
6367 QgsMeshLayer *mesh = new QgsMeshLayer( QStringLiteral( TEST_DATA_DIR ) + "/mesh/quad_and_triangle.2dm", QStringLiteral( "Triangle and Quad Mdal" ), QStringLiteral( "mdal" ) );
6368 mesh->dataProvider()->addDataset( QStringLiteral( TEST_DATA_DIR ) + "/mesh/quad_and_triangle_vertex_scalar_with_inactive_face.dat" );
6369 QVERIFY( mesh->isValid() );
6370 QgsProject::instance()->addMapLayer( mesh );
6371 QgsRasterLayer *raster = new QgsRasterLayer( QStringLiteral( TEST_DATA_DIR ) + "/raster/band1_byte_ct_epsg4326.tif", QStringLiteral( "band1_byte" ) );
6372 QgsProject::instance()->addMapLayer( raster );
6373
6374 auto testWrapper = [ = ]( QgsProcessingGui::WidgetType type )
6375 {
6376 // non optional
6377 QgsProcessingParameterMapLayer param( QStringLiteral( "layer" ), QStringLiteral( "layer" ), false );
6378
6379 QgsProcessingMapLayerWidgetWrapper wrapper( ¶m, type );
6380
6381 QgsProcessingContext context;
6382 QWidget *w = wrapper.createWrappedWidget( context );
6383
6384 QSignalSpy spy( &wrapper, &QgsProcessingEnumWidgetWrapper::widgetValueHasChanged );
6385 wrapper.setWidgetValue( QStringLiteral( "bb" ), context );
6386
6387 switch ( type )
6388 {
6389 case QgsProcessingGui::Standard:
6390 case QgsProcessingGui::Batch:
6391 case QgsProcessingGui::Modeler:
6392 QCOMPARE( spy.count(), 1 );
6393 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "bb" ) );
6394 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper.wrappedWidget() )->currentText(), QStringLiteral( "bb" ) );
6395 wrapper.setWidgetValue( QStringLiteral( "aa" ), context );
6396 QCOMPARE( spy.count(), 2 );
6397 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "aa" ) );
6398 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper.wrappedWidget() )->currentText(), QStringLiteral( "aa" ) );
6399 break;
6400 }
6401
6402 delete w;
6403
6404 // with project
6405 QgsProcessingParameterWidgetContext widgetContext;
6406 widgetContext.setProject( QgsProject::instance() );
6407 context.setProject( QgsProject::instance() );
6408
6409 QgsProcessingMapLayerWidgetWrapper wrapper2( ¶m, type );
6410 wrapper2.setWidgetContext( widgetContext );
6411 w = wrapper2.createWrappedWidget( context );
6412
6413 QSignalSpy spy2( &wrapper2, &QgsProcessingMapLayerWidgetWrapper::widgetValueHasChanged );
6414 wrapper2.setWidgetValue( QStringLiteral( "bb" ), context );
6415 QCOMPARE( spy2.count(), 1 );
6416 QCOMPARE( wrapper2.widgetValue().toString(), QStringLiteral( "bb" ) );
6417 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "bb" ) );
6418 wrapper2.setWidgetValue( QStringLiteral( "band1_byte" ), context );
6419 QCOMPARE( spy2.count(), 2 );
6420 QCOMPARE( wrapper2.widgetValue().toString(), raster->id() );
6421 switch ( type )
6422 {
6423 case QgsProcessingGui::Standard:
6424 case QgsProcessingGui::Batch:
6425 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "band1_byte [EPSG:4326]" ) );
6426 break;
6427 case QgsProcessingGui::Modeler:
6428 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "band1_byte" ) );
6429 break;
6430 }
6431
6432 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentLayer()->name(), QStringLiteral( "band1_byte" ) );
6433
6434 // check signal
6435 static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->setLayer( polygon );
6436 QCOMPARE( spy2.count(), 3 );
6437 QCOMPARE( wrapper2.widgetValue().toString(), polygon->id() );
6438 switch ( type )
6439 {
6440 case QgsProcessingGui::Standard:
6441 case QgsProcessingGui::Batch:
6442 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "l1 [EPSG:4326]" ) );
6443 break;
6444
6445 case QgsProcessingGui::Modeler:
6446 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "l1" ) );
6447 break;
6448 }
6449 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentLayer()->name(), QStringLiteral( "l1" ) );
6450
6451 delete w;
6452
6453 // optional
6454 QgsProcessingParameterMapLayer param2( QStringLiteral( "layer" ), QStringLiteral( "layer" ), QVariant(), true );
6455 QgsProcessingMapLayerWidgetWrapper wrapper3( ¶m2, type );
6456 wrapper3.setWidgetContext( widgetContext );
6457 w = wrapper3.createWrappedWidget( context );
6458
6459 QSignalSpy spy3( &wrapper3, &QgsProcessingMapLayerWidgetWrapper::widgetValueHasChanged );
6460 wrapper3.setWidgetValue( QStringLiteral( "bb" ), context );
6461 QCOMPARE( spy3.count(), 1 );
6462 QCOMPARE( wrapper3.widgetValue().toString(), QStringLiteral( "bb" ) );
6463 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "bb" ) );
6464 wrapper3.setWidgetValue( QStringLiteral( "band1_byte" ), context );
6465 QCOMPARE( spy3.count(), 2 );
6466 QCOMPARE( wrapper3.widgetValue().toString(), raster->id() );
6467 switch ( type )
6468 {
6469 case QgsProcessingGui::Standard:
6470 case QgsProcessingGui::Batch:
6471 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "band1_byte [EPSG:4326]" ) );
6472 break;
6473 case QgsProcessingGui::Modeler:
6474 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "band1_byte" ) );
6475 break;
6476 }
6477 wrapper3.setWidgetValue( QVariant(), context );
6478 QCOMPARE( spy3.count(), 3 );
6479 QVERIFY( !wrapper3.widgetValue().isValid() );
6480 delete w;
6481
6482
6483 QLabel *l = wrapper.createWrappedLabel();
6484 if ( wrapper.type() != QgsProcessingGui::Batch )
6485 {
6486 QVERIFY( l );
6487 QCOMPARE( l->text(), QStringLiteral( "layer" ) );
6488 QCOMPARE( l->toolTip(), param.toolTip() );
6489 delete l;
6490 }
6491 else
6492 {
6493 QVERIFY( !l );
6494 }
6495 };
6496
6497 // standard wrapper
6498 testWrapper( QgsProcessingGui::Standard );
6499
6500 // batch wrapper
6501 testWrapper( QgsProcessingGui::Batch );
6502
6503 // modeler wrapper
6504 testWrapper( QgsProcessingGui::Modeler );
6505
6506 // config widget
6507 QgsProcessingParameterWidgetContext widgetContext;
6508 QgsProcessingContext context;
6509 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "layer" ), context, widgetContext );
6510 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
6511 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
6512 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
6513 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
6514
6515 // using a parameter definition as initial values
6516 QgsProcessingParameterMapLayer layerParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), QVariant(), false, QList< int >() << QgsProcessing::TypeVectorAnyGeometry );
6517 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "layer" ), context, widgetContext, &layerParam );
6518 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
6519 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
6520 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
6521 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
6522 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
6523 QCOMPARE( static_cast< QgsProcessingParameterMapLayer * >( def.get() )->dataTypes(), QList< int >() << QgsProcessing::TypeVectorAnyGeometry );
6524 layerParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
6525 layerParam.setDataTypes( QList< int >() << QgsProcessing::TypeRaster << QgsProcessing::TypeVectorPoint );
6526 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "layer" ), context, widgetContext, &layerParam );
6527 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
6528 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
6529 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
6530 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
6531 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
6532 QCOMPARE( static_cast< QgsProcessingParameterMapLayer * >( def.get() )->dataTypes(), QList< int >() << QgsProcessing::TypeVectorPoint << QgsProcessing::TypeRaster );
6533 }
6534
testRasterLayerWrapper()6535 void TestProcessingGui::testRasterLayerWrapper()
6536 {
6537 // setup a project
6538 QgsProject::instance()->removeAllMapLayers();
6539 QgsRasterLayer *raster = new QgsRasterLayer( QStringLiteral( TEST_DATA_DIR ) + "/raster/band1_byte_ct_epsg4326.tif", QStringLiteral( "band1_byte" ) );
6540 QgsProject::instance()->addMapLayer( raster );
6541 QgsRasterLayer *raster2 = new QgsRasterLayer( QStringLiteral( TEST_DATA_DIR ) + "/raster/band1_byte_ct_epsg4326.tif", QStringLiteral( "band1_byte2" ) );
6542 QgsProject::instance()->addMapLayer( raster2 );
6543
6544 auto testWrapper = [ = ]( QgsProcessingGui::WidgetType type )
6545 {
6546 // non optional
6547 QgsProcessingParameterRasterLayer param( QStringLiteral( "raster" ), QStringLiteral( "raster" ), false );
6548
6549 QgsProcessingMapLayerWidgetWrapper wrapper( ¶m, type );
6550
6551 QgsProcessingContext context;
6552 QWidget *w = wrapper.createWrappedWidget( context );
6553
6554 QSignalSpy spy( &wrapper, &QgsProcessingMapLayerWidgetWrapper::widgetValueHasChanged );
6555 wrapper.setWidgetValue( QStringLiteral( "bb" ), context );
6556
6557 switch ( type )
6558 {
6559 case QgsProcessingGui::Standard:
6560 case QgsProcessingGui::Batch:
6561 case QgsProcessingGui::Modeler:
6562 QCOMPARE( spy.count(), 1 );
6563 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "bb" ) );
6564 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper.wrappedWidget() )->currentText(), QStringLiteral( "bb" ) );
6565 wrapper.setWidgetValue( QStringLiteral( "aa" ), context );
6566 QCOMPARE( spy.count(), 2 );
6567 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "aa" ) );
6568 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper.wrappedWidget() )->currentText(), QStringLiteral( "aa" ) );
6569 break;
6570 }
6571
6572 delete w;
6573
6574 // with project
6575 QgsProcessingParameterWidgetContext widgetContext;
6576 widgetContext.setProject( QgsProject::instance() );
6577 context.setProject( QgsProject::instance() );
6578
6579 QgsProcessingMapLayerWidgetWrapper wrapper2( ¶m, type );
6580 wrapper2.setWidgetContext( widgetContext );
6581 w = wrapper2.createWrappedWidget( context );
6582
6583 QSignalSpy spy2( &wrapper2, &QgsProcessingRasterLayerWidgetWrapper::widgetValueHasChanged );
6584 wrapper2.setWidgetValue( QStringLiteral( "bb" ), context );
6585 QCOMPARE( spy2.count(), 1 );
6586 QCOMPARE( wrapper2.widgetValue().toString(), QStringLiteral( "bb" ) );
6587 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "bb" ) );
6588 wrapper2.setWidgetValue( QStringLiteral( "band1_byte" ), context );
6589 QCOMPARE( spy2.count(), 2 );
6590 QCOMPARE( wrapper2.widgetValue().toString(), raster->id() );
6591 switch ( type )
6592 {
6593 case QgsProcessingGui::Standard:
6594 case QgsProcessingGui::Batch:
6595 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "band1_byte [EPSG:4326]" ) );
6596 break;
6597 case QgsProcessingGui::Modeler:
6598 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "band1_byte" ) );
6599 break;
6600 }
6601
6602 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentLayer()->name(), QStringLiteral( "band1_byte" ) );
6603
6604 // check signal
6605 static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->setLayer( raster2 );
6606 QCOMPARE( spy2.count(), 3 );
6607 QCOMPARE( wrapper2.widgetValue().toString(), raster2->id() );
6608 switch ( type )
6609 {
6610 case QgsProcessingGui::Standard:
6611 case QgsProcessingGui::Batch:
6612 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "band1_byte2 [EPSG:4326]" ) );
6613 break;
6614
6615 case QgsProcessingGui::Modeler:
6616 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "band1_byte2" ) );
6617 break;
6618 }
6619 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentLayer()->name(), QStringLiteral( "band1_byte2" ) );
6620
6621 delete w;
6622
6623 // optional
6624 QgsProcessingParameterRasterLayer param2( QStringLiteral( "raster" ), QStringLiteral( "raster" ), QVariant(), true );
6625 QgsProcessingMapLayerWidgetWrapper wrapper3( ¶m2, type );
6626 wrapper3.setWidgetContext( widgetContext );
6627 w = wrapper3.createWrappedWidget( context );
6628
6629 QSignalSpy spy3( &wrapper3, &QgsProcessingMapLayerWidgetWrapper::widgetValueHasChanged );
6630 wrapper3.setWidgetValue( QStringLiteral( "bb" ), context );
6631 QCOMPARE( spy3.count(), 1 );
6632 QCOMPARE( wrapper3.widgetValue().toString(), QStringLiteral( "bb" ) );
6633 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "bb" ) );
6634 wrapper3.setWidgetValue( QStringLiteral( "band1_byte" ), context );
6635 QCOMPARE( spy3.count(), 2 );
6636 QCOMPARE( wrapper3.widgetValue().toString(), raster->id() );
6637 switch ( type )
6638 {
6639 case QgsProcessingGui::Standard:
6640 case QgsProcessingGui::Batch:
6641 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "band1_byte [EPSG:4326]" ) );
6642 break;
6643 case QgsProcessingGui::Modeler:
6644 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "band1_byte" ) );
6645 break;
6646 }
6647 wrapper3.setWidgetValue( QVariant(), context );
6648 QCOMPARE( spy3.count(), 3 );
6649 QVERIFY( !wrapper3.widgetValue().isValid() );
6650 delete w;
6651
6652
6653 QLabel *l = wrapper.createWrappedLabel();
6654 if ( wrapper.type() != QgsProcessingGui::Batch )
6655 {
6656 QVERIFY( l );
6657 QCOMPARE( l->text(), QStringLiteral( "raster" ) );
6658 QCOMPARE( l->toolTip(), param.toolTip() );
6659 delete l;
6660 }
6661 else
6662 {
6663 QVERIFY( !l );
6664 }
6665 };
6666
6667 // standard wrapper
6668 testWrapper( QgsProcessingGui::Standard );
6669
6670 // batch wrapper
6671 testWrapper( QgsProcessingGui::Batch );
6672
6673 // modeler wrapper
6674 testWrapper( QgsProcessingGui::Modeler );
6675 }
6676
testVectorLayerWrapper()6677 void TestProcessingGui::testVectorLayerWrapper()
6678 {
6679 // setup a project with a range of vector layers
6680 QgsProject::instance()->removeAllMapLayers();
6681 QgsVectorLayer *point = new QgsVectorLayer( QStringLiteral( "Point" ), QStringLiteral( "point" ), QStringLiteral( "memory" ) );
6682 QgsProject::instance()->addMapLayer( point );
6683 QgsVectorLayer *line = new QgsVectorLayer( QStringLiteral( "LineString" ), QStringLiteral( "l1" ), QStringLiteral( "memory" ) );
6684 QgsProject::instance()->addMapLayer( line );
6685 QgsVectorLayer *polygon = new QgsVectorLayer( QStringLiteral( "Polygon" ), QStringLiteral( "l1" ), QStringLiteral( "memory" ) );
6686 QgsProject::instance()->addMapLayer( polygon );
6687 QgsVectorLayer *noGeom = new QgsVectorLayer( QStringLiteral( "None" ), QStringLiteral( "l1" ), QStringLiteral( "memory" ) );
6688 QgsProject::instance()->addMapLayer( noGeom );
6689
6690 auto testWrapper = [ = ]( QgsProcessingGui::WidgetType type )
6691 {
6692 // non optional
6693 QgsProcessingParameterVectorLayer param( QStringLiteral( "vector" ), QStringLiteral( "vector" ), QList<int >() << QgsProcessing::TypeVector, false );
6694
6695 QgsProcessingVectorLayerWidgetWrapper wrapper( ¶m, type );
6696
6697 QgsProcessingContext context;
6698 QWidget *w = wrapper.createWrappedWidget( context );
6699
6700 QSignalSpy spy( &wrapper, &QgsProcessingVectorLayerWidgetWrapper::widgetValueHasChanged );
6701 wrapper.setWidgetValue( QStringLiteral( "bb" ), context );
6702
6703 switch ( type )
6704 {
6705 case QgsProcessingGui::Standard:
6706 case QgsProcessingGui::Batch:
6707 case QgsProcessingGui::Modeler:
6708 QCOMPARE( spy.count(), 1 );
6709 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "bb" ) );
6710 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper.wrappedWidget() )->currentText(), QStringLiteral( "bb" ) );
6711 wrapper.setWidgetValue( QStringLiteral( "aa" ), context );
6712 QCOMPARE( spy.count(), 2 );
6713 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "aa" ) );
6714 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper.wrappedWidget() )->currentText(), QStringLiteral( "aa" ) );
6715 break;
6716 }
6717
6718 delete w;
6719
6720 // with project
6721 QgsProcessingParameterWidgetContext widgetContext;
6722 widgetContext.setProject( QgsProject::instance() );
6723 context.setProject( QgsProject::instance() );
6724
6725 QgsProcessingMapLayerWidgetWrapper wrapper2( ¶m, type );
6726 wrapper2.setWidgetContext( widgetContext );
6727 w = wrapper2.createWrappedWidget( context );
6728
6729 QSignalSpy spy2( &wrapper2, &QgsProcessingMapLayerWidgetWrapper::widgetValueHasChanged );
6730 wrapper2.setWidgetValue( QStringLiteral( "bb" ), context );
6731 QCOMPARE( spy2.count(), 1 );
6732 QCOMPARE( wrapper2.widgetValue().toString(), QStringLiteral( "bb" ) );
6733 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "bb" ) );
6734 wrapper2.setWidgetValue( QStringLiteral( "point" ), context );
6735 QCOMPARE( spy2.count(), 2 );
6736 QCOMPARE( wrapper2.widgetValue().toString(), point->id() );
6737 switch ( type )
6738 {
6739 case QgsProcessingGui::Standard:
6740 case QgsProcessingGui::Batch:
6741 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "point [EPSG:4326]" ) );
6742 break;
6743 case QgsProcessingGui::Modeler:
6744 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "point" ) );
6745 break;
6746 }
6747
6748 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentLayer()->name(), QStringLiteral( "point" ) );
6749
6750 // check signal
6751 static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->setLayer( polygon );
6752 QCOMPARE( spy2.count(), 3 );
6753 QCOMPARE( wrapper2.widgetValue().toString(), polygon->id() );
6754 switch ( type )
6755 {
6756 case QgsProcessingGui::Standard:
6757 case QgsProcessingGui::Batch:
6758 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "l1 [EPSG:4326]" ) );
6759 break;
6760
6761 case QgsProcessingGui::Modeler:
6762 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "l1" ) );
6763 break;
6764 }
6765 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentLayer()->name(), QStringLiteral( "l1" ) );
6766
6767 delete w;
6768
6769 // optional
6770 QgsProcessingParameterVectorLayer param2( QStringLiteral( "vector" ), QStringLiteral( "vector" ), QList< int >() << QgsProcessing::TypeVector, QVariant(), true );
6771 QgsProcessingVectorLayerWidgetWrapper wrapper3( ¶m2, type );
6772 wrapper3.setWidgetContext( widgetContext );
6773 w = wrapper3.createWrappedWidget( context );
6774
6775 QSignalSpy spy3( &wrapper3, &QgsProcessingVectorLayerWidgetWrapper::widgetValueHasChanged );
6776 wrapper3.setWidgetValue( QStringLiteral( "bb" ), context );
6777 QCOMPARE( spy3.count(), 1 );
6778 QCOMPARE( wrapper3.widgetValue().toString(), QStringLiteral( "bb" ) );
6779 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "bb" ) );
6780 wrapper3.setWidgetValue( QStringLiteral( "point" ), context );
6781 QCOMPARE( spy3.count(), 2 );
6782 QCOMPARE( wrapper3.widgetValue().toString(), point->id() );
6783 switch ( type )
6784 {
6785 case QgsProcessingGui::Standard:
6786 case QgsProcessingGui::Batch:
6787 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "point [EPSG:4326]" ) );
6788 break;
6789 case QgsProcessingGui::Modeler:
6790 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "point" ) );
6791 break;
6792 }
6793 wrapper3.setWidgetValue( QVariant(), context );
6794 QCOMPARE( spy3.count(), 3 );
6795 QVERIFY( !wrapper3.widgetValue().isValid() );
6796 delete w;
6797
6798
6799 QLabel *l = wrapper.createWrappedLabel();
6800 if ( wrapper.type() != QgsProcessingGui::Batch )
6801 {
6802 QVERIFY( l );
6803 QCOMPARE( l->text(), QStringLiteral( "vector" ) );
6804 QCOMPARE( l->toolTip(), param.toolTip() );
6805 delete l;
6806 }
6807 else
6808 {
6809 QVERIFY( !l );
6810 }
6811 };
6812
6813 // standard wrapper
6814 testWrapper( QgsProcessingGui::Standard );
6815
6816 // batch wrapper
6817 testWrapper( QgsProcessingGui::Batch );
6818
6819 // modeler wrapper
6820 testWrapper( QgsProcessingGui::Modeler );
6821
6822 // config widget
6823 QgsProcessingParameterWidgetContext widgetContext;
6824 QgsProcessingContext context;
6825 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "vector" ), context, widgetContext );
6826 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
6827 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
6828 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
6829 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
6830
6831 // using a parameter definition as initial values
6832 QgsProcessingParameterVectorLayer layerParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), QList< int >() << QgsProcessing::TypeVectorAnyGeometry );
6833 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "vector" ), context, widgetContext, &layerParam );
6834 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
6835 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
6836 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
6837 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
6838 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
6839 QCOMPARE( static_cast< QgsProcessingParameterVectorLayer * >( def.get() )->dataTypes(), QList< int >() << QgsProcessing::TypeVectorAnyGeometry );
6840 layerParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
6841 layerParam.setDataTypes( QList< int >() << QgsProcessing::TypeVectorLine << QgsProcessing::TypeVectorPoint );
6842 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "vector" ), context, widgetContext, &layerParam );
6843 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
6844 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
6845 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
6846 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
6847 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
6848 QCOMPARE( static_cast< QgsProcessingParameterVectorLayer * >( def.get() )->dataTypes(), QList< int >() << QgsProcessing::TypeVectorPoint << QgsProcessing::TypeVectorLine );
6849 }
6850
testFeatureSourceWrapper()6851 void TestProcessingGui::testFeatureSourceWrapper()
6852 {
6853 // setup a project with a range of vector layers
6854 QgsProject::instance()->removeAllMapLayers();
6855 QgsVectorLayer *point = new QgsVectorLayer( QStringLiteral( "Point" ), QStringLiteral( "point" ), QStringLiteral( "memory" ) );
6856 QgsProject::instance()->addMapLayer( point );
6857 QgsVectorLayer *line = new QgsVectorLayer( QStringLiteral( "LineString" ), QStringLiteral( "l1" ), QStringLiteral( "memory" ) );
6858 QgsProject::instance()->addMapLayer( line );
6859 QgsVectorLayer *polygon = new QgsVectorLayer( QStringLiteral( "Polygon" ), QStringLiteral( "l1" ), QStringLiteral( "memory" ) );
6860 QgsProject::instance()->addMapLayer( polygon );
6861 QgsVectorLayer *noGeom = new QgsVectorLayer( QStringLiteral( "None" ), QStringLiteral( "l1" ), QStringLiteral( "memory" ) );
6862 QgsProject::instance()->addMapLayer( noGeom );
6863
6864 auto testWrapper = [ = ]( QgsProcessingGui::WidgetType type )
6865 {
6866 // non optional
6867 QgsProcessingParameterFeatureSource param( QStringLiteral( "source" ), QStringLiteral( "source" ), QList<int >() << QgsProcessing::TypeVector, false );
6868
6869 QgsProcessingFeatureSourceWidgetWrapper wrapper( ¶m, type );
6870
6871 QgsProcessingContext context;
6872 QWidget *w = wrapper.createWrappedWidget( context );
6873
6874 QSignalSpy spy( &wrapper, &QgsProcessingFeatureSourceWidgetWrapper::widgetValueHasChanged );
6875 wrapper.setWidgetValue( QStringLiteral( "bb" ), context );
6876
6877 switch ( type )
6878 {
6879 case QgsProcessingGui::Standard:
6880 case QgsProcessingGui::Batch:
6881 case QgsProcessingGui::Modeler:
6882 QCOMPARE( spy.count(), 1 );
6883 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "bb" ) );
6884 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper.wrappedWidget() )->currentText(), QStringLiteral( "bb" ) );
6885 wrapper.setWidgetValue( QStringLiteral( "aa" ), context );
6886 QCOMPARE( spy.count(), 2 );
6887 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "aa" ) );
6888 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper.wrappedWidget() )->currentText(), QStringLiteral( "aa" ) );
6889 break;
6890 }
6891
6892 delete w;
6893
6894 // with project
6895 QgsProcessingParameterWidgetContext widgetContext;
6896 widgetContext.setProject( QgsProject::instance() );
6897 context.setProject( QgsProject::instance() );
6898
6899 QgsProcessingMapLayerWidgetWrapper wrapper2( ¶m, type );
6900 wrapper2.setWidgetContext( widgetContext );
6901 w = wrapper2.createWrappedWidget( context );
6902
6903 QSignalSpy spy2( &wrapper2, &QgsProcessingMapLayerWidgetWrapper::widgetValueHasChanged );
6904 wrapper2.setWidgetValue( QStringLiteral( "bb" ), context );
6905 QCOMPARE( spy2.count(), 1 );
6906 QCOMPARE( wrapper2.widgetValue().toString(), QStringLiteral( "bb" ) );
6907 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "bb" ) );
6908 wrapper2.setWidgetValue( QStringLiteral( "point" ), context );
6909 QCOMPARE( spy2.count(), 2 );
6910 QCOMPARE( wrapper2.widgetValue().toString(), point->id() );
6911 switch ( type )
6912 {
6913 case QgsProcessingGui::Standard:
6914 case QgsProcessingGui::Batch:
6915 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "point [EPSG:4326]" ) );
6916 break;
6917 case QgsProcessingGui::Modeler:
6918 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "point" ) );
6919 break;
6920 }
6921
6922 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentLayer()->name(), QStringLiteral( "point" ) );
6923
6924 // check signal
6925 static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->setLayer( polygon );
6926 QCOMPARE( spy2.count(), 3 );
6927 QCOMPARE( wrapper2.widgetValue().toString(), polygon->id() );
6928 switch ( type )
6929 {
6930 case QgsProcessingGui::Standard:
6931 case QgsProcessingGui::Batch:
6932 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "l1 [EPSG:4326]" ) );
6933 break;
6934
6935 case QgsProcessingGui::Modeler:
6936 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "l1" ) );
6937 break;
6938 }
6939 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentLayer()->name(), QStringLiteral( "l1" ) );
6940
6941 delete w;
6942
6943 // optional
6944 QgsProcessingParameterFeatureSource param2( QStringLiteral( "source" ), QStringLiteral( "source" ), QList< int >() << QgsProcessing::TypeVector, QVariant(), true );
6945 QgsProcessingFeatureSourceWidgetWrapper wrapper3( ¶m2, type );
6946 wrapper3.setWidgetContext( widgetContext );
6947 w = wrapper3.createWrappedWidget( context );
6948
6949 QSignalSpy spy3( &wrapper3, &QgsProcessingFeatureSourceWidgetWrapper::widgetValueHasChanged );
6950 wrapper3.setWidgetValue( QStringLiteral( "bb" ), context );
6951 QCOMPARE( spy3.count(), 1 );
6952 QCOMPARE( wrapper3.widgetValue().toString(), QStringLiteral( "bb" ) );
6953 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "bb" ) );
6954 wrapper3.setWidgetValue( QStringLiteral( "point" ), context );
6955 QCOMPARE( spy3.count(), 2 );
6956 QCOMPARE( wrapper3.widgetValue().toString(), point->id() );
6957 switch ( type )
6958 {
6959 case QgsProcessingGui::Standard:
6960 case QgsProcessingGui::Batch:
6961 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "point [EPSG:4326]" ) );
6962 break;
6963 case QgsProcessingGui::Modeler:
6964 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "point" ) );
6965 break;
6966 }
6967 wrapper3.setWidgetValue( QVariant(), context );
6968 QCOMPARE( spy3.count(), 3 );
6969 QVERIFY( !wrapper3.widgetValue().isValid() );
6970 delete w;
6971
6972
6973 QLabel *l = wrapper.createWrappedLabel();
6974 if ( wrapper.type() != QgsProcessingGui::Batch )
6975 {
6976 QVERIFY( l );
6977 QCOMPARE( l->text(), QStringLiteral( "source" ) );
6978 QCOMPARE( l->toolTip(), param.toolTip() );
6979 delete l;
6980 }
6981 else
6982 {
6983 QVERIFY( !l );
6984 }
6985 };
6986
6987 // standard wrapper
6988 testWrapper( QgsProcessingGui::Standard );
6989
6990 // batch wrapper
6991 testWrapper( QgsProcessingGui::Batch );
6992
6993 // modeler wrapper
6994 testWrapper( QgsProcessingGui::Modeler );
6995
6996 // config widget
6997 QgsProcessingParameterWidgetContext widgetContext;
6998 QgsProcessingContext context;
6999 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "source" ), context, widgetContext );
7000 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
7001 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
7002 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
7003 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
7004
7005 // using a parameter definition as initial values
7006 QgsProcessingParameterFeatureSource sourceParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), QList< int >() << QgsProcessing::TypeVectorAnyGeometry );
7007 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "source" ), context, widgetContext, &sourceParam );
7008 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
7009 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
7010 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
7011 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
7012 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
7013 QCOMPARE( static_cast< QgsProcessingParameterFeatureSource * >( def.get() )->dataTypes(), QList< int >() << QgsProcessing::TypeVectorAnyGeometry );
7014 sourceParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
7015 sourceParam.setDataTypes( QList< int >() << QgsProcessing::TypeVectorPoint << QgsProcessing::TypeVectorLine );
7016 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "source" ), context, widgetContext, &sourceParam );
7017 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
7018 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
7019 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
7020 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
7021 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
7022 QCOMPARE( static_cast< QgsProcessingParameterFeatureSource * >( def.get() )->dataTypes(), QList< int >() << QgsProcessing::TypeVectorPoint << QgsProcessing::TypeVectorLine );
7023 }
7024
testMeshLayerWrapper()7025 void TestProcessingGui::testMeshLayerWrapper()
7026 {
7027 // setup a project with a range of layer types
7028 QgsProject::instance()->removeAllMapLayers();
7029 QgsMeshLayer *mesh = new QgsMeshLayer( QStringLiteral( TEST_DATA_DIR ) + "/mesh/quad_and_triangle.2dm", QStringLiteral( "mesh1" ), QStringLiteral( "mdal" ) );
7030 mesh->dataProvider()->addDataset( QStringLiteral( TEST_DATA_DIR ) + "/mesh/quad_and_triangle_vertex_scalar_with_inactive_face.dat" );
7031 QVERIFY( mesh->isValid() );
7032 mesh->setCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) );
7033 QgsProject::instance()->addMapLayer( mesh );
7034 QgsMeshLayer *mesh2 = new QgsMeshLayer( QStringLiteral( TEST_DATA_DIR ) + "/mesh/quad_and_triangle.2dm", QStringLiteral( "mesh2" ), QStringLiteral( "mdal" ) );
7035 mesh2->dataProvider()->addDataset( QStringLiteral( TEST_DATA_DIR ) + "/mesh/quad_and_triangle_vertex_scalar_with_inactive_face.dat" );
7036 QVERIFY( mesh2->isValid() );
7037 mesh2->setCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) );
7038 QgsProject::instance()->addMapLayer( mesh2 );
7039
7040 auto testWrapper = [ = ]( QgsProcessingGui::WidgetType type )
7041 {
7042 // non optional
7043 QgsProcessingParameterMeshLayer param( QStringLiteral( "mesh" ), QStringLiteral( "mesh" ), false );
7044
7045 QgsProcessingMeshLayerWidgetWrapper wrapper( ¶m, type );
7046
7047 QgsProcessingContext context;
7048 QWidget *w = wrapper.createWrappedWidget( context );
7049
7050 QSignalSpy spy( &wrapper, &QgsProcessingMeshLayerWidgetWrapper::widgetValueHasChanged );
7051 wrapper.setWidgetValue( QStringLiteral( "bb" ), context );
7052
7053 switch ( type )
7054 {
7055 case QgsProcessingGui::Standard:
7056 case QgsProcessingGui::Batch:
7057 case QgsProcessingGui::Modeler:
7058 QCOMPARE( spy.count(), 1 );
7059 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "bb" ) );
7060 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper.wrappedWidget() )->currentText(), QStringLiteral( "bb" ) );
7061 wrapper.setWidgetValue( QStringLiteral( "aa" ), context );
7062 QCOMPARE( spy.count(), 2 );
7063 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "aa" ) );
7064 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper.wrappedWidget() )->currentText(), QStringLiteral( "aa" ) );
7065 break;
7066 }
7067
7068 delete w;
7069
7070 // with project
7071 QgsProcessingParameterWidgetContext widgetContext;
7072 widgetContext.setProject( QgsProject::instance() );
7073 context.setProject( QgsProject::instance() );
7074
7075 QgsProcessingMapLayerWidgetWrapper wrapper2( ¶m, type );
7076 wrapper2.setWidgetContext( widgetContext );
7077 w = wrapper2.createWrappedWidget( context );
7078
7079 QSignalSpy spy2( &wrapper2, &QgsProcessingMeshLayerWidgetWrapper::widgetValueHasChanged );
7080 wrapper2.setWidgetValue( QStringLiteral( "bb" ), context );
7081 QCOMPARE( spy2.count(), 1 );
7082 QCOMPARE( wrapper2.widgetValue().toString(), QStringLiteral( "bb" ) );
7083 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "bb" ) );
7084 wrapper2.setWidgetValue( QStringLiteral( "mesh2" ), context );
7085 QCOMPARE( spy2.count(), 2 );
7086 QCOMPARE( wrapper2.widgetValue().toString(), mesh2->id() );
7087 switch ( type )
7088 {
7089 case QgsProcessingGui::Standard:
7090 case QgsProcessingGui::Batch:
7091 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "mesh2 [EPSG:4326]" ) );
7092 break;
7093 case QgsProcessingGui::Modeler:
7094 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "mesh2" ) );
7095 break;
7096 }
7097
7098 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentLayer()->name(), QStringLiteral( "mesh2" ) );
7099
7100 // check signal
7101 static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->setLayer( mesh );
7102 QCOMPARE( spy2.count(), 3 );
7103 QCOMPARE( wrapper2.widgetValue().toString(), mesh->id() );
7104 switch ( type )
7105 {
7106 case QgsProcessingGui::Standard:
7107 case QgsProcessingGui::Batch:
7108 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "mesh1 [EPSG:4326]" ) );
7109 break;
7110
7111 case QgsProcessingGui::Modeler:
7112 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "mesh1" ) );
7113 break;
7114 }
7115 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentLayer()->name(), QStringLiteral( "mesh1" ) );
7116
7117 delete w;
7118
7119 // optional
7120 QgsProcessingParameterMeshLayer param2( QStringLiteral( "mesh" ), QStringLiteral( "mesh" ), QVariant(), true );
7121 QgsProcessingMeshLayerWidgetWrapper wrapper3( ¶m2, type );
7122 wrapper3.setWidgetContext( widgetContext );
7123 w = wrapper3.createWrappedWidget( context );
7124
7125 QSignalSpy spy3( &wrapper3, &QgsProcessingMeshLayerWidgetWrapper::widgetValueHasChanged );
7126 wrapper3.setWidgetValue( QStringLiteral( "bb" ), context );
7127 QCOMPARE( spy3.count(), 1 );
7128 QCOMPARE( wrapper3.widgetValue().toString(), QStringLiteral( "bb" ) );
7129 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "bb" ) );
7130 wrapper3.setWidgetValue( QStringLiteral( "mesh2" ), context );
7131 QCOMPARE( spy3.count(), 2 );
7132 QCOMPARE( wrapper3.widgetValue().toString(), mesh2->id() );
7133 switch ( type )
7134 {
7135 case QgsProcessingGui::Standard:
7136 case QgsProcessingGui::Batch:
7137 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "mesh2 [EPSG:4326]" ) );
7138 break;
7139 case QgsProcessingGui::Modeler:
7140 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "mesh2" ) );
7141 break;
7142 }
7143 wrapper3.setWidgetValue( QVariant(), context );
7144 QCOMPARE( spy3.count(), 3 );
7145 QVERIFY( !wrapper3.widgetValue().isValid() );
7146 delete w;
7147
7148
7149 QLabel *l = wrapper.createWrappedLabel();
7150 if ( wrapper.type() != QgsProcessingGui::Batch )
7151 {
7152 QVERIFY( l );
7153 QCOMPARE( l->text(), QStringLiteral( "mesh" ) );
7154 QCOMPARE( l->toolTip(), param.toolTip() );
7155 delete l;
7156 }
7157 else
7158 {
7159 QVERIFY( !l );
7160 }
7161 };
7162
7163 // standard wrapper
7164 testWrapper( QgsProcessingGui::Standard );
7165
7166 // batch wrapper
7167 testWrapper( QgsProcessingGui::Batch );
7168
7169 // modeler wrapper
7170 testWrapper( QgsProcessingGui::Modeler );
7171 }
7172
paramConfigWidget()7173 void TestProcessingGui::paramConfigWidget()
7174 {
7175 QgsProcessingContext context;
7176 QgsProcessingParameterWidgetContext widgetContext;
7177 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "string" ), context, widgetContext );
7178 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
7179 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
7180 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
7181 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
7182
7183 // using a parameter definition as initial values
7184 def->setDescription( QStringLiteral( "test desc" ) );
7185 def->setFlags( QgsProcessingParameterDefinition::FlagOptional );
7186 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "string" ), context, widgetContext, def.get() );
7187 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
7188 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
7189 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
7190 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
7191 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
7192 def->setFlags( QgsProcessingParameterDefinition::FlagAdvanced );
7193 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "string" ), context, widgetContext, def.get() );
7194 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
7195 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
7196 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
7197 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
7198 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
7199 }
7200
testMapThemeWrapper()7201 void TestProcessingGui::testMapThemeWrapper()
7202 {
7203 // add some themes to the project
7204 QgsProject p;
7205 p.mapThemeCollection()->insert( QStringLiteral( "aa" ), QgsMapThemeCollection::MapThemeRecord() );
7206 p.mapThemeCollection()->insert( QStringLiteral( "bb" ), QgsMapThemeCollection::MapThemeRecord() );
7207
7208 QCOMPARE( p.mapThemeCollection()->mapThemes(), QStringList() << QStringLiteral( "aa" ) << QStringLiteral( "bb" ) );
7209
7210 auto testWrapper = [&p]( QgsProcessingGui::WidgetType type )
7211 {
7212 // non optional, no existing themes
7213 QgsProcessingParameterMapTheme param( QStringLiteral( "theme" ), QStringLiteral( "theme" ), false );
7214
7215 QgsProcessingMapThemeWidgetWrapper wrapper( ¶m, type );
7216
7217 QgsProcessingContext context;
7218 QWidget *w = wrapper.createWrappedWidget( context );
7219
7220 QSignalSpy spy( &wrapper, &QgsProcessingEnumWidgetWrapper::widgetValueHasChanged );
7221 wrapper.setWidgetValue( QStringLiteral( "bb" ), context );
7222
7223 switch ( type )
7224 {
7225 case QgsProcessingGui::Standard:
7226 case QgsProcessingGui::Batch:
7227 // batch or standard mode, only valid themes can be set!
7228 QCOMPARE( spy.count(), 0 );
7229 QVERIFY( !wrapper.widgetValue().isValid() );
7230 QCOMPARE( static_cast< QComboBox * >( wrapper.wrappedWidget() )->currentIndex(), -1 );
7231 wrapper.setWidgetValue( QStringLiteral( "aa" ), context );
7232 QCOMPARE( spy.count(), 0 );
7233 QVERIFY( !wrapper.widgetValue().isValid() );
7234 QCOMPARE( static_cast< QComboBox * >( wrapper.wrappedWidget() )->currentIndex(), -1 );
7235 break;
7236
7237 case QgsProcessingGui::Modeler:
7238 QCOMPARE( spy.count(), 1 );
7239 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "bb" ) );
7240 QCOMPARE( static_cast< QComboBox * >( wrapper.wrappedWidget() )->currentText(), QStringLiteral( "bb" ) );
7241 wrapper.setWidgetValue( QStringLiteral( "aa" ), context );
7242 QCOMPARE( spy.count(), 2 );
7243 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "aa" ) );
7244 QCOMPARE( static_cast< QComboBox * >( wrapper.wrappedWidget() )->currentText(), QStringLiteral( "aa" ) );
7245 break;
7246 }
7247
7248 delete w;
7249
7250 // with project
7251 QgsProcessingParameterWidgetContext widgetContext;
7252 widgetContext.setProject( &p );
7253
7254 QgsProcessingMapThemeWidgetWrapper wrapper2( ¶m, type );
7255 wrapper2.setWidgetContext( widgetContext );
7256 w = wrapper2.createWrappedWidget( context );
7257
7258 QSignalSpy spy2( &wrapper2, &QgsProcessingEnumWidgetWrapper::widgetValueHasChanged );
7259 wrapper2.setWidgetValue( QStringLiteral( "bb" ), context );
7260 QCOMPARE( spy2.count(), 1 );
7261 QCOMPARE( wrapper2.widgetValue().toString(), QStringLiteral( "bb" ) );
7262 QCOMPARE( static_cast< QComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "bb" ) );
7263 wrapper2.setWidgetValue( QStringLiteral( "aa" ), context );
7264 QCOMPARE( spy2.count(), 2 );
7265 QCOMPARE( wrapper2.widgetValue().toString(), QStringLiteral( "aa" ) );
7266 QCOMPARE( static_cast< QComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "aa" ) );
7267
7268 // check signal
7269 static_cast< QComboBox * >( wrapper2.wrappedWidget() )->setCurrentIndex( 2 );
7270 QCOMPARE( spy2.count(), 3 );
7271
7272 delete w;
7273
7274 // optional
7275 QgsProcessingParameterMapTheme param2( QStringLiteral( "theme" ), QStringLiteral( "theme" ), true );
7276 QgsProcessingMapThemeWidgetWrapper wrapper3( ¶m2, type );
7277 wrapper3.setWidgetContext( widgetContext );
7278 w = wrapper3.createWrappedWidget( context );
7279
7280 QSignalSpy spy3( &wrapper3, &QgsProcessingEnumWidgetWrapper::widgetValueHasChanged );
7281 wrapper3.setWidgetValue( QStringLiteral( "bb" ), context );
7282 QCOMPARE( spy3.count(), 1 );
7283 QCOMPARE( wrapper3.widgetValue().toString(), QStringLiteral( "bb" ) );
7284 QCOMPARE( static_cast< QComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "bb" ) );
7285 wrapper3.setWidgetValue( QStringLiteral( "aa" ), context );
7286 QCOMPARE( spy3.count(), 2 );
7287 QCOMPARE( wrapper3.widgetValue().toString(), QStringLiteral( "aa" ) );
7288 QCOMPARE( static_cast< QComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "aa" ) );
7289 wrapper3.setWidgetValue( QVariant(), context );
7290 QCOMPARE( spy3.count(), 3 );
7291 QVERIFY( !wrapper3.widgetValue().isValid() );
7292 delete w;
7293
7294
7295 QLabel *l = wrapper.createWrappedLabel();
7296 if ( wrapper.type() != QgsProcessingGui::Batch )
7297 {
7298 QVERIFY( l );
7299 QCOMPARE( l->text(), QStringLiteral( "theme" ) );
7300 QCOMPARE( l->toolTip(), param.toolTip() );
7301 delete l;
7302 }
7303 else
7304 {
7305 QVERIFY( !l );
7306 }
7307 };
7308
7309 // standard wrapper
7310 testWrapper( QgsProcessingGui::Standard );
7311
7312 // batch wrapper
7313 testWrapper( QgsProcessingGui::Batch );
7314
7315 // modeler wrapper
7316 testWrapper( QgsProcessingGui::Modeler );
7317
7318
7319 // config widget
7320 QgsProcessingParameterWidgetContext widgetContext;
7321 widgetContext.setProject( &p );
7322 QgsProcessingContext context;
7323 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "maptheme" ), context, widgetContext );
7324 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
7325 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
7326 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
7327 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
7328 QVERIFY( !static_cast< QgsProcessingParameterMapTheme * >( def.get() )->defaultValue().isValid() );
7329
7330 // using a parameter definition as initial values
7331 QgsProcessingParameterMapTheme themeParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), QStringLiteral( "aaa" ), false );
7332 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "maptheme" ), context, widgetContext, &themeParam );
7333 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
7334 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
7335 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
7336 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
7337 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
7338 QCOMPARE( static_cast< QgsProcessingParameterMapTheme * >( def.get() )->defaultValue().toString(), QStringLiteral( "aaa" ) );
7339 themeParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
7340 themeParam.setDefaultValue( QStringLiteral( "xxx" ) );
7341 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "maptheme" ), context, widgetContext, &themeParam );
7342 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
7343 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
7344 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
7345 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
7346 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
7347 QCOMPARE( static_cast< QgsProcessingParameterMapTheme * >( def.get() )->defaultValue().toString(), QStringLiteral( "xxx" ) );
7348 themeParam.setDefaultValue( QVariant() );
7349 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "maptheme" ), context, widgetContext, &themeParam );
7350 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
7351 QVERIFY( !static_cast< QgsProcessingParameterMapTheme * >( def.get() )->defaultValue().isValid() );
7352 }
7353
testDateTimeWrapper()7354 void TestProcessingGui::testDateTimeWrapper()
7355 {
7356 auto testWrapper = [ = ]( QgsProcessingGui::WidgetType type )
7357 {
7358 // non optional, no existing themes
7359 QgsProcessingParameterDateTime param( QStringLiteral( "datetime" ), QStringLiteral( "datetime" ), QgsProcessingParameterDateTime::DateTime, QVariant(), false );
7360
7361 QgsProcessingDateTimeWidgetWrapper wrapper( ¶m, type );
7362
7363 QgsProcessingContext context;
7364 QWidget *w = wrapper.createWrappedWidget( context );
7365
7366 QSignalSpy spy( &wrapper, &QgsProcessingDateTimeWidgetWrapper::widgetValueHasChanged );
7367 // not a date value
7368 wrapper.setWidgetValue( QStringLiteral( "bb" ), context );
7369 QCOMPARE( spy.count(), 0 );
7370 // not optional, so an invalid value gets a date anyway...
7371 QVERIFY( wrapper.widgetValue().isValid() );
7372 wrapper.setWidgetValue( QStringLiteral( "2019-08-07" ), context );
7373 QCOMPARE( spy.count(), 1 );
7374 QVERIFY( wrapper.widgetValue().isValid() );
7375 QCOMPARE( wrapper.widgetValue().toDateTime(), QDateTime( QDate( 2019, 8, 7 ), QTime( 0, 0, 0 ) ) );
7376 QCOMPARE( static_cast< QgsDateTimeEdit * >( wrapper.wrappedWidget() )->dateTime(), QDateTime( QDate( 2019, 8, 7 ), QTime( 0, 0, 0 ) ) );
7377 wrapper.setWidgetValue( QStringLiteral( "2019-08-07" ), context );
7378 QCOMPARE( spy.count(), 1 );
7379
7380 // check signal
7381 static_cast< QgsDateTimeEdit * >( wrapper.wrappedWidget() )->setDateTime( QDateTime( QDate( 2019, 8, 9 ), QTime( 0, 0, 0 ) ) );
7382 QCOMPARE( spy.count(), 2 );
7383
7384 delete w;
7385
7386 // optional
7387 QgsProcessingParameterDateTime param2( QStringLiteral( "datetime" ), QStringLiteral( "datetime" ), QgsProcessingParameterDateTime::DateTime, QVariant(), true );
7388 QgsProcessingDateTimeWidgetWrapper wrapper3( ¶m2, type );
7389 w = wrapper3.createWrappedWidget( context );
7390 QVERIFY( !wrapper3.widgetValue().isValid() );
7391 QSignalSpy spy3( &wrapper3, &QgsProcessingDateTimeWidgetWrapper::widgetValueHasChanged );
7392 wrapper3.setWidgetValue( QStringLiteral( "bb" ), context );
7393 QCOMPARE( spy3.count(), 0 );
7394 QVERIFY( !wrapper3.widgetValue().isValid() );
7395 QVERIFY( !static_cast< QgsDateTimeEdit * >( wrapper3.wrappedWidget() )->dateTime().isValid() );
7396 wrapper3.setWidgetValue( QStringLiteral( "2019-03-20" ), context );
7397 QCOMPARE( spy3.count(), 1 );
7398 QCOMPARE( wrapper3.widgetValue().toDateTime(), QDateTime( QDate( 2019, 3, 20 ), QTime( 0, 0, 0 ) ) );
7399 QCOMPARE( static_cast< QgsDateTimeEdit * >( wrapper3.wrappedWidget() )->dateTime(), QDateTime( QDate( 2019, 3, 20 ), QTime( 0, 0, 0 ) ) );
7400 wrapper3.setWidgetValue( QVariant(), context );
7401 QCOMPARE( spy3.count(), 2 );
7402 QVERIFY( !wrapper3.widgetValue().isValid() );
7403 delete w;
7404
7405 // date mode
7406 QgsProcessingParameterDateTime param3( QStringLiteral( "datetime" ), QStringLiteral( "datetime" ), QgsProcessingParameterDateTime::Date, QVariant(), true );
7407 QgsProcessingDateTimeWidgetWrapper wrapper4( ¶m3, type );
7408 w = wrapper4.createWrappedWidget( context );
7409 QVERIFY( !wrapper4.widgetValue().isValid() );
7410 QSignalSpy spy4( &wrapper4, &QgsProcessingDateTimeWidgetWrapper::widgetValueHasChanged );
7411 wrapper4.setWidgetValue( QStringLiteral( "bb" ), context );
7412 QCOMPARE( spy4.count(), 0 );
7413 QVERIFY( !wrapper4.widgetValue().isValid() );
7414 QVERIFY( !static_cast< QgsDateEdit * >( wrapper4.wrappedWidget() )->date().isValid() );
7415 wrapper4.setWidgetValue( QStringLiteral( "2019-03-20" ), context );
7416 QCOMPARE( spy4.count(), 1 );
7417 QCOMPARE( wrapper4.widgetValue().toDate(), QDate( 2019, 3, 20 ) );
7418 QCOMPARE( static_cast< QgsDateEdit * >( wrapper4.wrappedWidget() )->date(), QDate( 2019, 3, 20 ) );
7419 wrapper4.setWidgetValue( QDate( 2020, 1, 3 ), context );
7420 QCOMPARE( spy4.count(), 2 );
7421 QCOMPARE( wrapper4.widgetValue().toDate(), QDate( 2020, 1, 3 ) );
7422 QCOMPARE( static_cast< QgsDateEdit * >( wrapper4.wrappedWidget() )->date(), QDate( 2020, 1, 3 ) );
7423 wrapper4.setWidgetValue( QVariant(), context );
7424 QCOMPARE( spy4.count(), 3 );
7425 QVERIFY( !wrapper4.widgetValue().isValid() );
7426 delete w;
7427
7428 // time mode
7429 QgsProcessingParameterDateTime param4( QStringLiteral( "datetime" ), QStringLiteral( "datetime" ), QgsProcessingParameterDateTime::Time, QVariant(), true );
7430 QgsProcessingDateTimeWidgetWrapper wrapper5( ¶m4, type );
7431 w = wrapper5.createWrappedWidget( context );
7432 QVERIFY( !wrapper5.widgetValue().isValid() );
7433 QSignalSpy spy5( &wrapper5, &QgsProcessingDateTimeWidgetWrapper::widgetValueHasChanged );
7434 wrapper5.setWidgetValue( QStringLiteral( "bb" ), context );
7435 QCOMPARE( spy5.count(), 0 );
7436 QVERIFY( !wrapper5.widgetValue().isValid() );
7437 QVERIFY( !static_cast< QgsTimeEdit * >( wrapper5.wrappedWidget() )->time().isValid() );
7438 wrapper5.setWidgetValue( QStringLiteral( "11:34:56" ), context );
7439 QCOMPARE( spy5.count(), 1 );
7440 QCOMPARE( wrapper5.widgetValue().toTime(), QTime( 11, 34, 56 ) );
7441 QCOMPARE( static_cast< QgsTimeEdit * >( wrapper5.wrappedWidget() )->time(), QTime( 11, 34, 56 ) );
7442 wrapper5.setWidgetValue( QTime( 9, 34, 56 ), context );
7443 QCOMPARE( spy5.count(), 2 );
7444 QCOMPARE( wrapper5.widgetValue().toTime(), QTime( 9, 34, 56 ) );
7445 QCOMPARE( static_cast< QgsTimeEdit * >( wrapper5.wrappedWidget() )->time(), QTime( 9, 34, 56 ) );
7446 wrapper5.setWidgetValue( QVariant(), context );
7447 QCOMPARE( spy5.count(), 3 );
7448 QVERIFY( !wrapper5.widgetValue().isValid() );
7449 delete w;
7450
7451 QLabel *l = wrapper.createWrappedLabel();
7452 if ( wrapper.type() != QgsProcessingGui::Batch )
7453 {
7454 QVERIFY( l );
7455 QCOMPARE( l->text(), QStringLiteral( "datetime" ) );
7456 QCOMPARE( l->toolTip(), param.toolTip() );
7457 delete l;
7458 }
7459 else
7460 {
7461 QVERIFY( !l );
7462 }
7463 };
7464
7465 // standard wrapper
7466 testWrapper( QgsProcessingGui::Standard );
7467
7468 // batch wrapper
7469 testWrapper( QgsProcessingGui::Batch );
7470
7471 // modeler wrapper
7472 testWrapper( QgsProcessingGui::Modeler );
7473
7474 // config widget
7475 QgsProcessingParameterWidgetContext widgetContext;
7476 QgsProcessingContext context;
7477 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "datetime" ), context, widgetContext );
7478 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
7479 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
7480 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
7481 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
7482 QVERIFY( !static_cast< QgsProcessingParameterDateTime * >( def.get() )->defaultValue().isValid() );
7483
7484 // using a parameter definition as initial values
7485 QgsProcessingParameterDateTime datetimeParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), QgsProcessingParameterDateTime::Date, QVariant(), false );
7486 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "datetime" ), context, widgetContext, &datetimeParam );
7487 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
7488 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
7489 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
7490 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
7491 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
7492 QCOMPARE( static_cast< QgsProcessingParameterDateTime * >( def.get() )->dataType(), QgsProcessingParameterDateTime::Date );
7493 datetimeParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
7494 datetimeParam.setDefaultValue( QStringLiteral( "xxx" ) );
7495 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "datetime" ), context, widgetContext, &datetimeParam );
7496 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
7497 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
7498 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
7499 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
7500 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
7501 QCOMPARE( static_cast< QgsProcessingParameterDateTime * >( def.get() )->dataType(), QgsProcessingParameterDateTime::Date );
7502 }
7503
testProviderConnectionWrapper()7504 void TestProcessingGui::testProviderConnectionWrapper()
7505 {
7506 // register some connections
7507 QgsProviderMetadata *md = QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "ogr" ) );
7508 QgsAbstractProviderConnection *conn = md->createConnection( QStringLiteral( "test uri" ), QVariantMap() );
7509 md->saveConnection( conn, QStringLiteral( "aa" ) );
7510 md->saveConnection( conn, QStringLiteral( "bb" ) );
7511
7512 auto testWrapper = []( QgsProcessingGui::WidgetType type )
7513 {
7514 QgsProcessingParameterProviderConnection param( QStringLiteral( "conn" ), QStringLiteral( "connection" ), QStringLiteral( "ogr" ), false );
7515
7516 QgsProcessingProviderConnectionWidgetWrapper wrapper( ¶m, type );
7517
7518 QgsProcessingContext context;
7519 QWidget *w = wrapper.createWrappedWidget( context );
7520
7521 QSignalSpy spy( &wrapper, &QgsProcessingProviderConnectionWidgetWrapper::widgetValueHasChanged );
7522 wrapper.setWidgetValue( QStringLiteral( "bb" ), context );
7523 QCOMPARE( spy.count(), 1 );
7524 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "bb" ) );
7525 QCOMPARE( static_cast< QgsProviderConnectionComboBox * >( wrapper.wrappedWidget() )->currentConnection(), QStringLiteral( "bb" ) );
7526 wrapper.setWidgetValue( QStringLiteral( "bb" ), context );
7527 QCOMPARE( spy.count(), 1 );
7528 wrapper.setWidgetValue( QStringLiteral( "aa" ), context );
7529 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "aa" ) );
7530 QCOMPARE( spy.count(), 2 );
7531
7532 switch ( type )
7533 {
7534 case QgsProcessingGui::Standard:
7535 case QgsProcessingGui::Batch:
7536 {
7537 // batch or standard mode, only valid connections can be set!
7538 // not valid
7539 wrapper.setWidgetValue( QStringLiteral( "cc" ), context );
7540 QCOMPARE( spy.count(), 3 );
7541 QVERIFY( !wrapper.widgetValue().isValid() );
7542 QCOMPARE( static_cast< QComboBox * >( wrapper.wrappedWidget() )->currentIndex(), -1 );
7543 break;
7544
7545 }
7546 case QgsProcessingGui::Modeler:
7547 // invalid connections permitted
7548 wrapper.setWidgetValue( QStringLiteral( "cc" ), context );
7549 QCOMPARE( spy.count(), 3 );
7550 QCOMPARE( static_cast< QgsProviderConnectionComboBox * >( wrapper.wrappedWidget() )->currentText(), QStringLiteral( "cc" ) );
7551 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "cc" ) );
7552 wrapper.setWidgetValue( QStringLiteral( "aa" ), context );
7553 QCOMPARE( spy.count(), 4 );
7554 QCOMPARE( static_cast< QgsProviderConnectionComboBox * >( wrapper.wrappedWidget() )->currentText(), QStringLiteral( "aa" ) );
7555 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "aa" ) );
7556 break;
7557 }
7558
7559 delete w;
7560 // optional
7561 QgsProcessingParameterProviderConnection param2( QStringLiteral( "conn" ), QStringLiteral( "connection" ), QStringLiteral( "ogr" ), QVariant(), true );
7562 QgsProcessingProviderConnectionWidgetWrapper wrapper3( ¶m2, type );
7563 w = wrapper3.createWrappedWidget( context );
7564
7565 QSignalSpy spy3( &wrapper3, &QgsProcessingEnumWidgetWrapper::widgetValueHasChanged );
7566 wrapper3.setWidgetValue( QStringLiteral( "bb" ), context );
7567 QCOMPARE( spy3.count(), 1 );
7568 QCOMPARE( wrapper3.widgetValue().toString(), QStringLiteral( "bb" ) );
7569 QCOMPARE( static_cast< QComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "bb" ) );
7570 wrapper3.setWidgetValue( QStringLiteral( "aa" ), context );
7571 QCOMPARE( spy3.count(), 2 );
7572 QCOMPARE( wrapper3.widgetValue().toString(), QStringLiteral( "aa" ) );
7573 QCOMPARE( static_cast< QComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "aa" ) );
7574 wrapper3.setWidgetValue( QVariant(), context );
7575 QCOMPARE( spy3.count(), 3 );
7576 QVERIFY( !wrapper3.widgetValue().isValid() );
7577 delete w;
7578 QLabel *l = wrapper.createWrappedLabel();
7579 if ( wrapper.type() != QgsProcessingGui::Batch )
7580 {
7581 QVERIFY( l );
7582 QCOMPARE( l->text(), QStringLiteral( "connection" ) );
7583 QCOMPARE( l->toolTip(), param.toolTip() );
7584 delete l;
7585 }
7586 else
7587 {
7588 QVERIFY( !l );
7589 }
7590 };
7591
7592 // standard wrapper
7593 testWrapper( QgsProcessingGui::Standard );
7594
7595 // batch wrapper
7596 testWrapper( QgsProcessingGui::Batch );
7597
7598 // modeler wrapper
7599 testWrapper( QgsProcessingGui::Modeler );
7600
7601 // config widget
7602 QgsProcessingParameterWidgetContext widgetContext;
7603 QgsProcessingContext context;
7604 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "providerconnection" ), context, widgetContext );
7605 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
7606 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
7607 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
7608 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
7609 QVERIFY( !static_cast< QgsProcessingParameterProviderConnection * >( def.get() )->defaultValue().isValid() );
7610
7611 // using a parameter definition as initial values
7612 QgsProcessingParameterProviderConnection connParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), QStringLiteral( "spatialite" ), QStringLiteral( "aaa" ), false );
7613 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "providerconnection" ), context, widgetContext, &connParam );
7614 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
7615 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
7616 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
7617 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
7618 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
7619 QCOMPARE( static_cast< QgsProcessingParameterProviderConnection * >( def.get() )->defaultValue().toString(), QStringLiteral( "aaa" ) );
7620 QCOMPARE( static_cast< QgsProcessingParameterProviderConnection * >( def.get() )->providerId(), QStringLiteral( "spatialite" ) );
7621 connParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
7622 connParam.setDefaultValue( QStringLiteral( "xxx" ) );
7623 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "providerconnection" ), context, widgetContext, &connParam );
7624 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
7625 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
7626 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
7627 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
7628 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
7629 QCOMPARE( static_cast< QgsProcessingParameterProviderConnection * >( def.get() )->defaultValue().toString(), QStringLiteral( "xxx" ) );
7630 connParam.setDefaultValue( QVariant() );
7631 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "providerconnection" ), context, widgetContext, &connParam );
7632 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
7633 QVERIFY( !static_cast< QgsProcessingParameterProviderConnection * >( def.get() )->defaultValue().isValid() );
7634 }
7635
testDatabaseSchemaWrapper()7636 void TestProcessingGui::testDatabaseSchemaWrapper()
7637 {
7638 #ifdef ENABLE_PGTEST
7639 // register some connections
7640 QgsProviderMetadata *md = QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "postgres" ) );
7641
7642 QString dbConn = getenv( "QGIS_PGTEST_DB" );
7643 if ( dbConn.isEmpty() )
7644 {
7645 dbConn = "service=\"qgis_test\"";
7646 }
7647 QgsAbstractProviderConnection *conn = md->createConnection( QStringLiteral( "%1 sslmode=disable" ).arg( dbConn ), QVariantMap() );
7648 md->saveConnection( conn, QStringLiteral( "aa" ) );
7649
7650 const QStringList schemas = dynamic_cast<QgsAbstractDatabaseProviderConnection *>( conn )->schemas();
7651 QVERIFY( !schemas.isEmpty() );
7652
7653 auto testWrapper = [&schemas]( QgsProcessingGui::WidgetType type )
7654 {
7655 QgsProcessingParameterProviderConnection connParam( QStringLiteral( "conn" ), QStringLiteral( "connection" ), QStringLiteral( "postgres" ), QVariant(), true );
7656 TestLayerWrapper connWrapper( &connParam );
7657
7658 QgsProcessingParameterDatabaseSchema param( QStringLiteral( "schema" ), QStringLiteral( "schema" ), QStringLiteral( "conn" ), QVariant(), false );
7659
7660 QgsProcessingDatabaseSchemaWidgetWrapper wrapper( ¶m, type );
7661
7662 QgsProcessingContext context;
7663 QWidget *w = wrapper.createWrappedWidget( context );
7664 // no connection associated yet
7665 QCOMPARE( static_cast< QgsDatabaseSchemaComboBox * >( wrapper.wrappedWidget() )->comboBox()->count(), 0 );
7666
7667 // Set the parent widget connection value
7668 connWrapper.setWidgetValue( QStringLiteral( "aa" ), context );
7669 wrapper.setParentConnectionWrapperValue( &connWrapper );
7670
7671 // now we should have schemas available
7672 QCOMPARE( static_cast< QgsDatabaseSchemaComboBox * >( wrapper.wrappedWidget() )->comboBox()->count(), schemas.count() );
7673
7674 QSignalSpy spy( &wrapper, &QgsProcessingDatabaseSchemaWidgetWrapper::widgetValueHasChanged );
7675 wrapper.setWidgetValue( QStringLiteral( "qgis_test" ), context );
7676 QCOMPARE( spy.count(), 1 );
7677 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "qgis_test" ) );
7678 QCOMPARE( static_cast< QgsDatabaseSchemaComboBox * >( wrapper.wrappedWidget() )->currentSchema(), QStringLiteral( "qgis_test" ) );
7679 wrapper.setWidgetValue( QStringLiteral( "public" ), context );
7680 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "public" ) );
7681 QCOMPARE( static_cast< QgsDatabaseSchemaComboBox * >( wrapper.wrappedWidget() )->currentSchema(), QStringLiteral( "public" ) );
7682 QCOMPARE( spy.count(), 2 );
7683 wrapper.setWidgetValue( QStringLiteral( "public" ), context );
7684 QCOMPARE( spy.count(), 2 );
7685
7686 switch ( type )
7687 {
7688 case QgsProcessingGui::Standard:
7689 case QgsProcessingGui::Batch:
7690 {
7691 // batch or standard mode, only valid schemas can be set!
7692 // not valid
7693 wrapper.setWidgetValue( QStringLiteral( "cc" ), context );
7694 QCOMPARE( spy.count(), 3 );
7695 QVERIFY( !wrapper.widgetValue().isValid() );
7696 QCOMPARE( static_cast< QgsDatabaseSchemaComboBox * >( wrapper.wrappedWidget() )->comboBox()->currentIndex(), -1 );
7697 break;
7698
7699 }
7700 case QgsProcessingGui::Modeler:
7701 // invalid schemas permitted
7702 wrapper.setWidgetValue( QStringLiteral( "cc" ), context );
7703 QCOMPARE( spy.count(), 3 );
7704 QCOMPARE( static_cast< QgsDatabaseSchemaComboBox * >( wrapper.wrappedWidget() )->comboBox()->currentText(), QStringLiteral( "cc" ) );
7705 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "cc" ) );
7706 wrapper.setWidgetValue( QStringLiteral( "aa" ), context );
7707 QCOMPARE( spy.count(), 4 );
7708 QCOMPARE( static_cast< QgsDatabaseSchemaComboBox * >( wrapper.wrappedWidget() )->comboBox()->currentText(), QStringLiteral( "aa" ) );
7709 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "aa" ) );
7710 break;
7711 }
7712
7713 // make sure things are ok if connection is changed back to nothing
7714 connWrapper.setWidgetValue( QVariant(), context );
7715 wrapper.setParentConnectionWrapperValue( &connWrapper );
7716 QCOMPARE( static_cast< QgsDatabaseSchemaComboBox * >( wrapper.wrappedWidget() )->comboBox()->count(), 0 );
7717
7718 switch ( type )
7719 {
7720 case QgsProcessingGui::Standard:
7721 case QgsProcessingGui::Batch:
7722 {
7723 QCOMPARE( spy.count(), 3 );
7724 break;
7725 }
7726
7727 case QgsProcessingGui::Modeler:
7728 QCOMPARE( spy.count(), 5 );
7729 break;
7730 }
7731 QVERIFY( !wrapper.widgetValue().isValid() );
7732
7733 wrapper.setWidgetValue( QStringLiteral( "qgis_test" ), context );
7734 switch ( type )
7735 {
7736 case QgsProcessingGui::Standard:
7737 case QgsProcessingGui::Batch:
7738 {
7739 QVERIFY( !wrapper.widgetValue().isValid() );
7740 break;
7741 }
7742
7743 case QgsProcessingGui::Modeler:
7744 // invalid schemas permitted
7745 QCOMPARE( spy.count(), 6 );
7746 QCOMPARE( static_cast< QgsDatabaseSchemaComboBox * >( wrapper.wrappedWidget() )->comboBox()->currentText(), QStringLiteral( "qgis_test" ) );
7747 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "qgis_test" ) );
7748
7749 break;
7750 }
7751 delete w;
7752
7753 connWrapper.setWidgetValue( QStringLiteral( "aa" ), context );
7754
7755 // optional
7756 QgsProcessingParameterDatabaseSchema param2( QStringLiteral( "schema" ), QStringLiteral( "schema" ), QStringLiteral( "conn" ), QVariant(), true );
7757 QgsProcessingDatabaseSchemaWidgetWrapper wrapper3( ¶m2, type );
7758 w = wrapper3.createWrappedWidget( context );
7759
7760 wrapper3.setParentConnectionWrapperValue( &connWrapper );
7761
7762 QSignalSpy spy3( &wrapper3, &QgsProcessingDatabaseSchemaWidgetWrapper::widgetValueHasChanged );
7763 wrapper3.setWidgetValue( QStringLiteral( "qgis_test" ), context );
7764 QCOMPARE( spy3.count(), 1 );
7765 QCOMPARE( wrapper3.widgetValue().toString(), QStringLiteral( "qgis_test" ) );
7766 QCOMPARE( static_cast< QgsDatabaseSchemaComboBox * >( wrapper3.wrappedWidget() )->comboBox()->currentText(), QStringLiteral( "qgis_test" ) );
7767 wrapper3.setWidgetValue( QStringLiteral( "public" ), context );
7768 QCOMPARE( spy3.count(), 2 );
7769 QCOMPARE( wrapper3.widgetValue().toString(), QStringLiteral( "public" ) );
7770 QCOMPARE( static_cast< QgsDatabaseSchemaComboBox * >( wrapper3.wrappedWidget() )->comboBox()->currentText(), QStringLiteral( "public" ) );
7771 wrapper3.setWidgetValue( QVariant(), context );
7772 QCOMPARE( spy3.count(), 3 );
7773 QVERIFY( !wrapper3.widgetValue().isValid() );
7774
7775 delete w;
7776 QLabel *l = wrapper.createWrappedLabel();
7777 if ( wrapper.type() != QgsProcessingGui::Batch )
7778 {
7779 QVERIFY( l );
7780 QCOMPARE( l->text(), QStringLiteral( "schema" ) );
7781 QCOMPARE( l->toolTip(), param.toolTip() );
7782 delete l;
7783 }
7784 else
7785 {
7786 QVERIFY( !l );
7787 }
7788
7789 };
7790
7791 // standard wrapper
7792 testWrapper( QgsProcessingGui::Standard );
7793
7794 // batch wrapper
7795 testWrapper( QgsProcessingGui::Batch );
7796
7797 // modeler wrapper
7798 testWrapper( QgsProcessingGui::Modeler );
7799
7800 // config widget
7801 QgsProcessingParameterWidgetContext widgetContext;
7802 QgsProcessingContext context;
7803 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "databaseschema" ), context, widgetContext );
7804 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
7805 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
7806 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
7807 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
7808 QVERIFY( !static_cast< QgsProcessingParameterDatabaseSchema * >( def.get() )->defaultValue().isValid() );
7809
7810 // using a parameter definition as initial values
7811 QgsProcessingParameterDatabaseSchema schemaParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), QStringLiteral( "connparam" ), QStringLiteral( "aaa" ), false );
7812 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "databaseschema" ), context, widgetContext, &schemaParam );
7813 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
7814 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
7815 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
7816 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
7817 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
7818 QCOMPARE( static_cast< QgsProcessingParameterDatabaseSchema * >( def.get() )->defaultValue().toString(), QStringLiteral( "aaa" ) );
7819 QCOMPARE( static_cast< QgsProcessingParameterDatabaseSchema * >( def.get() )->parentConnectionParameterName(), QStringLiteral( "connparam" ) );
7820 schemaParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
7821 schemaParam.setDefaultValue( QStringLiteral( "xxx" ) );
7822 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "databaseschema" ), context, widgetContext, &schemaParam );
7823 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
7824 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
7825 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
7826 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
7827 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
7828 QCOMPARE( static_cast< QgsProcessingParameterDatabaseSchema * >( def.get() )->defaultValue().toString(), QStringLiteral( "xxx" ) );
7829 schemaParam.setDefaultValue( QVariant() );
7830 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "databaseschema" ), context, widgetContext, &schemaParam );
7831 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
7832 QVERIFY( !static_cast< QgsProcessingParameterDatabaseSchema * >( def.get() )->defaultValue().isValid() );
7833 #endif
7834 }
7835
testDatabaseTableWrapper()7836 void TestProcessingGui::testDatabaseTableWrapper()
7837 {
7838 #ifdef ENABLE_PGTEST
7839 // register some connections
7840 QgsProviderMetadata *md = QgsProviderRegistry::instance()->providerMetadata( QStringLiteral( "postgres" ) );
7841
7842 QString dbConn = getenv( "QGIS_PGTEST_DB" );
7843 if ( dbConn.isEmpty() )
7844 {
7845 dbConn = "service=\"qgis_test\"";
7846 }
7847 QgsAbstractProviderConnection *conn = md->createConnection( QStringLiteral( "%1 sslmode=disable" ).arg( dbConn ), QVariantMap() );
7848 md->saveConnection( conn, QStringLiteral( "aa" ) );
7849
7850 const QList<QgsAbstractDatabaseProviderConnection::TableProperty> tables = dynamic_cast<QgsAbstractDatabaseProviderConnection *>( conn )->tables( QStringLiteral( "qgis_test" ) );
7851 QStringList tableNames;
7852 for ( const QgsAbstractDatabaseProviderConnection::TableProperty &prop : tables )
7853 tableNames << prop.tableName();
7854
7855 QVERIFY( !tableNames.isEmpty() );
7856
7857 auto testWrapper = [&tableNames]( QgsProcessingGui::WidgetType type )
7858 {
7859 QgsProcessingParameterProviderConnection connParam( QStringLiteral( "conn" ), QStringLiteral( "connection" ), QStringLiteral( "postgres" ), QVariant(), true );
7860 TestLayerWrapper connWrapper( &connParam );
7861 QgsProcessingParameterDatabaseSchema schemaParam( QStringLiteral( "schema" ), QStringLiteral( "schema" ), QStringLiteral( "connection" ), QVariant(), true );
7862 TestLayerWrapper schemaWrapper( &schemaParam );
7863
7864 QgsProcessingParameterDatabaseTable param( QStringLiteral( "table" ), QStringLiteral( "table" ), QStringLiteral( "conn" ), QStringLiteral( "schema" ), QVariant(), false );
7865
7866 QgsProcessingDatabaseTableWidgetWrapper wrapper( ¶m, type );
7867
7868 QgsProcessingContext context;
7869 QWidget *w = wrapper.createWrappedWidget( context );
7870 // no connection associated yet
7871 QCOMPARE( static_cast< QgsDatabaseTableComboBox * >( wrapper.wrappedWidget() )->comboBox()->count(), 0 );
7872
7873 // Set the parent widget connection value
7874 connWrapper.setWidgetValue( QStringLiteral( "aa" ), context );
7875 wrapper.setParentConnectionWrapperValue( &connWrapper );
7876 schemaWrapper.setWidgetValue( QStringLiteral( "qgis_test" ), context );
7877 wrapper.setParentSchemaWrapperValue( &schemaWrapper );
7878
7879 // now we should have tables available
7880 QCOMPARE( static_cast< QgsDatabaseTableComboBox * >( wrapper.wrappedWidget() )->comboBox()->count(), tableNames.count() );
7881
7882 QSignalSpy spy( &wrapper, &QgsProcessingDatabaseTableWidgetWrapper::widgetValueHasChanged );
7883 wrapper.setWidgetValue( QStringLiteral( "someData" ), context );
7884 QCOMPARE( spy.count(), 1 );
7885 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "someData" ) );
7886 QCOMPARE( static_cast< QgsDatabaseTableComboBox * >( wrapper.wrappedWidget() )->currentTable(), QStringLiteral( "someData" ) );
7887 wrapper.setWidgetValue( QStringLiteral( "some_poly_data" ), context );
7888 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "some_poly_data" ) );
7889 QCOMPARE( static_cast< QgsDatabaseTableComboBox * >( wrapper.wrappedWidget() )->currentTable(), QStringLiteral( "some_poly_data" ) );
7890 QCOMPARE( spy.count(), 2 );
7891 wrapper.setWidgetValue( QStringLiteral( "some_poly_data" ), context );
7892 QCOMPARE( spy.count(), 2 );
7893
7894 switch ( type )
7895 {
7896 case QgsProcessingGui::Standard:
7897 case QgsProcessingGui::Batch:
7898 {
7899 // batch or standard mode, only valid tables can be set!
7900 // not valid
7901 wrapper.setWidgetValue( QStringLiteral( "cc" ), context );
7902 QCOMPARE( spy.count(), 3 );
7903 QVERIFY( !wrapper.widgetValue().isValid() );
7904 QCOMPARE( static_cast< QgsDatabaseTableComboBox * >( wrapper.wrappedWidget() )->comboBox()->currentIndex(), -1 );
7905 break;
7906
7907 }
7908 case QgsProcessingGui::Modeler:
7909 // invalid tables permitted
7910 wrapper.setWidgetValue( QStringLiteral( "cc" ), context );
7911 QCOMPARE( spy.count(), 3 );
7912 QCOMPARE( static_cast< QgsDatabaseTableComboBox * >( wrapper.wrappedWidget() )->comboBox()->currentText(), QStringLiteral( "cc" ) );
7913 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "cc" ) );
7914 wrapper.setWidgetValue( QStringLiteral( "someData" ), context );
7915 QCOMPARE( spy.count(), 4 );
7916 QCOMPARE( static_cast< QgsDatabaseTableComboBox * >( wrapper.wrappedWidget() )->comboBox()->currentText(), QStringLiteral( "someData" ) );
7917 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "someData" ) );
7918 break;
7919 }
7920
7921 // make sure things are ok if connection is changed back to nothing
7922 connWrapper.setWidgetValue( QVariant(), context );
7923 wrapper.setParentConnectionWrapperValue( &connWrapper );
7924 QCOMPARE( static_cast< QgsDatabaseTableComboBox * >( wrapper.wrappedWidget() )->comboBox()->count(), 0 );
7925
7926 switch ( type )
7927 {
7928 case QgsProcessingGui::Standard:
7929 case QgsProcessingGui::Batch:
7930 {
7931 QCOMPARE( spy.count(), 3 );
7932 break;
7933 }
7934
7935 case QgsProcessingGui::Modeler:
7936 QCOMPARE( spy.count(), 5 );
7937 break;
7938 }
7939 QVERIFY( !wrapper.widgetValue().isValid() );
7940
7941 wrapper.setWidgetValue( QStringLiteral( "some_poly_data" ), context );
7942 switch ( type )
7943 {
7944 case QgsProcessingGui::Standard:
7945 case QgsProcessingGui::Batch:
7946 {
7947 QVERIFY( !wrapper.widgetValue().isValid() );
7948 break;
7949 }
7950
7951 case QgsProcessingGui::Modeler:
7952 // invalid tables permitted
7953 QCOMPARE( spy.count(), 6 );
7954 QCOMPARE( static_cast< QgsDatabaseTableComboBox * >( wrapper.wrappedWidget() )->comboBox()->currentText(), QStringLiteral( "some_poly_data" ) );
7955 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "some_poly_data" ) );
7956
7957 break;
7958 }
7959 delete w;
7960
7961 connWrapper.setWidgetValue( QStringLiteral( "aa" ), context );
7962
7963 // optional
7964 QgsProcessingParameterDatabaseTable param2( QStringLiteral( "table" ), QStringLiteral( "table" ), QStringLiteral( "conn" ), QStringLiteral( "schema" ), QVariant(), true );
7965 QgsProcessingDatabaseTableWidgetWrapper wrapper3( ¶m2, type );
7966 w = wrapper3.createWrappedWidget( context );
7967
7968 wrapper3.setParentConnectionWrapperValue( &connWrapper );
7969 wrapper3.setParentSchemaWrapperValue( &schemaWrapper );
7970
7971 QSignalSpy spy3( &wrapper3, &QgsProcessingDatabaseTableWidgetWrapper::widgetValueHasChanged );
7972 wrapper3.setWidgetValue( QStringLiteral( "someData" ), context );
7973 QCOMPARE( spy3.count(), 1 );
7974 QCOMPARE( wrapper3.widgetValue().toString(), QStringLiteral( "someData" ) );
7975 QCOMPARE( static_cast< QgsDatabaseTableComboBox * >( wrapper3.wrappedWidget() )->comboBox()->currentText(), QStringLiteral( "someData" ) );
7976 wrapper3.setWidgetValue( QStringLiteral( "some_poly_data" ), context );
7977 QCOMPARE( spy3.count(), 2 );
7978 QCOMPARE( wrapper3.widgetValue().toString(), QStringLiteral( "some_poly_data" ) );
7979 QCOMPARE( static_cast< QgsDatabaseTableComboBox * >( wrapper3.wrappedWidget() )->comboBox()->currentText(), QStringLiteral( "some_poly_data" ) );
7980 wrapper3.setWidgetValue( QVariant(), context );
7981 QCOMPARE( spy3.count(), 3 );
7982 QVERIFY( !wrapper3.widgetValue().isValid() );
7983
7984 delete w;
7985
7986 // allowing new table names
7987 QgsProcessingParameterDatabaseTable param3( QStringLiteral( "table" ), QStringLiteral( "table" ), QStringLiteral( "conn" ), QStringLiteral( "schema" ), QVariant(), false, true );
7988 QgsProcessingDatabaseTableWidgetWrapper wrapper4( ¶m3, type );
7989 w = wrapper4.createWrappedWidget( context );
7990
7991 wrapper4.setParentConnectionWrapperValue( &connWrapper );
7992 wrapper4.setParentSchemaWrapperValue( &schemaWrapper );
7993
7994 QSignalSpy spy4( &wrapper4, &QgsProcessingDatabaseTableWidgetWrapper::widgetValueHasChanged );
7995 wrapper4.setWidgetValue( QStringLiteral( "someData" ), context );
7996 QCOMPARE( spy4.count(), 1 );
7997 QCOMPARE( wrapper4.widgetValue().toString(), QStringLiteral( "someData" ) );
7998 QCOMPARE( static_cast< QgsDatabaseTableComboBox * >( wrapper4.wrappedWidget() )->comboBox()->currentText(), QStringLiteral( "someData" ) );
7999 wrapper4.setWidgetValue( QStringLiteral( "some_poly_data" ), context );
8000 QCOMPARE( spy4.count(), 2 );
8001 QCOMPARE( wrapper4.widgetValue().toString(), QStringLiteral( "some_poly_data" ) );
8002 QCOMPARE( static_cast< QgsDatabaseTableComboBox * >( wrapper4.wrappedWidget() )->comboBox()->currentText(), QStringLiteral( "some_poly_data" ) );
8003 wrapper4.setWidgetValue( QVariant(), context );
8004 QCOMPARE( spy4.count(), 3 );
8005 QVERIFY( !wrapper4.widgetValue().isValid() );
8006 // should always allow non existing table names
8007 wrapper4.setWidgetValue( QStringLiteral( "someDataxxxxxxxxxxxxxxxxxxxx" ), context );
8008 QCOMPARE( spy4.count(), 4 );
8009 QCOMPARE( wrapper4.widgetValue().toString(), QStringLiteral( "someDataxxxxxxxxxxxxxxxxxxxx" ) );
8010 QCOMPARE( static_cast< QgsDatabaseTableComboBox * >( wrapper4.wrappedWidget() )->comboBox()->currentText(), QStringLiteral( "someDataxxxxxxxxxxxxxxxxxxxx" ) );
8011
8012
8013 delete w;
8014
8015
8016 QLabel *l = wrapper.createWrappedLabel();
8017 if ( wrapper.type() != QgsProcessingGui::Batch )
8018 {
8019 QVERIFY( l );
8020 QCOMPARE( l->text(), QStringLiteral( "table" ) );
8021 QCOMPARE( l->toolTip(), param.toolTip() );
8022 delete l;
8023 }
8024 else
8025 {
8026 QVERIFY( !l );
8027 }
8028 };
8029
8030 // standard wrapper
8031 testWrapper( QgsProcessingGui::Standard );
8032
8033 // batch wrapper
8034 testWrapper( QgsProcessingGui::Batch );
8035
8036 // modeler wrapper
8037 testWrapper( QgsProcessingGui::Modeler );
8038
8039 // config widget
8040 QgsProcessingParameterWidgetContext widgetContext;
8041 QgsProcessingContext context;
8042 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "databasetable" ), context, widgetContext );
8043 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
8044 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
8045 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
8046 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
8047 QVERIFY( !static_cast< QgsProcessingParameterDatabaseTable * >( def.get() )->defaultValue().isValid() );
8048
8049 // using a parameter definition as initial values
8050 QgsProcessingParameterDatabaseTable tableParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), QStringLiteral( "connparam" ), QStringLiteral( "schemaparam" ), QStringLiteral( "aaa" ), false );
8051 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "databasetable" ), context, widgetContext, &tableParam );
8052 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
8053 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
8054 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
8055 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
8056 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
8057 QCOMPARE( static_cast< QgsProcessingParameterDatabaseTable * >( def.get() )->defaultValue().toString(), QStringLiteral( "aaa" ) );
8058 QCOMPARE( static_cast< QgsProcessingParameterDatabaseTable * >( def.get() )->parentConnectionParameterName(), QStringLiteral( "connparam" ) );
8059 QCOMPARE( static_cast< QgsProcessingParameterDatabaseTable * >( def.get() )->parentSchemaParameterName(), QStringLiteral( "schemaparam" ) );
8060 tableParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
8061 tableParam.setDefaultValue( QStringLiteral( "xxx" ) );
8062 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "databasetable" ), context, widgetContext, &tableParam );
8063 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
8064 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
8065 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
8066 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
8067 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
8068 QCOMPARE( static_cast< QgsProcessingParameterDatabaseTable * >( def.get() )->defaultValue().toString(), QStringLiteral( "xxx" ) );
8069 tableParam.setDefaultValue( QVariant() );
8070 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "databasetable" ), context, widgetContext, &tableParam );
8071 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
8072 QVERIFY( !static_cast< QgsProcessingParameterDatabaseTable * >( def.get() )->defaultValue().isValid() );
8073 #endif
8074 }
8075
testFieldMapWidget()8076 void TestProcessingGui::testFieldMapWidget()
8077 {
8078 QgsProcessingFieldMapPanelWidget widget;
8079
8080 QVariantMap map;
8081 map.insert( QStringLiteral( "name" ), QStringLiteral( "n" ) );
8082 map.insert( QStringLiteral( "type" ), static_cast< int >( QVariant::Double ) );
8083 map.insert( QStringLiteral( "length" ), 8 );
8084 map.insert( QStringLiteral( "precision" ), 5 );
8085 QVariantMap map2;
8086 map2.insert( QStringLiteral( "name" ), QStringLiteral( "n2" ) );
8087 map2.insert( QStringLiteral( "type" ), static_cast< int >( QVariant::String ) );
8088 map2.insert( QStringLiteral( "expression" ), QStringLiteral( "'abc' || \"def\"" ) );
8089
8090 QSignalSpy spy( &widget, &QgsProcessingFieldMapPanelWidget::changed );
8091 widget.setValue( QVariantList() << map << map2 );
8092 QCOMPARE( spy.size(), 1 );
8093
8094 QCOMPARE( widget.value().toList().size(), 2 );
8095 QCOMPARE( widget.value().toList().at( 0 ).toMap().value( QStringLiteral( "name" ) ).toString(), QStringLiteral( "n" ) );
8096 QCOMPARE( widget.value().toList().at( 0 ).toMap().value( QStringLiteral( "type" ) ).toInt(), static_cast< int >( QVariant::Double ) );
8097 QCOMPARE( widget.value().toList().at( 0 ).toMap().value( QStringLiteral( "length" ) ).toInt(), 8 );
8098 QCOMPARE( widget.value().toList().at( 0 ).toMap().value( QStringLiteral( "precision" ) ).toInt(), 5 );
8099 QCOMPARE( widget.value().toList().at( 0 ).toMap().value( QStringLiteral( "expression" ) ).toString(), QString() );
8100 QCOMPARE( widget.value().toList().at( 1 ).toMap().value( QStringLiteral( "name" ) ).toString(), QStringLiteral( "n2" ) );
8101 QCOMPARE( widget.value().toList().at( 1 ).toMap().value( QStringLiteral( "type" ) ).toInt(), static_cast< int >( QVariant::String ) );
8102 QCOMPARE( widget.value().toList().at( 1 ).toMap().value( QStringLiteral( "expression" ) ).toString(), QStringLiteral( "'abc' || \"def\"" ) );
8103 }
8104
testFieldMapWrapper()8105 void TestProcessingGui::testFieldMapWrapper()
8106 {
8107 const QgsProcessingAlgorithm *centroidAlg = QgsApplication::processingRegistry()->algorithmById( QStringLiteral( "native:centroids" ) );
8108 const QgsProcessingParameterDefinition *layerDef = centroidAlg->parameterDefinition( QStringLiteral( "INPUT" ) );
8109
8110 auto testWrapper = [layerDef]( QgsProcessingGui::WidgetType type )
8111 {
8112 QgsProcessingParameterFieldMapping param( QStringLiteral( "mapping" ), QStringLiteral( "mapping" ) );
8113
8114 QgsProcessingFieldMapWidgetWrapper wrapper( ¶m, type );
8115
8116 QgsProcessingContext context;
8117 QWidget *w = wrapper.createWrappedWidget( context );
8118
8119 QVariantMap map;
8120 map.insert( QStringLiteral( "name" ), QStringLiteral( "n" ) );
8121 map.insert( QStringLiteral( "type" ), static_cast< int >( QVariant::Double ) );
8122 map.insert( QStringLiteral( "length" ), 8 );
8123 map.insert( QStringLiteral( "precision" ), 5 );
8124 QVariantMap map2;
8125 map2.insert( QStringLiteral( "name" ), QStringLiteral( "n2" ) );
8126 map2.insert( QStringLiteral( "type" ), static_cast< int >( QVariant::String ) );
8127 map2.insert( QStringLiteral( "expression" ), QStringLiteral( "'abc' || \"def\"" ) );
8128
8129 QSignalSpy spy( &wrapper, &QgsProcessingFieldMapWidgetWrapper::widgetValueHasChanged );
8130 wrapper.setWidgetValue( QVariantList() << map << map2, context );
8131 QCOMPARE( spy.count(), 1 );
8132 QCOMPARE( wrapper.widgetValue().toList().at( 0 ).toMap().value( QStringLiteral( "name" ) ).toString(), QStringLiteral( "n" ) );
8133 QCOMPARE( wrapper.widgetValue().toList().at( 0 ).toMap().value( QStringLiteral( "type" ) ).toInt(), static_cast< int >( QVariant::Double ) );
8134 QCOMPARE( wrapper.widgetValue().toList().at( 0 ).toMap().value( QStringLiteral( "length" ) ).toInt(), 8 );
8135 QCOMPARE( wrapper.widgetValue().toList().at( 0 ).toMap().value( QStringLiteral( "precision" ) ).toInt(), 5 );
8136 QCOMPARE( wrapper.widgetValue().toList().at( 0 ).toMap().value( QStringLiteral( "expression" ) ).toString(), QString() );
8137 QCOMPARE( wrapper.widgetValue().toList().at( 1 ).toMap().value( QStringLiteral( "name" ) ).toString(), QStringLiteral( "n2" ) );
8138 QCOMPARE( wrapper.widgetValue().toList().at( 1 ).toMap().value( QStringLiteral( "type" ) ).toInt(), static_cast< int >( QVariant::String ) );
8139 QCOMPARE( wrapper.widgetValue().toList().at( 1 ).toMap().value( QStringLiteral( "expression" ) ).toString(), QStringLiteral( "'abc' || \"def\"" ) );
8140
8141 QCOMPARE( static_cast< QgsProcessingFieldMapPanelWidget * >( wrapper.wrappedWidget() )->value().toList().count(), 2 );
8142 QCOMPARE( static_cast< QgsProcessingFieldMapPanelWidget * >( wrapper.wrappedWidget() )->value().toList().at( 0 ).toMap().value( QStringLiteral( "name" ) ).toString(), QStringLiteral( "n" ) );
8143 QCOMPARE( static_cast< QgsProcessingFieldMapPanelWidget * >( wrapper.wrappedWidget() )->value().toList().at( 1 ).toMap().value( QStringLiteral( "name" ) ).toString(), QStringLiteral( "n2" ) );
8144 wrapper.setWidgetValue( QVariantList() << map, context );
8145 QCOMPARE( spy.count(), 2 );
8146 QCOMPARE( wrapper.widgetValue().toList().size(), 1 );
8147 QCOMPARE( static_cast< QgsProcessingFieldMapPanelWidget * >( wrapper.wrappedWidget() )->value().toList().size(), 1 );
8148
8149 QLabel *l = wrapper.createWrappedLabel();
8150 if ( wrapper.type() != QgsProcessingGui::Batch )
8151 {
8152 QVERIFY( l );
8153 QCOMPARE( l->text(), QStringLiteral( "mapping" ) );
8154 QCOMPARE( l->toolTip(), param.toolTip() );
8155 delete l;
8156 }
8157 else
8158 {
8159 QVERIFY( !l );
8160 }
8161
8162 // check signal
8163 static_cast< QgsProcessingFieldMapPanelWidget * >( wrapper.wrappedWidget() )->setValue( QVariantList() << map << map2 );
8164 QCOMPARE( spy.count(), 3 );
8165
8166 delete w;
8167
8168 // with layer
8169 param.setParentLayerParameterName( QStringLiteral( "other" ) );
8170 QgsProcessingFieldMapWidgetWrapper wrapper2( ¶m, type );
8171 w = wrapper2.createWrappedWidget( context );
8172
8173 QSignalSpy spy2( &wrapper2, &QgsProcessingFieldMapWidgetWrapper::widgetValueHasChanged );
8174 wrapper2.setWidgetValue( QVariantList() << map, context );
8175 QCOMPARE( spy2.count(), 1 );
8176 QCOMPARE( wrapper2.widgetValue().toList().size(), 1 );
8177 QCOMPARE( wrapper2.widgetValue().toList().at( 0 ).toMap().value( QStringLiteral( "name" ) ).toString(), QStringLiteral( "n" ) );
8178 QCOMPARE( static_cast< QgsProcessingFieldMapPanelWidget * >( wrapper2.wrappedWidget() )->value().toList().at( 0 ).toMap().value( QStringLiteral( "name" ) ).toString(), QStringLiteral( "n" ) );
8179
8180 wrapper2.setWidgetValue( QVariantList() << map2, context );
8181 QCOMPARE( spy2.count(), 2 );
8182 QCOMPARE( wrapper2.widgetValue().toList().size(), 1 );
8183 QCOMPARE( wrapper2.widgetValue().toList().at( 0 ).toMap().value( QStringLiteral( "name" ) ).toString(), QStringLiteral( "n2" ) );
8184 QCOMPARE( static_cast< QgsProcessingFieldMapPanelWidget * >( wrapper2.wrappedWidget() )->value().toList().at( 0 ).toMap().value( QStringLiteral( "name" ) ).toString(), QStringLiteral( "n2" ) );
8185
8186 static_cast< QgsProcessingFieldMapPanelWidget * >( wrapper2.wrappedWidget() )->setValue( QVariantList() << map );
8187 QCOMPARE( spy2.count(), 3 );
8188
8189 TestLayerWrapper layerWrapper( layerDef );
8190 QgsProject p;
8191 QgsVectorLayer *vl = new QgsVectorLayer( QStringLiteral( "LineString" ), QStringLiteral( "x" ), QStringLiteral( "memory" ) );
8192 p.addMapLayer( vl );
8193
8194 QVERIFY( !wrapper2.mPanel->layer() );
8195 layerWrapper.setWidgetValue( QVariant::fromValue( vl ), context );
8196 wrapper2.setParentLayerWrapperValue( &layerWrapper );
8197 QCOMPARE( wrapper2.mPanel->layer(), vl );
8198
8199 // should not be owned by wrapper
8200 QVERIFY( !wrapper2.mParentLayer.get() );
8201 layerWrapper.setWidgetValue( QVariant(), context );
8202 wrapper2.setParentLayerWrapperValue( &layerWrapper );
8203 QVERIFY( !wrapper2.mPanel->layer() );
8204
8205 layerWrapper.setWidgetValue( vl->id(), context );
8206 wrapper2.setParentLayerWrapperValue( &layerWrapper );
8207 QVERIFY( !wrapper2.mPanel->layer() );
8208 QVERIFY( !wrapper2.mParentLayer.get() );
8209
8210 // with project layer
8211 context.setProject( &p );
8212 TestProcessingContextGenerator generator( context );
8213 wrapper2.registerProcessingContextGenerator( &generator );
8214
8215 layerWrapper.setWidgetValue( vl->id(), context );
8216 wrapper2.setParentLayerWrapperValue( &layerWrapper );
8217 QCOMPARE( wrapper2.mPanel->layer(), vl );
8218 QVERIFY( !wrapper2.mParentLayer.get() );
8219
8220 // non-project layer
8221 QString pointFileName = TEST_DATA_DIR + QStringLiteral( "/points.shp" );
8222 layerWrapper.setWidgetValue( pointFileName, context );
8223 wrapper2.setParentLayerWrapperValue( &layerWrapper );
8224 QCOMPARE( wrapper2.mPanel->layer()->publicSource(), pointFileName );
8225 // must be owned by wrapper, or layer may be deleted while still required by wrapper
8226 QCOMPARE( wrapper2.mParentLayer->publicSource(), pointFileName );
8227
8228 };
8229
8230 // standard wrapper
8231 testWrapper( QgsProcessingGui::Standard );
8232
8233 // batch wrapper
8234 testWrapper( QgsProcessingGui::Batch );
8235
8236 // modeler wrapper
8237 testWrapper( QgsProcessingGui::Modeler );
8238
8239 // config widget
8240 QgsProcessingParameterWidgetContext widgetContext;
8241 QgsProcessingContext context;
8242 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "fields_mapping" ), context, widgetContext );
8243 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
8244 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
8245 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
8246 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
8247
8248 // using a parameter definition as initial values
8249 QgsProcessingParameterFieldMapping mapParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), QStringLiteral( "parent" ) );
8250 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "fields_mapping" ), context, widgetContext, &mapParam );
8251 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
8252 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
8253 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
8254 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
8255 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
8256 QCOMPARE( static_cast< QgsProcessingParameterFieldMapping * >( def.get() )->parentLayerParameterName(), QStringLiteral( "parent" ) );
8257 mapParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
8258 mapParam.setParentLayerParameterName( QString() );
8259 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "fields_mapping" ), context, widgetContext, &mapParam );
8260 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
8261 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
8262 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
8263 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
8264 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
8265 QVERIFY( static_cast< QgsProcessingParameterFieldMapping * >( def.get() )->parentLayerParameterName().isEmpty() );
8266 }
8267
testAggregateWidget()8268 void TestProcessingGui::testAggregateWidget()
8269 {
8270 QgsProcessingAggregatePanelWidget widget;
8271
8272 QVariantMap map;
8273 map.insert( QStringLiteral( "name" ), QStringLiteral( "n" ) );
8274 map.insert( QStringLiteral( "type" ), static_cast< int >( QVariant::Double ) );
8275 map.insert( QStringLiteral( "length" ), 8 );
8276 map.insert( QStringLiteral( "precision" ), 5 );
8277 QVariantMap map2;
8278 map2.insert( QStringLiteral( "name" ), QStringLiteral( "n2" ) );
8279 map2.insert( QStringLiteral( "type" ), static_cast< int >( QVariant::String ) );
8280 map2.insert( QStringLiteral( "input" ), QStringLiteral( "'abc' || \"def\"" ) );
8281 map2.insert( QStringLiteral( "aggregate" ), QStringLiteral( "concatenate" ) );
8282 map2.insert( QStringLiteral( "delimiter" ), QStringLiteral( "|" ) );
8283
8284 QSignalSpy spy( &widget, &QgsProcessingAggregatePanelWidget::changed );
8285 widget.setValue( QVariantList() << map << map2 );
8286 QCOMPARE( spy.size(), 1 );
8287
8288 QCOMPARE( widget.value().toList().size(), 2 );
8289 QCOMPARE( widget.value().toList().at( 0 ).toMap().value( QStringLiteral( "name" ) ).toString(), QStringLiteral( "n" ) );
8290 QCOMPARE( widget.value().toList().at( 0 ).toMap().value( QStringLiteral( "type" ) ).toInt(), static_cast< int >( QVariant::Double ) );
8291 QCOMPARE( widget.value().toList().at( 0 ).toMap().value( QStringLiteral( "length" ) ).toInt(), 8 );
8292 QCOMPARE( widget.value().toList().at( 0 ).toMap().value( QStringLiteral( "precision" ) ).toInt(), 5 );
8293 QCOMPARE( widget.value().toList().at( 0 ).toMap().value( QStringLiteral( "input" ) ).toString(), QString() );
8294 QCOMPARE( widget.value().toList().at( 0 ).toMap().value( QStringLiteral( "aggregate" ) ).toString(), QString() );
8295 QCOMPARE( widget.value().toList().at( 0 ).toMap().value( QStringLiteral( "delimiter" ) ).toString(), QString() );
8296 QCOMPARE( widget.value().toList().at( 1 ).toMap().value( QStringLiteral( "name" ) ).toString(), QStringLiteral( "n2" ) );
8297 QCOMPARE( widget.value().toList().at( 1 ).toMap().value( QStringLiteral( "type" ) ).toInt(), static_cast< int >( QVariant::String ) );
8298 QCOMPARE( widget.value().toList().at( 1 ).toMap().value( QStringLiteral( "input" ) ).toString(), QStringLiteral( "'abc' || \"def\"" ) );
8299 QCOMPARE( widget.value().toList().at( 1 ).toMap().value( QStringLiteral( "aggregate" ) ).toString(), QStringLiteral( "concatenate" ) );
8300 QCOMPARE( widget.value().toList().at( 1 ).toMap().value( QStringLiteral( "delimiter" ) ).toString(), QStringLiteral( "|" ) );
8301 }
8302
testAggregateWrapper()8303 void TestProcessingGui::testAggregateWrapper()
8304 {
8305 const QgsProcessingAlgorithm *centroidAlg = QgsApplication::processingRegistry()->algorithmById( QStringLiteral( "native:centroids" ) );
8306 const QgsProcessingParameterDefinition *layerDef = centroidAlg->parameterDefinition( QStringLiteral( "INPUT" ) );
8307
8308 auto testWrapper = [layerDef]( QgsProcessingGui::WidgetType type )
8309 {
8310 QgsProcessingParameterAggregate param( QStringLiteral( "mapping" ), QStringLiteral( "mapping" ) );
8311
8312 QgsProcessingAggregateWidgetWrapper wrapper( ¶m, type );
8313
8314 QgsProcessingContext context;
8315 QWidget *w = wrapper.createWrappedWidget( context );
8316
8317 QVariantMap map;
8318 map.insert( QStringLiteral( "name" ), QStringLiteral( "n" ) );
8319 map.insert( QStringLiteral( "type" ), static_cast< int >( QVariant::Double ) );
8320 map.insert( QStringLiteral( "length" ), 8 );
8321 map.insert( QStringLiteral( "precision" ), 5 );
8322 QVariantMap map2;
8323 map2.insert( QStringLiteral( "name" ), QStringLiteral( "n2" ) );
8324 map2.insert( QStringLiteral( "type" ), static_cast< int >( QVariant::String ) );
8325 map2.insert( QStringLiteral( "input" ), QStringLiteral( "'abc' || \"def\"" ) );
8326 map2.insert( QStringLiteral( "aggregate" ), QStringLiteral( "concatenate" ) );
8327 map2.insert( QStringLiteral( "delimiter" ), QStringLiteral( "|" ) );
8328
8329 QSignalSpy spy( &wrapper, &QgsProcessingFieldMapWidgetWrapper::widgetValueHasChanged );
8330 wrapper.setWidgetValue( QVariantList() << map << map2, context );
8331 QCOMPARE( spy.count(), 1 );
8332 QCOMPARE( wrapper.widgetValue().toList().at( 0 ).toMap().value( QStringLiteral( "name" ) ).toString(), QStringLiteral( "n" ) );
8333 QCOMPARE( wrapper.widgetValue().toList().at( 0 ).toMap().value( QStringLiteral( "type" ) ).toInt(), static_cast< int >( QVariant::Double ) );
8334 QCOMPARE( wrapper.widgetValue().toList().at( 0 ).toMap().value( QStringLiteral( "length" ) ).toInt(), 8 );
8335 QCOMPARE( wrapper.widgetValue().toList().at( 0 ).toMap().value( QStringLiteral( "precision" ) ).toInt(), 5 );
8336 QCOMPARE( wrapper.widgetValue().toList().at( 0 ).toMap().value( QStringLiteral( "input" ) ).toString(), QString() );
8337 QCOMPARE( wrapper.widgetValue().toList().at( 0 ).toMap().value( QStringLiteral( "aggregate" ) ).toString(), QString() );
8338 QCOMPARE( wrapper.widgetValue().toList().at( 0 ).toMap().value( QStringLiteral( "delimiter" ) ).toString(), QString() );
8339 QCOMPARE( wrapper.widgetValue().toList().at( 1 ).toMap().value( QStringLiteral( "name" ) ).toString(), QStringLiteral( "n2" ) );
8340 QCOMPARE( wrapper.widgetValue().toList().at( 1 ).toMap().value( QStringLiteral( "type" ) ).toInt(), static_cast< int >( QVariant::String ) );
8341 QCOMPARE( wrapper.widgetValue().toList().at( 1 ).toMap().value( QStringLiteral( "input" ) ).toString(), QStringLiteral( "'abc' || \"def\"" ) );
8342 QCOMPARE( wrapper.widgetValue().toList().at( 1 ).toMap().value( QStringLiteral( "aggregate" ) ).toString(), QStringLiteral( "concatenate" ) );
8343 QCOMPARE( wrapper.widgetValue().toList().at( 1 ).toMap().value( QStringLiteral( "delimiter" ) ).toString(), QStringLiteral( "|" ) );
8344
8345 QCOMPARE( static_cast< QgsProcessingAggregatePanelWidget * >( wrapper.wrappedWidget() )->value().toList().count(), 2 );
8346 QCOMPARE( static_cast< QgsProcessingAggregatePanelWidget * >( wrapper.wrappedWidget() )->value().toList().at( 0 ).toMap().value( QStringLiteral( "name" ) ).toString(), QStringLiteral( "n" ) );
8347 QCOMPARE( static_cast< QgsProcessingAggregatePanelWidget * >( wrapper.wrappedWidget() )->value().toList().at( 1 ).toMap().value( QStringLiteral( "name" ) ).toString(), QStringLiteral( "n2" ) );
8348 wrapper.setWidgetValue( QVariantList() << map, context );
8349 QCOMPARE( spy.count(), 2 );
8350 QCOMPARE( wrapper.widgetValue().toList().size(), 1 );
8351 QCOMPARE( static_cast< QgsProcessingAggregatePanelWidget * >( wrapper.wrappedWidget() )->value().toList().size(), 1 );
8352
8353 QLabel *l = wrapper.createWrappedLabel();
8354 if ( wrapper.type() != QgsProcessingGui::Batch )
8355 {
8356 QVERIFY( l );
8357 QCOMPARE( l->text(), QStringLiteral( "mapping" ) );
8358 QCOMPARE( l->toolTip(), param.toolTip() );
8359 delete l;
8360 }
8361 else
8362 {
8363 QVERIFY( !l );
8364 }
8365
8366 // check signal
8367 static_cast< QgsProcessingAggregatePanelWidget * >( wrapper.wrappedWidget() )->setValue( QVariantList() << map << map2 );
8368 QCOMPARE( spy.count(), 3 );
8369
8370 delete w;
8371
8372 // with layer
8373 param.setParentLayerParameterName( QStringLiteral( "other" ) );
8374 QgsProcessingAggregateWidgetWrapper wrapper2( ¶m, type );
8375 w = wrapper2.createWrappedWidget( context );
8376
8377 QSignalSpy spy2( &wrapper2, &QgsProcessingAggregateWidgetWrapper::widgetValueHasChanged );
8378 wrapper2.setWidgetValue( QVariantList() << map, context );
8379 QCOMPARE( spy2.count(), 1 );
8380 QCOMPARE( wrapper2.widgetValue().toList().size(), 1 );
8381 QCOMPARE( wrapper2.widgetValue().toList().at( 0 ).toMap().value( QStringLiteral( "name" ) ).toString(), QStringLiteral( "n" ) );
8382 QCOMPARE( static_cast< QgsProcessingAggregatePanelWidget * >( wrapper2.wrappedWidget() )->value().toList().at( 0 ).toMap().value( QStringLiteral( "name" ) ).toString(), QStringLiteral( "n" ) );
8383
8384 wrapper2.setWidgetValue( QVariantList() << map2, context );
8385 QCOMPARE( spy2.count(), 2 );
8386 QCOMPARE( wrapper2.widgetValue().toList().size(), 1 );
8387 QCOMPARE( wrapper2.widgetValue().toList().at( 0 ).toMap().value( QStringLiteral( "name" ) ).toString(), QStringLiteral( "n2" ) );
8388 QCOMPARE( static_cast< QgsProcessingAggregatePanelWidget * >( wrapper2.wrappedWidget() )->value().toList().at( 0 ).toMap().value( QStringLiteral( "name" ) ).toString(), QStringLiteral( "n2" ) );
8389
8390 static_cast< QgsProcessingAggregatePanelWidget * >( wrapper2.wrappedWidget() )->setValue( QVariantList() << map );
8391 QCOMPARE( spy2.count(), 3 );
8392
8393
8394 TestLayerWrapper layerWrapper( layerDef );
8395 QgsProject p;
8396 QgsVectorLayer *vl = new QgsVectorLayer( QStringLiteral( "LineString" ), QStringLiteral( "x" ), QStringLiteral( "memory" ) );
8397 p.addMapLayer( vl );
8398
8399 QVERIFY( !wrapper2.mPanel->layer() );
8400 layerWrapper.setWidgetValue( QVariant::fromValue( vl ), context );
8401 wrapper2.setParentLayerWrapperValue( &layerWrapper );
8402 QCOMPARE( wrapper2.mPanel->layer(), vl );
8403
8404 // should not be owned by wrapper
8405 QVERIFY( !wrapper2.mParentLayer.get() );
8406 layerWrapper.setWidgetValue( QVariant(), context );
8407 wrapper2.setParentLayerWrapperValue( &layerWrapper );
8408 QVERIFY( !wrapper2.mPanel->layer() );
8409
8410 layerWrapper.setWidgetValue( vl->id(), context );
8411 wrapper2.setParentLayerWrapperValue( &layerWrapper );
8412 QVERIFY( !wrapper2.mPanel->layer() );
8413 QVERIFY( !wrapper2.mParentLayer.get() );
8414
8415 // with project layer
8416 context.setProject( &p );
8417 TestProcessingContextGenerator generator( context );
8418 wrapper2.registerProcessingContextGenerator( &generator );
8419
8420 layerWrapper.setWidgetValue( vl->id(), context );
8421 wrapper2.setParentLayerWrapperValue( &layerWrapper );
8422 QCOMPARE( wrapper2.mPanel->layer(), vl );
8423 QVERIFY( !wrapper2.mParentLayer.get() );
8424
8425 // non-project layer
8426 QString pointFileName = TEST_DATA_DIR + QStringLiteral( "/points.shp" );
8427 layerWrapper.setWidgetValue( pointFileName, context );
8428 wrapper2.setParentLayerWrapperValue( &layerWrapper );
8429 QCOMPARE( wrapper2.mPanel->layer()->publicSource(), pointFileName );
8430 // must be owned by wrapper, or layer may be deleted while still required by wrapper
8431 QCOMPARE( wrapper2.mParentLayer->publicSource(), pointFileName );
8432
8433 };
8434
8435 // standard wrapper
8436 testWrapper( QgsProcessingGui::Standard );
8437
8438 // batch wrapper
8439 testWrapper( QgsProcessingGui::Batch );
8440
8441 // modeler wrapper
8442 testWrapper( QgsProcessingGui::Modeler );
8443
8444 // config widget
8445 QgsProcessingParameterWidgetContext widgetContext;
8446 QgsProcessingContext context;
8447 std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "aggregates" ), context, widgetContext );
8448 std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
8449 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
8450 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
8451 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
8452
8453 // using a parameter definition as initial values
8454 QgsProcessingParameterAggregate mapParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), QStringLiteral( "parent" ) );
8455 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "aggregates" ), context, widgetContext, &mapParam );
8456 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
8457 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
8458 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
8459 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
8460 QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
8461 QCOMPARE( static_cast< QgsProcessingParameterAggregate * >( def.get() )->parentLayerParameterName(), QStringLiteral( "parent" ) );
8462 mapParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
8463 mapParam.setParentLayerParameterName( QString() );
8464 widget = std::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "aggregates" ), context, widgetContext, &mapParam );
8465 def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
8466 QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
8467 QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
8468 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
8469 QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
8470 QVERIFY( static_cast< QgsProcessingParameterAggregate * >( def.get() )->parentLayerParameterName().isEmpty() );
8471 }
8472
testOutputDefinitionWidget()8473 void TestProcessingGui::testOutputDefinitionWidget()
8474 {
8475 QgsProcessingParameterFeatureSink sink( QStringLiteral( "test" ) );
8476 QgsProcessingLayerOutputDestinationWidget panel( &sink, false );
8477
8478 QSignalSpy skipSpy( &panel, &QgsProcessingLayerOutputDestinationWidget::skipOutputChanged );
8479 QSignalSpy changedSpy( &panel, &QgsProcessingLayerOutputDestinationWidget::destinationChanged );
8480
8481 QVariant v = panel.value();
8482 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8483 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QgsProcessing::TEMPORARY_OUTPUT );
8484 QVERIFY( !panel.outputIsSkipped() );
8485
8486 panel.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8487 v = panel.value();
8488 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8489 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().createOptions.value( QStringLiteral( "fileEncoding" ) ).toString(), QStringLiteral( "System" ) );
8490 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QgsProcessing::TEMPORARY_OUTPUT );
8491 QVERIFY( !panel.outputIsSkipped() );
8492 QCOMPARE( skipSpy.count(), 0 );
8493 QCOMPARE( changedSpy.count(), 0 );
8494 panel.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8495 QCOMPARE( skipSpy.count(), 0 );
8496 QCOMPARE( changedSpy.count(), 0 );
8497
8498 QgsProcessingOutputLayerDefinition def;
8499 def.sink.setStaticValue( QgsProcessing::TEMPORARY_OUTPUT );
8500 def.createOptions.insert( QStringLiteral( "fileEncoding" ), QStringLiteral( "utf8" ) );
8501 panel.setValue( def );
8502 QCOMPARE( skipSpy.count(), 0 );
8503 QCOMPARE( changedSpy.count(), 0 );
8504 v = panel.value();
8505 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8506 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().createOptions.value( QStringLiteral( "fileEncoding" ) ).toString(), QStringLiteral( "utf8" ) );
8507 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QgsProcessing::TEMPORARY_OUTPUT );
8508
8509 panel.setValue( QStringLiteral( "memory:" ) );
8510 v = panel.value();
8511 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8512 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().createOptions.value( QStringLiteral( "fileEncoding" ) ).toString(), QStringLiteral( "utf8" ) );
8513 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QgsProcessing::TEMPORARY_OUTPUT );
8514 QVERIFY( !panel.outputIsSkipped() );
8515 QCOMPARE( skipSpy.count(), 0 );
8516 QCOMPARE( changedSpy.count(), 0 );
8517 panel.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8518 QCOMPARE( skipSpy.count(), 0 );
8519 QCOMPARE( changedSpy.count(), 0 );
8520
8521 def.sink.setStaticValue( QStringLiteral( "memory:" ) );
8522 panel.setValue( def );
8523 QCOMPARE( skipSpy.count(), 0 );
8524 QCOMPARE( changedSpy.count(), 0 );
8525 v = panel.value();
8526 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8527 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().createOptions.value( QStringLiteral( "fileEncoding" ) ).toString(), QStringLiteral( "utf8" ) );
8528 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QgsProcessing::TEMPORARY_OUTPUT );
8529
8530 panel.setValue( QStringLiteral( "ogr:dbname='/me/a.gpkg' table=\"d\" (geom) sql=''" ) );
8531 QCOMPARE( skipSpy.count(), 0 );
8532 QCOMPARE( changedSpy.count(), 1 );
8533 v = panel.value();
8534 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8535 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().createOptions.value( QStringLiteral( "fileEncoding" ) ).toString(), QStringLiteral( "utf8" ) );
8536 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QStringLiteral( "ogr:dbname='/me/a.gpkg' table=\"d\" (geom) sql=''" ) );
8537 QVERIFY( !panel.outputIsSkipped() );
8538 panel.setValue( QStringLiteral( "ogr:dbname='/me/a.gpkg' table=\"d\" (geom) sql=''" ) );
8539 QCOMPARE( skipSpy.count(), 0 );
8540 QCOMPARE( changedSpy.count(), 1 );
8541
8542 panel.setValue( QStringLiteral( "postgis:dbname='oraclesux' host=10.1.1.221 port=5432 user='qgis' password='qgis' table=\"stufff\".\"output\" (the_geom) sql=" ) );
8543 v = panel.value();
8544 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8545 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().createOptions.value( QStringLiteral( "fileEncoding" ) ).toString(), QStringLiteral( "utf8" ) );
8546 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QStringLiteral( "postgis:dbname='oraclesux' host=10.1.1.221 port=5432 user='qgis' password='qgis' table=\"stufff\".\"output\" (the_geom) sql=" ) );
8547 QVERIFY( !panel.outputIsSkipped() );
8548 QCOMPARE( skipSpy.count(), 0 );
8549 QCOMPARE( changedSpy.count(), 2 );
8550 panel.setValue( QStringLiteral( "postgis:dbname='oraclesux' host=10.1.1.221 port=5432 user='qgis' password='qgis' table=\"stufff\".\"output\" (the_geom) sql=" ) );
8551 QCOMPARE( skipSpy.count(), 0 );
8552 QCOMPARE( changedSpy.count(), 2 );
8553
8554 panel.setValue( QStringLiteral( "/home/me/test.shp" ) );
8555 v = panel.value();
8556 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8557 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().createOptions.value( QStringLiteral( "fileEncoding" ) ).toString(), QStringLiteral( "utf8" ) );
8558 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QStringLiteral( "/home/me/test.shp" ) );
8559 QVERIFY( !panel.outputIsSkipped() );
8560 QCOMPARE( skipSpy.count(), 0 );
8561 QCOMPARE( changedSpy.count(), 3 );
8562 panel.setValue( QStringLiteral( "/home/me/test.shp" ) );
8563 QCOMPARE( skipSpy.count(), 0 );
8564 QCOMPARE( changedSpy.count(), 3 );
8565 panel.setValue( QStringLiteral( "/home/me/test2.shp" ) );
8566 QCOMPARE( skipSpy.count(), 0 );
8567 QCOMPARE( changedSpy.count(), 4 );
8568
8569 QgsSettings settings;
8570 settings.setValue( QStringLiteral( "/Processing/Configuration/OUTPUTS_FOLDER" ), TEST_DATA_DIR );
8571 panel.setValue( QStringLiteral( "test.shp" ) );
8572 v = panel.value();
8573 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8574 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().createOptions.value( QStringLiteral( "fileEncoding" ) ).toString(), QStringLiteral( "utf8" ) );
8575 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QString( TEST_DATA_DIR + QStringLiteral( "/test.shp" ) ) );
8576
8577 // optional, test skipping
8578 sink.setFlags( sink.flags() | QgsProcessingParameterDefinition::FlagOptional );
8579 sink.setCreateByDefault( true );
8580 QgsProcessingLayerOutputDestinationWidget panel2( &sink, false );
8581
8582 QSignalSpy skipSpy2( &panel2, &QgsProcessingLayerOutputDestinationWidget::skipOutputChanged );
8583 QSignalSpy changedSpy2( &panel2, &QgsProcessingLayerOutputDestinationWidget::destinationChanged );
8584
8585 v = panel2.value();
8586 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8587 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QgsProcessing::TEMPORARY_OUTPUT );
8588 QVERIFY( !panel2.outputIsSkipped() );
8589
8590 panel2.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8591 v = panel2.value();
8592 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8593 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().createOptions.value( QStringLiteral( "fileEncoding" ) ).toString(), QStringLiteral( "System" ) );
8594 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QgsProcessing::TEMPORARY_OUTPUT );
8595 QVERIFY( !panel2.outputIsSkipped() );
8596 QCOMPARE( skipSpy2.count(), 0 );
8597 QCOMPARE( changedSpy2.count(), 0 );
8598 panel2.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8599 QCOMPARE( skipSpy2.count(), 0 );
8600 QCOMPARE( changedSpy2.count(), 0 );
8601
8602 panel2.setValue( QVariant() );
8603 v = panel2.value();
8604 QVERIFY( !v.isValid() );
8605 QVERIFY( panel2.outputIsSkipped() );
8606 QCOMPARE( skipSpy2.count(), 1 );
8607 QCOMPARE( changedSpy2.count(), 1 );
8608 panel2.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8609 QCOMPARE( skipSpy2.count(), 2 );
8610 QCOMPARE( changedSpy2.count(), 2 );
8611
8612 sink.setCreateByDefault( false );
8613 QgsProcessingLayerOutputDestinationWidget panel3( &sink, false );
8614
8615 QSignalSpy skipSpy3( &panel3, &QgsProcessingLayerOutputDestinationWidget::skipOutputChanged );
8616 QSignalSpy changedSpy3( &panel3, &QgsProcessingLayerOutputDestinationWidget::destinationChanged );
8617
8618 v = panel3.value();
8619 QVERIFY( !v.isValid() );
8620 QVERIFY( panel3.outputIsSkipped() );
8621
8622 panel3.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8623 v = panel3.value();
8624 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8625 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().createOptions.value( QStringLiteral( "fileEncoding" ) ).toString(), QStringLiteral( "System" ) );
8626 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QgsProcessing::TEMPORARY_OUTPUT );
8627 QVERIFY( !panel3.outputIsSkipped() );
8628 QCOMPARE( skipSpy3.count(), 1 );
8629 QCOMPARE( changedSpy3.count(), 1 );
8630 panel3.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8631 QCOMPARE( skipSpy3.count(), 1 );
8632 QCOMPARE( changedSpy3.count(), 1 );
8633
8634 panel3.setValue( QVariant() );
8635 v = panel3.value();
8636 QVERIFY( !v.isValid() );
8637 QVERIFY( panel3.outputIsSkipped() );
8638 QCOMPARE( skipSpy3.count(), 2 );
8639 QCOMPARE( changedSpy3.count(), 2 );
8640 panel3.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8641 QCOMPARE( skipSpy3.count(), 3 );
8642 QCOMPARE( changedSpy3.count(), 3 );
8643
8644 // with remapping
8645 def = QgsProcessingOutputLayerDefinition( QStringLiteral( "test.shp" ) );
8646 QgsRemappingSinkDefinition remap;
8647 QMap< QString, QgsProperty > fieldMap;
8648 fieldMap.insert( QStringLiteral( "field1" ), QgsProperty::fromField( QStringLiteral( "source1" ) ) );
8649 fieldMap.insert( QStringLiteral( "field2" ), QgsProperty::fromExpression( QStringLiteral( "source || source2" ) ) );
8650 remap.setFieldMap( fieldMap );
8651 def.setRemappingDefinition( remap );
8652
8653 panel3.setValue( def );
8654 v = panel3.value();
8655 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8656 QVERIFY( v.value< QgsProcessingOutputLayerDefinition>().useRemapping() );
8657 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().remappingDefinition().fieldMap().size(), 2 );
8658 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().remappingDefinition().fieldMap().value( QStringLiteral( "field1" ) ), QgsProperty::fromField( QStringLiteral( "source1" ) ) );
8659 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().remappingDefinition().fieldMap().value( QStringLiteral( "field2" ) ), QgsProperty::fromExpression( QStringLiteral( "source || source2" ) ) );
8660
8661 panel3.setValue( QStringLiteral( "other.shp" ) );
8662 v = panel3.value();
8663 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8664 QVERIFY( !v.value< QgsProcessingOutputLayerDefinition>().useRemapping() );
8665 }
8666
testOutputDefinitionWidgetVectorOut()8667 void TestProcessingGui::testOutputDefinitionWidgetVectorOut()
8668 {
8669 QgsProcessingParameterVectorDestination vector( QStringLiteral( "test" ) );
8670 QgsProcessingLayerOutputDestinationWidget panel( &vector, false );
8671
8672 QSignalSpy skipSpy( &panel, &QgsProcessingLayerOutputDestinationWidget::skipOutputChanged );
8673 QSignalSpy changedSpy( &panel, &QgsProcessingLayerOutputDestinationWidget::destinationChanged );
8674
8675 QVariant v = panel.value();
8676 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8677 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QgsProcessing::TEMPORARY_OUTPUT );
8678 QVERIFY( !panel.outputIsSkipped() );
8679
8680 panel.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8681 v = panel.value();
8682 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8683 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().createOptions.value( QStringLiteral( "fileEncoding" ) ).toString(), QStringLiteral( "System" ) );
8684 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QgsProcessing::TEMPORARY_OUTPUT );
8685 QVERIFY( !panel.outputIsSkipped() );
8686 QCOMPARE( skipSpy.count(), 0 );
8687 QCOMPARE( changedSpy.count(), 0 );
8688 panel.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8689 QCOMPARE( skipSpy.count(), 0 );
8690 QCOMPARE( changedSpy.count(), 0 );
8691
8692 panel.setValue( QStringLiteral( "memory:" ) );
8693 v = panel.value();
8694 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8695 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().createOptions.value( QStringLiteral( "fileEncoding" ) ).toString(), QStringLiteral( "System" ) );
8696 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QgsProcessing::TEMPORARY_OUTPUT );
8697 QVERIFY( !panel.outputIsSkipped() );
8698 QCOMPARE( skipSpy.count(), 0 );
8699 QCOMPARE( changedSpy.count(), 0 );
8700 panel.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8701 QCOMPARE( skipSpy.count(), 0 );
8702 QCOMPARE( changedSpy.count(), 0 );
8703
8704
8705 panel.setValue( QStringLiteral( "ogr:dbname='/me/a.gpkg' table=\"d\" (geom) sql=''" ) );
8706 QCOMPARE( skipSpy.count(), 0 );
8707 QCOMPARE( changedSpy.count(), 1 );
8708 v = panel.value();
8709 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8710 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().createOptions.value( QStringLiteral( "fileEncoding" ) ).toString(), QStringLiteral( "System" ) );
8711 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QStringLiteral( "ogr:dbname='/me/a.gpkg' table=\"d\" (geom) sql=''" ) );
8712 QVERIFY( !panel.outputIsSkipped() );
8713 panel.setValue( QStringLiteral( "ogr:dbname='/me/a.gpkg' table=\"d\" (geom) sql=''" ) );
8714 QCOMPARE( skipSpy.count(), 0 );
8715 QCOMPARE( changedSpy.count(), 1 );
8716
8717 panel.setValue( QStringLiteral( "postgis:dbname='oraclesux' host=10.1.1.221 port=5432 user='qgis' password='qgis' table=\"stufff\".\"output\" (the_geom) sql=" ) );
8718 v = panel.value();
8719 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8720 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().createOptions.value( QStringLiteral( "fileEncoding" ) ).toString(), QStringLiteral( "System" ) );
8721 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QStringLiteral( "postgis:dbname='oraclesux' host=10.1.1.221 port=5432 user='qgis' password='qgis' table=\"stufff\".\"output\" (the_geom) sql=" ) );
8722 QVERIFY( !panel.outputIsSkipped() );
8723 QCOMPARE( skipSpy.count(), 0 );
8724 QCOMPARE( changedSpy.count(), 2 );
8725 panel.setValue( QStringLiteral( "postgis:dbname='oraclesux' host=10.1.1.221 port=5432 user='qgis' password='qgis' table=\"stufff\".\"output\" (the_geom) sql=" ) );
8726 QCOMPARE( skipSpy.count(), 0 );
8727 QCOMPARE( changedSpy.count(), 2 );
8728
8729 panel.setValue( QStringLiteral( "/home/me/test.shp" ) );
8730 v = panel.value();
8731 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8732 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().createOptions.value( QStringLiteral( "fileEncoding" ) ).toString(), QStringLiteral( "System" ) );
8733 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QStringLiteral( "/home/me/test.shp" ) );
8734 QVERIFY( !panel.outputIsSkipped() );
8735 QCOMPARE( skipSpy.count(), 0 );
8736 QCOMPARE( changedSpy.count(), 3 );
8737 panel.setValue( QStringLiteral( "/home/me/test.shp" ) );
8738 QCOMPARE( skipSpy.count(), 0 );
8739 QCOMPARE( changedSpy.count(), 3 );
8740 panel.setValue( QStringLiteral( "/home/me/test2.shp" ) );
8741 QCOMPARE( skipSpy.count(), 0 );
8742 QCOMPARE( changedSpy.count(), 4 );
8743
8744 QgsSettings settings;
8745 settings.setValue( QStringLiteral( "/Processing/Configuration/OUTPUTS_FOLDER" ), TEST_DATA_DIR );
8746 panel.setValue( QStringLiteral( "test.shp" ) );
8747 v = panel.value();
8748 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8749 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().createOptions.value( QStringLiteral( "fileEncoding" ) ).toString(), QStringLiteral( "System" ) );
8750 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QString( TEST_DATA_DIR + QStringLiteral( "/test.shp" ) ) );
8751
8752 // optional, test skipping
8753 vector.setFlags( vector.flags() | QgsProcessingParameterDefinition::FlagOptional );
8754 vector.setCreateByDefault( true );
8755 QgsProcessingLayerOutputDestinationWidget panel2( &vector, false );
8756
8757 QSignalSpy skipSpy2( &panel2, &QgsProcessingLayerOutputDestinationWidget::skipOutputChanged );
8758 QSignalSpy changedSpy2( &panel2, &QgsProcessingLayerOutputDestinationWidget::destinationChanged );
8759
8760 v = panel2.value();
8761 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8762 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QgsProcessing::TEMPORARY_OUTPUT );
8763 QVERIFY( !panel2.outputIsSkipped() );
8764
8765 panel2.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8766 v = panel2.value();
8767 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8768 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().createOptions.value( QStringLiteral( "fileEncoding" ) ).toString(), QStringLiteral( "System" ) );
8769 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QgsProcessing::TEMPORARY_OUTPUT );
8770 QVERIFY( !panel2.outputIsSkipped() );
8771 QCOMPARE( skipSpy2.count(), 0 );
8772 QCOMPARE( changedSpy2.count(), 0 );
8773 panel2.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8774 QCOMPARE( skipSpy2.count(), 0 );
8775 QCOMPARE( changedSpy2.count(), 0 );
8776
8777 panel2.setValue( QVariant() );
8778 v = panel2.value();
8779 QVERIFY( !v.isValid() );
8780 QVERIFY( panel2.outputIsSkipped() );
8781 QCOMPARE( skipSpy2.count(), 1 );
8782 QCOMPARE( changedSpy2.count(), 1 );
8783 panel2.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8784 QCOMPARE( skipSpy2.count(), 2 );
8785 QCOMPARE( changedSpy2.count(), 2 );
8786
8787 vector.setCreateByDefault( false );
8788 QgsProcessingLayerOutputDestinationWidget panel3( &vector, false );
8789
8790 QSignalSpy skipSpy3( &panel3, &QgsProcessingLayerOutputDestinationWidget::skipOutputChanged );
8791 QSignalSpy changedSpy3( &panel3, &QgsProcessingLayerOutputDestinationWidget::destinationChanged );
8792
8793 v = panel3.value();
8794 QVERIFY( !v.isValid() );
8795 QVERIFY( panel3.outputIsSkipped() );
8796
8797 panel3.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8798 v = panel3.value();
8799 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8800 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().createOptions.value( QStringLiteral( "fileEncoding" ) ).toString(), QStringLiteral( "System" ) );
8801 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QgsProcessing::TEMPORARY_OUTPUT );
8802 QVERIFY( !panel3.outputIsSkipped() );
8803 QCOMPARE( skipSpy3.count(), 1 );
8804 QCOMPARE( changedSpy3.count(), 1 );
8805 panel3.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8806 QCOMPARE( skipSpy3.count(), 1 );
8807 QCOMPARE( changedSpy3.count(), 1 );
8808
8809 panel3.setValue( QVariant() );
8810 v = panel3.value();
8811 QVERIFY( !v.isValid() );
8812 QVERIFY( panel3.outputIsSkipped() );
8813 QCOMPARE( skipSpy3.count(), 2 );
8814 QCOMPARE( changedSpy3.count(), 2 );
8815 panel3.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8816 QCOMPARE( skipSpy3.count(), 3 );
8817 QCOMPARE( changedSpy3.count(), 3 );
8818 }
8819
testOutputDefinitionWidgetRasterOut()8820 void TestProcessingGui::testOutputDefinitionWidgetRasterOut()
8821 {
8822 QgsProcessingParameterRasterDestination raster( QStringLiteral( "test" ) );
8823 QgsProcessingLayerOutputDestinationWidget panel( &raster, false );
8824
8825 QSignalSpy skipSpy( &panel, &QgsProcessingLayerOutputDestinationWidget::skipOutputChanged );
8826 QSignalSpy changedSpy( &panel, &QgsProcessingLayerOutputDestinationWidget::destinationChanged );
8827
8828 QVariant v = panel.value();
8829 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8830 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QgsProcessing::TEMPORARY_OUTPUT );
8831 QVERIFY( !panel.outputIsSkipped() );
8832
8833 panel.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8834 v = panel.value();
8835 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8836 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().createOptions.value( QStringLiteral( "fileEncoding" ) ).toString(), QStringLiteral( "System" ) );
8837 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QgsProcessing::TEMPORARY_OUTPUT );
8838 QVERIFY( !panel.outputIsSkipped() );
8839 QCOMPARE( skipSpy.count(), 0 );
8840 QCOMPARE( changedSpy.count(), 0 );
8841 panel.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8842 QCOMPARE( skipSpy.count(), 0 );
8843 QCOMPARE( changedSpy.count(), 0 );
8844
8845 panel.setValue( QStringLiteral( "/home/me/test.tif" ) );
8846 QCOMPARE( skipSpy.count(), 0 );
8847 QCOMPARE( changedSpy.count(), 1 );
8848 v = panel.value();
8849 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8850 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().createOptions.value( QStringLiteral( "fileEncoding" ) ).toString(), QStringLiteral( "System" ) );
8851 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QStringLiteral( "/home/me/test.tif" ) );
8852 QVERIFY( !panel.outputIsSkipped() );
8853 panel.setValue( QStringLiteral( "/home/me/test.tif" ) );
8854 QCOMPARE( skipSpy.count(), 0 );
8855 QCOMPARE( changedSpy.count(), 1 );
8856
8857 QgsSettings settings;
8858 settings.setValue( QStringLiteral( "/Processing/Configuration/OUTPUTS_FOLDER" ), TEST_DATA_DIR );
8859 panel.setValue( QStringLiteral( "test.tif" ) );
8860 v = panel.value();
8861 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8862 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().createOptions.value( QStringLiteral( "fileEncoding" ) ).toString(), QStringLiteral( "System" ) );
8863 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QString( TEST_DATA_DIR + QStringLiteral( "/test.tif" ) ) );
8864
8865 // optional, test skipping
8866 raster.setFlags( raster.flags() | QgsProcessingParameterDefinition::FlagOptional );
8867 raster.setCreateByDefault( true );
8868 QgsProcessingLayerOutputDestinationWidget panel2( &raster, false );
8869
8870 QSignalSpy skipSpy2( &panel2, &QgsProcessingLayerOutputDestinationWidget::skipOutputChanged );
8871 QSignalSpy changedSpy2( &panel2, &QgsProcessingLayerOutputDestinationWidget::destinationChanged );
8872
8873 v = panel2.value();
8874 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8875 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QgsProcessing::TEMPORARY_OUTPUT );
8876 QVERIFY( !panel2.outputIsSkipped() );
8877
8878 panel2.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8879 v = panel2.value();
8880 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8881 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().createOptions.value( QStringLiteral( "fileEncoding" ) ).toString(), QStringLiteral( "System" ) );
8882 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QgsProcessing::TEMPORARY_OUTPUT );
8883 QVERIFY( !panel2.outputIsSkipped() );
8884 QCOMPARE( skipSpy2.count(), 0 );
8885 QCOMPARE( changedSpy2.count(), 0 );
8886 panel2.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8887 QCOMPARE( skipSpy2.count(), 0 );
8888 QCOMPARE( changedSpy2.count(), 0 );
8889
8890 panel2.setValue( QVariant() );
8891 v = panel2.value();
8892 QVERIFY( !v.isValid() );
8893 QVERIFY( panel2.outputIsSkipped() );
8894 QCOMPARE( skipSpy2.count(), 1 );
8895 QCOMPARE( changedSpy2.count(), 1 );
8896 panel2.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8897 QCOMPARE( skipSpy2.count(), 2 );
8898 QCOMPARE( changedSpy2.count(), 2 );
8899
8900 raster.setCreateByDefault( false );
8901 QgsProcessingLayerOutputDestinationWidget panel3( &raster, false );
8902
8903 QSignalSpy skipSpy3( &panel3, &QgsProcessingLayerOutputDestinationWidget::skipOutputChanged );
8904 QSignalSpy changedSpy3( &panel3, &QgsProcessingLayerOutputDestinationWidget::destinationChanged );
8905
8906 v = panel3.value();
8907 QVERIFY( !v.isValid() );
8908 QVERIFY( panel3.outputIsSkipped() );
8909
8910 panel3.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8911 v = panel3.value();
8912 QVERIFY( v.canConvert< QgsProcessingOutputLayerDefinition>() );
8913 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().createOptions.value( QStringLiteral( "fileEncoding" ) ).toString(), QStringLiteral( "System" ) );
8914 QCOMPARE( v.value< QgsProcessingOutputLayerDefinition>().sink.staticValue().toString(), QgsProcessing::TEMPORARY_OUTPUT );
8915 QVERIFY( !panel3.outputIsSkipped() );
8916 QCOMPARE( skipSpy3.count(), 1 );
8917 QCOMPARE( changedSpy3.count(), 1 );
8918 panel3.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8919 QCOMPARE( skipSpy3.count(), 1 );
8920 QCOMPARE( changedSpy3.count(), 1 );
8921
8922 panel3.setValue( QVariant() );
8923 v = panel3.value();
8924 QVERIFY( !v.isValid() );
8925 QVERIFY( panel3.outputIsSkipped() );
8926 QCOMPARE( skipSpy3.count(), 2 );
8927 QCOMPARE( changedSpy3.count(), 2 );
8928 panel3.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8929 QCOMPARE( skipSpy3.count(), 3 );
8930 QCOMPARE( changedSpy3.count(), 3 );
8931 }
8932
testOutputDefinitionWidgetFolder()8933 void TestProcessingGui::testOutputDefinitionWidgetFolder()
8934 {
8935 QgsProcessingParameterFolderDestination folder( QStringLiteral( "test" ) );
8936 QgsProcessingLayerOutputDestinationWidget panel( &folder, false );
8937
8938 QSignalSpy skipSpy( &panel, &QgsProcessingLayerOutputDestinationWidget::skipOutputChanged );
8939 QSignalSpy changedSpy( &panel, &QgsProcessingLayerOutputDestinationWidget::destinationChanged );
8940
8941 QVariant v = panel.value();
8942 QCOMPARE( v.toString(), QgsProcessing::TEMPORARY_OUTPUT );
8943 QVERIFY( !panel.outputIsSkipped() );
8944
8945 panel.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8946 v = panel.value();
8947 QCOMPARE( v.toString(), QgsProcessing::TEMPORARY_OUTPUT );
8948 QVERIFY( !panel.outputIsSkipped() );
8949 QCOMPARE( skipSpy.count(), 0 );
8950 QCOMPARE( changedSpy.count(), 0 );
8951 panel.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8952 QCOMPARE( skipSpy.count(), 0 );
8953 QCOMPARE( changedSpy.count(), 0 );
8954
8955 panel.setValue( QStringLiteral( "/home/me/" ) );
8956 QCOMPARE( skipSpy.count(), 0 );
8957 QCOMPARE( changedSpy.count(), 1 );
8958 v = panel.value();
8959 QCOMPARE( v.toString(), QStringLiteral( "/home/me/" ) );
8960 QVERIFY( !panel.outputIsSkipped() );
8961 panel.setValue( QStringLiteral( "/home/me/" ) );
8962 QCOMPARE( skipSpy.count(), 0 );
8963 QCOMPARE( changedSpy.count(), 1 );
8964
8965 QgsSettings settings;
8966 settings.setValue( QStringLiteral( "/Processing/Configuration/OUTPUTS_FOLDER" ), TEST_DATA_DIR );
8967 panel.setValue( QStringLiteral( "mystuff" ) );
8968 v = panel.value();
8969 QCOMPARE( v.toString(), QString( TEST_DATA_DIR + QStringLiteral( "/mystuff" ) ) );
8970
8971 // optional, test skipping
8972 folder.setFlags( folder.flags() | QgsProcessingParameterDefinition::FlagOptional );
8973 folder.setCreateByDefault( true );
8974 QgsProcessingLayerOutputDestinationWidget panel2( &folder, false );
8975
8976 QSignalSpy skipSpy2( &panel2, &QgsProcessingLayerOutputDestinationWidget::skipOutputChanged );
8977 QSignalSpy changedSpy2( &panel2, &QgsProcessingLayerOutputDestinationWidget::destinationChanged );
8978
8979 v = panel2.value();
8980 QCOMPARE( v.toString(), QgsProcessing::TEMPORARY_OUTPUT );
8981 QVERIFY( !panel2.outputIsSkipped() );
8982
8983 panel2.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8984 v = panel2.value();
8985 QCOMPARE( v.toString(), QgsProcessing::TEMPORARY_OUTPUT );
8986 QVERIFY( !panel2.outputIsSkipped() );
8987 QCOMPARE( skipSpy2.count(), 0 );
8988 QCOMPARE( changedSpy2.count(), 0 );
8989 panel2.setValue( QgsProcessing::TEMPORARY_OUTPUT );
8990 QCOMPARE( skipSpy2.count(), 0 );
8991 QCOMPARE( changedSpy2.count(), 0 );
8992
8993 panel2.setValue( QVariant() );
8994 v = panel2.value();
8995 QVERIFY( !v.isValid() );
8996 QVERIFY( panel2.outputIsSkipped() );
8997 QCOMPARE( skipSpy2.count(), 1 );
8998 QCOMPARE( changedSpy2.count(), 1 );
8999 panel2.setValue( QgsProcessing::TEMPORARY_OUTPUT );
9000 QCOMPARE( skipSpy2.count(), 2 );
9001 QCOMPARE( changedSpy2.count(), 2 );
9002
9003 folder.setCreateByDefault( false );
9004 QgsProcessingLayerOutputDestinationWidget panel3( &folder, false );
9005
9006 QSignalSpy skipSpy3( &panel3, &QgsProcessingLayerOutputDestinationWidget::skipOutputChanged );
9007 QSignalSpy changedSpy3( &panel3, &QgsProcessingLayerOutputDestinationWidget::destinationChanged );
9008
9009 v = panel3.value();
9010 QVERIFY( !v.isValid() );
9011 QVERIFY( panel3.outputIsSkipped() );
9012
9013 panel3.setValue( QgsProcessing::TEMPORARY_OUTPUT );
9014 v = panel3.value();
9015 QCOMPARE( v.toString(), QgsProcessing::TEMPORARY_OUTPUT );
9016 QVERIFY( !panel3.outputIsSkipped() );
9017 QCOMPARE( skipSpy3.count(), 1 );
9018 QCOMPARE( changedSpy3.count(), 1 );
9019 panel3.setValue( QgsProcessing::TEMPORARY_OUTPUT );
9020 QCOMPARE( skipSpy3.count(), 1 );
9021 QCOMPARE( changedSpy3.count(), 1 );
9022
9023 panel3.setValue( QVariant() );
9024 v = panel3.value();
9025 QVERIFY( !v.isValid() );
9026 QVERIFY( panel3.outputIsSkipped() );
9027 QCOMPARE( skipSpy3.count(), 2 );
9028 QCOMPARE( changedSpy3.count(), 2 );
9029 panel3.setValue( QgsProcessing::TEMPORARY_OUTPUT );
9030 QCOMPARE( skipSpy3.count(), 3 );
9031 QCOMPARE( changedSpy3.count(), 3 );
9032 }
9033
testOutputDefinitionWidgetFileOut()9034 void TestProcessingGui::testOutputDefinitionWidgetFileOut()
9035 {
9036 QgsProcessingParameterFileDestination file( QStringLiteral( "test" ) );
9037 QgsProcessingLayerOutputDestinationWidget panel( &file, false );
9038
9039 QSignalSpy skipSpy( &panel, &QgsProcessingLayerOutputDestinationWidget::skipOutputChanged );
9040 QSignalSpy changedSpy( &panel, &QgsProcessingLayerOutputDestinationWidget::destinationChanged );
9041
9042 QVariant v = panel.value();
9043 QCOMPARE( v.toString(), QgsProcessing::TEMPORARY_OUTPUT );
9044 QVERIFY( !panel.outputIsSkipped() );
9045
9046 panel.setValue( QgsProcessing::TEMPORARY_OUTPUT );
9047 v = panel.value();
9048 QCOMPARE( v.toString(), QgsProcessing::TEMPORARY_OUTPUT );
9049 QVERIFY( !panel.outputIsSkipped() );
9050 QCOMPARE( skipSpy.count(), 0 );
9051 QCOMPARE( changedSpy.count(), 0 );
9052 panel.setValue( QgsProcessing::TEMPORARY_OUTPUT );
9053 QCOMPARE( skipSpy.count(), 0 );
9054 QCOMPARE( changedSpy.count(), 0 );
9055
9056 panel.setValue( QStringLiteral( "/home/me/test.tif" ) );
9057 QCOMPARE( skipSpy.count(), 0 );
9058 QCOMPARE( changedSpy.count(), 1 );
9059 v = panel.value();
9060 QCOMPARE( v.toString(), QStringLiteral( "/home/me/test.tif" ) );
9061 QVERIFY( !panel.outputIsSkipped() );
9062 panel.setValue( QStringLiteral( "/home/me/test.tif" ) );
9063 QCOMPARE( skipSpy.count(), 0 );
9064 QCOMPARE( changedSpy.count(), 1 );
9065
9066 QgsSettings settings;
9067 settings.setValue( QStringLiteral( "/Processing/Configuration/OUTPUTS_FOLDER" ), TEST_DATA_DIR );
9068 panel.setValue( QStringLiteral( "test.tif" ) );
9069 v = panel.value();
9070 QCOMPARE( v.toString(), QString( TEST_DATA_DIR + QStringLiteral( "/test.tif" ) ) );
9071
9072 // optional, test skipping
9073 file.setFlags( file.flags() | QgsProcessingParameterDefinition::FlagOptional );
9074 file.setCreateByDefault( true );
9075 QgsProcessingLayerOutputDestinationWidget panel2( &file, false );
9076
9077 QSignalSpy skipSpy2( &panel2, &QgsProcessingLayerOutputDestinationWidget::skipOutputChanged );
9078 QSignalSpy changedSpy2( &panel2, &QgsProcessingLayerOutputDestinationWidget::destinationChanged );
9079
9080 v = panel2.value();
9081 QCOMPARE( v.toString(), QgsProcessing::TEMPORARY_OUTPUT );
9082 QVERIFY( !panel2.outputIsSkipped() );
9083
9084 panel2.setValue( QgsProcessing::TEMPORARY_OUTPUT );
9085 v = panel2.value();
9086 QCOMPARE( v.toString(), QgsProcessing::TEMPORARY_OUTPUT );
9087 QVERIFY( !panel2.outputIsSkipped() );
9088 QCOMPARE( skipSpy2.count(), 0 );
9089 QCOMPARE( changedSpy2.count(), 0 );
9090 panel2.setValue( QgsProcessing::TEMPORARY_OUTPUT );
9091 QCOMPARE( skipSpy2.count(), 0 );
9092 QCOMPARE( changedSpy2.count(), 0 );
9093
9094 panel2.setValue( QVariant() );
9095 v = panel2.value();
9096 QVERIFY( !v.isValid() );
9097 QVERIFY( panel2.outputIsSkipped() );
9098 QCOMPARE( skipSpy2.count(), 1 );
9099 QCOMPARE( changedSpy2.count(), 1 );
9100 panel2.setValue( QgsProcessing::TEMPORARY_OUTPUT );
9101 QCOMPARE( skipSpy2.count(), 2 );
9102 QCOMPARE( changedSpy2.count(), 2 );
9103
9104 file.setCreateByDefault( false );
9105 QgsProcessingLayerOutputDestinationWidget panel3( &file, false );
9106
9107 QSignalSpy skipSpy3( &panel3, &QgsProcessingLayerOutputDestinationWidget::skipOutputChanged );
9108 QSignalSpy changedSpy3( &panel3, &QgsProcessingLayerOutputDestinationWidget::destinationChanged );
9109
9110 v = panel3.value();
9111 QVERIFY( !v.isValid() );
9112 QVERIFY( panel3.outputIsSkipped() );
9113
9114 panel3.setValue( QgsProcessing::TEMPORARY_OUTPUT );
9115 v = panel3.value();
9116 QCOMPARE( v.toString(), QgsProcessing::TEMPORARY_OUTPUT );
9117 QVERIFY( !panel3.outputIsSkipped() );
9118 QCOMPARE( skipSpy3.count(), 1 );
9119 QCOMPARE( changedSpy3.count(), 1 );
9120 panel3.setValue( QgsProcessing::TEMPORARY_OUTPUT );
9121 QCOMPARE( skipSpy3.count(), 1 );
9122 QCOMPARE( changedSpy3.count(), 1 );
9123
9124 panel3.setValue( QVariant() );
9125 v = panel3.value();
9126 QVERIFY( !v.isValid() );
9127 QVERIFY( panel3.outputIsSkipped() );
9128 QCOMPARE( skipSpy3.count(), 2 );
9129 QCOMPARE( changedSpy3.count(), 2 );
9130 panel3.setValue( QgsProcessing::TEMPORARY_OUTPUT );
9131 QCOMPARE( skipSpy3.count(), 3 );
9132 QCOMPARE( changedSpy3.count(), 3 );
9133 }
9134
testFeatureSourceOptionsWidget()9135 void TestProcessingGui::testFeatureSourceOptionsWidget()
9136 {
9137 QgsProcessingFeatureSourceOptionsWidget w;
9138 QSignalSpy spy( &w, &QgsProcessingFeatureSourceOptionsWidget::widgetChanged );
9139
9140 w.setFeatureLimit( 66 );
9141 QCOMPARE( spy.count(), 1 );
9142 QCOMPARE( w.featureLimit(), 66 );
9143 w.setFeatureLimit( 66 );
9144 QCOMPARE( spy.count(), 1 );
9145 w.setFeatureLimit( -1 );
9146 QCOMPARE( spy.count(), 2 );
9147 QCOMPARE( w.featureLimit(), -1 );
9148
9149 w.setGeometryCheckMethod( false, QgsFeatureRequest::GeometrySkipInvalid );
9150 QCOMPARE( spy.count(), 2 );
9151 QVERIFY( !w.isOverridingInvalidGeometryCheck() );
9152 w.setGeometryCheckMethod( true, QgsFeatureRequest::GeometrySkipInvalid );
9153 QCOMPARE( spy.count(), 3 );
9154 QVERIFY( w.isOverridingInvalidGeometryCheck() );
9155 QCOMPARE( w.geometryCheckMethod(), QgsFeatureRequest::GeometrySkipInvalid );
9156 w.setGeometryCheckMethod( true, QgsFeatureRequest::GeometrySkipInvalid );
9157 QCOMPARE( spy.count(), 3 );
9158 w.setGeometryCheckMethod( true, QgsFeatureRequest::GeometryAbortOnInvalid );
9159 QCOMPARE( spy.count(), 4 );
9160 QVERIFY( w.isOverridingInvalidGeometryCheck() );
9161 QCOMPARE( w.geometryCheckMethod(), QgsFeatureRequest::GeometryAbortOnInvalid );
9162 w.setGeometryCheckMethod( false, QgsFeatureRequest::GeometryAbortOnInvalid );
9163 QVERIFY( !w.isOverridingInvalidGeometryCheck() );
9164 QCOMPARE( spy.count(), 5 );
9165 }
9166
testVectorOutWrapper()9167 void TestProcessingGui::testVectorOutWrapper()
9168 {
9169 auto testWrapper = [ = ]( QgsProcessingGui::WidgetType type )
9170 {
9171 // non optional
9172 QgsProcessingParameterVectorDestination param( QStringLiteral( "vector" ), QStringLiteral( "vector" ) );
9173
9174 QgsProcessingVectorDestinationWidgetWrapper wrapper( ¶m, type );
9175
9176 QgsProcessingContext context;
9177 QWidget *w = wrapper.createWrappedWidget( context );
9178
9179 QSignalSpy spy( &wrapper, &QgsProcessingVectorDestinationWidgetWrapper::widgetValueHasChanged );
9180 wrapper.setWidgetValue( QStringLiteral( "/bb.shp" ), context );
9181
9182 switch ( type )
9183 {
9184 case QgsProcessingGui::Standard:
9185 case QgsProcessingGui::Batch:
9186 case QgsProcessingGui::Modeler:
9187 QCOMPARE( spy.count(), 1 );
9188 QCOMPARE( wrapper.widgetValue().value< QgsProcessingOutputLayerDefinition >().sink.staticValue().toString(), QStringLiteral( "/bb.shp" ) );
9189 QCOMPARE( static_cast< QgsProcessingLayerOutputDestinationWidget * >( wrapper.wrappedWidget() )->value().value< QgsProcessingOutputLayerDefinition >().sink.staticValue().toString(), QStringLiteral( "/bb.shp" ) );
9190 wrapper.setWidgetValue( QStringLiteral( "/aa.shp" ), context );
9191 QCOMPARE( spy.count(), 2 );
9192 QCOMPARE( wrapper.widgetValue().value< QgsProcessingOutputLayerDefinition >().sink.staticValue().toString(), QStringLiteral( "/aa.shp" ) );
9193 QCOMPARE( static_cast< QgsProcessingLayerOutputDestinationWidget * >( wrapper.wrappedWidget() )->value().value< QgsProcessingOutputLayerDefinition >().sink.staticValue().toString(), QStringLiteral( "/aa.shp" ) );
9194 break;
9195 }
9196
9197 // check signal
9198 static_cast< QgsProcessingLayerOutputDestinationWidget * >( wrapper.wrappedWidget() )->setValue( QStringLiteral( "/cc.shp" ) );
9199 QCOMPARE( spy.count(), 3 );
9200 QCOMPARE( wrapper.widgetValue().value< QgsProcessingOutputLayerDefinition >().sink.staticValue().toString(), QStringLiteral( "/cc.shp" ) );
9201 delete w;
9202
9203 // optional
9204 QgsProcessingParameterVectorDestination param2( QStringLiteral( "vector" ), QStringLiteral( "vector" ), QgsProcessing::TypeVector, QVariant(), true );
9205 QgsProcessingVectorDestinationWidgetWrapper wrapper3( ¶m2, type );
9206 w = wrapper3.createWrappedWidget( context );
9207
9208 QSignalSpy spy3( &wrapper3, &QgsProcessingVectorDestinationWidgetWrapper::widgetValueHasChanged );
9209 wrapper3.setWidgetValue( QStringLiteral( "/bb.shp" ), context );
9210 QCOMPARE( spy3.count(), 1 );
9211 QCOMPARE( wrapper3.widgetValue().value< QgsProcessingOutputLayerDefinition >().sink.staticValue().toString(), QStringLiteral( "/bb.shp" ) );
9212 QCOMPARE( static_cast< QgsProcessingLayerOutputDestinationWidget * >( wrapper3.wrappedWidget() )->value().value< QgsProcessingOutputLayerDefinition >().sink.staticValue().toString(), QStringLiteral( "/bb.shp" ) );
9213 wrapper3.setWidgetValue( QVariant(), context );
9214 QCOMPARE( spy3.count(), 2 );
9215 QVERIFY( !wrapper3.widgetValue().isValid() );
9216 delete w;
9217
9218 QLabel *l = wrapper.createWrappedLabel();
9219 if ( wrapper.type() != QgsProcessingGui::Batch )
9220 {
9221 QVERIFY( l );
9222 QCOMPARE( l->text(), QStringLiteral( "vector" ) );
9223 QCOMPARE( l->toolTip(), param.toolTip() );
9224 delete l;
9225 }
9226 else
9227 {
9228 QVERIFY( !l );
9229 }
9230 };
9231
9232 // standard wrapper
9233 testWrapper( QgsProcessingGui::Standard );
9234
9235 // batch wrapper
9236 // testWrapper( QgsProcessingGui::Batch );
9237
9238 // modeler wrapper
9239 testWrapper( QgsProcessingGui::Modeler );
9240 }
9241
testSinkWrapper()9242 void TestProcessingGui::testSinkWrapper()
9243 {
9244 auto testWrapper = [ = ]( QgsProcessingGui::WidgetType type )
9245 {
9246 // non optional
9247 QgsProcessingParameterFeatureSink param( QStringLiteral( "sink" ), QStringLiteral( "sink" ) );
9248
9249 QgsProcessingFeatureSinkWidgetWrapper wrapper( ¶m, type );
9250
9251 QgsProcessingContext context;
9252 QWidget *w = wrapper.createWrappedWidget( context );
9253
9254 QSignalSpy spy( &wrapper, &QgsProcessingFeatureSinkWidgetWrapper::widgetValueHasChanged );
9255 wrapper.setWidgetValue( QStringLiteral( "/bb.shp" ), context );
9256
9257 switch ( type )
9258 {
9259 case QgsProcessingGui::Standard:
9260 case QgsProcessingGui::Batch:
9261 case QgsProcessingGui::Modeler:
9262 QCOMPARE( spy.count(), 1 );
9263 QCOMPARE( wrapper.widgetValue().value< QgsProcessingOutputLayerDefinition >().sink.staticValue().toString(), QStringLiteral( "/bb.shp" ) );
9264 QCOMPARE( static_cast< QgsProcessingLayerOutputDestinationWidget * >( wrapper.wrappedWidget() )->value().value< QgsProcessingOutputLayerDefinition >().sink.staticValue().toString(), QStringLiteral( "/bb.shp" ) );
9265 wrapper.setWidgetValue( QStringLiteral( "/aa.shp" ), context );
9266 QCOMPARE( spy.count(), 2 );
9267 QCOMPARE( wrapper.widgetValue().value< QgsProcessingOutputLayerDefinition >().sink.staticValue().toString(), QStringLiteral( "/aa.shp" ) );
9268 QCOMPARE( static_cast< QgsProcessingLayerOutputDestinationWidget * >( wrapper.wrappedWidget() )->value().value< QgsProcessingOutputLayerDefinition >().sink.staticValue().toString(), QStringLiteral( "/aa.shp" ) );
9269 break;
9270 }
9271
9272 // check signal
9273 static_cast< QgsProcessingLayerOutputDestinationWidget * >( wrapper.wrappedWidget() )->setValue( QStringLiteral( "/cc.shp" ) );
9274 QCOMPARE( spy.count(), 3 );
9275 QCOMPARE( wrapper.widgetValue().value< QgsProcessingOutputLayerDefinition >().sink.staticValue().toString(), QStringLiteral( "/cc.shp" ) );
9276 delete w;
9277
9278 // optional
9279 QgsProcessingParameterFeatureSink param2( QStringLiteral( "sink" ), QStringLiteral( "sink" ), QgsProcessing::TypeVector, QVariant(), true );
9280 QgsProcessingFeatureSinkWidgetWrapper wrapper3( ¶m2, type );
9281 w = wrapper3.createWrappedWidget( context );
9282
9283 QSignalSpy spy3( &wrapper3, &QgsProcessingFeatureSinkWidgetWrapper::widgetValueHasChanged );
9284 wrapper3.setWidgetValue( QStringLiteral( "/bb.shp" ), context );
9285 QCOMPARE( spy3.count(), 1 );
9286 QCOMPARE( wrapper3.widgetValue().value< QgsProcessingOutputLayerDefinition >().sink.staticValue().toString(), QStringLiteral( "/bb.shp" ) );
9287 QCOMPARE( static_cast< QgsProcessingLayerOutputDestinationWidget * >( wrapper3.wrappedWidget() )->value().value< QgsProcessingOutputLayerDefinition >().sink.staticValue().toString(), QStringLiteral( "/bb.shp" ) );
9288 wrapper3.setWidgetValue( QVariant(), context );
9289 QCOMPARE( spy3.count(), 2 );
9290 QVERIFY( !wrapper3.widgetValue().isValid() );
9291 delete w;
9292
9293 QLabel *l = wrapper.createWrappedLabel();
9294 if ( wrapper.type() != QgsProcessingGui::Batch )
9295 {
9296 QVERIFY( l );
9297 QCOMPARE( l->text(), QStringLiteral( "sink" ) );
9298 QCOMPARE( l->toolTip(), param.toolTip() );
9299 delete l;
9300 }
9301 else
9302 {
9303 QVERIFY( !l );
9304 }
9305 };
9306
9307 // standard wrapper
9308 testWrapper( QgsProcessingGui::Standard );
9309
9310 // batch wrapper
9311 // testWrapper( QgsProcessingGui::Batch );
9312
9313 // modeler wrapper
9314 testWrapper( QgsProcessingGui::Modeler );
9315 }
9316
testRasterOutWrapper()9317 void TestProcessingGui::testRasterOutWrapper()
9318 {
9319 auto testWrapper = [ = ]( QgsProcessingGui::WidgetType type )
9320 {
9321 // non optional
9322 QgsProcessingParameterRasterDestination param( QStringLiteral( "raster" ), QStringLiteral( "raster" ) );
9323
9324 QgsProcessingRasterDestinationWidgetWrapper wrapper( ¶m, type );
9325
9326 QgsProcessingContext context;
9327 QWidget *w = wrapper.createWrappedWidget( context );
9328
9329 QSignalSpy spy( &wrapper, &QgsProcessingRasterDestinationWidgetWrapper::widgetValueHasChanged );
9330 wrapper.setWidgetValue( QStringLiteral( "/bb.tif" ), context );
9331
9332 switch ( type )
9333 {
9334 case QgsProcessingGui::Standard:
9335 case QgsProcessingGui::Batch:
9336 case QgsProcessingGui::Modeler:
9337 QCOMPARE( spy.count(), 1 );
9338 QCOMPARE( wrapper.widgetValue().value< QgsProcessingOutputLayerDefinition >().sink.staticValue().toString(), QStringLiteral( "/bb.tif" ) );
9339 QCOMPARE( static_cast< QgsProcessingLayerOutputDestinationWidget * >( wrapper.wrappedWidget() )->value().value< QgsProcessingOutputLayerDefinition >().sink.staticValue().toString(), QStringLiteral( "/bb.tif" ) );
9340 wrapper.setWidgetValue( QStringLiteral( "/aa.tif" ), context );
9341 QCOMPARE( spy.count(), 2 );
9342 QCOMPARE( wrapper.widgetValue().value< QgsProcessingOutputLayerDefinition >().sink.staticValue().toString(), QStringLiteral( "/aa.tif" ) );
9343 QCOMPARE( static_cast< QgsProcessingLayerOutputDestinationWidget * >( wrapper.wrappedWidget() )->value().value< QgsProcessingOutputLayerDefinition >().sink.staticValue().toString(), QStringLiteral( "/aa.tif" ) );
9344 break;
9345 }
9346
9347 // check signal
9348 static_cast< QgsProcessingLayerOutputDestinationWidget * >( wrapper.wrappedWidget() )->setValue( QStringLiteral( "/cc.tif" ) );
9349 QCOMPARE( spy.count(), 3 );
9350 QCOMPARE( wrapper.widgetValue().value< QgsProcessingOutputLayerDefinition >().sink.staticValue().toString(), QStringLiteral( "/cc.tif" ) );
9351 delete w;
9352
9353 // optional
9354 QgsProcessingParameterRasterDestination param2( QStringLiteral( "raster" ), QStringLiteral( "raster" ), QVariant(), true );
9355 QgsProcessingRasterDestinationWidgetWrapper wrapper3( ¶m2, type );
9356 w = wrapper3.createWrappedWidget( context );
9357
9358 QSignalSpy spy3( &wrapper3, &QgsProcessingRasterDestinationWidgetWrapper::widgetValueHasChanged );
9359 wrapper3.setWidgetValue( QStringLiteral( "/bb.tif" ), context );
9360 QCOMPARE( spy3.count(), 1 );
9361 QCOMPARE( wrapper3.widgetValue().value< QgsProcessingOutputLayerDefinition >().sink.staticValue().toString(), QStringLiteral( "/bb.tif" ) );
9362 QCOMPARE( static_cast< QgsProcessingLayerOutputDestinationWidget * >( wrapper3.wrappedWidget() )->value().value< QgsProcessingOutputLayerDefinition >().sink.staticValue().toString(), QStringLiteral( "/bb.tif" ) );
9363 wrapper3.setWidgetValue( QVariant(), context );
9364 QCOMPARE( spy3.count(), 2 );
9365 QVERIFY( !wrapper3.widgetValue().isValid() );
9366 delete w;
9367
9368 QLabel *l = wrapper.createWrappedLabel();
9369 if ( wrapper.type() != QgsProcessingGui::Batch )
9370 {
9371 QVERIFY( l );
9372 QCOMPARE( l->text(), QStringLiteral( "raster" ) );
9373 QCOMPARE( l->toolTip(), param.toolTip() );
9374 delete l;
9375 }
9376 else
9377 {
9378 QVERIFY( !l );
9379 }
9380 };
9381
9382 // standard wrapper
9383 testWrapper( QgsProcessingGui::Standard );
9384
9385 // batch wrapper
9386 // testWrapper( QgsProcessingGui::Batch );
9387
9388 // modeler wrapper
9389 testWrapper( QgsProcessingGui::Modeler );
9390 }
9391
testFileOutWrapper()9392 void TestProcessingGui::testFileOutWrapper()
9393 {
9394 auto testWrapper = [ = ]( QgsProcessingGui::WidgetType type )
9395 {
9396 // non optional
9397 QgsProcessingParameterFileDestination param( QStringLiteral( "file" ), QStringLiteral( "file" ) );
9398
9399 QgsProcessingFileDestinationWidgetWrapper wrapper( ¶m, type );
9400
9401 QgsProcessingContext context;
9402 QWidget *w = wrapper.createWrappedWidget( context );
9403
9404 QSignalSpy spy( &wrapper, &QgsProcessingFileDestinationWidgetWrapper::widgetValueHasChanged );
9405 wrapper.setWidgetValue( QStringLiteral( "/bb.tif" ), context );
9406
9407 switch ( type )
9408 {
9409 case QgsProcessingGui::Standard:
9410 case QgsProcessingGui::Batch:
9411 case QgsProcessingGui::Modeler:
9412 QCOMPARE( spy.count(), 1 );
9413 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "/bb.tif" ) );
9414 QCOMPARE( static_cast< QgsProcessingLayerOutputDestinationWidget * >( wrapper.wrappedWidget() )->value().toString(), QStringLiteral( "/bb.tif" ) );
9415 wrapper.setWidgetValue( QStringLiteral( "/aa.tif" ), context );
9416 QCOMPARE( spy.count(), 2 );
9417 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "/aa.tif" ) );
9418 QCOMPARE( static_cast< QgsProcessingLayerOutputDestinationWidget * >( wrapper.wrappedWidget() )->value().toString(), QStringLiteral( "/aa.tif" ) );
9419 break;
9420 }
9421
9422 // check signal
9423 static_cast< QgsProcessingLayerOutputDestinationWidget * >( wrapper.wrappedWidget() )->setValue( QStringLiteral( "/cc.tif" ) );
9424 QCOMPARE( spy.count(), 3 );
9425 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "/cc.tif" ) );
9426 delete w;
9427
9428 // optional
9429 QgsProcessingParameterFileDestination param2( QStringLiteral( "file" ), QStringLiteral( "file" ), QString(), QVariant(), true );
9430 QgsProcessingFileDestinationWidgetWrapper wrapper3( ¶m2, type );
9431 w = wrapper3.createWrappedWidget( context );
9432
9433 QSignalSpy spy3( &wrapper3, &QgsProcessingFileDestinationWidgetWrapper::widgetValueHasChanged );
9434 wrapper3.setWidgetValue( QStringLiteral( "/bb.tif" ), context );
9435 QCOMPARE( spy3.count(), 1 );
9436 QCOMPARE( wrapper3.widgetValue().toString(), QStringLiteral( "/bb.tif" ) );
9437 QCOMPARE( static_cast< QgsProcessingLayerOutputDestinationWidget * >( wrapper3.wrappedWidget() )->value().toString(), QStringLiteral( "/bb.tif" ) );
9438 wrapper3.setWidgetValue( QVariant(), context );
9439 QCOMPARE( spy3.count(), 2 );
9440 QVERIFY( !wrapper3.widgetValue().isValid() );
9441 delete w;
9442
9443 QLabel *l = wrapper.createWrappedLabel();
9444 if ( wrapper.type() != QgsProcessingGui::Batch )
9445 {
9446 QVERIFY( l );
9447 QCOMPARE( l->text(), QStringLiteral( "file" ) );
9448 QCOMPARE( l->toolTip(), param.toolTip() );
9449 delete l;
9450 }
9451 else
9452 {
9453 QVERIFY( !l );
9454 }
9455 };
9456
9457 // standard wrapper
9458 testWrapper( QgsProcessingGui::Standard );
9459
9460 // batch wrapper
9461 // testWrapper( QgsProcessingGui::Batch );
9462
9463 // modeler wrapper
9464 testWrapper( QgsProcessingGui::Modeler );
9465 }
9466
testFolderOutWrapper()9467 void TestProcessingGui::testFolderOutWrapper()
9468 {
9469 auto testWrapper = [ = ]( QgsProcessingGui::WidgetType type )
9470 {
9471 // non optional
9472 QgsProcessingParameterFolderDestination param( QStringLiteral( "folder" ), QStringLiteral( "folder" ) );
9473
9474 QgsProcessingFolderDestinationWidgetWrapper wrapper( ¶m, type );
9475
9476 QgsProcessingContext context;
9477 QWidget *w = wrapper.createWrappedWidget( context );
9478
9479 QSignalSpy spy( &wrapper, &QgsProcessingFolderDestinationWidgetWrapper::widgetValueHasChanged );
9480 wrapper.setWidgetValue( QStringLiteral( "/bb" ), context );
9481
9482 switch ( type )
9483 {
9484 case QgsProcessingGui::Standard:
9485 case QgsProcessingGui::Batch:
9486 case QgsProcessingGui::Modeler:
9487 QCOMPARE( spy.count(), 1 );
9488 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "/bb" ) );
9489 QCOMPARE( static_cast< QgsProcessingLayerOutputDestinationWidget * >( wrapper.wrappedWidget() )->value().toString(), QStringLiteral( "/bb" ) );
9490 wrapper.setWidgetValue( QStringLiteral( "/aa" ), context );
9491 QCOMPARE( spy.count(), 2 );
9492 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "/aa" ) );
9493 QCOMPARE( static_cast< QgsProcessingLayerOutputDestinationWidget * >( wrapper.wrappedWidget() )->value().toString(), QStringLiteral( "/aa" ) );
9494 break;
9495 }
9496
9497 // check signal
9498 static_cast< QgsProcessingLayerOutputDestinationWidget * >( wrapper.wrappedWidget() )->setValue( QStringLiteral( "/cc" ) );
9499 QCOMPARE( spy.count(), 3 );
9500 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "/cc" ) );
9501 delete w;
9502
9503 // optional
9504 QgsProcessingParameterFolderDestination param2( QStringLiteral( "folder" ), QStringLiteral( "folder" ), QVariant(), true );
9505 QgsProcessingFolderDestinationWidgetWrapper wrapper3( ¶m2, type );
9506 w = wrapper3.createWrappedWidget( context );
9507
9508 QSignalSpy spy3( &wrapper3, &QgsProcessingFolderDestinationWidgetWrapper::widgetValueHasChanged );
9509 wrapper3.setWidgetValue( QStringLiteral( "/bb" ), context );
9510 QCOMPARE( spy3.count(), 1 );
9511 QCOMPARE( wrapper3.widgetValue().toString(), QStringLiteral( "/bb" ) );
9512 QCOMPARE( static_cast< QgsProcessingLayerOutputDestinationWidget * >( wrapper3.wrappedWidget() )->value().toString(), QStringLiteral( "/bb" ) );
9513 wrapper3.setWidgetValue( QVariant(), context );
9514 QCOMPARE( spy3.count(), 2 );
9515 QVERIFY( !wrapper3.widgetValue().isValid() );
9516 delete w;
9517
9518 QLabel *l = wrapper.createWrappedLabel();
9519 if ( wrapper.type() != QgsProcessingGui::Batch )
9520 {
9521 QVERIFY( l );
9522 QCOMPARE( l->text(), QStringLiteral( "folder" ) );
9523 QCOMPARE( l->toolTip(), param.toolTip() );
9524 delete l;
9525 }
9526 else
9527 {
9528 QVERIFY( !l );
9529 }
9530 };
9531
9532 // standard wrapper
9533 testWrapper( QgsProcessingGui::Standard );
9534
9535 // batch wrapper
9536 // testWrapper( QgsProcessingGui::Batch );
9537
9538 // modeler wrapper
9539 testWrapper( QgsProcessingGui::Modeler );
9540 }
9541
testTinInputLayerWrapper()9542 void TestProcessingGui::testTinInputLayerWrapper()
9543 {
9544 QgsProcessingParameterTinInputLayers definition( QStringLiteral( "TIN input layers" ) ) ;
9545 QgsProcessingTinInputLayersWidgetWrapper wrapper;
9546
9547 std::unique_ptr<QWidget> w( wrapper.createWidget() );
9548 QVERIFY( w );
9549
9550 QSignalSpy spy( &wrapper, &QgsProcessingTinInputLayersWidgetWrapper::widgetValueHasChanged );
9551
9552 QgsProcessingContext context;
9553 QgsProject project;
9554 context.setProject( &project );
9555 QgsVectorLayer *vectorLayer = new QgsVectorLayer( QStringLiteral( "Point" ),
9556 QStringLiteral( "PointLayerForTin" ),
9557 QStringLiteral( "memory" ) );
9558 project.addMapLayer( vectorLayer );
9559
9560 QVariantList layerList;
9561 QVariantMap layerMap;
9562 layerMap["source"] = "PointLayerForTin";
9563 layerMap["type"] = 0;
9564 layerMap["attributeIndex"] = -1;
9565 layerList.append( layerMap );
9566
9567 QVERIFY( definition.checkValueIsAcceptable( layerList, &context ) );
9568 wrapper.setWidgetValue( layerList, context );
9569 QCOMPARE( spy.count(), 1 );
9570
9571 QVariant value = wrapper.widgetValue();
9572
9573 QVERIFY( definition.checkValueIsAcceptable( value, &context ) );
9574 QString valueAsPythonString = definition.valueAsPythonString( value, context );
9575 QCOMPARE( valueAsPythonString, QStringLiteral( "[{'source': 'PointLayerForTin','type': 0,'attributeIndex': -1}]" ) );
9576 }
9577
testDxfLayersWrapper()9578 void TestProcessingGui::testDxfLayersWrapper()
9579 {
9580 QgsProcessingParameterDxfLayers definition( QStringLiteral( "DXF layers" ) ) ;
9581 QgsProcessingDxfLayersWidgetWrapper wrapper;
9582
9583 std::unique_ptr<QWidget> w( wrapper.createWidget() );
9584 QVERIFY( w );
9585
9586 QSignalSpy spy( &wrapper, &QgsProcessingTinInputLayersWidgetWrapper::widgetValueHasChanged );
9587
9588 QgsProcessingContext context;
9589 QgsProject project;
9590 context.setProject( &project );
9591 QgsVectorLayer *vectorLayer = new QgsVectorLayer( QStringLiteral( "Point" ),
9592 QStringLiteral( "PointLayer" ),
9593 QStringLiteral( "memory" ) );
9594 project.addMapLayer( vectorLayer );
9595
9596 QVariantList layerList;
9597 QVariantMap layerMap;
9598 layerMap["layer"] = "PointLayer";
9599 layerMap["attributeIndex"] = -1;
9600 layerList.append( layerMap );
9601
9602 QVERIFY( definition.checkValueIsAcceptable( layerList, &context ) );
9603 wrapper.setWidgetValue( layerList, context );
9604 QCOMPARE( spy.count(), 1 );
9605
9606 QVariant value = wrapper.widgetValue();
9607
9608 QVERIFY( definition.checkValueIsAcceptable( value, &context ) );
9609 QString valueAsPythonString = definition.valueAsPythonString( value, context );
9610 QCOMPARE( valueAsPythonString, QStringLiteral( "[{'layer': '%1','attributeIndex': -1}]" ).arg( vectorLayer->source() ) );
9611 }
9612
testMeshDatasetWrapperLayerInProject()9613 void TestProcessingGui::testMeshDatasetWrapperLayerInProject()
9614 {
9615 QgsProcessingParameterMeshLayer layerDefinition( QStringLiteral( "layer" ), QStringLiteral( "layer" ) );
9616 QgsProcessingMeshLayerWidgetWrapper layerWrapper( &layerDefinition );
9617
9618 QSet<int> supportedDataType( {QgsMeshDatasetGroupMetadata::DataOnVertices} );
9619 QgsProcessingParameterMeshDatasetGroups groupsDefinition( QStringLiteral( "groups" ),
9620 QStringLiteral( "groups" ),
9621 QStringLiteral( "layer" ),
9622 supportedDataType );
9623 QgsProcessingMeshDatasetGroupsWidgetWrapper groupsWrapper( &groupsDefinition );
9624
9625 QgsProcessingParameterMeshDatasetTime timeDefinition( QStringLiteral( "time" ), QStringLiteral( "time" ), QStringLiteral( "layer" ), QStringLiteral( "groups" ) );
9626 QgsProcessingMeshDatasetTimeWidgetWrapper timeWrapper( &timeDefinition );
9627
9628 QList<QgsAbstractProcessingParameterWidgetWrapper *> wrappers;
9629 wrappers << &layerWrapper << &groupsWrapper << &timeWrapper;
9630
9631 QgsProject project;
9632 QgsProcessingContext context;
9633 context.setProject( &project );
9634 QgsProcessingParameterWidgetContext widgetContext;
9635 std::unique_ptr<QgsMapCanvas> mapCanvas = std::make_unique<QgsMapCanvas>();
9636 widgetContext.setMapCanvas( mapCanvas.get() );
9637
9638 widgetContext.setProject( &project );
9639 layerWrapper.setWidgetContext( widgetContext );
9640 groupsWrapper.setWidgetContext( widgetContext );
9641 timeWrapper.setWidgetContext( widgetContext );
9642
9643 TestProcessingContextGenerator generator( context );
9644 layerWrapper.registerProcessingContextGenerator( &generator );
9645 groupsWrapper.registerProcessingContextGenerator( &generator );
9646 timeWrapper.registerProcessingContextGenerator( &generator );
9647
9648 QSignalSpy layerSpy( &layerWrapper, &QgsProcessingMeshLayerWidgetWrapper::widgetValueHasChanged );
9649 QSignalSpy groupsSpy( &groupsWrapper, &QgsProcessingMeshDatasetGroupsWidgetWrapper::widgetValueHasChanged );
9650 QSignalSpy timeSpy( &timeWrapper, &QgsProcessingMeshDatasetTimeWidgetWrapper::widgetValueHasChanged );
9651
9652 std::unique_ptr<QWidget> layerWidget( layerWrapper.createWrappedWidget( context ) );
9653 std::unique_ptr<QWidget> groupWidget( groupsWrapper.createWrappedWidget( context ) );
9654 std::unique_ptr<QWidget> timeWidget( timeWrapper.createWrappedWidget( context ) );
9655 QgsProcessingMeshDatasetGroupsWidget *datasetGroupWidget = qobject_cast<QgsProcessingMeshDatasetGroupsWidget *>( groupWidget.get() );
9656 QgsProcessingMeshDatasetTimeWidget *datasetTimeWidget = qobject_cast<QgsProcessingMeshDatasetTimeWidget *>( timeWidget.get() );
9657
9658 QVERIFY( layerWidget );
9659 QVERIFY( groupWidget );
9660 QVERIFY( datasetGroupWidget );
9661 QVERIFY( timeWidget );
9662
9663 groupsWrapper.postInitialize( wrappers );
9664 timeWrapper.postInitialize( wrappers );
9665
9666 QString dataDir = QString( TEST_DATA_DIR ); //defined in CmakeLists.txt
9667 dataDir += "/mesh";
9668 QString uri( dataDir + "/quad_and_triangle.2dm" );
9669 QString meshLayerName = QStringLiteral( "mesh layer" );
9670 QgsMeshLayer *layer = new QgsMeshLayer( uri, meshLayerName, QStringLiteral( "mdal" ) );
9671 QVERIFY( layer->isValid() );
9672 layer->addDatasets( dataDir + "/quad_and_triangle_vertex_scalar.dat" );
9673 layer->addDatasets( dataDir + "/quad_and_triangle_vertex_vector.dat" );
9674 layer->addDatasets( dataDir + "/quad_and_triangle_els_face_scalar.dat" );
9675 layer->addDatasets( dataDir + "/quad_and_triangle_els_face_vector.dat" );
9676 QgsMeshRendererSettings settings = layer->rendererSettings();
9677 // 1 dataset on vertices and 1 dataset on faces
9678 settings.setActiveScalarDatasetGroup( 1 );
9679 settings.setActiveVectorDatasetGroup( 4 );
9680 layer->setRendererSettings( settings );
9681 QCOMPARE( layer->datasetGroupCount(), 5 );
9682
9683 layerSpy.clear();
9684 groupsSpy.clear();
9685 timeSpy.clear();
9686
9687 // without layer in the project
9688 QString meshOutOfProject( dataDir + "/trap_steady_05_3D.nc" );
9689 layerWrapper.setWidgetValue( meshOutOfProject, context );
9690
9691 QCOMPARE( layerSpy.count(), 1 );
9692 QCOMPARE( groupsSpy.count(), 1 );
9693 QCOMPARE( timeSpy.count(), 1 );
9694
9695 QVERIFY( datasetTimeWidget->radioButtonDatasetGroupTimeStep->isChecked() );
9696
9697 QVariantList groups;
9698 groups << 0;
9699 groupsWrapper.setWidgetValue( groups, context );
9700 QVERIFY( groupsDefinition.checkValueIsAcceptable( groupsWrapper.widgetValue() ) );
9701 QCOMPARE( QgsProcessingParameterMeshDatasetGroups::valueAsDatasetGroup( groupsWrapper.widgetValue() ), QList<int>() << 0 );
9702 QCOMPARE( QgsProcessingParameterMeshDatasetTime::valueAsTimeType( timeWrapper.widgetValue() ), QStringLiteral( "static" ) );
9703
9704 QCOMPARE( layerSpy.count(), 1 );
9705 QCOMPARE( groupsSpy.count(), 2 );
9706 QCOMPARE( timeSpy.count(), 3 );
9707
9708 // with layer in the project
9709 layerSpy.clear();
9710 groupsSpy.clear();
9711 timeSpy.clear();
9712
9713 project.addMapLayer( layer );
9714 static_cast<QgsMeshLayerTemporalProperties *>( layer->temporalProperties() )->setReferenceTime(
9715 QDateTime( QDate( 2020, 01, 01 ), QTime( 0, 0, 0 ), Qt::UTC ), layer->dataProvider()->temporalCapabilities() );
9716 layerWrapper.setWidgetValue( meshLayerName, context );
9717
9718 QCOMPARE( layerSpy.count(), 1 );
9719 QCOMPARE( groupsSpy.count(), 1 );
9720 QCOMPARE( timeSpy.count(), 2 );
9721
9722 datasetGroupWidget->selectCurrentActiveDatasetGroup();
9723
9724 QCOMPARE( layerSpy.count(), 1 );
9725 QCOMPARE( groupsSpy.count(), 2 );
9726 QCOMPARE( timeSpy.count(), 3 );
9727
9728 QVariant groupsValue = groupsWrapper.widgetValue();
9729 QVERIFY( groupsValue.type() == QVariant::List );
9730 QVariantList groupsList = groupsValue.toList();
9731 QCOMPARE( groupsList.count(), 1 );
9732 QCOMPARE( groupsList.at( 0 ).toInt(), 1 );
9733 QString pythonString = groupsDefinition.valueAsPythonString( groupsValue, context );
9734 QCOMPARE( pythonString, QStringLiteral( "[1]" ) );
9735 QVERIFY( groupsDefinition.checkValueIsAcceptable( groupsValue ) );
9736 QCOMPARE( QgsProcessingParameterMeshDatasetGroups::valueAsDatasetGroup( groupsValue ), QList<int>( {1} ) );
9737
9738 // 2 datasets on vertices
9739 settings = layer->rendererSettings();
9740 settings.setActiveVectorDatasetGroup( 2 );
9741 layer->setRendererSettings( settings );
9742 datasetGroupWidget->selectCurrentActiveDatasetGroup();
9743
9744 QCOMPARE( layerSpy.count(), 1 );
9745 QCOMPARE( groupsSpy.count(), 3 );
9746 QCOMPARE( timeSpy.count(), 4 );
9747
9748 pythonString = groupsDefinition.valueAsPythonString( groupsWrapper.widgetValue(), context );
9749 QCOMPARE( pythonString, QStringLiteral( "[1,2]" ) );
9750 QVERIFY( groupsDefinition.checkValueIsAcceptable( groupsWrapper.widgetValue() ) );
9751 QCOMPARE( QgsProcessingParameterMeshDatasetGroups::valueAsDatasetGroup( groupsWrapper.widgetValue() ), QList<int>() << 1 << 2 );
9752
9753 datasetTimeWidget->radioButtonDatasetGroupTimeStep->setChecked( true );
9754 QCOMPARE( layerSpy.count(), 1 );
9755 QCOMPARE( groupsSpy.count(), 3 );
9756 QCOMPARE( timeSpy.count(), 4 ); //radioButtonDatasetGroupTimeStep already checked
9757
9758 QVariant timeValue = timeWrapper.widgetValue();
9759 QVERIFY( timeValue.type() == QVariant::Map );
9760 QVariantMap timeValueMap = timeValue.toMap();
9761 QCOMPARE( timeValueMap[QStringLiteral( "type" )].toString(), QStringLiteral( "dataset-time-step" ) );
9762 pythonString = timeDefinition.valueAsPythonString( timeWrapper.widgetValue(), context );
9763 QCOMPARE( pythonString, QStringLiteral( "{'type': 'dataset-time-step','value': [1,0]}" ) );
9764 QVERIFY( timeDefinition.checkValueIsAcceptable( timeValue ) );
9765 QCOMPARE( QgsProcessingParameterMeshDatasetTime::valueAsTimeType( timeValue ), QStringLiteral( "dataset-time-step" ) );
9766 QVERIFY( QgsProcessingParameterMeshDatasetTime::timeValueAsDatasetIndex( timeValue ) == QgsMeshDatasetIndex( 1, 0 ) );
9767
9768 datasetTimeWidget->radioButtonDefinedDateTime->setChecked( true );
9769 QDateTime dateTime = QDateTime( QDate( 2020, 1, 1 ), QTime( 0, 1, 0 ), Qt::UTC );
9770 datasetTimeWidget->dateTimeEdit->setDateTime( dateTime );
9771 QCOMPARE( layerSpy.count(), 1 );
9772 QCOMPARE( groupsSpy.count(), 3 );
9773 QCOMPARE( timeSpy.count(), 6 );
9774 pythonString = timeDefinition.valueAsPythonString( timeWrapper.widgetValue(), context );
9775 QCOMPARE( pythonString, QStringLiteral( "{'type': 'defined-date-time','value': QDateTime(QDate(2020, 1, 1), QTime(0, 1, 0))}" ) );
9776 QVERIFY( timeDefinition.checkValueIsAcceptable( timeWrapper.widgetValue() ) );
9777 QCOMPARE( QgsProcessingParameterMeshDatasetTime::valueAsTimeType( timeWrapper.widgetValue() ), QStringLiteral( "defined-date-time" ) );
9778 QCOMPARE( QgsProcessingParameterMeshDatasetTime::timeValueAsDefinedDateTime( timeWrapper.widgetValue() ), dateTime );
9779
9780 QVERIFY( !datasetTimeWidget->radioButtonCurrentCanvasTime->isEnabled() );
9781 mapCanvas->setTemporalRange( QgsDateTimeRange( QDateTime( QDate( 2021, 1, 1 ), QTime( 0, 3, 0 ), Qt::UTC ), QDateTime( QDate( 2020, 1, 1 ), QTime( 0, 5, 0 ), Qt::UTC ) ) );
9782 QVERIFY( datasetTimeWidget->radioButtonCurrentCanvasTime->isEnabled() );
9783
9784 datasetTimeWidget->radioButtonCurrentCanvasTime->setChecked( true );
9785 QCOMPARE( layerSpy.count(), 1 );
9786 QCOMPARE( groupsSpy.count(), 3 );
9787 QCOMPARE( timeSpy.count(), 8 );
9788 pythonString = timeDefinition.valueAsPythonString( timeWrapper.widgetValue(), context );
9789 QCOMPARE( pythonString, QStringLiteral( "{'type': 'current-context-time'}" ) );
9790 QVERIFY( timeDefinition.checkValueIsAcceptable( timeWrapper.widgetValue() ) );
9791 QCOMPARE( QgsProcessingParameterMeshDatasetTime::valueAsTimeType( timeWrapper.widgetValue() ), QStringLiteral( "current-context-time" ) );
9792
9793 // 0 dataset on vertices
9794 settings = layer->rendererSettings();
9795 settings.setActiveScalarDatasetGroup( -1 );
9796 settings.setActiveVectorDatasetGroup( -1 );
9797 layer->setRendererSettings( settings );
9798 datasetGroupWidget->selectCurrentActiveDatasetGroup();
9799 QVERIFY( !datasetTimeWidget->isEnabled() );
9800 pythonString = timeDefinition.valueAsPythonString( timeWrapper.widgetValue(), context );
9801 QCOMPARE( pythonString, QStringLiteral( "{'type': 'static'}" ) );
9802 QVERIFY( timeDefinition.checkValueIsAcceptable( timeWrapper.widgetValue() ) );
9803 QCOMPARE( QgsProcessingParameterMeshDatasetTime::valueAsTimeType( timeWrapper.widgetValue() ), QStringLiteral( "static" ) );
9804
9805 // 1 static dataset on vertices
9806 settings = layer->rendererSettings();
9807 settings.setActiveScalarDatasetGroup( 0 );
9808 settings.setActiveVectorDatasetGroup( -1 );
9809 layer->setRendererSettings( settings );
9810 datasetGroupWidget->selectCurrentActiveDatasetGroup();
9811 QVERIFY( !datasetTimeWidget->isEnabled() );
9812 pythonString = timeDefinition.valueAsPythonString( timeWrapper.widgetValue(), context );
9813 QCOMPARE( pythonString, QStringLiteral( "{'type': 'static'}" ) );
9814 QVERIFY( timeDefinition.checkValueIsAcceptable( timeWrapper.widgetValue() ) );
9815 QCOMPARE( QgsProcessingParameterMeshDatasetTime::valueAsTimeType( timeWrapper.widgetValue() ), QStringLiteral( "static" ) );
9816
9817 groupsWrapper.setWidgetValue( 3, context );
9818 QCOMPARE( datasetGroupWidget->value(), QVariantList( {3} ) );
9819 groupsWrapper.setWidgetValue( QVariantList( {1, 2, 3} ), context );
9820 QCOMPARE( datasetGroupWidget->value().toList(), QVariantList( {1, 2, 3} ) );
9821 groupsWrapper.setWidgetValue( QVariantList( {"1", "2", "3"} ), context );
9822 QCOMPARE( datasetGroupWidget->value().toList(), QVariantList( {1, 2, 3} ) );
9823 groupsWrapper.setWidgetValue( QgsProperty::fromExpression( QStringLiteral( "1+3" ) ), context );
9824 QCOMPARE( datasetGroupWidget->value().toList(), QVariantList( {4} ) );
9825
9826 timeWrapper.setWidgetValue( QDateTime( QDate( 2020, 01, 02 ), QTime( 1, 2, 3 ) ), context );
9827 pythonString = timeDefinition.valueAsPythonString( timeWrapper.widgetValue(), context );
9828 QCOMPARE( pythonString, QStringLiteral( "{'type': 'defined-date-time','value': QDateTime(QDate(2020, 1, 2), QTime(1, 2, 3))}" ) );
9829 timeWrapper.setWidgetValue( QVariant::fromValue( QDateTime( QDate( 2020, 02, 01 ), QTime( 3, 2, 1 ) ) ).toString(), context );
9830 pythonString = timeDefinition.valueAsPythonString( timeWrapper.widgetValue(), context );
9831 QCOMPARE( pythonString, QStringLiteral( "{'type': 'defined-date-time','value': QDateTime(QDate(2020, 2, 1), QTime(3, 2, 1))}" ) );
9832 }
9833
testMeshDatasetWrapperLayerOutsideProject()9834 void TestProcessingGui::testMeshDatasetWrapperLayerOutsideProject()
9835 {
9836 QgsProcessingParameterMeshLayer layerDefinition( QStringLiteral( "layer" ), QStringLiteral( "layer" ) );
9837 QgsProcessingMeshLayerWidgetWrapper layerWrapper( &layerDefinition );
9838
9839 QSet<int> supportedDataType( {QgsMeshDatasetGroupMetadata::DataOnFaces} );
9840 QgsProcessingParameterMeshDatasetGroups groupsDefinition( QStringLiteral( "groups" ),
9841 QStringLiteral( "groups" ),
9842 QStringLiteral( "layer" ),
9843 supportedDataType );
9844 QgsProcessingMeshDatasetGroupsWidgetWrapper groupsWrapper( &groupsDefinition );
9845
9846 QgsProcessingParameterMeshDatasetTime timeDefinition( QStringLiteral( "time" ), QStringLiteral( "time" ), QStringLiteral( "layer" ), QStringLiteral( "groups" ) );
9847 QgsProcessingMeshDatasetTimeWidgetWrapper timeWrapper( &timeDefinition );
9848
9849 QList<QgsAbstractProcessingParameterWidgetWrapper *> wrappers;
9850 wrappers << &layerWrapper << &groupsWrapper << &timeWrapper;
9851
9852 QgsProject project;
9853 QgsProcessingContext context;
9854 context.setProject( &project );
9855 QgsProcessingParameterWidgetContext widgetContext;
9856 std::unique_ptr<QgsMapCanvas> mapCanvas = std::make_unique<QgsMapCanvas>();
9857 widgetContext.setMapCanvas( mapCanvas.get() );
9858
9859 widgetContext.setProject( &project );
9860 layerWrapper.setWidgetContext( widgetContext );
9861 groupsWrapper.setWidgetContext( widgetContext );
9862 timeWrapper.setWidgetContext( widgetContext );
9863
9864 TestProcessingContextGenerator generator( context );
9865 layerWrapper.registerProcessingContextGenerator( &generator );
9866 groupsWrapper.registerProcessingContextGenerator( &generator );
9867 timeWrapper.registerProcessingContextGenerator( &generator );
9868
9869 QSignalSpy layerSpy( &layerWrapper, &QgsProcessingMeshLayerWidgetWrapper::widgetValueHasChanged );
9870 QSignalSpy groupsSpy( &groupsWrapper, &QgsProcessingMeshDatasetGroupsWidgetWrapper::widgetValueHasChanged );
9871 QSignalSpy timeSpy( &timeWrapper, &QgsProcessingMeshDatasetTimeWidgetWrapper::widgetValueHasChanged );
9872
9873 std::unique_ptr<QWidget> layerWidget( layerWrapper.createWrappedWidget( context ) );
9874 std::unique_ptr<QWidget> groupWidget( groupsWrapper.createWrappedWidget( context ) );
9875 std::unique_ptr<QWidget> timeWidget( timeWrapper.createWrappedWidget( context ) );
9876 QgsProcessingMeshDatasetGroupsWidget *datasetGroupWidget = qobject_cast<QgsProcessingMeshDatasetGroupsWidget *>( groupWidget.get() );
9877 QgsProcessingMeshDatasetTimeWidget *datasetTimeWidget = qobject_cast<QgsProcessingMeshDatasetTimeWidget *>( timeWidget.get() );
9878
9879 QVERIFY( layerWidget );
9880 QVERIFY( groupWidget );
9881 QVERIFY( datasetGroupWidget );
9882 QVERIFY( timeWidget );
9883
9884 groupsWrapper.postInitialize( wrappers );
9885 timeWrapper.postInitialize( wrappers );
9886
9887 layerSpy.clear();
9888 groupsSpy.clear();
9889 timeSpy.clear();
9890
9891 QString dataDir = QString( TEST_DATA_DIR ); //defined in CmakeLists.txt
9892 QString meshOutOfProject( dataDir + "/mesh/trap_steady_05_3D.nc" );
9893 layerWrapper.setWidgetValue( meshOutOfProject, context );
9894
9895 QCOMPARE( layerSpy.count(), 1 );
9896 QCOMPARE( groupsSpy.count(), 1 );
9897 QCOMPARE( timeSpy.count(), 1 );
9898
9899 QVariantList groups;
9900 groups << 0;
9901 groupsWrapper.setWidgetValue( groups, context );
9902 QCOMPARE( layerSpy.count(), 1 );
9903 QCOMPARE( groupsSpy.count(), 2 );
9904 QCOMPARE( timeSpy.count(), 3 );
9905 QVERIFY( groupsDefinition.checkValueIsAcceptable( groupsWrapper.widgetValue() ) );
9906 QCOMPARE( QgsProcessingParameterMeshDatasetGroups::valueAsDatasetGroup( groupsWrapper.widgetValue() ), QList<int>() << 0 );
9907 QCOMPARE( QgsProcessingParameterMeshDatasetTime::valueAsTimeType( timeWrapper.widgetValue() ), QStringLiteral( "static" ) );
9908 QVERIFY( !datasetTimeWidget->isEnabled() );
9909
9910 groups << 11;
9911 groupsWrapper.setWidgetValue( groups, context );
9912 QCOMPARE( layerSpy.count(), 1 );
9913 QCOMPARE( groupsSpy.count(), 3 );
9914 QCOMPARE( timeSpy.count(), 5 );
9915 QVERIFY( datasetTimeWidget->isEnabled() );
9916 QVERIFY( groupsDefinition.checkValueIsAcceptable( groupsWrapper.widgetValue() ) );
9917 QCOMPARE( QgsProcessingParameterMeshDatasetGroups::valueAsDatasetGroup( groupsWrapper.widgetValue() ), QList<int>() << 0 << 11 );
9918 QCOMPARE( QgsProcessingParameterMeshDatasetTime::valueAsTimeType( timeWrapper.widgetValue() ), QStringLiteral( "dataset-time-step" ) );
9919 QVERIFY( QgsProcessingParameterMeshDatasetTime::timeValueAsDatasetIndex( timeWrapper.widgetValue() ) == QgsMeshDatasetIndex( 11, 0 ) );
9920
9921 QVERIFY( datasetTimeWidget->radioButtonDefinedDateTime->isEnabled() );
9922 QVERIFY( !datasetTimeWidget->radioButtonCurrentCanvasTime->isEnabled() );
9923
9924 datasetTimeWidget->radioButtonDefinedDateTime->setChecked( true );
9925 QCOMPARE( QgsProcessingParameterMeshDatasetTime::valueAsTimeType( timeWrapper.widgetValue() ), QStringLiteral( "defined-date-time" ) );
9926 QCOMPARE( QgsProcessingParameterMeshDatasetTime::timeValueAsDefinedDateTime( timeWrapper.widgetValue() ),
9927 QDateTime( QDate( 1990, 1, 1 ), QTime( 0, 0, 0 ), Qt::UTC ) );
9928
9929
9930 mapCanvas->setTemporalRange( QgsDateTimeRange( QDateTime( QDate( 2021, 1, 1 ), QTime( 0, 3, 0 ), Qt::UTC ), QDateTime( QDate( 2020, 1, 1 ), QTime( 0, 5, 0 ), Qt::UTC ) ) );
9931 QVERIFY( datasetTimeWidget->radioButtonCurrentCanvasTime->isEnabled() );
9932
9933 }
9934
testPointCloudLayerWrapper()9935 void TestProcessingGui::testPointCloudLayerWrapper()
9936 {
9937 // setup a project with a range of layer types
9938 QgsProject::instance()->removeAllMapLayers();
9939 QgsPointCloudLayer *cloud1 = new QgsPointCloudLayer( QStringLiteral( TEST_DATA_DIR ) + "/point_clouds/ept/sunshine-coast/ept.json", QStringLiteral( "cloud1" ), QStringLiteral( "ept" ) );
9940 QVERIFY( cloud1->isValid() );
9941 QgsProject::instance()->addMapLayer( cloud1 );
9942 QgsPointCloudLayer *cloud2 = new QgsPointCloudLayer( QStringLiteral( TEST_DATA_DIR ) + "/point_clouds/ept/sunshine-coast/ept.json", QStringLiteral( "cloud2" ), QStringLiteral( "ept" ) );
9943 QVERIFY( cloud2->isValid() );
9944 QgsProject::instance()->addMapLayer( cloud2 );
9945
9946 auto testWrapper = [ = ]( QgsProcessingGui::WidgetType type )
9947 {
9948 // non optional
9949 QgsProcessingParameterPointCloudLayer param( QStringLiteral( "cloud" ), QStringLiteral( "cloud" ), false );
9950
9951 QgsProcessingPointCloudLayerWidgetWrapper wrapper( ¶m, type );
9952
9953 QgsProcessingContext context;
9954 QWidget *w = wrapper.createWrappedWidget( context );
9955
9956 QSignalSpy spy( &wrapper, &QgsProcessingPointCloudLayerWidgetWrapper::widgetValueHasChanged );
9957 wrapper.setWidgetValue( QStringLiteral( "bb" ), context );
9958
9959 switch ( type )
9960 {
9961 case QgsProcessingGui::Standard:
9962 case QgsProcessingGui::Batch:
9963 case QgsProcessingGui::Modeler:
9964 QCOMPARE( spy.count(), 1 );
9965 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "bb" ) );
9966 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper.wrappedWidget() )->currentText(), QStringLiteral( "bb" ) );
9967 wrapper.setWidgetValue( QStringLiteral( "aa" ), context );
9968 QCOMPARE( spy.count(), 2 );
9969 QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "aa" ) );
9970 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper.wrappedWidget() )->currentText(), QStringLiteral( "aa" ) );
9971 break;
9972 }
9973
9974 delete w;
9975
9976 // with project
9977 QgsProcessingParameterWidgetContext widgetContext;
9978 widgetContext.setProject( QgsProject::instance() );
9979 context.setProject( QgsProject::instance() );
9980
9981 QgsProcessingMapLayerWidgetWrapper wrapper2( ¶m, type );
9982 wrapper2.setWidgetContext( widgetContext );
9983 w = wrapper2.createWrappedWidget( context );
9984
9985 QSignalSpy spy2( &wrapper2, &QgsProcessingPointCloudLayerWidgetWrapper::widgetValueHasChanged );
9986 wrapper2.setWidgetValue( QStringLiteral( "bb" ), context );
9987 QCOMPARE( spy2.count(), 1 );
9988 QCOMPARE( wrapper2.widgetValue().toString(), QStringLiteral( "bb" ) );
9989 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "bb" ) );
9990 wrapper2.setWidgetValue( QStringLiteral( "cloud2" ), context );
9991 QCOMPARE( spy2.count(), 2 );
9992 QCOMPARE( wrapper2.widgetValue().toString(), cloud2->id() );
9993 switch ( type )
9994 {
9995 case QgsProcessingGui::Standard:
9996 case QgsProcessingGui::Batch:
9997 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "cloud2 [EPSG:28356]" ) );
9998 break;
9999 case QgsProcessingGui::Modeler:
10000 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "cloud2" ) );
10001 break;
10002 }
10003
10004 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentLayer()->name(), QStringLiteral( "cloud2" ) );
10005
10006 // check signal
10007 static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->setLayer( cloud1 );
10008 QCOMPARE( spy2.count(), 3 );
10009 QCOMPARE( wrapper2.widgetValue().toString(), cloud1->id() );
10010 switch ( type )
10011 {
10012 case QgsProcessingGui::Standard:
10013 case QgsProcessingGui::Batch:
10014 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "cloud1 [EPSG:28356]" ) );
10015 break;
10016
10017 case QgsProcessingGui::Modeler:
10018 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "cloud1" ) );
10019 break;
10020 }
10021 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentLayer()->name(), QStringLiteral( "cloud1" ) );
10022
10023 delete w;
10024
10025 // optional
10026 QgsProcessingParameterPoint param2( QStringLiteral( "cloud" ), QStringLiteral( "cloud" ), QVariant(), true );
10027 QgsProcessingPointCloudLayerWidgetWrapper wrapper3( ¶m2, type );
10028 wrapper3.setWidgetContext( widgetContext );
10029 w = wrapper3.createWrappedWidget( context );
10030
10031 QSignalSpy spy3( &wrapper3, &QgsProcessingPointCloudLayerWidgetWrapper::widgetValueHasChanged );
10032 wrapper3.setWidgetValue( QStringLiteral( "bb" ), context );
10033 QCOMPARE( spy3.count(), 1 );
10034 QCOMPARE( wrapper3.widgetValue().toString(), QStringLiteral( "bb" ) );
10035 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "bb" ) );
10036 wrapper3.setWidgetValue( QStringLiteral( "cloud2" ), context );
10037 QCOMPARE( spy3.count(), 2 );
10038 QCOMPARE( wrapper3.widgetValue().toString(), cloud2->id() );
10039 switch ( type )
10040 {
10041 case QgsProcessingGui::Standard:
10042 case QgsProcessingGui::Batch:
10043 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "cloud2 [EPSG:28356]" ) );
10044 break;
10045 case QgsProcessingGui::Modeler:
10046 QCOMPARE( static_cast< QgsProcessingMapLayerComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "cloud2" ) );
10047 break;
10048 }
10049 wrapper3.setWidgetValue( QVariant(), context );
10050 QCOMPARE( spy3.count(), 3 );
10051 QVERIFY( !wrapper3.widgetValue().isValid() );
10052 delete w;
10053
10054 QLabel *l = wrapper.createWrappedLabel();
10055 if ( wrapper.type() != QgsProcessingGui::Batch )
10056 {
10057 QVERIFY( l );
10058 QCOMPARE( l->text(), QStringLiteral( "cloud" ) );
10059 QCOMPARE( l->toolTip(), param.toolTip() );
10060 delete l;
10061 }
10062 else
10063 {
10064 QVERIFY( !l );
10065 }
10066 };
10067
10068 // standard wrapper
10069 testWrapper( QgsProcessingGui::Standard );
10070
10071 // batch wrapper
10072 testWrapper( QgsProcessingGui::Batch );
10073
10074 // modeler wrapper
10075 testWrapper( QgsProcessingGui::Modeler );
10076 }
10077
testAnnotationLayerWrapper()10078 void TestProcessingGui::testAnnotationLayerWrapper()
10079 {
10080 // setup a project with a range of layer types
10081 QgsProject::instance()->removeAllMapLayers();
10082 QgsAnnotationLayer *layer1 = new QgsAnnotationLayer( QStringLiteral( "secondary annotations" ), QgsAnnotationLayer::LayerOptions( QgsProject::instance()->transformContext() ) );
10083 QVERIFY( layer1->isValid() );
10084 QgsProject::instance()->addMapLayer( layer1 );
10085
10086 auto testWrapper = [ = ]( QgsProcessingGui::WidgetType type )
10087 {
10088 // non optional
10089 QgsProcessingParameterAnnotationLayer param( QStringLiteral( "annotation" ), QStringLiteral( "annotation" ), false );
10090
10091 QgsProcessingAnnotationLayerWidgetWrapper wrapper( ¶m, type );
10092
10093 QgsProcessingContext context;
10094
10095 // with project
10096 QgsProcessingParameterWidgetContext widgetContext;
10097 widgetContext.setProject( QgsProject::instance() );
10098 context.setProject( QgsProject::instance() );
10099
10100 QgsProcessingAnnotationLayerWidgetWrapper wrapper2( ¶m, type );
10101 wrapper2.setWidgetContext( widgetContext );
10102 QWidget *w = wrapper2.createWrappedWidget( context );
10103
10104 QSignalSpy spy2( &wrapper2, &QgsProcessingAnnotationLayerWidgetWrapper::widgetValueHasChanged );
10105 wrapper2.setWidgetValue( QStringLiteral( "main" ), context );
10106 QCOMPARE( spy2.count(), 1 );
10107 QCOMPARE( wrapper2.widgetValue().toString(), QStringLiteral( "main" ) );
10108 QCOMPARE( qgis::down_cast< QgsMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "Annotations" ) );
10109 wrapper2.setWidgetValue( QStringLiteral( "secondary annotations" ), context );
10110 QCOMPARE( spy2.count(), 2 );
10111 QCOMPARE( wrapper2.widgetValue().toString(), layer1->id() );
10112 switch ( type )
10113 {
10114 case QgsProcessingGui::Standard:
10115 case QgsProcessingGui::Batch:
10116 QCOMPARE( qgis::down_cast< QgsMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "secondary annotations" ) );
10117 break;
10118 case QgsProcessingGui::Modeler:
10119 QCOMPARE( qgis::down_cast< QgsMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "secondary annotations" ) );
10120 break;
10121 }
10122
10123 QCOMPARE( static_cast< QgsMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentLayer()->name(), QStringLiteral( "secondary annotations" ) );
10124
10125 // check signal
10126 static_cast< QgsMapLayerComboBox * >( wrapper2.wrappedWidget() )->setLayer( QgsProject::instance()->mainAnnotationLayer() );
10127 QCOMPARE( spy2.count(), 3 );
10128 QCOMPARE( wrapper2.widgetValue().toString(), QStringLiteral( "main" ) );
10129 switch ( type )
10130 {
10131 case QgsProcessingGui::Standard:
10132 case QgsProcessingGui::Batch:
10133 QCOMPARE( qgis::down_cast< QgsMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "Annotations" ) );
10134 break;
10135
10136 case QgsProcessingGui::Modeler:
10137 QCOMPARE( qgis::down_cast< QgsMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "Annotations" ) );
10138 break;
10139 }
10140 QCOMPARE( qgis::down_cast< QgsMapLayerComboBox * >( wrapper2.wrappedWidget() )->currentLayer()->name(), QStringLiteral( "Annotations" ) );
10141
10142 delete w;
10143
10144 // optional
10145 QgsProcessingParameterAnnotationLayer param2( QStringLiteral( "annotation" ), QStringLiteral( "annotation" ), QVariant(), true );
10146 QgsProcessingAnnotationLayerWidgetWrapper wrapper3( ¶m2, type );
10147 wrapper3.setWidgetContext( widgetContext );
10148 w = wrapper3.createWrappedWidget( context );
10149
10150 QSignalSpy spy3( &wrapper3, &QgsProcessingAnnotationLayerWidgetWrapper::widgetValueHasChanged );
10151 wrapper3.setWidgetValue( QStringLiteral( "main" ), context );
10152 QCOMPARE( spy3.count(), 1 );
10153 QCOMPARE( wrapper3.widgetValue().toString(), QStringLiteral( "main" ) );
10154 QCOMPARE( qgis::down_cast< QgsMapLayerComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "Annotations" ) );
10155 wrapper3.setWidgetValue( QStringLiteral( "secondary annotations" ), context );
10156 QCOMPARE( spy3.count(), 2 );
10157 QCOMPARE( wrapper3.widgetValue().toString(), layer1->id() );
10158 switch ( type )
10159 {
10160 case QgsProcessingGui::Standard:
10161 case QgsProcessingGui::Batch:
10162 QCOMPARE( qgis::down_cast< QgsMapLayerComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "secondary annotations" ) );
10163 break;
10164 case QgsProcessingGui::Modeler:
10165 QCOMPARE( qgis::down_cast< QgsMapLayerComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "secondary annotations" ) );
10166 break;
10167 }
10168 wrapper3.setWidgetValue( QVariant(), context );
10169 QCOMPARE( spy3.count(), 3 );
10170 QVERIFY( !wrapper3.widgetValue().isValid() );
10171 delete w;
10172
10173 QLabel *l = wrapper.createWrappedLabel();
10174 if ( wrapper.type() != QgsProcessingGui::Batch )
10175 {
10176 QVERIFY( l );
10177 QCOMPARE( l->text(), QStringLiteral( "annotation" ) );
10178 QCOMPARE( l->toolTip(), param.toolTip() );
10179 delete l;
10180 }
10181 else
10182 {
10183 QVERIFY( !l );
10184 }
10185 };
10186
10187 // standard wrapper
10188 testWrapper( QgsProcessingGui::Standard );
10189
10190 // batch wrapper
10191 testWrapper( QgsProcessingGui::Batch );
10192
10193 // modeler wrapper
10194 testWrapper( QgsProcessingGui::Modeler );
10195 }
10196
testModelGraphicsView()10197 void TestProcessingGui::testModelGraphicsView()
10198 {
10199 // test model
10200 QgsProcessingModelAlgorithm model1;
10201
10202 QgsProcessingModelChildAlgorithm algc1;
10203 algc1.setChildId( "buffer" );
10204 algc1.setAlgorithmId( "native:buffer" );
10205 QgsProcessingModelParameter param;
10206 param.setParameterName( QStringLiteral( "LAYER" ) );
10207 param.setSize( QSizeF( 500, 400 ) );
10208 param.setPosition( QPointF( 101, 102 ) );
10209 param.comment()->setDescription( QStringLiteral( "input comment" ) );
10210 model1.addModelParameter( new QgsProcessingParameterMapLayer( QStringLiteral( "LAYER" ) ), param );
10211 algc1.addParameterSources( QStringLiteral( "INPUT" ), QList< QgsProcessingModelChildParameterSource >() << QgsProcessingModelChildParameterSource::fromModelParameter( QStringLiteral( "LAYER" ) ) );
10212 algc1.comment()->setDescription( QStringLiteral( "alg comment" ) );
10213 algc1.comment()->setSize( QSizeF( 300, 200 ) );
10214 algc1.comment()->setPosition( QPointF( 201, 202 ) );
10215
10216 QgsProcessingModelOutput modelOut;
10217 modelOut.setChildId( algc1.childId() );
10218 modelOut.setChildOutputName( QStringLiteral( "my_output" ) );
10219 modelOut.comment()->setDescription( QStringLiteral( "output comm" ) );
10220 QMap< QString, QgsProcessingModelOutput > outs;
10221 outs.insert( QStringLiteral( "OUTPUT" ), modelOut );
10222 algc1.setModelOutputs( outs );
10223 model1.addChildAlgorithm( algc1 );
10224
10225 QgsProcessingModelGroupBox groupBox;
10226 groupBox.setDescription( QStringLiteral( "group" ) );
10227 model1.addGroupBox( groupBox );
10228
10229 // hiding comments
10230 QgsProcessingContext context;
10231 QgsModelGraphicsScene scene2;
10232 scene2.setModel( &model1 );
10233 scene2.setFlags( QgsModelGraphicsScene::FlagHideComments );
10234 scene2.createItems( &model1, context );
10235 QList< QGraphicsItem * > items = scene2.items();
10236 QgsModelParameterGraphicItem *layerItem = nullptr;
10237 for ( QGraphicsItem *item : items )
10238 {
10239 if ( QgsModelParameterGraphicItem *param = dynamic_cast< QgsModelParameterGraphicItem * >( item ) )
10240 {
10241 layerItem = param;
10242 break;
10243 }
10244 }
10245 QVERIFY( layerItem );
10246 QgsModelCommentGraphicItem *layerCommentItem = nullptr;
10247 for ( QGraphicsItem *item : items )
10248 {
10249 if ( QgsModelCommentGraphicItem *comment = dynamic_cast< QgsModelCommentGraphicItem * >( item ) )
10250 {
10251 layerCommentItem = comment;
10252 break;
10253 }
10254 }
10255 // should not exist
10256 QVERIFY( !layerCommentItem );
10257
10258
10259 QgsModelGraphicsScene scene;
10260 QVERIFY( !scene.model() );
10261 scene.setModel( &model1 );
10262 QCOMPARE( scene.model(), &model1 );
10263
10264 QVERIFY( scene.items().empty() );
10265 scene.createItems( &model1, context );
10266 items = scene.items();
10267 layerItem = nullptr;
10268 for ( QGraphicsItem *item : items )
10269 {
10270 if ( QgsModelParameterGraphicItem *param = dynamic_cast< QgsModelParameterGraphicItem * >( item ) )
10271 {
10272 layerItem = param;
10273
10274 }
10275 }
10276 QVERIFY( layerItem );
10277 QCOMPARE( dynamic_cast< QgsProcessingModelParameter * >( layerItem->component() )->parameterName(), QStringLiteral( "LAYER" ) );
10278 QCOMPARE( layerItem->itemRect().size(), QSizeF( 500, 400 ) );
10279 QCOMPARE( layerItem->scenePos(), QPointF( 101, 102 ) );
10280
10281 QgsModelChildAlgorithmGraphicItem *algItem = nullptr;
10282 for ( QGraphicsItem *item : items )
10283 {
10284 if ( QgsModelChildAlgorithmGraphicItem *param = dynamic_cast< QgsModelChildAlgorithmGraphicItem * >( item ) )
10285 {
10286 algItem = param;
10287 break;
10288 }
10289 }
10290 QVERIFY( algItem );
10291 QCOMPARE( dynamic_cast< QgsProcessingModelChildAlgorithm * >( algItem->component() )->algorithmId(), QStringLiteral( "native:buffer" ) );
10292
10293 QgsModelOutputGraphicItem *outputItem = nullptr;
10294 for ( QGraphicsItem *item : items )
10295 {
10296 if ( QgsModelOutputGraphicItem *comment = dynamic_cast< QgsModelOutputGraphicItem * >( item ) )
10297 {
10298 outputItem = comment;
10299 break;
10300 }
10301 }
10302 QVERIFY( outputItem );
10303 QCOMPARE( dynamic_cast< QgsProcessingModelOutput * >( outputItem->component() )->childOutputName(), QStringLiteral( "my_output" ) );
10304
10305
10306 layerCommentItem = nullptr;
10307 QgsModelCommentGraphicItem *algCommentItem = nullptr;
10308 QgsModelCommentGraphicItem *outputCommentItem = nullptr;
10309 for ( QGraphicsItem *item : items )
10310 {
10311 if ( QgsModelCommentGraphicItem *comment = dynamic_cast< QgsModelCommentGraphicItem * >( item ) )
10312 {
10313 if ( comment->parentComponentItem() == layerItem )
10314 {
10315 layerCommentItem = comment;
10316 }
10317 else if ( comment->parentComponentItem() == algItem )
10318 {
10319 algCommentItem = comment;
10320 }
10321 else if ( comment->parentComponentItem() == outputItem )
10322 {
10323 outputCommentItem = comment;
10324 }
10325 }
10326 }
10327
10328 QVERIFY( algCommentItem );
10329 QCOMPARE( algCommentItem->component()->description(), QStringLiteral( "alg comment" ) );
10330 QCOMPARE( algCommentItem->itemRect().size(), QSizeF( 300, 200 ) );
10331 QCOMPARE( algCommentItem->scenePos(), QPointF( 201, 202 ) );
10332
10333 QVERIFY( layerCommentItem );
10334 QCOMPARE( layerCommentItem->component()->description(), QStringLiteral( "input comment" ) );
10335
10336 QVERIFY( outputCommentItem );
10337 QCOMPARE( outputCommentItem->component()->description(), QStringLiteral( "output comm" ) );
10338
10339 QgsModelGroupBoxGraphicItem *groupItem = nullptr;
10340 for ( QGraphicsItem *item : items )
10341 {
10342 if ( QgsModelGroupBoxGraphicItem *comment = dynamic_cast< QgsModelGroupBoxGraphicItem * >( item ) )
10343 {
10344 groupItem = comment;
10345 break;
10346 }
10347 }
10348 QVERIFY( groupItem );
10349 QCOMPARE( dynamic_cast< QgsProcessingModelGroupBox * >( groupItem->component() )->description(), QStringLiteral( "group" ) );
10350
10351
10352 QgsModelGraphicsView view;
10353 view.setModelScene( &scene );
10354
10355 // copy some items
10356 view.copyItems( QList< QgsModelComponentGraphicItem * >() << layerItem << algItem << groupItem, QgsModelGraphicsView::ClipboardCopy );
10357
10358
10359 // second view to paste into
10360 QgsProcessingModelAlgorithm algDest;
10361 QVERIFY( algDest.childAlgorithms().empty() );
10362 QVERIFY( algDest.parameterComponents().empty() );
10363 QVERIFY( algDest.groupBoxes().empty() );
10364 QgsModelGraphicsScene sceneDest;
10365 sceneDest.setModel( &algDest );
10366 QgsModelGraphicsView viewDest;
10367 viewDest.setModelScene( &sceneDest );
10368 viewDest.pasteItems( QgsModelGraphicsView::PasteModeInPlace );
10369
10370 QCOMPARE( algDest.parameterComponents().size(), 1 );
10371 QCOMPARE( algDest.parameterComponents().value( QStringLiteral( "LAYER" ) ).parameterName(), QStringLiteral( "LAYER" ) );
10372 // comment should not be copied, was not selected
10373 QCOMPARE( algDest.parameterComponents().value( QStringLiteral( "LAYER" ) ).comment()->description(), QString() );
10374 QCOMPARE( algDest.childAlgorithms().size(), 1 );
10375 QCOMPARE( algDest.childAlgorithms().keys().at( 0 ), QStringLiteral( "native:buffer_1" ) );
10376 QCOMPARE( algDest.childAlgorithms().value( QStringLiteral( "native:buffer_1" ) ).algorithmId(), QStringLiteral( "native:buffer" ) );
10377 QCOMPARE( algDest.childAlgorithms().value( QStringLiteral( "native:buffer_1" ) ).comment()->description(), QString() );
10378 // output was not selected
10379 QVERIFY( algDest.childAlgorithms().value( QStringLiteral( "native:buffer_1" ) ).modelOutputs().empty() );
10380 QCOMPARE( algDest.groupBoxes().size(), 1 );
10381 QCOMPARE( algDest.groupBoxes().at( 0 ).description(), QStringLiteral( "group" ) );
10382
10383 // copy comments and output (not output comment though!)
10384 view.copyItems( QList< QgsModelComponentGraphicItem * >() << layerItem << layerCommentItem << algItem << algCommentItem << outputItem << groupItem, QgsModelGraphicsView::ClipboardCopy );
10385 viewDest.pasteItems( QgsModelGraphicsView::PasteModeInPlace );
10386
10387 QCOMPARE( algDest.parameterComponents().size(), 2 );
10388 QCOMPARE( algDest.parameterComponents().value( QStringLiteral( "LAYER" ) ).parameterName(), QStringLiteral( "LAYER" ) );
10389 QCOMPARE( algDest.parameterComponents().value( QStringLiteral( "LAYER (2)" ) ).parameterName(), QStringLiteral( "LAYER (2)" ) );
10390 QCOMPARE( algDest.parameterComponents().value( QStringLiteral( "LAYER" ) ).comment()->description(), QString() );
10391 QCOMPARE( algDest.parameterComponents().value( QStringLiteral( "LAYER (2)" ) ).comment()->description(), QStringLiteral( "input comment" ) );
10392 QCOMPARE( algDest.childAlgorithms().size(), 2 );
10393 QCOMPARE( algDest.childAlgorithms().value( QStringLiteral( "native:buffer_1" ) ).algorithmId(), QStringLiteral( "native:buffer" ) );
10394 QCOMPARE( algDest.childAlgorithms().value( QStringLiteral( "native:buffer_1" ) ).comment()->description(), QString() );
10395 QCOMPARE( algDest.childAlgorithms().value( QStringLiteral( "native:buffer_2" ) ).algorithmId(), QStringLiteral( "native:buffer" ) );
10396 QCOMPARE( algDest.childAlgorithms().value( QStringLiteral( "native:buffer_2" ) ).comment()->description(), QStringLiteral( "alg comment" ) );
10397 QVERIFY( algDest.childAlgorithms().value( QStringLiteral( "native:buffer_1" ) ).modelOutputs().empty() );
10398 QCOMPARE( algDest.childAlgorithms().value( QStringLiteral( "native:buffer_2" ) ).modelOutputs().size(), 1 );
10399 // output comment wasn't selected
10400 QCOMPARE( algDest.childAlgorithms().value( QStringLiteral( "native:buffer_2" ) ).modelOutputs().value( algDest.childAlgorithms().value( QStringLiteral( "native:buffer_2" ) ).modelOutputs().keys().at( 0 ) ).comment()->description(), QString() );
10401 QCOMPARE( algDest.groupBoxes().size(), 2 );
10402 QCOMPARE( algDest.groupBoxes().at( 0 ).description(), QStringLiteral( "group" ) );
10403 QCOMPARE( algDest.groupBoxes().at( 1 ).description(), QStringLiteral( "group" ) );
10404
10405 // output and output comment
10406 view.copyItems( QList< QgsModelComponentGraphicItem * >() << algItem << outputItem << outputCommentItem, QgsModelGraphicsView::ClipboardCopy );
10407 viewDest.pasteItems( QgsModelGraphicsView::PasteModeInPlace );
10408 QCOMPARE( algDest.childAlgorithms().size(), 3 );
10409 QCOMPARE( algDest.childAlgorithms().value( QStringLiteral( "native:buffer_3" ) ).modelOutputs().size(), 1 );
10410 QCOMPARE( algDest.childAlgorithms().value( QStringLiteral( "native:buffer_3" ) ).modelOutputs().value( algDest.childAlgorithms().value( QStringLiteral( "native:buffer_3" ) ).modelOutputs().keys().at( 0 ) ).comment()->description(), QStringLiteral( "output comm" ) );
10411 }
10412
cleanupTempDir()10413 void TestProcessingGui::cleanupTempDir()
10414 {
10415 QDir tmpDir = QDir( mTempDir );
10416 if ( tmpDir.exists() )
10417 {
10418 for ( const QString &tf : tmpDir.entryList( QDir::NoDotAndDotDot | QDir::Files ) )
10419 {
10420 QVERIFY2( tmpDir.remove( mTempDir + '/' + tf ), qPrintable( "Could not remove " + mTempDir + '/' + tf ) );
10421 }
10422 QVERIFY2( tmpDir.rmdir( mTempDir ), qPrintable( "Could not remove directory " + mTempDir ) );
10423 }
10424 }
10425
10426 QGSTEST_MAIN( TestProcessingGui )
10427 #include "testprocessinggui.moc"
10428