Skip to content

Commit de547ad

Browse files
committed
Find a suitable editor widget if widget and config mismatch
If a .ui file is specified and the widget specified in the .ui file is not supported by the widgetwrapper which is configured in the layer properties the system will automatically try to find a better suitable widgetwrapper. To do this, widgetwrappers (respectively their factories) can return a map of supported widget types with priority values. The widgetwrapper which offers the heighest priority for a certain widget type will be used in case of a mismatch. Sponsored by OPENGIS.ch special projects team (aka gis.se troubleshooting section)
1 parent 1d888ac commit de547ad

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+322
-88
lines changed

python/gui/editorwidgets/core/qgseditorwidgetwrapper.sip

+1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ class QgsEditorWidgetWrapper : QObject
8888
*/
8989
void setEnabled( bool enabled );
9090

91+
virtual bool valid() = 0;
9192
protected:
9293
virtual QWidget* createWidget( QWidget* parent ) = 0;
9394

python/gui/editorwidgets/core/qgswidgetwrapper.sip

+11
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,17 @@ class QgsWidgetWrapper : QObject
111111
*/
112112
static QgsWidgetWrapper* fromWidget( QWidget* widget );
113113

114+
/**
115+
* Return true if the widget has been properly initialized.
116+
* This acts as hint for the calling party if this wrapper can be used
117+
* after initializing it.
118+
* If it cannot be used this is a hint tothe caller that he may try to find
119+
* another suitable widget type instead.
120+
*
121+
* @return Validity status of this widget.
122+
*/
123+
virtual bool valid() = 0;
124+
114125
protected:
115126
/**
116127
* This method should create a new widget with the provided parent. This will only be called

src/gui/editorwidgets/core/qgseditorwidgetfactory.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@ QgsEditorWidgetFactory::~QgsEditorWidgetFactory()
3030
{
3131
}
3232

33-
/** Override in own factory to get something different than the default (a simple QgsFilterLineEdit)
34-
*
33+
/**
34+
* By default a simple QgsFilterLineEdit is returned as search widget.
35+
* Override in own factory to get something different than the default.
3536
*/
3637
QgsSearchWidgetWrapper* QgsEditorWidgetFactory::createSearchWidget( QgsVectorLayer* vl, int fieldIdx, QWidget* parent ) const
3738
{

src/gui/editorwidgets/core/qgseditorwidgetfactory.h

+9
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,15 @@ class GUI_EXPORT QgsEditorWidgetFactory
115115
*/
116116
inline bool supportsField( QgsVectorLayer* vl, int fieldIdx ) { return isFieldSupported( vl, fieldIdx ); }
117117

118+
/**
119+
* Returns a list of widget types which this editor widget supports.
120+
* Each widget type can have a priority value attached, the factory with the highest one
121+
* will be used.
122+
*
123+
* @return A map of widget type names and weight values
124+
*/
125+
virtual QMap<const char*, int> supportedWidgetTypes() { return QMap<const char*, int>(); }
126+
118127
/**
119128
* Create a pretty String representation of the value.
120129
*

src/gui/editorwidgets/core/qgseditorwidgetregistry.cpp

+55
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,21 @@ QgsEditorWidgetWrapper* QgsEditorWidgetRegistry::create( const QString& widgetId
9595
// Make sure that there is a widget created at this point
9696
// so setValue() et al won't crash
9797
ww->widget();
98+
99+
// If we tried to set a widget which is not supported by this wrapper
100+
if ( !ww->valid() )
101+
{
102+
delete ww;
103+
QString wid = findSuitableWrapper( editor );
104+
ww = mWidgetFactories[wid]->create( vl, fieldIdx, editor, parent );
105+
ww->setConfig( config );
106+
ww->setContext( context );
107+
}
108+
98109
return ww;
99110
}
100111
}
112+
101113
return 0;
102114
}
103115

@@ -164,6 +176,20 @@ bool QgsEditorWidgetRegistry::registerWidget( const QString& widgetId, QgsEditor
164176
else
165177
{
166178
mWidgetFactories.insert( widgetId, widgetFactory );
179+
180+
// Use this factory as default where it provides the heighest priority
181+
QMap<const char*, int> types = widgetFactory->supportedWidgetTypes();
182+
QMap<const char*, int>::ConstIterator it;
183+
it = types.constBegin();
184+
185+
for ( ; it != types.constEnd(); ++it )
186+
{
187+
if ( it.value() > mFactoriesByType[it.key()].first )
188+
{
189+
mFactoriesByType[it.key()] = qMakePair( it.value(), widgetFactory );
190+
}
191+
}
192+
167193
return true;
168194
}
169195
}
@@ -316,3 +342,32 @@ void QgsEditorWidgetRegistry::writeSymbology( QDomElement& element, QDomDocument
316342

317343
writeMapLayer( vl, element, doc );
318344
}
345+
346+
QString QgsEditorWidgetRegistry::findSuitableWrapper( QWidget* editor )
347+
{
348+
QMap<const char*, QPair<int, QgsEditorWidgetFactory*> >::ConstIterator it;
349+
350+
QString widgetid;
351+
int weight = 0;
352+
353+
it = mFactoriesByType.constBegin();
354+
for ( ; it != mFactoriesByType.constEnd(); ++it )
355+
{
356+
if ( editor->staticMetaObject.className() == it.key() )
357+
{
358+
// if it's a perfect match: return it directly
359+
return it.value().second->name();
360+
}
361+
else if ( editor->inherits( it.key() ) )
362+
{
363+
// if it's a subclass, continue evaluating, maybe we find a more-specific or one with more weight
364+
if ( it.value().first > weight )
365+
{
366+
weight = it.value().first;
367+
widgetid = it.value().second->name();
368+
}
369+
}
370+
}
371+
372+
return widgetid;
373+
}

src/gui/editorwidgets/core/qgseditorwidgetregistry.h

+3
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,10 @@ class GUI_EXPORT QgsEditorWidgetRegistry : public QObject
193193
void writeSymbology( QDomElement& element, QDomDocument& doc, QString& errorMessage );
194194

195195
private:
196+
QString findSuitableWrapper( QWidget* editor );
197+
196198
QMap<QString, QgsEditorWidgetFactory*> mWidgetFactories;
199+
QMap<const char*, QPair<int, QgsEditorWidgetFactory*> > mFactoriesByType;
197200
};
198201

199202
#endif // QGSEDITORWIDGETREGISTRY_H

src/gui/editorwidgets/core/qgswidgetwrapper.h

+11
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,17 @@ class GUI_EXPORT QgsWidgetWrapper : public QObject
119119
*/
120120
static QgsWidgetWrapper* fromWidget( QWidget* widget );
121121

122+
/**
123+
* Return true if the widget has been properly initialized.
124+
* This acts as hint for the calling party if this wrapper can be used
125+
* after initializing it.
126+
* If it cannot be used this is a hint tothe caller that he may try to find
127+
* another suitable widget type instead.
128+
*
129+
* @return Validity status of this widget.
130+
*/
131+
virtual bool valid() = 0;
132+
122133
protected:
123134
/**
124135
* This method should create a new widget with the provided parent. This will only be called

src/gui/editorwidgets/qgscheckboxwidgetwrapper.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ void QgsCheckboxWidgetWrapper::initWidget( QWidget* editor )
5353
connect( mGroupBox, SIGNAL( toggled( bool ) ), this, SLOT( valueChanged( bool ) ) );
5454
}
5555

56+
bool QgsCheckboxWidgetWrapper::valid()
57+
{
58+
return mCheckBox || mGroupBox;
59+
}
60+
5661
void QgsCheckboxWidgetWrapper::setValue( const QVariant& value )
5762
{
5863
if ( mGroupBox )

src/gui/editorwidgets/qgscheckboxwidgetwrapper.h

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class GUI_EXPORT QgsCheckboxWidgetWrapper : public QgsEditorWidgetWrapper
4545
protected:
4646
QWidget* createWidget( QWidget* parent ) override;
4747
void initWidget( QWidget* editor ) override;
48+
bool valid() override;
4849

4950
public slots:
5051
void setValue( const QVariant& value ) override;

src/gui/editorwidgets/qgsclassificationwidgetwrapper.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ void QgsClassificationWidgetWrapper::initWidget( QWidget* editor )
5959
}
6060
}
6161

62+
bool QgsClassificationWidgetWrapper::valid()
63+
{
64+
return mComboBox;
65+
}
66+
6267
void QgsClassificationWidgetWrapper::setValue( const QVariant& value )
6368
{
6469
mComboBox->setCurrentIndex( mComboBox->findData( value ) );

src/gui/editorwidgets/qgsclassificationwidgetwrapper.h

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class GUI_EXPORT QgsClassificationWidgetWrapper : public QgsEditorWidgetWrapper
3333
protected:
3434
QWidget*createWidget( QWidget* parent ) override;
3535
void initWidget( QWidget* editor ) override;
36+
bool valid() override;
3637

3738
public slots:
3839
void setValue( const QVariant& value ) override;

src/gui/editorwidgets/qgscolorwidgetwrapper.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ void QgsColorWidgetWrapper::initWidget( QWidget* editor )
4646
connect( mColorButton, SIGNAL( colorChanged( QColor ) ), this, SLOT( valueChanged() ) );
4747
}
4848

49+
bool QgsColorWidgetWrapper::valid()
50+
{
51+
return mColorButton;
52+
}
53+
4954
void QgsColorWidgetWrapper::setValue( const QVariant& value )
5055
{
5156
if ( mColorButton )

src/gui/editorwidgets/qgscolorwidgetwrapper.h

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class GUI_EXPORT QgsColorWidgetWrapper : public QgsEditorWidgetWrapper
3939
protected:
4040
QWidget* createWidget( QWidget* parent ) override;
4141
void initWidget( QWidget* editor ) override;
42+
bool valid() override;
4243

4344
public slots:
4445
void setValue( const QVariant& value ) override;

src/gui/editorwidgets/qgsdatetimeeditwrapper.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@ void QgsDateTimeEditWrapper::initWidget( QWidget *editor )
9090
}
9191
}
9292

93+
bool QgsDateTimeEditWrapper::valid()
94+
{
95+
return mQgsDateTimeEdit || mQDateTimeEdit;
96+
}
97+
9398
void QgsDateTimeEditWrapper::dateTimeChanged( const QDateTime& dateTime )
9499
{
95100
const QString fieldFormat = config( "field_format", QGSDATETIMEEDIT_DATEFORMAT ).toString();

src/gui/editorwidgets/qgsdatetimeeditwrapper.h

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ class GUI_EXPORT QgsDateTimeEditWrapper : public QgsEditorWidgetWrapper
5454
QVariant value() override;
5555
QWidget *createWidget( QWidget *parent ) override;
5656
void initWidget( QWidget *editor ) override;
57+
bool valid() override;
5758

5859
public slots:
5960
void setValue( const QVariant &value ) override;

src/gui/editorwidgets/qgsdefaultsearchwidgetwrapper.cpp

+49-44
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ QgsDefaultSearchWidgetWrapper::QgsDefaultSearchWidgetWrapper( QgsVectorLayer* vl
2626
, mLineEdit( NULL )
2727
, mCheckbox( NULL )
2828
, mContainer( NULL )
29-
, mCaseString(QString("LIKE"))
29+
, mCaseString( QString( "LIKE" ) )
3030
{
3131
}
3232

@@ -36,67 +36,72 @@ QString QgsDefaultSearchWidgetWrapper::expression()
3636
return mExpression;
3737
}
3838

39-
void QgsDefaultSearchWidgetWrapper::setCaseString(int caseSensitiveCheckState)
39+
void QgsDefaultSearchWidgetWrapper::setCaseString( int caseSensitiveCheckState )
4040
{
41-
if ( caseSensitiveCheckState == Qt::Checked)
42-
{
43-
mCaseString = "LIKE";
44-
}
45-
else
46-
{
47-
mCaseString = "ILIKE";
48-
}
49-
// need to update also the line edit
50-
setExpression(mLineEdit->text());
41+
if ( caseSensitiveCheckState == Qt::Checked )
42+
{
43+
mCaseString = "LIKE";
44+
}
45+
else
46+
{
47+
mCaseString = "ILIKE";
48+
}
49+
// need to update also the line edit
50+
setExpression( mLineEdit->text() );
5151
}
5252

53-
void QgsDefaultSearchWidgetWrapper::setExpression(QString exp)
53+
void QgsDefaultSearchWidgetWrapper::setExpression( QString exp )
5454
{
55-
QVariant::Type fldType = layer()->pendingFields()[mFieldIdx].type();
56-
bool numeric = ( fldType == QVariant::Int || fldType == QVariant::Double || fldType == QVariant::LongLong );
57-
58-
QSettings settings;
59-
QString nullValue = settings.value( "qgis/nullValue", "NULL" ).toString();
60-
QString fieldName = layer()->pendingFields()[mFieldIdx].name();
61-
QString str;
62-
if ( exp == nullValue )
63-
{
64-
str = QString( "%1 IS NULL" ).arg( QgsExpression::quotedColumnRef( fieldName ) );
65-
}
66-
else
67-
{
68-
str = QString( "%1 %2 '%3'" )
69-
.arg( QgsExpression::quotedColumnRef( fieldName ) )
70-
.arg( numeric ? "=" : mCaseString )
71-
.arg( numeric
72-
? exp.replace( "'", "''" )
73-
:
74-
"%" + exp.replace( "'", "''" ) + "%" ); // escape quotes
75-
}
76-
mExpression = str;
77-
emit expressionChanged(mExpression);
55+
QVariant::Type fldType = layer()->pendingFields()[mFieldIdx].type();
56+
bool numeric = ( fldType == QVariant::Int || fldType == QVariant::Double || fldType == QVariant::LongLong );
57+
58+
QSettings settings;
59+
QString nullValue = settings.value( "qgis/nullValue", "NULL" ).toString();
60+
QString fieldName = layer()->pendingFields()[mFieldIdx].name();
61+
QString str;
62+
if ( exp == nullValue )
63+
{
64+
str = QString( "%1 IS NULL" ).arg( QgsExpression::quotedColumnRef( fieldName ) );
65+
}
66+
else
67+
{
68+
str = QString( "%1 %2 '%3'" )
69+
.arg( QgsExpression::quotedColumnRef( fieldName ) )
70+
.arg( numeric ? "=" : mCaseString )
71+
.arg( numeric
72+
? exp.replace( "'", "''" )
73+
:
74+
"%" + exp.replace( "'", "''" ) + "%" ); // escape quotes
75+
}
76+
mExpression = str;
77+
emit expressionChanged( mExpression );
7878
}
7979

8080
QWidget* QgsDefaultSearchWidgetWrapper::createWidget( QWidget* parent )
8181
{
8282
return new QWidget( parent );
8383
}
8484

85-
bool QgsDefaultSearchWidgetWrapper::applyDirectly()
85+
bool QgsDefaultSearchWidgetWrapper::applyDirectly()
8686
{
87-
return false;
87+
return false;
8888
}
8989

9090
void QgsDefaultSearchWidgetWrapper::initWidget( QWidget* widget )
9191
{
9292
mContainer = widget;
93-
mContainer->setLayout(new QHBoxLayout() );
93+
mContainer->setLayout( new QHBoxLayout() );
9494
mLineEdit = new QgsFilterLineEdit();
95-
mCheckbox = new QCheckBox("Case sensitive");
96-
mContainer->layout()->addWidget(mLineEdit);
97-
mContainer->layout()->addWidget(mCheckbox);
95+
mCheckbox = new QCheckBox( "Case sensitive" );
96+
mContainer->layout()->addWidget( mLineEdit );
97+
mContainer->layout()->addWidget( mCheckbox );
9898
connect( mLineEdit, SIGNAL( textChanged( QString ) ), this, SLOT( setExpression( QString ) ) );
99-
connect( mCheckbox, SIGNAL( stateChanged( int ) ), this, SLOT( setCaseString(int) ) );
100-
mCheckbox->setChecked(Qt::Unchecked);
99+
connect( mCheckbox, SIGNAL( stateChanged( int ) ), this, SLOT( setCaseString( int ) ) );
100+
mCheckbox->setChecked( Qt::Unchecked );
101101
mCaseString = "ILIKE";
102102
}
103+
104+
bool QgsDefaultSearchWidgetWrapper::valid()
105+
{
106+
return true;
107+
}

src/gui/editorwidgets/qgsdefaultsearchwidgetwrapper.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,15 @@ class GUI_EXPORT QgsDefaultSearchWidgetWrapper : public QgsSearchWidgetWrapper
3737
QString expression() override;
3838
bool applyDirectly() override;
3939
protected slots:
40-
void setExpression(QString exp) override;
40+
void setExpression( QString exp ) override;
4141

4242
private slots:
43-
void setCaseString(int);
44-
43+
void setCaseString( int );
44+
4545
protected:
4646
QWidget* createWidget( QWidget* parent ) override;
4747
void initWidget( QWidget* editor ) override;
48+
bool valid() override;
4849

4950
private:
5051
QgsFilterLineEdit* mLineEdit;

src/gui/editorwidgets/qgsenumerationwidgetwrapper.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ void QgsEnumerationWidgetWrapper::initWidget( QWidget* editor )
5757
}
5858
}
5959

60+
bool QgsEnumerationWidgetWrapper::valid()
61+
{
62+
return mComboBox;
63+
}
64+
6065
void QgsEnumerationWidgetWrapper::setValue( const QVariant& value )
6166
{
6267
if ( mComboBox )

0 commit comments

Comments
 (0)