Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #35688 from elpaso/alias-expressions
Forms: expression controlled aliases (labels)
  • Loading branch information
elpaso committed Apr 15, 2020
2 parents 2589750 + 6f3cac2 commit 869e148
Show file tree
Hide file tree
Showing 15 changed files with 286 additions and 44 deletions.
Expand Up @@ -15,7 +15,7 @@ class QgsAttributeEditorElement /Abstract/
This is an abstract base class for any elements of a drag and drop form.

This can either be a container which will be represented on the screen
as a tab widget or ca collapsible group box. Or it can be a field which will
as a tab widget or a collapsible group box. Or it can be a field which will
then be represented based on the QgsEditorWidget type and configuration.
Or it can be a relation and embed the form of several children of another
layer.
Expand Down
29 changes: 29 additions & 0 deletions python/core/auto_generated/qgseditformconfig.sip.in
Expand Up @@ -67,6 +67,13 @@ Constructor for TabData
CodeSourceEnvironment
};

enum DataDefinedProperty
{
NoProperty,
AllProperties,
Alias,
};

QgsEditFormConfig( const QgsEditFormConfig &o );
%Docstring
Copy constructor
Expand Down Expand Up @@ -275,6 +282,28 @@ Deserialize drag and drop designer elements.
explicit QgsEditFormConfig();
%Docstring
Create a new edit form config. Normally invoked by :py:class:`QgsVectorLayer`
%End

void setDataDefinedFieldProperties( const QString &fieldName, const QgsPropertyCollection &properties );
%Docstring
Set data defined properties for ``fieldName`` to ``properties``

.. versionadded:: 3.14
%End

QgsPropertyCollection dataDefinedFieldProperties( const QString &fieldName ) const;
%Docstring
Returns data defined properties for ``fieldName``

.. versionadded:: 3.14
%End


static const QgsPropertiesDefinition &propertyDefinitions();
%Docstring
Returns data defined property definitions.

.. versionadded:: 3.14
%End

};
Expand Down
10 changes: 10 additions & 0 deletions src/core/expression/qgsexpressioncontextutils.cpp
Expand Up @@ -132,6 +132,11 @@ class GetCurrentFormFieldValue : public QgsScopedExpressionFunction
return new GetCurrentFormFieldValue( );
}

bool isStatic( const QgsExpressionNodeFunction *, QgsExpression *, const QgsExpressionContext * ) const override
{
return false;
};

};

class GetCurrentParentFormFieldValue : public QgsScopedExpressionFunction
Expand All @@ -157,6 +162,11 @@ class GetCurrentParentFormFieldValue : public QgsScopedExpressionFunction
return new GetCurrentParentFormFieldValue( );
}

bool isStatic( const QgsExpressionNodeFunction *, QgsExpression *, const QgsExpressionContext * ) const override
{
return false;
};

};


Expand Down
2 changes: 1 addition & 1 deletion src/core/qgsattributeeditorelement.cpp
Expand Up @@ -16,6 +16,7 @@
#include "qgsattributeeditorelement.h"
#include "qgsrelationmanager.h"


void QgsAttributeEditorContainer::addChildElement( QgsAttributeEditorElement *widget )
{
mChildren.append( widget );
Expand Down Expand Up @@ -115,7 +116,6 @@ QDomElement QgsAttributeEditorElement::toDomElement( QDomDocument &doc ) const
QDomElement elem = doc.createElement( typeIdentifier() );
elem.setAttribute( QStringLiteral( "name" ), mName );
elem.setAttribute( QStringLiteral( "showLabel" ), mShowLabel );

saveConfiguration( elem );
return elem;
}
Expand Down
5 changes: 3 additions & 2 deletions src/core/qgsattributeeditorelement.h
Expand Up @@ -19,6 +19,7 @@
#include "qgis_core.h"
#include "qgsrelation.h"
#include "qgsoptionalexpression.h"
#include "qgspropertycollection.h"
#include <QColor>

