Skip to content
Permalink
Browse files

[QgsQuick] Added soft and hard constraints in the form (#38742)

* [QgsQuick] Added soft and hard constraints in the form

* [QgsQuick] Fixed field description label in the QgsQuick form

* [QgsQuick] code layout

Co-authored-by: vsklencar <viktor.sklencar@lutraconsulting.co.uk>
  • Loading branch information
sklencar and vsklencar committed Oct 27, 2020
1 parent 730c554 commit f9dfea8dab79a329c95d47b9fd00b56ee367cfd6
@@ -23,7 +23,8 @@ QgsQuickAttributeFormModel::QgsQuickAttributeFormModel( QObject *parent )
setSourceModel( mSourceModel );
connect( mSourceModel, &QgsQuickAttributeFormModelBase::hasTabsChanged, this, &QgsQuickAttributeFormModel::hasTabsChanged );
connect( mSourceModel, &QgsQuickAttributeFormModelBase::attributeModelChanged, this, &QgsQuickAttributeFormModel::attributeModelChanged );
connect( mSourceModel, &QgsQuickAttributeFormModelBase::constraintsValidChanged, this, &QgsQuickAttributeFormModel::constraintsValidChanged );
connect( mSourceModel, &QgsQuickAttributeFormModelBase::constraintsHardValidChanged, this, &QgsQuickAttributeFormModel::constraintsHardValidChanged );
connect( mSourceModel, &QgsQuickAttributeFormModelBase::constraintsSoftValidChanged, this, &QgsQuickAttributeFormModel::constraintsSoftValidChanged );
}

bool QgsQuickAttributeFormModel::hasTabs() const
@@ -46,9 +47,14 @@ void QgsQuickAttributeFormModel::setAttributeModel( QgsQuickAttributeModel *attr
mSourceModel->setAttributeModel( attributeModel );
}

bool QgsQuickAttributeFormModel::constraintsValid() const
bool QgsQuickAttributeFormModel::constraintsHardValid() const
{
return mSourceModel->constraintsValid();
return mSourceModel->constraintsHardValid();
}

bool QgsQuickAttributeFormModel::constraintsSoftValid() const
{
return mSourceModel->constraintsSoftValid();
}

void QgsQuickAttributeFormModel::save()
@@ -49,8 +49,10 @@ class QUICK_EXPORT QgsQuickAttributeFormModel : public QSortFilterProxyModel
//! Whether use tabs layout
Q_PROPERTY( bool hasTabs READ hasTabs WRITE setHasTabs NOTIFY hasTabsChanged )

//! Returns TRUE if all constraints defined on fields are satisfied with the current attribute values
Q_PROPERTY( bool constraintsValid READ constraintsValid NOTIFY constraintsValidChanged )
//! Returns TRUE if all hard constraints defined on fields are satisfied with the current attribute values
Q_PROPERTY( bool constraintsHardValid READ constraintsHardValid NOTIFY constraintsHardValidChanged )
//! Returns TRUE if all soft constraints defined on fields are satisfied with the current attribute values
Q_PROPERTY( bool constraintsSoftValid READ constraintsSoftValid NOTIFY constraintsSoftValidChanged )

public:

@@ -69,7 +71,8 @@ class QUICK_EXPORT QgsQuickAttributeFormModel : public QSortFilterProxyModel
Group, //!< Group
AttributeEditorElement, //!< Attribute editor element
CurrentlyVisible, //!< Field visible
ConstraintValid, //!< Contraint valid
ConstraintSoftValid, //! Constraint soft valid
ConstraintHardValid, //! Constraint hard valid
ConstraintDescription //!< Contraint description
};

@@ -90,8 +93,11 @@ class QUICK_EXPORT QgsQuickAttributeFormModel : public QSortFilterProxyModel
//! \copydoc QgsQuickAttributeFormModel::attributeModel
void setAttributeModel( QgsQuickAttributeModel *attributeModel );

//! \copydoc QgsQuickAttributeFormModel::constraintsValid
bool constraintsValid() const;
//! \copydoc QgsQuickAttributeFormModel::constraintsHardValid
bool constraintsHardValid() const;

//! \copydoc QgsQuickAttributeFormModel::constraintsSoftValid
bool constraintsSoftValid() const;

