diff --git a/python/core/qgseditformconfig.sip b/python/core/qgseditformconfig.sip index ee8e13674db..acc8f1a38fc 100644 --- a/python/core/qgseditformconfig.sip +++ b/python/core/qgseditformconfig.sip @@ -492,6 +492,22 @@ class QgsEditFormConfig : QObject */ void setExpression( int idx, const QString& str ); + /** + * Returns the constraint expression description of a specific filed. + * @param idx The index of the field + * @return the expression description + * @note added in QGIS 2.16 + */ + QString expressionDescription( int idx ) const; + + /** + * Set the constraint expression description for a specific field. + * @param idx The index of the field + * @param descr The description of the expression + * @note added in QGIS 2.16 + */ + void setExpressionDescription( int idx, const QString &descr ); + /** * Returns if the field at fieldidx should be treated as NOT NULL value */ diff --git a/python/gui/editorwidgets/core/qgseditorwidgetwrapper.sip b/python/gui/editorwidgets/core/qgseditorwidgetwrapper.sip index d50b593073f..7515f6600b5 100644 --- a/python/gui/editorwidgets/core/qgseditorwidgetwrapper.sip +++ b/python/gui/editorwidgets/core/qgseditorwidgetwrapper.sip @@ -115,6 +115,7 @@ class QgsEditorWidgetWrapper : QgsWidgetWrapper * Emit this signal when the constraint status changed. * @brief constraintStatusChanged * @param constraint represented as a string + * @param desc is the constraint description * @param err the error represented as a string. Empty if none. * @param status */ diff --git a/src/app/qgsattributetypedialog.cpp b/src/app/qgsattributetypedialog.cpp index 20e5779642a..6791bd94bf0 100644 --- a/src/app/qgsattributetypedialog.cpp +++ b/src/app/qgsattributetypedialog.cpp @@ -180,6 +180,16 @@ bool QgsAttributeTypeDialog::labelOnTop() const return labelOnTopCheckBox->isChecked(); } +void QgsAttributeTypeDialog::setExpressionDescription( const QString &desc ) +{ + constraintExpressionDescription->setText( desc ); +} + +QString QgsAttributeTypeDialog::expressionDescription() +{ + return constraintExpressionDescription->text(); +} + bool QgsAttributeTypeDialog::notNull() const { return notNullCheckBox->isChecked(); diff --git a/src/app/qgsattributetypedialog.h b/src/app/qgsattributetypedialog.h index b380a5899c9..012ea3e318d 100644 --- a/src/app/qgsattributetypedialog.h +++ b/src/app/qgsattributetypedialog.h @@ -85,7 +85,7 @@ class APP_EXPORT QgsAttributeTypeDialog: public QDialog, private Ui::QgsAttribut bool fieldEditable() const; /** - * Getter for checkbox for not null + * Setter for checkbox for not null */ void setNotNull( bool notNull ); @@ -94,6 +94,20 @@ class APP_EXPORT QgsAttributeTypeDialog: public QDialog, private Ui::QgsAttribut */ bool notNull() const; + /* + * Setter for constraint expression description + * @param desc the expression description + * @note added in QGIS 2.16 + **/ + void setExpressionDescription( const QString &desc ); + + /* + * Getter for constraint expression description + * @return the expression description + * @note added in QGIS 2.16 + **/ + QString expressionDescription(); + /** * Getter for the constraint expression * @note added in QGIS 2.16 diff --git a/src/app/qgsfieldsproperties.cpp b/src/app/qgsfieldsproperties.cpp index 0b026992ea8..8a0aa3dddff 100644 --- a/src/app/qgsfieldsproperties.cpp +++ b/src/app/qgsfieldsproperties.cpp @@ -529,6 +529,7 @@ void QgsFieldsProperties::attributeTypeDialog() attributeTypeDialog.setLabelOnTop( cfg.mLabelOnTop ); attributeTypeDialog.setNotNull( cfg.mNotNull ); attributeTypeDialog.setExpression( cfg.mConstraint ); + attributeTypeDialog.setExpressionDescription( cfg.mConstraintDescription ); attributeTypeDialog.setWidgetV2Config( cfg.mEditorWidgetV2Config ); attributeTypeDialog.setWidgetV2Type( cfg.mEditorWidgetV2Type ); @@ -539,6 +540,7 @@ void QgsFieldsProperties::attributeTypeDialog() cfg.mEditable = attributeTypeDialog.fieldEditable(); cfg.mLabelOnTop = attributeTypeDialog.labelOnTop(); cfg.mNotNull = attributeTypeDialog.notNull(); + cfg.mConstraintDescription = attributeTypeDialog.expressionDescription(); cfg.mConstraint = attributeTypeDialog.expression(); cfg.mEditorWidgetV2Type = attributeTypeDialog.editorWidgetV2Type(); @@ -913,6 +915,7 @@ void QgsFieldsProperties::apply() mLayer->editFormConfig()->setReadOnly( i, !cfg.mEditable ); mLayer->editFormConfig()->setLabelOnTop( i, cfg.mLabelOnTop ); mLayer->editFormConfig()->setNotNull( i, cfg.mNotNull ); + mLayer->editFormConfig()->setExpressionDescription( i, cfg.mConstraintDescription ); mLayer->editFormConfig()->setExpression( i, cfg.mConstraint ); mLayer->editFormConfig()->setWidgetType( idx, cfg.mEditorWidgetV2Type ); @@ -981,6 +984,7 @@ QgsFieldsProperties::FieldConfig::FieldConfig() , mEditableEnabled( true ) , mLabelOnTop( false ) , mNotNull( false ) + , mConstraintDescription( QString() ) , mButton( nullptr ) { } @@ -994,6 +998,7 @@ QgsFieldsProperties::FieldConfig::FieldConfig( QgsVectorLayer* layer, int idx ) mLabelOnTop = layer->editFormConfig()->labelOnTop( idx ); mNotNull = layer->editFormConfig()->notNull( idx ); mConstraint = layer->editFormConfig()->expression( idx ); + mConstraintDescription = layer->editFormConfig()->expressionDescription( idx ); mEditorWidgetV2Type = layer->editFormConfig()->widgetType( idx ); mEditorWidgetV2Config = layer->editFormConfig()->widgetConfig( idx ); diff --git a/src/app/qgsfieldsproperties.h b/src/app/qgsfieldsproperties.h index 1d982c99111..39d96eb6e82 100644 --- a/src/app/qgsfieldsproperties.h +++ b/src/app/qgsfieldsproperties.h @@ -94,6 +94,7 @@ class APP_EXPORT QgsFieldsProperties : public QWidget, private Ui_QgsFieldsPrope bool mLabelOnTop; bool mNotNull; QString mConstraint; + QString mConstraintDescription; QPushButton* mButton; QString mEditorWidgetV2Type; QMap mEditorWidgetV2Config; diff --git a/src/core/qgseditformconfig.cpp b/src/core/qgseditformconfig.cpp index b6404ab8fa2..17ee3bd7d71 100644 --- a/src/core/qgseditformconfig.cpp +++ b/src/core/qgseditformconfig.cpp @@ -135,6 +135,22 @@ void QgsEditFormConfig::setExpression( int idx, const QString& str ) mConstraints[ mFields.at( idx ).name()] = str; } +QString QgsEditFormConfig::expressionDescription( int idx ) const +{ + QString description; + + if ( idx >= 0 && idx < mFields.count() ) + description = mConstraintsDescription[ mFields.at( idx ).name()]; + + return description; +} + +void QgsEditFormConfig::setExpressionDescription( int idx, const QString &descr ) +{ + if ( idx >= 0 && idx < mFields.count() ) + mConstraintsDescription[ mFields.at( idx ).name()] = descr; +} + bool QgsEditFormConfig::notNull( int idx ) const { if ( idx >= 0 && idx < mFields.count() ) diff --git a/src/core/qgseditformconfig.h b/src/core/qgseditformconfig.h index 0371314fc03..4d0c7634fcf 100644 --- a/src/core/qgseditformconfig.h +++ b/src/core/qgseditformconfig.h @@ -484,12 +484,12 @@ class CORE_EXPORT QgsEditFormConfig : public QObject QgsEditorWidgetConfig widgetConfig( const QString& widgetName ) const; /** - * Remove the configuration for the editor widget used to represent the field at the given index - * - * @param fieldIdx The index of the field - * - * @return true if successful, false if the field does not exist - */ + * Remove the configuration for the editor widget used to represent the field at the given index + * + * @param fieldIdx The index of the field + * + * @return true if successful, false if the field does not exist + */ bool removeWidgetConfig( int fieldIdx ); /** @@ -528,6 +528,22 @@ class CORE_EXPORT QgsEditFormConfig : public QObject */ void setExpression( int idx, const QString& str ); + /** + * Returns the constraint expression description of a specific filed. + * @param idx The index of the field + * @return the expression description + * @note added in QGIS 2.16 + */ + QString expressionDescription( int idx ) const; + + /** + * Set the constraint expression description for a specific field. + * @param idx The index of the field + * @param descr The description of the expression + * @note added in QGIS 2.16 + */ + void setExpressionDescription( int idx, const QString &descr ); + /** * Returns if the field at fieldidx should be treated as NOT NULL value */ @@ -657,6 +673,7 @@ class CORE_EXPORT QgsEditFormConfig : public QObject QList< TabData > mTabs; QMap< QString, QString> mConstraints; + QMap< QString, QString> mConstraintsDescription; QMap< QString, bool> mFieldEditables; QMap< QString, bool> mLabelOnTop; QMap< QString, bool> mNotNull; diff --git a/src/gui/editorwidgets/core/qgseditorwidgetregistry.cpp b/src/gui/editorwidgets/core/qgseditorwidgetregistry.cpp index 3c16faf8be5..649f2d35bdc 100644 --- a/src/gui/editorwidgets/core/qgseditorwidgetregistry.cpp +++ b/src/gui/editorwidgets/core/qgseditorwidgetregistry.cpp @@ -253,6 +253,7 @@ void QgsEditorWidgetRegistry::readMapLayer( QgsMapLayer* mapLayer, const QDomEle vectorLayer->editFormConfig()->setLabelOnTop( idx, ewv2CfgElem.attribute( "labelOnTop", "0" ) == "1" ); vectorLayer->editFormConfig()->setNotNull( idx, ewv2CfgElem.attribute( "notNull", "0" ) == "1" ); vectorLayer->editFormConfig()->setExpression( idx, ewv2CfgElem.attribute( "constraint", QString() ) ); + vectorLayer->editFormConfig()->setExpressionDescription( idx, ewv2CfgElem.attribute( "constraintDescription", QString() ) ); vectorLayer->editFormConfig()->setWidgetConfig( idx, cfg ); } @@ -312,6 +313,7 @@ void QgsEditorWidgetRegistry::writeMapLayer( QgsMapLayer* mapLayer, QDomElement& ewv2CfgElem.setAttribute( "labelOnTop", vectorLayer->editFormConfig()->labelOnTop( idx ) ); ewv2CfgElem.setAttribute( "notNull", vectorLayer->editFormConfig()->notNull( idx ) ); ewv2CfgElem.setAttribute( "constraint", vectorLayer->editFormConfig()->expression( idx ) ); + ewv2CfgElem.setAttribute( "constraintDescription", vectorLayer->editFormConfig()->expressionDescription( idx ) ); mWidgetFactories[widgetType]->writeConfig( vectorLayer->editFormConfig()->widgetConfig( idx ), ewv2CfgElem, doc, vectorLayer, idx ); diff --git a/src/gui/editorwidgets/core/qgseditorwidgetwrapper.cpp b/src/gui/editorwidgets/core/qgseditorwidgetwrapper.cpp index c0e8372c07b..7e4056b2283 100644 --- a/src/gui/editorwidgets/core/qgseditorwidgetwrapper.cpp +++ b/src/gui/editorwidgets/core/qgseditorwidgetwrapper.cpp @@ -108,10 +108,13 @@ void QgsEditorWidgetWrapper::updateConstraint( const QgsFeature &ft ) bool toEmit( false ); QString errStr( tr( "predicate is True" ) ); QString expression = layer()->editFormConfig()->expression( mFieldIdx ); + QString description; QVariant value = ft.attribute( mFieldIdx ); if ( ! expression.isEmpty() ) { + description = layer()->editFormConfig()->expressionDescription( mFieldIdx ); + QgsExpressionContext context = QgsExpressionContextUtils::createFeatureBasedContext( ft, *ft.fields() ); context << QgsExpressionContextUtils::layerScope( layer() ); @@ -139,9 +142,13 @@ void QgsEditorWidgetWrapper::updateConstraint( const QgsFeature &ft ) { QString fieldName = ft.fields()->field( mFieldIdx ).name(); expression = "( " + expression + " ) AND ( " + fieldName + " IS NOT NULL)"; + description = "( " + description + " ) AND NotNull"; } else + { + description = "NotNull"; expression = "NotNull"; + } mValidConstraint = mValidConstraint && !value.isNull(); @@ -154,7 +161,7 @@ void QgsEditorWidgetWrapper::updateConstraint( const QgsFeature &ft ) if ( toEmit ) { updateConstraintWidgetStatus(); - emit constraintStatusChanged( expression, errStr, mValidConstraint ); + emit constraintStatusChanged( expression, description, errStr, mValidConstraint ); } } diff --git a/src/gui/editorwidgets/core/qgseditorwidgetwrapper.h b/src/gui/editorwidgets/core/qgseditorwidgetwrapper.h index 38b8a89a760..d6ec48612e3 100644 --- a/src/gui/editorwidgets/core/qgseditorwidgetwrapper.h +++ b/src/gui/editorwidgets/core/qgseditorwidgetwrapper.h @@ -137,10 +137,11 @@ class GUI_EXPORT QgsEditorWidgetWrapper : public QgsWidgetWrapper * Emit this signal when the constraint status changed. * @brief constraintStatusChanged * @param constraint represented as a string + * @param desc is the constraint description * @param err the error represented as a string. Empty if none. * @param status */ - void constraintStatusChanged( const QString& constraint, const QString& err, bool status ); + void constraintStatusChanged( const QString& constraint, const QString &desc, const QString& err, bool status ); public slots: /** diff --git a/src/gui/qgsattributeform.cpp b/src/gui/qgsattributeform.cpp index f68ec46f8cd..91057fda794 100644 --- a/src/gui/qgsattributeform.cpp +++ b/src/gui/qgsattributeform.cpp @@ -795,17 +795,26 @@ void QgsAttributeForm::clearInvalidConstraintsMessage() } } -void QgsAttributeForm::displayInvalidConstraintMessage( const QStringList &f ) +void QgsAttributeForm::displayInvalidConstraintMessage( const QStringList &f, + const QStringList &d ) { clearInvalidConstraintsMessage(); + // show only the third first error + int max = 3; + int size = f.size() > max ? max : f.size(); + QString descriptions; + for ( int i = 0; i < size; i++ ) + descriptions += "
- " + f[i] + ": " + d[i]; + mInvalidConstraintMessageBarItem = - new QgsMessageBarItem( tr( "Invalid fields:" ), - f.join( ", " ), QgsMessageBar::WARNING ); + new QgsMessageBarItem( tr( "Invalid fields: " ), + descriptions, QgsMessageBar::WARNING ); mMessageBar->pushItem( mInvalidConstraintMessageBarItem ); } -bool QgsAttributeForm::currentFormValidConstraints( QStringList &invalidFields ) +bool QgsAttributeForm::currentFormValidConstraints( QStringList &invalidFields, + QStringList &descriptions ) { bool valid( true ); @@ -817,6 +826,10 @@ bool QgsAttributeForm::currentFormValidConstraints( QStringList &invalidFields ) if ( ! eww->isValidConstraint() ) { invalidFields.append( eww->field().name() ); + + QString desc = eww->layer()->editFormConfig()->expressionDescription( eww->fieldIdx() ); + descriptions.append( desc ); + valid = false; // continue to get all invalif fields } } @@ -883,7 +896,7 @@ void QgsAttributeForm::onUpdatedFields() } void QgsAttributeForm::onConstraintStatusChanged( const QString& constraint, - const QString& err, bool ok ) + const QString &description, const QString& err, bool ok ) { QgsEditorWidgetWrapper* eww = qobject_cast( sender() ); Q_ASSERT( eww ); @@ -892,7 +905,8 @@ void QgsAttributeForm::onConstraintStatusChanged( const QString& constraint, if ( buddy ) { - QString tooltip = tr( "Expression: " ) + constraint + "\n" + tr( "Constraint: " ) + err; + QString tooltip = tr( "Description: " ) + description + "\n" + + tr( "Raw expression: " ) + constraint + "\n" + tr( "Constraint: " ) + err; buddy->setToolTip( tooltip ); if ( !buddy->property( "originalText" ).isValid() ) @@ -986,11 +1000,11 @@ void QgsAttributeForm::synchronizeEnabledState() // push a message and disable the OK button if constraints are invalid clearInvalidConstraintsMessage(); - QStringList invalidFields; - bool validConstraint = currentFormValidConstraints( invalidFields ); + QStringList invalidFields, descriptions; + bool validConstraint = currentFormValidConstraints( invalidFields, descriptions ); if ( ! validConstraint ) - displayInvalidConstraintMessage( invalidFields ); + displayInvalidConstraintMessage( invalidFields, descriptions ); isEditable = isEditable & validConstraint; @@ -1205,7 +1219,6 @@ void QgsAttributeForm::init() } mButtonBox->setVisible( buttonBoxVisible ); -<<<<<<< HEAD if ( !mSearchButtonBox ) { mSearchButtonBox = new QWidget(); @@ -1618,7 +1631,8 @@ void QgsAttributeForm::afterWidgetInit() } connect( eww, SIGNAL( valueChanged( const QVariant& ) ), this, SLOT( onAttributeChanged( const QVariant& ) ) ); - connect( eww, SIGNAL( constraintStatusChanged( QString, QString, bool ) ), this, SLOT( onConstraintStatusChanged( QString, QString, bool ) ) ); + connect( eww, SIGNAL( constraintStatusChanged( QString, QString, QString, bool ) ), + this, SLOT( onConstraintStatusChanged( QString, QString, QString, bool ) ) ); } } diff --git a/src/gui/qgsattributeform.h b/src/gui/qgsattributeform.h index 36803dcef04..319daf71674 100644 --- a/src/gui/qgsattributeform.h +++ b/src/gui/qgsattributeform.h @@ -234,8 +234,8 @@ class GUI_EXPORT QgsAttributeForm : public QWidget void onAttributeAdded( int idx ); void onAttributeDeleted( int idx ); void onUpdatedFields(); - void onConstraintStatusChanged( const QString& constraint, const QString& err, bool ok ); - + void onConstraintStatusChanged( const QString& constraint, + const QString &description, const QString& err, bool ok ); void preventFeatureRefresh(); void synchronizeEnabledState(); void layerSelectionChanged(); @@ -302,10 +302,11 @@ class GUI_EXPORT QgsAttributeForm : public QWidget void updateAllConstaints(); void updateConstraints( QgsEditorWidgetWrapper *w ); bool currentFormFeature( QgsFeature &feature ); - bool currentFormValidConstraints( QStringList &invalidFields ); + bool currentFormValidConstraints( QStringList &invalidFields, QStringList &descriptions ); void constraintDependencies( QgsEditorWidgetWrapper *w, QList &wDeps ); void clearInvalidConstraintsMessage(); - void displayInvalidConstraintMessage( const QStringList &invalidFields ); + void displayInvalidConstraintMessage( const QStringList &invalidFields, + const QStringList &description ); void displayNullFieldsMessage(); QgsMessageBarItem *mInvalidConstraintMessageBarItem; QgsMessageBarItem *mFieldNotInitializedMessageBarItem; diff --git a/src/ui/qgsattributetypeedit.ui b/src/ui/qgsattributetypeedit.ui index e488e8b4854..e8175b7298d 100644 --- a/src/ui/qgsattributetypeedit.ui +++ b/src/ui/qgsattributetypeedit.ui @@ -74,6 +74,23 @@ + + + + 0 + + + + + Constraint description + + + + + + + +