Skip to content

Commit

Permalink
Merge pull request #4734 from opengisch/current_value
Browse files Browse the repository at this point in the history
Fix missing current_value support in the feature form and further optimize code
  • Loading branch information
nirvn authored Nov 9, 2023
2 parents c7fa00b + fd2e541 commit c4a8bb5
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 68 deletions.
95 changes: 47 additions & 48 deletions src/core/attributeformmodelbase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@
#include <qgsattributeeditortextelement.h>
#include <qgsdatetimefieldformatter.h>
#include <qgseditorwidgetsetup.h>
#include <qgsexpressioncontextutils.h>
#include <qgsmapthemecollection.h>
#include <qgsproject.h>
#include <qgsrelationmanager.h>
#include <qgsvaluerelationfieldformatter.h>
#include <qgsvectorlayer.h>
#include <qgsvectorlayerutils.h>

Expand Down Expand Up @@ -113,6 +115,8 @@ bool AttributeFormModelBase::setData( const QModelIndex &index, const QVariant &
bool changed = mFeatureModel->setData( mFeatureModel->index( fieldIndex ), value, FeatureModel::AttributeValue );
if ( changed )
{
mExpressionContext.popScope();
mExpressionContext << QgsExpressionContextUtils::formScope( mFeatureModel->feature() );
synchronizeFieldValue( fieldIndex, value );
}
updateDefaultValues( fieldIndex );
Expand Down Expand Up @@ -155,9 +159,12 @@ void AttributeFormModelBase::resetModel()
clear();

mVisibilityExpressions.clear();
mConstraints.clear();
mFields.clear();
mEditorWidgetCodes.clear();
mEditorWidgetCodesRequirements.clear();

setConstraintsHardValid( true );
setConstraintsSoftValid( true );
setHasTabs( false );

if ( !mFeatureModel )
Expand Down Expand Up @@ -244,6 +251,7 @@ void AttributeFormModelBase::resetModel()
void AttributeFormModelBase::applyFeatureModel()
{
mExpressionContext = mFeatureModel->createExpressionContext();
mExpressionContext << QgsExpressionContextUtils::formScope( mFeatureModel->feature() );
for ( int i = 0; i < invisibleRootItem()->rowCount(); ++i )
{
updateAttributeValue( invisibleRootItem()->child( i ) );
Expand Down Expand Up @@ -455,7 +463,7 @@ void AttributeFormModelBase::buildForm( QgsAttributeEditorContainer *container,

updateAttributeValue( item );

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

parent->appendRow( item );
break;
Expand Down Expand Up @@ -561,11 +569,11 @@ void AttributeFormModelBase::buildForm( QgsAttributeEditorContainer *container,

void AttributeFormModelBase::synchronizeFieldValue( int fieldIndex, QVariant value )
{
QMap<QStandardItem *, QgsFieldConstraints>::ConstIterator constraintIterator( mConstraints.constBegin() );
for ( ; constraintIterator != mConstraints.constEnd(); ++constraintIterator )
QMap<QStandardItem *, int>::ConstIterator fieldIterator( mFields.constBegin() );
for ( ; fieldIterator != mFields.constEnd(); ++fieldIterator )
{
QStandardItem *item = constraintIterator.key();
const int fidx = item->data( AttributeFormModel::FieldIndex ).toInt();
QStandardItem *item = fieldIterator.key();
const int fidx = fieldIterator.value();
if ( fidx != fieldIndex )
continue;

Expand All @@ -583,11 +591,11 @@ void AttributeFormModelBase::updateDefaultValues( int fieldIndex, QVector<int> u
mExpressionContext.setFields( fields );
mExpressionContext.setFeature( mFeatureModel->feature() );

QMap<QStandardItem *, QgsFieldConstraints>::ConstIterator constraintIterator( mConstraints.constBegin() );
for ( ; constraintIterator != mConstraints.constEnd(); ++constraintIterator )
QMap<QStandardItem *, int>::ConstIterator fieldIterator( mFields.constBegin() );
for ( ; fieldIterator != mFields.constEnd(); ++fieldIterator )
{
QStandardItem *item = constraintIterator.key();
const int fidx = item->data( AttributeFormModel::FieldIndex ).toInt();
QStandardItem *item = fieldIterator.key();
const int fidx = fieldIterator.value();
if ( fidx == fieldIndex || !fields.at( fidx ).defaultValueDefinition().isValid() || !fields.at( fidx ).defaultValueDefinition().applyOnUpdate() )
continue;

Expand Down Expand Up @@ -617,6 +625,29 @@ void AttributeFormModelBase::updateDefaultValues( int fieldIndex, QVector<int> u
updateEditorWidgetCodes( fieldName );
}

bool AttributeFormModelBase::codeRequiresUpdate( const QString &fieldName, const QString &code, const QRegularExpression &regEx )
{
if ( !mEditorWidgetCodesRequirements.contains( code ) )
{
CodeRequirements codeRequirements;
QRegularExpressionMatchIterator matchIt = regEx.globalMatch( code );
while ( matchIt.hasNext() )
{
const QRegularExpressionMatch match = matchIt.next();
QString expression = match.captured( 1 );
expression = expression.replace( QStringLiteral( "\\\"" ), QStringLiteral( "\"" ) );

QgsExpression exp( expression );
exp.prepare( &mExpressionContext );
codeRequirements.referencedColumns.unite( exp.referencedColumns() );
codeRequirements.formScope = codeRequirements.formScope || QgsValueRelationFieldFormatter::expressionRequiresFormScope( expression );
}
mEditorWidgetCodesRequirements.insert( code, codeRequirements );
}

return mEditorWidgetCodesRequirements[code].referencedColumns.contains( fieldName ) || mEditorWidgetCodesRequirements[code].referencedColumns.contains( QgsFeatureRequest::ALL_ATTRIBUTES ) || mEditorWidgetCodesRequirements[code].formScope;
}

void AttributeFormModelBase::updateEditorWidgetCodes( const QString &fieldName )
{
QMap<QStandardItem *, QString>::ConstIterator editorWidgetCodesIterator( mEditorWidgetCodes.constBegin() );
Expand All @@ -628,28 +659,10 @@ void AttributeFormModelBase::updateEditorWidgetCodes( const QString &fieldName )
continue;
}
QString code = editorWidgetCodesIterator.value();
bool needUpdate = false;

if ( item->data( AttributeFormModel::ElementType ) == QStringLiteral( "qml" ) || item->data( AttributeFormModel::ElementType ) == QStringLiteral( "html" ) )
{
const thread_local QRegularExpression sRegEx( "expression\\.evaluate\\(\\s*\\\"(.*?[^\\\\])\\\"\\s*\\)", QRegularExpression::MultilineOption | QRegularExpression::DotMatchesEverythingOption );
QRegularExpressionMatchIterator matchIt = sRegEx.globalMatch( code );
while ( matchIt.hasNext() )
{
const QRegularExpressionMatch match = matchIt.next();
QString expression = match.captured( 1 );
expression = expression.replace( QStringLiteral( "\\\"" ), QStringLiteral( "\"" ) );

QgsExpression exp( expression );
exp.prepare( &mExpressionContext );
if ( exp.referencedColumns().contains( fieldName ) || exp.referencedColumns().contains( QgsFeatureRequest::ALL_ATTRIBUTES ) )
{
needUpdate = true;
break;
}
}

if ( needUpdate )
if ( codeRequiresUpdate( fieldName, code, sRegEx ) )
{
QRegularExpressionMatch match = sRegEx.match( code );
while ( match.hasMatch() )
Expand Down Expand Up @@ -687,21 +700,7 @@ void AttributeFormModelBase::updateEditorWidgetCodes( const QString &fieldName )
else if ( item->data( AttributeFormModel::ElementType ) == QStringLiteral( "text" ) )
{
const thread_local QRegularExpression sRegEx( QStringLiteral( "\\[%(.*?)%\\]" ), QRegularExpression::MultilineOption | QRegularExpression::DotMatchesEverythingOption );
QRegularExpressionMatchIterator matchIt = sRegEx.globalMatch( code );
while ( matchIt.hasNext() )
{
const QRegularExpressionMatch match = matchIt.next();

QgsExpression exp( match.captured( 1 ) );
exp.prepare( &mExpressionContext );
if ( exp.referencedColumns().contains( fieldName ) || exp.referencedColumns().contains( QgsFeatureRequest::ALL_ATTRIBUTES ) )
{
needUpdate = true;
break;
}
}

if ( needUpdate )
if ( codeRequiresUpdate( fieldName, code, sRegEx ) )
{
code = QgsExpression::replaceExpressionText( code, &mExpressionContext );
item->setData( code, AttributeFormModel::EditorWidgetCode );
Expand Down Expand Up @@ -761,14 +760,14 @@ void AttributeFormModelBase::updateVisibilityAndConstraints( int fieldIndex )
}
}

QMap<QStandardItem *, QgsFieldConstraints>::ConstIterator constraintIterator( mConstraints.constBegin() );
QMap<QStandardItem *, int>::ConstIterator fieldIterator( mFields.constBegin() );
QMap<int, bool> hardConstraintsCache;
QMap<int, bool> softConstraintsCache;
bool validityChanged = false;
for ( ; constraintIterator != mConstraints.constEnd(); ++constraintIterator )
for ( ; fieldIterator != mFields.constEnd(); ++fieldIterator )
{
QStandardItem *item = constraintIterator.key();
int fidx = item->data( AttributeFormModel::FieldIndex ).toInt();
QStandardItem *item = fieldIterator.key();
int fidx = fieldIterator.value();
if ( fieldIndex != -1 && fidx != fieldIndex )
{
const QString fieldName = mLayer->fields().at( fieldIndex ).name();
Expand Down
12 changes: 11 additions & 1 deletion src/core/attributeformmodelbase.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ class AttributeFormModelBase : public QStandardItemModel
void constraintsSoftValidChanged();

private:
struct CodeRequirements
{
QSet<QString> referencedColumns;
bool formScope = false;
};

/**
* Generates a root container for autogenerated layouts, so we can just use the same
* form logic to deal with them.
Expand Down Expand Up @@ -96,6 +102,9 @@ class AttributeFormModelBase : public QStandardItemModel
//! Update QML, HTML, and text widget code.
void updateEditorWidgetCodes( const QString &fieldName );

//! Check if the given \a code requires update.
bool codeRequiresUpdate( const QString &fieldName, const QString &code, const QRegularExpression &regEx );

//! Udate the visibility state of groups as well as constraints of field items
void updateVisibilityAndConstraints( int fieldIndex = -1 );

Expand Down Expand Up @@ -123,8 +132,9 @@ class AttributeFormModelBase : public QStandardItemModel

typedef QPair<QgsExpression, QStandardItem *> VisibilityExpression;
QList<VisibilityExpression> mVisibilityExpressions;
QMap<QStandardItem *, QgsFieldConstraints> mConstraints;
QMap<QStandardItem *, int> mFields;
QMap<QStandardItem *, QString> mEditorWidgetCodes;
QMap<QString, CodeRequirements> mEditorWidgetCodesRequirements;

QgsExpressionContext mExpressionContext;
bool mConstraintsHardValid = true;
Expand Down
39 changes: 20 additions & 19 deletions src/qml/FeatureForm.qml
Original file line number Diff line number Diff line change
Expand Up @@ -341,27 +341,28 @@ Page {
}
}

Component.onCompleted: {
if (visible) {
if (htmlItem === undefined) {
// avoid cost of WevView creation until needed
htmlItem = Qt.createQmlObject('import QtWebView 1.14;
WebView {
id: htmlItem;
height: 0;
opacity: 0;
anchors { top: parent.top; left: parent.left; right: parent.right; }
onLoadingChanged: { if (!loading) { runJavaScript("document.body.offsetHeight", function(result) { anchors.left = parent.left; width = parent.width; height = (result + 18); opacity = 1.0; } ) } }
}'
, htmlContent);
}
htmlItem.loadHtml(htmlCode)
}
}
onHtmlCodeChanged: {
if (visible && htmlItem) {
htmlItem.loadHtml(htmlCode);
if (htmlItem === undefined) {
htmlItem = Qt.createQmlObject('import QtWebView 1.14;
WebView {
id: htmlItem;
height: 0;
opacity: 0;
anchors { top: parent.top; left: parent.left; right: parent.right; }
onLoadingChanged: {
if (!loading) {
runJavaScript("document.body.offsetHeight", function(result) {
anchors.left = parent.left;
width = parent.width;
height = (result + 18);
opacity = 1.0;
});
}
}
}'
, htmlContent);
}
htmlItem.loadHtml(htmlCode);
}
}
}
Expand Down

1 comment on commit c4a8bb5

@qfield-fairy
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.