//! Updates QgsFeature based on changes
Q_INVOKABLE void save();
@@ -109,8 +115,11 @@ class QUICK_EXPORT QgsQuickAttributeFormModel : public QSortFilterProxyModel
//! \copydoc QgsQuickAttributeFormModel::hasTabs
void hasTabsChanged();

//! \copydoc QgsQuickAttributeFormModel::constraintsValid
void constraintsValidChanged();
//! \copydoc QgsQuickAttributeFormModel::constraintsHardValid
void constraintsHardValidChanged();

//! \copydoc QgsQuickAttributeFormModel::constraintsSoftValid
void constraintsSoftValidChanged();

protected:
virtual bool filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const override;
@@ -18,6 +18,7 @@

#include "qgsquickattributeformmodelbase.h"
#include "qgsquickattributeformmodel.h"
#include <qgsvectorlayerutils.h>

/// @cond PRIVATE

@@ -40,7 +41,8 @@ QHash<int, QByteArray> QgsQuickAttributeFormModelBase::roleNames() const
roles[QgsQuickAttributeFormModel::RememberValue] = QByteArray( "RememberValue" );
roles[QgsQuickAttributeFormModel::Field] = QByteArray( "Field" );
roles[QgsQuickAttributeFormModel::Group] = QByteArray( "Group" );
roles[QgsQuickAttributeFormModel::ConstraintValid] = QByteArray( "ConstraintValid" );
roles[QgsQuickAttributeFormModel::ConstraintHardValid] = "ConstraintHardValid";
roles[QgsQuickAttributeFormModel::ConstraintSoftValid] = "ConstraintSoftValid";
roles[QgsQuickAttributeFormModel::ConstraintDescription] = QByteArray( "ConstraintDescription" );

return roles;
@@ -261,14 +263,32 @@ void QgsQuickAttributeFormModelBase::flatten( QgsAttributeEditorContainer *conta
item->setData( fieldIndex, QgsQuickAttributeFormModel::FieldIndex );
item->setData( container->isGroupBox() ? container->name() : QString(), QgsQuickAttributeFormModel::Group );
item->setData( true, QgsQuickAttributeFormModel::CurrentlyVisible );
item->setData( true, QgsQuickAttributeFormModel::ConstraintValid );
item->setData( true, QgsQuickAttributeFormModel::ConstraintHardValid );
item->setData( true, QgsQuickAttributeFormModel::ConstraintSoftValid );
item->setData( field.constraints().constraintDescription(), QgsQuickAttributeFormModel::ConstraintDescription );

if ( !field.constraints().constraintExpression().isEmpty() )
QStringList expressions;
QStringList descriptions;
QString expression = field.constraints().constraintExpression();

if ( !expression.isEmpty() )
{
descriptions << field.constraints().constraintDescription();
expressions << field.constraints().constraintExpression();
}

if ( field.constraints().constraints() & QgsFieldConstraints::ConstraintNotNull )
{
mConstraints.insert( item, field.constraints().constraintExpression() );
descriptions << tr( "Not NULL" );
}

if ( field.constraints().constraints() & QgsFieldConstraints::ConstraintUnique )
{
descriptions << tr( "Unique" );
}

mConstraints.insert( item, field.constraints() );

items.append( item );

parent->appendRow( item );
@@ -318,32 +338,50 @@ void QgsQuickAttributeFormModelBase::updateVisibility( int fieldIndex )
}
}

bool allConstraintsValid = true;
QMap<QStandardItem *, QgsExpression>::ConstIterator constraintIterator( mConstraints.constBegin() );
bool allConstraintsHardValid = true;
bool allConstraintsSoftValid = true;

