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