Skip to content

Commit e76b761

Browse files
committedSep 4, 2018
Correctly associate layer with dynamic properties
1 parent 8082497 commit e76b761

File tree

7 files changed

+310
-7
lines changed

7 files changed

+310
-7
lines changed
 

‎python/gui/auto_generated/processing/qgsprocessingwidgetwrapper.sip.in

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,32 @@
1010

1111

1212

13+
class QgsProcessingContextGenerator
14+
{
15+
%Docstring
16+
17+
An interface for objects which can create Processing contexts.
18+
19+
.. versionadded:: 3.4
20+
%End
21+
22+
%TypeHeaderCode
23+
#include "qgsprocessingwidgetwrapper.h"
24+
%End
25+
public:
26+
27+
virtual QgsProcessingContext *processingContext() = 0;
28+
%Docstring
29+
This method needs to be reimplemented in all classes which implement this interface
30+
and return a Processing context.
31+
32+
Note that ownership of the context is not transferred - it is intended that subclasses
33+
return a pointer to a context which they have already created and own.
34+
%End
35+
36+
virtual ~QgsProcessingContextGenerator();
37+
};
38+
1339
class QgsAbstractProcessingParameterWidgetWrapper : QObject
1440
{
1541
%Docstring
@@ -107,12 +133,26 @@ current value is associated with.
107133
Returns the current value of the parameter.
108134

109135
.. seealso:: :py:func:`setParameterValue`
136+
%End
137+
138+
void registerProcessingContextGenerator( QgsProcessingContextGenerator *generator );
139+
%Docstring
140+
Register a Processing context generator class that will be used to retrieve
141+
a Processing context for the wrapper when required.
110142
%End
111143

112144
virtual void postInitialize( const QList< QgsAbstractProcessingParameterWidgetWrapper * > &wrappers );
113145
%Docstring
114146
Called after all wrappers have been created within a particular dialog or context,
115147
allowing the wrapper to connect to the wrappers of other, related parameters.
148+
%End
149+
150+
signals:
151+
152+
153+
void widgetValueHasChanged( QgsAbstractProcessingParameterWidgetWrapper *wrapper );
154+
%Docstring
155+
Emitted whenever the parameter value (as defined by the wrapped widget) is changed.
116156
%End
117157

118158
protected:

‎python/plugins/processing/gui/ParametersPanel.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
QgsProcessingParameterFeatureSink,
4343
QgsProcessingParameterVectorDestination,
4444
QgsProject)
45+
from qgis.gui import QgsProcessingContextGenerator
4546

4647
from qgis.PyQt import uic
4748
from qgis.PyQt.QtCore import QCoreApplication, Qt
@@ -83,6 +84,19 @@ def __init__(self, parent, alg):
8384
self.dependentItems = {}
8485
self.iterateButtons = {}
8586

87+
self.processing_context = createContext()
88+
89+
class ContextGenerator(QgsProcessingContextGenerator):
90+
91+
def __init__(self, context):
92+
super().__init__()
93+
self.processing_context = context
94+
95+
def processingContext(self):
96+
return self.processing_context
97+
98+
self.context_generator = ContextGenerator(self.processing_context)
99+
86100
self.initWidgets()
87101

88102
QgsProject.instance().layerWasAdded.connect(self.layerRegistryChanged)
@@ -102,8 +116,6 @@ def formatParameterTooltip(self, parameter):
102116
)
103117

104118
def initWidgets(self):
105-
context = createContext()
106-
107119
# If there are advanced parameters — show corresponding groupbox
108120
for param in self.alg.parameterDefinitions():
109121
if param.flags() & QgsProcessingParameterDefinition.FlagAdvanced:
@@ -121,7 +133,8 @@ def initWidgets(self):
121133
self.wrappers[param.name()] = wrapper
122134
is_python_wrapper = issubclass(wrapper.__class__, WidgetWrapper)
123135
if not is_python_wrapper:
124-
widget = wrapper.createWrappedWidget(context)
136+
widget = wrapper.createWrappedWidget(self.processing_context)
137+
wrapper.registerProcessingContextGenerator(self.context_generator)
125138
else:
126139
widget = wrapper.widget
127140

@@ -203,7 +216,6 @@ def skipOutputChanged(checkbox, skipped):
203216
wrapper.postInitialize(list(self.wrappers.values()))
204217

