1 /***************************************************************************
2 qgseditorwidgetwrapper.cpp
3 --------------------------------------
4 Date : 20.4.2013
5 Copyright : (C) 2013 Matthias Kuhn
6 Email : matthias at opengis dot ch
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16 #include "qgseditorwidgetwrapper.h"
17 #include "qgsvectorlayer.h"
18 #include "qgsvectordataprovider.h"
19 #include "qgsfields.h"
20 #include "qgsvectorlayerutils.h"
21 #include "qgsvectorlayerjoinbuffer.h"
22 #include "qgsvectorlayerjoininfo.h"
23
24 #include <QTableView>
25
QgsEditorWidgetWrapper(QgsVectorLayer * vl,int fieldIdx,QWidget * editor,QWidget * parent)26 QgsEditorWidgetWrapper::QgsEditorWidgetWrapper( QgsVectorLayer *vl, int fieldIdx, QWidget *editor, QWidget *parent )
27 : QgsWidgetWrapper( vl, editor, parent )
28 , mFieldIdx( fieldIdx )
29 , mValidConstraint( true )
30 , mIsBlockingCommit( false )
31 {
32 }
33
fieldIdx() const34 int QgsEditorWidgetWrapper::fieldIdx() const
35 {
36 return mFieldIdx;
37 }
38
field() const39 QgsField QgsEditorWidgetWrapper::field() const
40 {
41 QgsVectorLayer *vl = layer();
42 if ( vl && mFieldIdx < vl->fields().count() )
43 return vl->fields().at( mFieldIdx );
44 else
45 return QgsField();
46 }
47
defaultValue() const48 QVariant QgsEditorWidgetWrapper::defaultValue() const
49 {
50 mDefaultValue = layer()->dataProvider()->defaultValueClause( mFieldIdx );
51
52 return mDefaultValue;
53 }
54
fromWidget(QWidget * widget)55 QgsEditorWidgetWrapper *QgsEditorWidgetWrapper::fromWidget( QWidget *widget )
56 {
57 return qobject_cast<QgsEditorWidgetWrapper *>( widget->property( "EWV2Wrapper" ).value<QgsWidgetWrapper *>() );
58 }
59
setEnabled(bool enabled)60 void QgsEditorWidgetWrapper::setEnabled( bool enabled )
61 {
62 QWidget *wdg = widget();
63 if ( wdg )
64 {
65 wdg->setEnabled( enabled );
66 }
67 }
68
setFeature(const QgsFeature & feature)69 void QgsEditorWidgetWrapper::setFeature( const QgsFeature &feature )
70 {
71 setFormFeature( feature );
72 QVariantList newAdditionalFieldValues;
73 const QStringList constAdditionalFields = additionalFields();
74 for ( const QString &fieldName : constAdditionalFields )
75 newAdditionalFieldValues << feature.attribute( fieldName );
76 setValues( feature.attribute( mFieldIdx ), newAdditionalFieldValues );
77 }
78
setValue(const QVariant & value)79 void QgsEditorWidgetWrapper::setValue( const QVariant &value )
80 {
81 isRunningDeprecatedSetValue = true;
82 updateValues( value, QVariantList() );
83 isRunningDeprecatedSetValue = false;
84 }
85
setValues(const QVariant & value,const QVariantList & additionalValues)86 void QgsEditorWidgetWrapper::setValues( const QVariant &value, const QVariantList &additionalValues )
87 {
88 updateValues( value, additionalValues );
89 }
90
emitValueChanged()91 void QgsEditorWidgetWrapper::emitValueChanged()
92 {
93 Q_NOWARN_DEPRECATED_PUSH
94 emit valueChanged( value() );
95 Q_NOWARN_DEPRECATED_POP
96 emit valuesChanged( value(), additionalFieldValues() );
97 }
98
parentFormValueChanged(const QString & attribute,const QVariant & value)99 void QgsEditorWidgetWrapper::parentFormValueChanged( const QString &attribute, const QVariant &value )
100 {
101 Q_UNUSED( attribute )
102 Q_UNUSED( value )
103 }
104
updateConstraintWidgetStatus()105 void QgsEditorWidgetWrapper::updateConstraintWidgetStatus()
106 {
107 if ( !mConstraintResultVisible )
108 {
109 widget()->setStyleSheet( QString() );
110 }
111 else
112 {
113 switch ( mConstraintResult )
114 {
115 case ConstraintResultPass:
116 widget()->setStyleSheet( QString() );
117 break;
118
119 case ConstraintResultFailHard:
120 widget()->setStyleSheet( QStringLiteral( "background-color: #FFE0B2;" ) );
121 break;
122
123 case ConstraintResultFailSoft:
124 widget()->setStyleSheet( QStringLiteral( "background-color: #FFECB3;" ) );
125 break;
126 }
127 }
128 }
129
setFormFeatureAttribute(const QString & attributeName,const QVariant & attributeValue)130 bool QgsEditorWidgetWrapper::setFormFeatureAttribute( const QString &attributeName, const QVariant &attributeValue )
131 {
132 return mFormFeature.setAttribute( attributeName, attributeValue );
133 }
134
updateValues(const QVariant & value,const QVariantList & additionalValues)135 void QgsEditorWidgetWrapper::updateValues( const QVariant &value, const QVariantList &additionalValues )
136 {
137 // this method should be made pure virtual in QGIS 4
138 Q_UNUSED( additionalValues );
139 Q_NOWARN_DEPRECATED_PUSH
140 // avoid infinite recursive loop
141 if ( !isRunningDeprecatedSetValue )
142 setValue( value );
143 Q_NOWARN_DEPRECATED_POP
144 }
145
constraintResult() const146 QgsEditorWidgetWrapper::ConstraintResult QgsEditorWidgetWrapper::constraintResult() const
147 {
148 return mConstraintResult;
149 }
150
constraintResultVisible() const151 bool QgsEditorWidgetWrapper::constraintResultVisible() const
152 {
153 return mConstraintResultVisible;
154 }
155
setConstraintResultVisible(bool constraintResultVisible)156 void QgsEditorWidgetWrapper::setConstraintResultVisible( bool constraintResultVisible )
157 {
158 if ( mConstraintResultVisible == constraintResultVisible )
159 return;
160
161 mConstraintResultVisible = constraintResultVisible;
162
163 updateConstraintWidgetStatus();
164
165 emit constraintResultVisibleChanged( mConstraintResultVisible );
166 }
167
updateConstraint(const QgsFeature & ft,QgsFieldConstraints::ConstraintOrigin constraintOrigin)168 void QgsEditorWidgetWrapper::updateConstraint( const QgsFeature &ft, QgsFieldConstraints::ConstraintOrigin constraintOrigin )
169 {
170 updateConstraint( layer(), mFieldIdx, ft, constraintOrigin );
171 }
172
updateConstraint(const QgsVectorLayer * layer,int index,const QgsFeature & ft,QgsFieldConstraints::ConstraintOrigin constraintOrigin)173 void QgsEditorWidgetWrapper::updateConstraint( const QgsVectorLayer *layer, int index, const QgsFeature &ft, QgsFieldConstraints::ConstraintOrigin constraintOrigin )
174 {
175 QStringList errors;
176 QStringList softErrors;
177 QStringList expressions;
178 QStringList descriptions;
179 bool toEmit( false );
180 bool hardConstraintsOk( true );
181 bool softConstraintsOk( true );
182
183 QgsField field = layer->fields().at( index );
184 QString expression = field.constraints().constraintExpression();
185
186 if ( ft.isValid() )
187 {
188 if ( ! expression.isEmpty() )
189 {
190 expressions << expression;
191 descriptions << field.constraints().constraintDescription();
192 toEmit = true;
193 }
194
195 if ( field.constraints().constraints() & QgsFieldConstraints::ConstraintNotNull )
196 {
197 descriptions << tr( "Not NULL" );
198 if ( !expression.isEmpty() )
199 {
200 expressions << field.name() + QStringLiteral( " IS NOT NULL" );
201 }
202 else
203 {
204 expressions << QStringLiteral( "IS NOT NULL" );
205 }
206 toEmit = true;
207 }
208
209 if ( field.constraints().constraints() & QgsFieldConstraints::ConstraintUnique )
210 {
211 descriptions << tr( "Unique" );
212 if ( !expression.isEmpty() )
213 {
214 expressions << field.name() + QStringLiteral( " IS UNIQUE" );
215 }
216 else
217 {
218 expressions << QStringLiteral( "IS UNIQUE" );
219 }
220 toEmit = true;
221 }
222
223 hardConstraintsOk = QgsVectorLayerUtils::validateAttribute( layer, ft, index, errors, QgsFieldConstraints::ConstraintStrengthHard, constraintOrigin );
224
225 softConstraintsOk = QgsVectorLayerUtils::validateAttribute( layer, ft, index, softErrors, QgsFieldConstraints::ConstraintStrengthSoft, constraintOrigin );
226 errors << softErrors;
227 }
228 else // invalid feature
229 {
230 if ( ! expression.isEmpty() )
231 {
232 hardConstraintsOk = true;
233 softConstraintsOk = false;
234
235 errors << QStringLiteral( "Invalid feature" );
236
237 toEmit = true;
238 }
239 }
240
241 mValidConstraint = hardConstraintsOk && softConstraintsOk;
242 mIsBlockingCommit = !hardConstraintsOk;
243
244 mConstraintFailureReason = errors.join( QLatin1String( ", " ) );
245
246 if ( toEmit )
247 {
248 QString errStr = errors.isEmpty() ? tr( "Constraint checks passed" ) : mConstraintFailureReason;
249
250 QString description = descriptions.join( QLatin1String( ", " ) );
251 QString expressionDesc;
252 if ( expressions.size() > 1 )
253 expressionDesc = "( " + expressions.join( QLatin1String( " ) AND ( " ) ) + " )";
254 else if ( !expressions.isEmpty() )
255 expressionDesc = expressions.at( 0 );
256
257 ConstraintResult result = !hardConstraintsOk ? ConstraintResultFailHard
258 : ( !softConstraintsOk ? ConstraintResultFailSoft : ConstraintResultPass );
259 //set the constraint result
260 mConstraintResult = result;
261 updateConstraintWidgetStatus();
262 emit constraintStatusChanged( expressionDesc, description, errStr, result );
263 }
264 }
265
isValidConstraint() const266 bool QgsEditorWidgetWrapper::isValidConstraint() const
267 {
268 return mValidConstraint;
269 }
270
isBlockingCommit() const271 bool QgsEditorWidgetWrapper::isBlockingCommit() const
272 {
273 return mIsBlockingCommit;
274 }
275
276
constraintFailureReason() const277 QString QgsEditorWidgetWrapper::constraintFailureReason() const
278 {
279 return mConstraintFailureReason;
280 }
281
isInTable(const QWidget * parent)282 bool QgsEditorWidgetWrapper::isInTable( const QWidget *parent )
283 {
284 if ( !parent ) return false;
285 if ( qobject_cast<const QTableView *>( parent ) ) return true;
286 return isInTable( parent->parentWidget() );
287 }
288
setHint(const QString & hintText)289 void QgsEditorWidgetWrapper::setHint( const QString &hintText )
290 {
291 if ( QWidget *w = widget() )
292 w->setToolTip( hintText );
293 }
294