QMap<QStandardItem *, QgsFieldConstraints>::ConstIterator constraintIterator( mConstraints.constBegin() );
for ( ; constraintIterator != mConstraints.constEnd(); ++constraintIterator )
{
QStandardItem *item = constraintIterator.key();
QgsExpression exp = constraintIterator.value();
exp.prepare( &mExpressionContext );
bool constraintSatisfied = exp.evaluate( &mExpressionContext ).toBool();
int fidx = item->data( QgsQuickAttributeFormModel::FieldIndex ).toInt();

if ( constraintSatisfied != item->data( QgsQuickAttributeFormModel::ConstraintValid ).toBool() )
QStringList errors;
bool hardConstraintSatisfied = QgsVectorLayerUtils::validateAttribute( mLayer, mAttributeModel->featureLayerPair().feature(), fidx, errors, QgsFieldConstraints::ConstraintStrengthHard );
if ( hardConstraintSatisfied != item->data( QgsQuickAttributeFormModel::ConstraintHardValid ).toBool() )
{
item->setData( hardConstraintSatisfied, QgsQuickAttributeFormModel::ConstraintHardValid );
}
if ( !item->data( QgsQuickAttributeFormModel::ConstraintHardValid ).toBool() )
{
item->setData( constraintSatisfied, QgsQuickAttributeFormModel::ConstraintValid );
allConstraintsHardValid = false;
}

if ( !item->data( QgsQuickAttributeFormModel::ConstraintValid ).toBool() )
QStringList softErrors;
bool softConstraintSatisfied = QgsVectorLayerUtils::validateAttribute( mLayer, mAttributeModel->featureLayerPair().feature(), fidx, softErrors, QgsFieldConstraints::ConstraintStrengthSoft );
if ( softConstraintSatisfied != item->data( QgsQuickAttributeFormModel::ConstraintSoftValid ).toBool() )
{
allConstraintsValid = false;
item->setData( softConstraintSatisfied, QgsQuickAttributeFormModel::ConstraintSoftValid );
}
if ( !item->data( QgsQuickAttributeFormModel::ConstraintSoftValid ).toBool() )
{
allConstraintsSoftValid = false;
}
}

setConstraintsValid( allConstraintsValid );
setConstraintsHardValid( allConstraintsHardValid );
setConstraintsSoftValid( allConstraintsSoftValid );
}

bool QgsQuickAttributeFormModelBase::constraintsHardValid() const
{
return mConstraintsHardValid;
}

bool QgsQuickAttributeFormModelBase::constraintsValid() const
bool QgsQuickAttributeFormModelBase::constraintsSoftValid() const
{
return mConstraintsValid;
return mConstraintsSoftValid;
}

QVariant QgsQuickAttributeFormModelBase::attribute( const QString &name ) const
@@ -355,13 +393,22 @@ QVariant QgsQuickAttributeFormModelBase::attribute( const QString &name ) const
return mAttributeModel->featureLayerPair().feature().attribute( idx );
}

void QgsQuickAttributeFormModelBase::setConstraintsValid( bool constraintsValid )
void QgsQuickAttributeFormModelBase::setConstraintsHardValid( bool constraintsHardValid )
{
if ( constraintsHardValid == mConstraintsHardValid )
return;

mConstraintsHardValid = constraintsHardValid;
emit constraintsHardValidChanged();
}

void QgsQuickAttributeFormModelBase::setConstraintsSoftValid( bool constraintsSoftValid )
{
if ( constraintsValid == mConstraintsValid )
if ( constraintsSoftValid == mConstraintsSoftValid )
return;

mConstraintsValid = constraintsValid;
emit constraintsValidChanged();
mConstraintsSoftValid = constraintsSoftValid;
emit constraintsSoftValidChanged();
}

bool QgsQuickAttributeFormModelBase::hasTabs() const
@@ -56,8 +56,10 @@ class QgsQuickAttributeFormModelBase : public QStandardItemModel
//! Whether use tabs layout
Q_PROPERTY( bool hasTabs READ hasTabs WRITE setHasTabs NOTIFY hasTabsChanged )

//! Returns TRUE if all constraints defined on fields are satisfied with the current attribute values
Q_PROPERTY( bool constraintsValid READ constraintsValid NOTIFY constraintsValidChanged )
//! Returns TRUE if all hard constraints defined on fields are satisfied with the current attribute values
Q_PROPERTY( bool constraintsHardValid READ constraintsHardValid NOTIFY constraintsHardValidChanged )
//! Returns TRUE if all soft constraints defined on fields are satisfied with the current attribute values
Q_PROPERTY( bool constraintsSoftValid READ constraintsSoftValid NOTIFY constraintsSoftValidChanged )

public:
//! Constructor
@@ -83,8 +85,11 @@ class QgsQuickAttributeFormModelBase : public QStandardItemModel
//! Creates a new feature
void create();

//! \copydoc QgsQuickAttributeFormModelBase::constraintsValid
bool constraintsValid() const;
//! \copydoc QgsQuickAttributeFormModelBase::constraintsHardValid
bool constraintsHardValid() const;

//! \copydoc QgsQuickAttributeFormModelBase::constraintsSoftValid
bool constraintsSoftValid() const;