205218
def setParameters(self, parameters):
206-
context = createContext()
207219
for param in self.alg.parameterDefinitions():
208220
if param.flags() & QgsProcessingParameterDefinition.FlagHidden:
209221
continue
@@ -215,7 +227,7 @@ def setParameters(self, parameters):
215227
value = parameters[param.name()]
216228

217229
wrapper = self.wrappers[param.name()]
218-
wrapper.setParameterValue(value, context)
230+
wrapper.setParameterValue(value, self.processing_context)
219231
else:
220232
dest_widget = self.outputWidgets[param.name()]
221233
dest_widget.setValue(parameters[param.name()])

‎python/plugins/processing/gui/wrappers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,13 @@ def getExtendedLayerName(layer):
148148

149149

150150
class WidgetWrapper(QgsAbstractProcessingParameterWidgetWrapper):
151-
widgetValueHasChanged = pyqtSignal(object)
152151

153152
NOT_SET_OPTION = '~~~~!!!!NOT SET!!!!~~~~~~~'
154153

155154
def __init__(self, param, dialog, row=0, col=0, **kwargs):
156155
self.dialogType = dialogTypes.get(dialog.__class__.__name__, QgsProcessingGui.Standard)
157156
super().__init__(param, self.dialogType)
157+
158158
self.param = param
159159
self.dialog = dialog
160160
self.row = row

‎src/gui/processing/qgsprocessingwidgetwrapper.cpp

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ void QgsAbstractProcessingParameterWidgetWrapper::setParameterValue( const QVari
9494
}
9595
else
9696
{
97+
if ( mPropertyButton )
98+
mPropertyButton->setToProperty( QgsProperty() );
99+
97100
setWidgetValue( value, context );
98101
}
99102
}
@@ -106,6 +109,11 @@ QVariant QgsAbstractProcessingParameterWidgetWrapper::parameterValue() const
106109
return widgetValue();
107110
}
108111

112+
void QgsAbstractProcessingParameterWidgetWrapper::registerProcessingContextGenerator( QgsProcessingContextGenerator *generator )
113+
{
114+
mProcessingContextGenerator = generator;
115+
}
116+
109117
QLabel *QgsAbstractProcessingParameterWidgetWrapper::createLabel()
110118
{
111119
switch ( mType )
@@ -124,9 +132,79 @@ QLabel *QgsAbstractProcessingParameterWidgetWrapper::createLabel()
124132
return nullptr;
125133
}
126134

127-
void QgsAbstractProcessingParameterWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> & )
135+
void QgsAbstractProcessingParameterWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
136+
{
137+
switch ( mType )
138+
{
139+
case QgsProcessingGui::Batch:
140+
case QgsProcessingGui::Standard:
141+
{
142+
if ( parameterDefinition()->isDynamic() )
143+
{
144+
for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
145+
{
146+
if ( wrapper->parameterDefinition()->name() == parameterDefinition()->dynamicLayerParameterName() )
147+
{
148+
setDynamicParentLayerParameter( wrapper->parameterValue() );
149+
connect( wrapper, &QgsAbstractProcessingParameterWidgetWrapper::widgetValueHasChanged, this, &QgsAbstractProcessingParameterWidgetWrapper::parentLayerChanged );
150+
break;
151+
}
152+
}
153+
}
154+
break;
155+
}
156+
157+
case QgsProcessingGui::Modeler:
158+
break;
159+
}
160+
}
161+
162+
void QgsAbstractProcessingParameterWidgetWrapper::parentLayerChanged( QgsAbstractProcessingParameterWidgetWrapper *wrapper )
163+
{
164+
if ( wrapper )
165+
{
166+
setDynamicParentLayerParameter( wrapper->parameterValue() );
167+
}
168+
}
169+
170+
void QgsAbstractProcessingParameterWidgetWrapper::setDynamicParentLayerParameter( const QVariant &value )
128171
{
172+
if ( mPropertyButton )
173+
{
174+
// evaluate value to layer
175+
QgsProcessingContext *context = nullptr;
176+
std::unique_ptr< QgsProcessingContext > tmpContext;
177+
if ( mProcessingContextGenerator )
178+
context = mProcessingContextGenerator->processingContext();
129179

180+
if ( !context )
181+
{
182+
tmpContext = qgis::make_unique< QgsProcessingContext >();
183+
context = tmpContext.get();
184+
}
185+
186+
QgsVectorLayer *layer = QgsProcessingParameters::parameterAsVectorLayer( parameterDefinition(), value, *context );
187+
if ( !layer )
188+
{
189+
mPropertyButton->setVectorLayer( nullptr );
190+
return;
191+
}
192+
193+
// need to grab ownership of layer if required - otherwise layer may be deleted when context
194+
// goes out of scope
195+
std::unique_ptr< QgsMapLayer > ownedLayer( context->takeResultLayer( layer->id() ) );
196+
if ( ownedLayer && ownedLayer->type() == QgsMapLayer::VectorLayer )
197+
{
198+
mDynamicLayer.reset( qobject_cast< QgsVectorLayer * >( ownedLayer.release() ) );
199+
layer = mDynamicLayer.get();
200+
}
201+
else
202+
{
203+
// don't need ownership of this layer - it wasn't owned by context (so e.g. is owned by the project)
204+
}
205+
206+
mPropertyButton->setVectorLayer( layer );
207+
}
130208
}
131209