class QgsRelationManager;
Expand All @@ -28,7 +29,7 @@ class QgsRelationManager;
* This is an abstract base class for any elements of a drag and drop form.
*
* This can either be a container which will be represented on the screen
* as a tab widget or ca collapsible group box. Or it can be a field which will
* as a tab widget or a collapsible group box. Or it can be a field which will
* then be represented based on the QgsEditorWidget type and configuration.
* Or it can be a relation and embed the form of several children of another
* layer.
Expand Down Expand Up @@ -129,7 +130,6 @@ class CORE_EXPORT QgsAttributeEditorElement SIP_ABSTRACT

/**
* Controls if this element should be labeled with a title (field, relation or groupname).
*
* \since QGIS 2.18
*/
void setShowLabel( bool showLabel );
Expand Down Expand Up @@ -158,6 +158,7 @@ class CORE_EXPORT QgsAttributeEditorElement SIP_ABSTRACT
* \since QGIS 2.18
*/
virtual QString typeIdentifier() const = 0;

};


Expand Down
39 changes: 37 additions & 2 deletions src/core/qgseditformconfig.cpp
Expand Up @@ -23,8 +23,6 @@
#include "qgsxmlutils.h"
#include "qgsapplication.h"

//#include "qgseditorwidgetregistry.h"