/**
* Gets the value of attribute of the feature in the model
@@ -93,13 +98,21 @@ class QgsQuickAttributeFormModelBase : public QStandardItemModel
*/
QVariant attribute( const QString &name ) const;

//! \copydoc QgsQuickAttributeFormModelBase::constraintsHardValid
void setConstraintsHardValid( bool constraintsHardValid );

//! \copydoc QgsQuickAttributeFormModelBase::constraintsSoftValid
void setConstraintsSoftValid( bool constraintsSoftValid );

signals:
//! \copydoc QgsQuickAttributeFormModelBase::attributeModel
void attributeModelChanged();
//! \copydoc QgsQuickAttributeFormModelBase::hasTabs
void hasTabsChanged();
//! \copydoc QgsQuickAttributeFormModelBase::constraintsValid
void constraintsValidChanged();
//! \copydoc QgsQuickAttributeFormModelBase::constraintsHardValid
void constraintsHardValidChanged();
//! \copydoc QgsQuickAttributeFormModelBase::constraintsSoftValid
void constraintsSoftValidChanged();

private slots:
void onFeatureChanged();
@@ -112,7 +125,6 @@ class QgsQuickAttributeFormModelBase : public QStandardItemModel
void updateAttributeValue( QStandardItem *item );
void flatten( QgsAttributeEditorContainer *container, QStandardItem *parent, const QString &parentVisibilityExpressions, QVector<QStandardItem *> &items );
void updateVisibility( int fieldIndex = -1 );
void setConstraintsValid( bool constraintsValid );

QgsQuickAttributeModel *mAttributeModel = nullptr; // not owned
QgsVectorLayer *mLayer = nullptr; // not owned
@@ -121,10 +133,11 @@ class QgsQuickAttributeFormModelBase : public QStandardItemModel

typedef QPair<QgsExpression, QVector<QStandardItem *> > VisibilityExpression;
QList<VisibilityExpression> mVisibilityExpressions;
QMap<QStandardItem *, QgsExpression> mConstraints;
QMap<QStandardItem *, QgsFieldConstraints> mConstraints;

QgsExpressionContext mExpressionContext;
bool mConstraintsValid = false;
bool mConstraintsHardValid = false;
bool mConstraintsSoftValid = false;
};

/// @endcond
@@ -159,6 +159,16 @@ Item {
}

function save() {
if ( !model.constraintsHardValid )
{
console.log( qsTr( 'Constraints not valid') )
return
}
else if ( !model.constraintsSoftValid )
{
console.log( qsTr( 'Note: soft constraints were not met') )
}

parent.focus = true
if ( form.state === "Add" ) {
model.create()
@@ -371,7 +381,7 @@ Item {

text: qsTr(Name) || ''
font.bold: true
color: ConstraintValid ? form.style.constraint.validColor : form.style.constraint.invalidColor
color: ConstraintSoftValid && ConstraintHardValid ? form.style.constraint.validColor : form.style.constraint.invalidColor
}

Label {
@@ -383,9 +393,9 @@ Item {
}

text: qsTr(ConstraintDescription)
height: ConstraintValid ? 0 : undefined
visible: !ConstraintValid

visible: !ConstraintHardValid || !ConstraintSoftValid
height: visible ? undefined : 0
wrapMode: Text.WordWrap
color: form.style.constraint.descriptionColor
}

@@ -404,7 +414,10 @@ Item {
property var config: EditorWidgetConfig
property var widget: EditorWidget
property var field: Field
property var constraintValid: ConstraintValid
property var constraintHardValid: ConstraintHardValid
property var constraintSoftValid: ConstraintSoftValid
property bool constraintsHardValid: form.model.constraintsHardValid
property bool constraintsSoftValid: form.model.constraintsSoftValid
property var homePath: form.project ? form.project.homePath : ""
property var customStyle: form.style
property var externalResourceHandler: form.externalResourceHandler
@@ -497,10 +510,10 @@ Item {
}

background: Rectangle {
color: model.constraintsValid ? form.style.toolbutton.backgroundColor : form.style.toolbutton.backgroundColorInvalid
color: model.constraintsSoftValid && model.constraintsHardValid ? form.style.toolbutton.backgroundColor : form.style.toolbutton.backgroundColorInvalid
}

enabled: model.constraintsValid
enabled: model.constraintsHardValid

onClicked: {
form.save()

0 comments on commit f9dfea8

Please sign in to comment.
You can’t perform that action at this time.