132210
QgsProcessingModelerParameterWidget *QgsProcessingParameterWidgetFactoryInterface::createModelerWidgetWrapper( QgsProcessingModelAlgorithm *model, const QString &childId, const QgsProcessingParameterDefinition *parameter, const QgsProcessingContext &context )

‎src/gui/processing/qgsprocessingwidgetwrapper.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,43 @@
2121
#include <QObject>
2222
#include <QWidget>
2323
#include <QPointer>
24+
#include <memory>
2425
#include "qgis_gui.h"
2526
#include "qgis_sip.h"
2627
#include "qgsprocessinggui.h"
28+
#include "qgsvectorlayer.h"
2729

2830
class QgsProcessingParameterDefinition;
2931
class QgsProcessingContext;
3032
class QgsProcessingModelerParameterWidget;
3133
class QgsProcessingModelAlgorithm;
3234
class QLabel;
3335
class QgsPropertyOverrideButton;
36+
class QgsVectorLayer;
37+
38+
/**
39+
* \class QgsProcessingContextGenerator
40+
*
41+
* An interface for objects which can create Processing contexts.
42+
*
43+
* \ingroup gui
44+
* \since QGIS 3.4
45+
*/
46+
class GUI_EXPORT QgsProcessingContextGenerator
47+
{
48+
public:
49+
50+
/**
51+
* This method needs to be reimplemented in all classes which implement this interface
52+
* and return a Processing context.
53+
*
54+
* Note that ownership of the context is not transferred - it is intended that subclasses
55+
* return a pointer to a context which they have already created and own.
56+
*/
57+
virtual QgsProcessingContext *processingContext() = 0;
58+
59+
virtual ~QgsProcessingContextGenerator() = default;
60+
};
3461

3562
/**
3663
* \class QgsAbstractProcessingParameterWidgetWrapper
@@ -129,12 +156,28 @@ class GUI_EXPORT QgsAbstractProcessingParameterWidgetWrapper : public QObject
129156
*/
130157
QVariant parameterValue() const;
131158

159+
/**
160+
* Register a Processing context generator class that will be used to retrieve
161+
* a Processing context for the wrapper when required.
162+
*/
163+
void registerProcessingContextGenerator( QgsProcessingContextGenerator *generator );
164+
132165
/**
133166
* Called after all wrappers have been created within a particular dialog or context,
134167
* allowing the wrapper to connect to the wrappers of other, related parameters.
135168
*/
136169
virtual void postInitialize( const QList< QgsAbstractProcessingParameterWidgetWrapper * > &wrappers );
137170

171+
signals:
172+
173+
// TODO QGIS 4.0 - remove wrapper parameter - this is kept for compatibility with 3.x API,
174+
// yet can easily be retrieved by checking the sender()
175+
176+
/**
177+
* Emitted whenever the parameter value (as defined by the wrapped widget) is changed.
178+
*/
179+
void widgetValueHasChanged( QgsAbstractProcessingParameterWidgetWrapper *wrapper );
180+
138181
protected:
139182