QgsAttributeEditorContainer::~QgsAttributeEditorContainer()
{
qDeleteAll( mChildren );
Expand All @@ -35,6 +33,22 @@ QgsEditFormConfig::QgsEditFormConfig()
{
}

void QgsEditFormConfig::setDataDefinedFieldProperties( const QString &fieldName, const QgsPropertyCollection &properties )
{
d.detach();
d->mDataDefinedFieldProperties[ fieldName ] = properties;
}

QgsPropertyCollection QgsEditFormConfig::dataDefinedFieldProperties( const QString &fieldName ) const
{
return d->mDataDefinedFieldProperties.value( fieldName );
}

const QgsPropertiesDefinition &QgsEditFormConfig::propertyDefinitions()
{
return QgsEditFormConfigPrivate::propertyDefinitions();
}

QVariantMap QgsEditFormConfig::widgetConfig( const QString &widgetName ) const
{
int fieldIndex = d->mFields.indexOf( widgetName );
Expand Down Expand Up @@ -382,6 +396,16 @@ void QgsEditFormConfig::readXml( const QDomNode &node, QgsReadWriteContext &cont
d->mLabelOnTop.insert( labelOnTopElement.attribute( QStringLiteral( "name" ) ), static_cast< bool >( labelOnTopElement.attribute( QStringLiteral( "labelOnTop" ) ).toInt() ) );
}

// Read data defined field properties
QDomNodeList fieldDDPropertiesNodeList = node.namedItem( QStringLiteral( "dataDefinedFieldProperties" ) ).toElement().childNodes();
for ( int i = 0; i < fieldDDPropertiesNodeList.size(); ++i )
{
QDomElement DDElement = fieldDDPropertiesNodeList.at( i ).toElement();
QgsPropertyCollection collection;
collection.readXml( DDElement, propertyDefinitions() );
d->mDataDefinedFieldProperties.insert( DDElement.attribute( QStringLiteral( "name" ) ), collection );
}

QDomNodeList widgetsNodeList = node.namedItem( QStringLiteral( "widgets" ) ).toElement().childNodes();

for ( int i = 0; i < widgetsNodeList.size(); ++i )
Expand Down Expand Up @@ -505,6 +529,17 @@ void QgsEditFormConfig::writeXml( QDomNode &node, const QgsReadWriteContext &con
}
node.appendChild( labelOnTopElem );

// Store data defined field properties
QDomElement ddFieldPropsElement = doc.createElement( QStringLiteral( "dataDefinedFieldProperties" ) );
for ( auto it = d->mDataDefinedFieldProperties.constBegin(); it != d->mDataDefinedFieldProperties.constEnd(); ++it )
{
QDomElement ddPropsElement = doc.createElement( QStringLiteral( "field" ) );
ddPropsElement.setAttribute( QStringLiteral( "name" ), it.key() );
it.value().writeXml( ddPropsElement, propertyDefinitions() );
ddFieldPropsElement.appendChild( ddPropsElement );
}
node.appendChild( ddFieldPropsElement );

QDomElement widgetsElem = doc.createElement( QStringLiteral( "widgets" ) );

QMap<QString, QVariantMap >::ConstIterator configIt( d->mWidgetConfigs.constBegin() );
Expand Down
37 changes: 35 additions & 2 deletions src/core/qgseditformconfig.h
Expand Up @@ -99,6 +99,20 @@ class CORE_EXPORT QgsEditFormConfig
};
Q_ENUM( PythonInitCodeSource )

/**
* Data defined properties.
* Form data defined overrides are stored in a property collection
* and they can be retrieved using the indexes specified in this
* enum.
* \since QGIS 3.14
*/
enum DataDefinedProperty
{
NoProperty = 0, //!< No property
AllProperties = 1, //!< All properties for item
Alias = 2, //!< Alias
};

/**
* Copy constructor
*
Expand Down Expand Up @@ -208,15 +222,15 @@ class CORE_EXPORT QgsEditFormConfig
* If this returns TRUE, the widget at the given index will receive its label on the previous line
* while if it returns FALSE, the widget will receive its label on the left hand side.
* Labeling on top leaves more horizontal space for the widget itself.
**/
*/
bool labelOnTop( int idx ) const;

/**
* If this is set to TRUE, the widget at the given index will receive its label on
* the previous line while if it is set to FALSE, the widget will receive its label
* on the left hand side.
* Labeling on top leaves more horizontal space for the widget itself.
**/
*/
void setLabelOnTop( int idx, bool onTop );


Expand Down Expand Up @@ -301,6 +315,25 @@ class CORE_EXPORT QgsEditFormConfig
*/
explicit QgsEditFormConfig();

/**
* Set data defined properties for \a fieldName to \a properties
* \since QGIS 3.14
*/
void setDataDefinedFieldProperties( const QString &fieldName, const QgsPropertyCollection &properties );

/**
* Returns data defined properties for \a fieldName
* \since QGIS 3.14
*/
QgsPropertyCollection dataDefinedFieldProperties( const QString &fieldName ) const;


/**
* Returns data defined property definitions.
* \since QGIS 3.14
*/
static const QgsPropertiesDefinition &propertyDefinitions();

private:

/**
Expand Down
19 changes: 18 additions & 1 deletion src/core/qgseditformconfig_p.h
Expand Up @@ -17,7 +17,6 @@
#define QGSEDITFORMCONFIG_P_H

#include <QMap>

#include "qgsfields.h"
#include "qgseditformconfig.h"

Expand All @@ -36,6 +35,7 @@ class QgsEditFormConfigPrivate : public QSharedData
, mConfiguredRootContainer( o.mConfiguredRootContainer )
, mFieldEditables( o.mFieldEditables )
, mLabelOnTop( o.mLabelOnTop )
, mDataDefinedFieldProperties( o.mDataDefinedFieldProperties )
, mWidgetConfigs( o.mWidgetConfigs )
, mEditorLayout( o.mEditorLayout )
, mUiFormPath( o.mUiFormPath )
Expand All @@ -51,6 +51,20 @@ class QgsEditFormConfigPrivate : public QSharedData
delete mInvisibleRootContainer;
}

static QgsPropertiesDefinition &propertyDefinitions()
{
static QgsPropertiesDefinition sPropertyDefinitions
{
{
QgsEditFormConfig::DataDefinedProperty::Alias,
QgsPropertyDefinition( "dataDefinedAlias",
QObject::tr( "Alias" ),
QgsPropertyDefinition::String )
},
};
return sPropertyDefinitions;
};

//! The invisible root container for attribute editors in the drag and drop designer
QgsAttributeEditorContainer *mInvisibleRootContainer = nullptr;

Expand All @@ -59,6 +73,7 @@ class QgsEditFormConfigPrivate : public QSharedData

QMap< QString, bool> mFieldEditables;
QMap< QString, bool> mLabelOnTop;
QMap< QString, QgsPropertyCollection> mDataDefinedFieldProperties;

QMap<QString, QVariantMap > mWidgetConfigs;

Expand All @@ -80,8 +95,10 @@ class QgsEditFormConfigPrivate : public QSharedData
QgsEditFormConfig::FeatureFormSuppress mSuppressForm = QgsEditFormConfig::FeatureFormSuppress::SuppressDefault;

QgsFields mFields;

};


/// @endcond

#endif // QGSEDITFORMCONFIG_P_H
32 changes: 30 additions & 2 deletions src/gui/attributeformconfig/qgsattributetypedialog.cpp
Expand Up @@ -16,6 +16,7 @@
***************************************************************************/

#include "qgsattributetypedialog.h"
#include "qgsattributeeditorelement.h"
#include "qgsattributetypeloaddialog.h"
#include "qgsvectordataprovider.h"
#include "qgsmapcanvas.h"
Expand Down Expand Up @@ -73,6 +74,12 @@ QgsAttributeTypeDialog::QgsAttributeTypeDialog( QgsVectorLayer *vl, int fieldIdx
mExpressionWidget->registerExpressionContextGenerator( this );
mExpressionWidget->setLayer( mLayer );

mAliasExpressionButton->registerExpressionContextGenerator( this );
connect( mAliasExpressionButton, &QgsPropertyOverrideButton::changed, this, [ = ]
{
mDataDefinedProperties.setProperty( QgsEditFormConfig::DataDefinedProperty::Alias, mAliasExpressionButton->toProperty() );
} );

connect( mExpressionWidget, &QgsExpressionLineEdit::expressionChanged, this, &QgsAttributeTypeDialog::defaultExpressionChanged );
connect( mUniqueCheckBox, &QCheckBox::toggled, this, [ = ]( bool checked )
{
Expand All @@ -92,6 +99,7 @@ QgsAttributeTypeDialog::QgsAttributeTypeDialog( QgsVectorLayer *vl, int fieldIdx

constraintExpressionWidget->setAllowEmptyFieldName( true );
constraintExpressionWidget->setLayer( vl );

}

QgsAttributeTypeDialog::~QgsAttributeTypeDialog()
Expand Down Expand Up @@ -303,8 +311,14 @@ QgsExpressionContext QgsAttributeTypeDialog::createExpressionContext() const
<< QgsExpressionContextUtils::globalScope()
<< QgsExpressionContextUtils::projectScope( QgsProject::instance() )
<< QgsExpressionContextUtils::layerScope( mLayer )
<< QgsExpressionContextUtils::formScope( QgsFeature( mLayer->fields() ) )
<< QgsExpressionContextUtils::mapToolCaptureScope( QList<QgsPointLocator::Match>() );

context.setHighlightedFunctions( QStringList() << QStringLiteral( "current_value" ) );
context.setHighlightedVariables( QStringList() << QStringLiteral( "current_geometry" )
<< QStringLiteral( "current_feature" )
<< QStringLiteral( "form_mode" ) );

return context;
}

Expand Down Expand Up @@ -339,12 +353,21 @@ void QgsAttributeTypeDialog::setFieldEditable( bool editable )

void QgsAttributeTypeDialog::setAlias( const QString &alias )
{
leAlias->setText( alias );
mAlias->setText( alias );
}

QString QgsAttributeTypeDialog::alias() const
{
return leAlias->text();
return mAlias->text();
}

void QgsAttributeTypeDialog::setDataDefinedProperties( const QgsPropertyCollection &properties )
{
mDataDefinedProperties = properties;
if ( properties.hasProperty( QgsEditFormConfig::DataDefinedProperty::Alias ) )
{
mAliasExpressionButton->setToProperty( properties.property( QgsEditFormConfig::DataDefinedProperty::Alias ) );
}
}

void QgsAttributeTypeDialog::setComment( const QString &comment )
Expand Down Expand Up @@ -412,3 +435,8 @@ QStandardItem *QgsAttributeTypeDialog::currentItem() const
QStandardItemModel *widgetTypeModel = qobject_cast<QStandardItemModel *>( mWidgetTypeComboBox->model() );
return widgetTypeModel->item( mWidgetTypeComboBox->currentIndex() );
}

QgsPropertyCollection QgsAttributeTypeDialog::dataDefinedProperties() const
{
return mDataDefinedProperties;
}

0 comments on commit 869e148

Please sign in to comment.