140183
/**
@@ -175,14 +218,24 @@ class GUI_EXPORT QgsAbstractProcessingParameterWidgetWrapper : public QObject
175218
*/
176219
virtual QVariant widgetValue() const = 0;
177220

221+
private slots:
222+
223+
void parentLayerChanged( QgsAbstractProcessingParameterWidgetWrapper *wrapper );
224+
178225
private:
179226

180227
QgsProcessingGui::WidgetType mType = QgsProcessingGui::Standard;
181228
const QgsProcessingParameterDefinition *mParameterDefinition = nullptr;
229+
QgsProcessingContextGenerator *mProcessingContextGenerator = nullptr;
230+
231+
void setDynamicParentLayerParameter( const QVariant &value );
182232

183233
QPointer< QWidget > mWidget;
184234
QPointer< QgsPropertyOverrideButton > mPropertyButton;
185235
QPointer< QLabel > mLabel;
236+
std::unique_ptr< QgsVectorLayer > mDynamicLayer;
237+
238+
friend class TestProcessingGui;
186239

187240
};
188241

‎src/gui/processing/qgsprocessingwidgetwrapperimpl.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ QWidget *QgsProcessingBooleanWidgetWrapper::createWidget()
4646

4747
mCheckBox = new QCheckBox( description );
4848
mCheckBox->setToolTip( parameterDefinition()->toolTip() );
49+
50+
connect( mCheckBox, &QCheckBox::toggled, this, [ = ]
51+
{
52+
emit widgetValueHasChanged( this );
53+
} );
4954
return mCheckBox;
5055
};
5156

@@ -56,6 +61,12 @@ QWidget *QgsProcessingBooleanWidgetWrapper::createWidget()
5661
mComboBox->addItem( tr( "Yes" ), true );
5762
mComboBox->addItem( tr( "No" ), false );
5863
mComboBox->setToolTip( parameterDefinition()->toolTip() );
64+
65+
connect( mComboBox, qgis::overload< int>::of( &QComboBox::currentIndexChanged ), this, [ = ]
66+
{
67+
emit widgetValueHasChanged( this );
68+
} );
69+
5970
return mComboBox;
6071
}
6172
}

‎tests/src/gui/testprocessinggui.cpp

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,15 @@
2626
#include "qgsgui.h"
2727
#include "qgsprocessingguiregistry.h"
2828
#include "qgsprocessingregistry.h"
29+
#include "qgsprocessingalgorithm.h"
2930
#include "qgsprocessingalgorithmconfigurationwidget.h"
3031
#include "qgsprocessingwidgetwrapper.h"
3132
#include "qgsprocessingwidgetwrapperimpl.h"
3233
#include "qgsprocessingmodelerwidget.h"
3334
#include "qgsnativealgorithms.h"
3435
#include "processing/models/qgsprocessingmodelalgorithm.h"
3536
#include "qgsxmlutils.h"
37+
#include "qgspropertyoverridebutton.h"
3638

3739
class TestParamType : public QgsProcessingParameterDefinition
3840
{
@@ -133,6 +135,7 @@ class TestProcessingGui : public QObject
133135
void testFilterAlgorithmConfig();
134136
void testWrapperFactoryRegistry();
135137
void testWrapperGeneral();
138+
void testWrapperDynamic();
136139
void testModelerWrapper();
137140
void testBooleanWrapper();
138141
};
@@ -295,6 +298,84 @@ void TestProcessingGui::testWrapperGeneral()
295298
delete w;
296299
}
297300

301+
class TestProcessingContextGenerator : public QgsProcessingContextGenerator
302+
{
303+
public:
304+
305+
TestProcessingContextGenerator( QgsProcessingContext &context )
306+
: mContext( context )
307+
{}
308+
309+
QgsProcessingContext *processingContext() override
310+
{
311+
return &mContext;
312+
}
313+
314+
QgsProcessingContext &mContext;
315+
};
316+
317+
void TestProcessingGui::testWrapperDynamic()
318+
{
319+
const QgsProcessingAlgorithm *centroidAlg = QgsApplication::processingRegistry()->algorithmById( QStringLiteral( "native:centroids" ) );
320+
const QgsProcessingParameterDefinition *layerDef = centroidAlg->parameterDefinition( QStringLiteral( "INPUT" ) );
321+
const QgsProcessingParameterDefinition *allPartsDef = centroidAlg->parameterDefinition( QStringLiteral( "ALL_PARTS" ) );
322+
323+
QgsProcessingBooleanWidgetWrapper inputWrapper( layerDef, QgsProcessingGui::Standard );
324+
QgsProcessingBooleanWidgetWrapper allPartsWrapper( allPartsDef, QgsProcessingGui::Standard );
325+
326+
QgsProcessingContext context;
327+
328+
std::unique_ptr< QWidget > allPartsWidget( allPartsWrapper.createWrappedWidget( context ) );
329+
// dynamic parameter, so property button should be created
330+
QVERIFY( allPartsWrapper.mPropertyButton.data() != nullptr );
331+
332+
std::unique_ptr< QWidget > inputWidget( inputWrapper.createWrappedWidget( context ) );
333+
// not dynamic parameter, so property button should be NOT created
334+
QVERIFY( inputWrapper.mPropertyButton.data() == nullptr );
335+
336+
// set dynamic parameter to dynamic value
337+
allPartsWrapper.setParameterValue( QgsProperty::fromExpression( QStringLiteral( "1+2" ) ), context );
338+
QCOMPARE( allPartsWrapper.parameterValue().value< QgsProperty >().expressionString(), QStringLiteral( "1+2" ) );
339+
// not dynamic value
340+
allPartsWrapper.setParameterValue( true, context );
341+
QCOMPARE( allPartsWrapper.parameterValue().toBool(), true );
342+
allPartsWrapper.setParameterValue( false, context );
343+
QCOMPARE( allPartsWrapper.parameterValue().toBool(), false );
344+
345+
// project layer
346+
QgsProject p;
347+
QgsVectorLayer *vl = new QgsVectorLayer( QStringLiteral( "LineString" ), QStringLiteral( "x" ), QStringLiteral( "memory" ) );
348+
p.addMapLayer( vl );
349+
350+
QVERIFY( !allPartsWrapper.mPropertyButton->vectorLayer() );
351+
allPartsWrapper.setDynamicParentLayerParameter( QVariant::fromValue( vl ) );
352+
QCOMPARE( allPartsWrapper.mPropertyButton->vectorLayer(), vl );
353+
// should not be owned by wrapper
354+
QVERIFY( !allPartsWrapper.mDynamicLayer.get() );
355+
allPartsWrapper.setDynamicParentLayerParameter( QVariant() );
356+
QVERIFY( !allPartsWrapper.mPropertyButton->vectorLayer() );
357+
358+
allPartsWrapper.setDynamicParentLayerParameter( vl->id() );
359+
QVERIFY( !allPartsWrapper.mPropertyButton->vectorLayer() );
360+
QVERIFY( !allPartsWrapper.mDynamicLayer.get() );
361+
362+
// with project layer
363+
context.setProject( &p );
364+
TestProcessingContextGenerator generator( context );
365+
allPartsWrapper.registerProcessingContextGenerator( &generator );
366+
367+
allPartsWrapper.setDynamicParentLayerParameter( vl->id() );
368+
QCOMPARE( allPartsWrapper.mPropertyButton->vectorLayer(), vl );
369+
QVERIFY( !allPartsWrapper.mDynamicLayer.get() );
370+
371+
// non-project layer
372+
QString pointFileName = TEST_DATA_DIR + QStringLiteral( "/points.shp" );
373+
allPartsWrapper.setDynamicParentLayerParameter( pointFileName );
374+
QCOMPARE( allPartsWrapper.mPropertyButton->vectorLayer()->publicSource(), pointFileName );
375+
// must be owned by wrapper, or layer may be deleted while still required by wrapper
376+
QCOMPARE( allPartsWrapper.mDynamicLayer->publicSource(), pointFileName );
377+
}
378+
298379
void TestProcessingGui::testModelerWrapper()
299380
{
300381
// make a little model
@@ -402,32 +483,51 @@ void TestProcessingGui::testBooleanWrapper()
402483

403484
// standard wrapper
404485
QgsProcessingBooleanWidgetWrapper wrapper( &param );
486+
QSignalSpy spy( &wrapper, &QgsProcessingBooleanWidgetWrapper::widgetValueHasChanged );
405487

406488
QgsProcessingContext context;
407489
QWidget *w = wrapper.createWrappedWidget( context );
408490
wrapper.setWidgetValue( true, context );
491+
QCOMPARE( spy.count(), 1 );
409492
QVERIFY( wrapper.widgetValue().toBool() );
410493
QVERIFY( static_cast< QCheckBox * >( wrapper.wrappedWidget() )->isChecked() );
411494
wrapper.setWidgetValue( false, context );
495+
QCOMPARE( spy.count(), 2 );
412496
QVERIFY( !wrapper.widgetValue().toBool() );
413497
QVERIFY( !static_cast< QCheckBox * >( wrapper.wrappedWidget() )->isChecked() );
414498

415499
// should be no label in standard mode
416500
QVERIFY( !wrapper.createWrappedLabel() );
417501
QCOMPARE( static_cast< QCheckBox * >( wrapper.wrappedWidget() )->text(), QStringLiteral( "bool" ) );
502+
503+
// check signal
504+
static_cast< QCheckBox * >( wrapper.wrappedWidget() )->setChecked( true );
505+
QCOMPARE( spy.count(), 3 );
506+
static_cast< QCheckBox * >( wrapper.wrappedWidget() )->setChecked( false );
507+
QCOMPARE( spy.count(), 4 );
508+
418509
delete w;
419510

420511
// batch wrapper
421512
QgsProcessingBooleanWidgetWrapper wrapperB( &param, QgsProcessingGui::Batch );
422513

423514
w = wrapperB.createWrappedWidget( context );
515+
QSignalSpy spy2( &wrapperB, &QgsProcessingBooleanWidgetWrapper::widgetValueHasChanged );
424516
wrapperB.setWidgetValue( true, context );
517+
QCOMPARE( spy2.count(), 1 );
425518
QVERIFY( wrapperB.widgetValue().toBool() );
426519
QVERIFY( static_cast< QComboBox * >( wrapperB.wrappedWidget() )->currentData().toBool() );
427520
wrapperB.setWidgetValue( false, context );
521+
QCOMPARE( spy2.count(), 2 );
428522
QVERIFY( !wrapperB.widgetValue().toBool() );
429523
QVERIFY( !static_cast< QComboBox * >( wrapperB.wrappedWidget() )->currentData().toBool() );
430524

525+
// check signal
526+
static_cast< QComboBox * >( w )->setCurrentIndex( 0 );
527+
QCOMPARE( spy2.count(), 3 );
528+
static_cast< QComboBox * >( w )->setCurrentIndex( 1 );
529+
QCOMPARE( spy2.count(), 4 );
530+
431531
// should be no label in batch mode
432532
QVERIFY( !wrapperB.createWrappedLabel() );
433533
delete w;
@@ -436,13 +536,22 @@ void TestProcessingGui::testBooleanWrapper()
436536
QgsProcessingBooleanWidgetWrapper wrapperM( &param, QgsProcessingGui::Modeler );
437537

438538
w = wrapperM.createWrappedWidget( context );
539+
QSignalSpy spy3( &wrapperM, &QgsProcessingBooleanWidgetWrapper::widgetValueHasChanged );
439540
wrapperM.setWidgetValue( true, context );
440541
QVERIFY( wrapperM.widgetValue().toBool() );
542+
QCOMPARE( spy3.count(), 1 );
441543
QVERIFY( static_cast< QComboBox * >( wrapperM.wrappedWidget() )->currentData().toBool() );
442544
wrapperM.setWidgetValue( false, context );
443545
QVERIFY( !wrapperM.widgetValue().toBool() );
546+
QCOMPARE( spy3.count(), 2 );
444547
QVERIFY( !static_cast< QComboBox * >( wrapperM.wrappedWidget() )->currentData().toBool() );
445548

549+
// check signal
550+
static_cast< QComboBox * >( w )->setCurrentIndex( 0 );
551+
QCOMPARE( spy3.count(), 3 );
552+
static_cast< QComboBox * >( w )->setCurrentIndex( 1 );
553+
QCOMPARE( spy3.count(), 4 );
554+
446555
// should be a label in modeler mode
447556
QLabel *l = wrapperM.createWrappedLabel();
448557
QVERIFY( l );

0 commit comments

Comments
 (0)
Please sign in to comment.