From 62aa486ae065646deb745220ba43d25609611af5 Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Tue, 27 Aug 2024 14:28:02 +0700 Subject: [PATCH 1/7] Fix variable editor text fields' width --- src/qml/VariableEditor.qml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/qml/VariableEditor.qml b/src/qml/VariableEditor.qml index 05d3433bbf..f0adefbf7e 100644 --- a/src/qml/VariableEditor.qml +++ b/src/qml/VariableEditor.qml @@ -39,6 +39,7 @@ ColumnLayout { anchors.margins: 3 anchors.leftMargin: 9 anchors.rightMargin: 5 + delegate: Rectangle { id: rectangle width: parent ? parent.width : 0 @@ -71,6 +72,7 @@ ColumnLayout { bottomPadding: 10 leftPadding: 1 rightPadding: 1 + width: variableNameTextAnimator.width text: VariableName enabled: VariableEditable font: Theme.tipFont @@ -108,6 +110,7 @@ ColumnLayout { bottomPadding: 10 leftPadding: 1 rightPadding: 1 + width: variableValueTextAnimator.width text: VariableValue enabled: VariableEditable font: Theme.tipFont From db394da87c2900b1a1af44281ea07ae290181259 Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Tue, 27 Aug 2024 14:30:27 +0700 Subject: [PATCH 2/7] Project variable names should not be editable --- src/qml/VariableEditor.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qml/VariableEditor.qml b/src/qml/VariableEditor.qml index f0adefbf7e..891d2fc8a4 100644 --- a/src/qml/VariableEditor.qml +++ b/src/qml/VariableEditor.qml @@ -74,7 +74,7 @@ ColumnLayout { rightPadding: 1 width: variableNameTextAnimator.width text: VariableName - enabled: VariableEditable + enabled: VariableScope == ExpressionVariableModel.GlobalScope && VariableEditable font: Theme.tipFont horizontalAlignment: TextInput.AlignLeft placeholderText: displayText === '' ? qsTr("Enter name") : '' From 80fcaed82381def65861ad9926159228204b87ca Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Tue, 27 Aug 2024 15:00:38 +0700 Subject: [PATCH 3/7] Fix deleted variables not deleted, and duplication of variables when renaming --- src/core/expressionvariablemodel.cpp | 105 +++++++++++++++++---------- src/core/expressionvariablemodel.h | 17 ++--- src/qml/VariableEditor.qml | 8 +- 3 files changed, 79 insertions(+), 51 deletions(-) diff --git a/src/core/expressionvariablemodel.cpp b/src/core/expressionvariablemodel.cpp index 065d1f64f9..1a3d2f1dd8 100644 --- a/src/core/expressionvariablemodel.cpp +++ b/src/core/expressionvariablemodel.cpp @@ -32,10 +32,42 @@ ExpressionVariableModel::ExpressionVariableModel( QObject *parent ) bool ExpressionVariableModel::setData( const QModelIndex &index, const QVariant &value, int role ) { - return QStandardItemModel::setData( index, value, role ); + QStandardItem *rowItem = item( index.row() ); + if ( !rowItem || !rowItem->data( VariableEditableRole ).toBool() ) + { + return false; + } + + switch ( role ) + { + case VariableNameRole: + if ( rowItem->data( VariableNameRole ) == value ) + { + return false; + } + + rowItem->setData( value, VariableNameRole ); + return true; + + case VariableValueRole: + + if ( rowItem->data( VariableValueRole ) == value ) + { + return false; + } + + rowItem->setData( value, VariableValueRole ); + return true; + + case VariableEditableRole: + case VariableScopeRole: + break; + } + + return false; } -int ExpressionVariableModel::addVariable( VariableScope scope, const QString &name, const QString &value, bool editable ) +int ExpressionVariableModel::addVariable( VariableScope scope, const QString &name, const QString &value, bool editable, bool preexisting ) { int lastVariableInScope = rowCount(); for ( int i = 0; i < rowCount(); ++i ) @@ -47,10 +79,11 @@ int ExpressionVariableModel::addVariable( VariableScope scope, const QString &na } QStandardItem *nameItem = new QStandardItem( name ); - nameItem->setData( name, VariableName ); - nameItem->setData( value, VariableValue ); + nameItem->setData( name, VariableNameRole ); + nameItem->setData( value, VariableValueRole ); nameItem->setData( QVariant::fromValue( scope ), VariableScopeRole ); - nameItem->setData( editable, VariableEditable ); + nameItem->setData( editable, VariableEditableRole ); + nameItem->setData( preexisting ? name : QString(), VariableOriginalNameRole ); nameItem->setEditable( editable ); insertRow( lastVariableInScope, QList() << nameItem ); @@ -63,11 +96,12 @@ void ExpressionVariableModel::removeVariable( VariableScope scope, const QString for ( int i = 0; i < rowCount(); ++i ) { const QStandardItem *rowItem = item( i ); - const QString variableName = rowItem->data( VariableName ).toString(); + const QString variableName = rowItem->data( VariableNameRole ).toString(); const VariableScope variableScope = rowItem->data( VariableScopeRole ).value(); if ( variableName == name && variableScope == scope ) { + mRemovedVariables << QPair( variableScope, variableName ); removeRow( i ); return; } @@ -76,15 +110,29 @@ void ExpressionVariableModel::removeVariable( VariableScope scope, const QString void ExpressionVariableModel::save() { + for ( const QPair &variable : mRemovedVariables ) + { + if ( variable.first == VariableScope::GlobalScope ) + { + QgsExpressionContextUtils::removeGlobalVariable( variable.second ); + } + } + for ( int i = 0; i < rowCount(); ++i ) { const QStandardItem *currentItem = item( i ); const VariableScope itemScope = currentItem->data( VariableScopeRole ).value(); - const QString itemName = currentItem->data( VariableName ).toString(); - const QString itemValue = currentItem->data( VariableValue ).toString(); + const QString itemName = currentItem->data( VariableNameRole ).toString(); + const QString itemOriginalName = currentItem->data( VariableOriginalNameRole ).toString(); + const QString itemValue = currentItem->data( VariableValueRole ).toString(); if ( currentItem->isEditable() && itemScope == VariableScope::GlobalScope ) { + if ( !itemOriginalName.isEmpty() && itemName != itemOriginalName ) + { + // Remove renamed variable + QgsExpressionContextUtils::removeGlobalVariable( itemOriginalName ); + } QgsExpressionContextUtils::setGlobalVariable( itemName, itemValue ); } else if ( itemScope == VariableScope::ProjectScope ) @@ -98,8 +146,9 @@ void ExpressionVariableModel::reloadVariables() { clear(); - std::unique_ptr scope( QgsExpressionContextUtils::globalScope() ); + mRemovedVariables.clear(); + std::unique_ptr scope( QgsExpressionContextUtils::globalScope() ); QStringList variableNames = scope->variableNames(); variableNames.sort(); @@ -112,7 +161,7 @@ void ExpressionVariableModel::reloadVariables() if ( QString::compare( varValue.toString(), QStringLiteral( "Not available" ) ) == 0 ) varValue = QVariant( QT_TR_NOOP( "Not Available" ) ); - addVariable( VariableScope::GlobalScope, varName, varValue.toString(), false ); + addVariable( VariableScope::GlobalScope, varName, varValue.toString(), false, true ); } } // Second add custom variables @@ -120,7 +169,7 @@ void ExpressionVariableModel::reloadVariables() { if ( !scope->isReadOnly( varName ) ) { - addVariable( VariableScope::GlobalScope, varName, scope->variable( varName ).toString() ); + addVariable( VariableScope::GlobalScope, varName, scope->variable( varName ).toString(), true, true ); } } // Finally add readonly project variables @@ -130,43 +179,19 @@ void ExpressionVariableModel::reloadVariables() { QVariant varValue = projectVariables.value( varName ).toString(); - addVariable( VariableScope::ProjectScope, varName, varValue.toString() ); + addVariable( VariableScope::ProjectScope, varName, varValue.toString(), true, true ); } } -void ExpressionVariableModel::setName( int row, const QString &name ) -{ - QStandardItem *rowItem = item( row ); - - if ( !rowItem ) - return; - - if ( rowItem->data( VariableName ).toString() == name ) - return; - - rowItem->setData( name, VariableName ); -} - -void ExpressionVariableModel::setValue( int row, const QString &value ) -{ - QStandardItem *rowItem = item( row ); - - if ( !rowItem ) - return; - - if ( rowItem->data( VariableValue ).toString() == value ) - return; - - rowItem->setData( value, VariableValue ); -} QHash ExpressionVariableModel::roleNames() const { QHash names = QStandardItemModel::roleNames(); - names[VariableName] = "VariableName"; - names[VariableValue] = "VariableValue"; + names[VariableNameRole] = "VariableName"; + names[VariableValueRole] = "VariableValue"; names[VariableScopeRole] = "VariableScope"; - names[VariableEditable] = "VariableEditable"; + names[VariableEditableRole] = "VariableEditable"; + names[VariableOriginalNameRole] = "VariableOriginalName"; return names; } diff --git a/src/core/expressionvariablemodel.h b/src/core/expressionvariablemodel.h index b827a47d6e..96e8162c8b 100644 --- a/src/core/expressionvariablemodel.h +++ b/src/core/expressionvariablemodel.h @@ -28,10 +28,11 @@ class ExpressionVariableModel : public QStandardItemModel public: enum Roles { - VariableName = Qt::UserRole, - VariableValue, - VariableScopeRole, - VariableEditable = Qt::EditRole + VariableEditableRole = Qt::EditRole, + VariableNameRole = Qt::UserRole, + VariableValueRole = Qt::UserRole + 1, + VariableScopeRole = Qt::UserRole + 2, + VariableOriginalNameRole = Qt::UserRole + 3, }; enum class VariableScope @@ -46,7 +47,7 @@ class ExpressionVariableModel : public QStandardItemModel bool setData( const QModelIndex &index, const QVariant &value, int role ) override; - Q_INVOKABLE int addVariable( VariableScope scope, const QString &name, const QString &value, bool editable = true ); + Q_INVOKABLE int addVariable( VariableScope scope, const QString &name, const QString &value, bool editable = true, bool preexisting = false ); Q_INVOKABLE void removeVariable( VariableScope scope, const QString &name ); @@ -54,10 +55,6 @@ class ExpressionVariableModel : public QStandardItemModel Q_INVOKABLE void reloadVariables(); - Q_INVOKABLE void setName( int row, const QString &name ); - - Q_INVOKABLE void setValue( int row, const QString &value ); - QHash roleNames() const override; /** @@ -78,6 +75,8 @@ class ExpressionVariableModel : public QStandardItemModel private: QgsProject *mCurrentProject = nullptr; + + QList> mRemovedVariables; }; #endif // EXPRESSIONVARIABLEMODEL_H diff --git a/src/qml/VariableEditor.qml b/src/qml/VariableEditor.qml index 891d2fc8a4..09ecb5f81a 100644 --- a/src/qml/VariableEditor.qml +++ b/src/qml/VariableEditor.qml @@ -86,7 +86,9 @@ ColumnLayout { } onTextChanged: { - table.model.setName(index, text); + if (enabled && VariableName != text) { + VariableName = text; + } } onCursorRectangleChanged: { @@ -124,7 +126,9 @@ ColumnLayout { } onTextChanged: { - table.model.setValue(index, text); + if (enabled && VariableValue != text) { + VariableValue = text; + } } onCursorRectangleChanged: { From a2fce16c292cbaf23f54cb38f6582780b16eae85 Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Tue, 27 Aug 2024 15:15:04 +0700 Subject: [PATCH 4/7] Save/restore edited project variables --- src/core/expressionvariablemodel.cpp | 1 + src/core/projectinfo.cpp | 16 ++++++++++++++++ src/core/projectinfo.h | 2 ++ src/core/utils/expressioncontextutils.cpp | 1 + src/qml/VariableEditor.qml | 3 +++ 5 files changed, 23 insertions(+) diff --git a/src/core/expressionvariablemodel.cpp b/src/core/expressionvariablemodel.cpp index 1a3d2f1dd8..efb4e80b26 100644 --- a/src/core/expressionvariablemodel.cpp +++ b/src/core/expressionvariablemodel.cpp @@ -61,6 +61,7 @@ bool ExpressionVariableModel::setData( const QModelIndex &index, const QVariant case VariableEditableRole: case VariableScopeRole: + default: break; } diff --git a/src/core/projectinfo.cpp b/src/core/projectinfo.cpp index e313103af1..346760e4ed 100644 --- a/src/core/projectinfo.cpp +++ b/src/core/projectinfo.cpp @@ -15,6 +15,7 @@ ***************************************************************************/ +#include "expressioncontextutils.h" #include "projectinfo.h" #include @@ -445,6 +446,14 @@ void ProjectInfo::mapThemeChanged() mSettings.endGroup(); } +void ProjectInfo::saveVariable( const QString &name, const QString &value ) +{ + if ( mFilePath.isEmpty() ) + return; + + mSettings.setValue( QStringLiteral( "/qgis/projectInfo/%1/variables/%2" ).arg( mFilePath, name ), value ); +} + void ProjectInfo::restoreSettings( QString &projectFilePath, QgsProject *project, QgsQuickMapCanvasMap *mapCanvas, FlatLayerTreeModel *layerTree ) { QSettings settings; @@ -625,6 +634,13 @@ void ProjectInfo::restoreSettings( QString &projectFilePath, QgsProject *project project->setSnappingConfig( config ); } settings.endGroup(); + + settings.beginGroup( QStringLiteral( "/qgis/projectInfo/%1/variables" ).arg( projectFilePath ) ); + const QStringList variableNames = settings.allKeys(); + for ( const QString &name : variableNames ) + { + ExpressionContextUtils::setProjectVariable( project, name, settings.value( name ).toString() ); + } } QVariantMap ProjectInfo::getTitleDecorationConfiguration() diff --git a/src/core/projectinfo.h b/src/core/projectinfo.h index ab07b4af70..f50dfd5f7f 100644 --- a/src/core/projectinfo.h +++ b/src/core/projectinfo.h @@ -180,6 +180,8 @@ class ProjectInfo : public QObject //! Restore the last tracking session that occured within a vector \a layer. Q_INVOKABLE QModelIndex restoreTracker( QgsVectorLayer *layer ); + Q_INVOKABLE void saveVariable( const QString &name, const QString &value ); + //! Restore various project settings static void restoreSettings( QString &projectFilePath, QgsProject *project, QgsQuickMapCanvasMap *mapCanvas, FlatLayerTreeModel *layerTree ); diff --git a/src/core/utils/expressioncontextutils.cpp b/src/core/utils/expressioncontextutils.cpp index c02fa3864d..c7fb6514d2 100644 --- a/src/core/utils/expressioncontextutils.cpp +++ b/src/core/utils/expressioncontextutils.cpp @@ -211,6 +211,7 @@ void ExpressionContextUtils::setProjectVariable( QgsProject *project, const QStr variables.insert( name, value ); project->setCustomVariables( variables ); } + void ExpressionContextUtils::setProjectVariables( QgsProject *project, const QVariantMap &variables ) { if ( !project ) diff --git a/src/qml/VariableEditor.qml b/src/qml/VariableEditor.qml index 09ecb5f81a..587b8308d8 100644 --- a/src/qml/VariableEditor.qml +++ b/src/qml/VariableEditor.qml @@ -128,6 +128,9 @@ ColumnLayout { onTextChanged: { if (enabled && VariableValue != text) { VariableValue = text; + if (VariableScope == ExpressionVariableModel.ProjectScope) { + projectInfo.saveVariable(VariableName, text); + } } } From 18ef7957c57e91057ee739351da673e2e4837208 Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Tue, 27 Aug 2024 16:45:15 +0700 Subject: [PATCH 5/7] Beautify the variable editor a bit, make it look more like the feature form / processing algorithm form --- src/qml/VariableEditor.qml | 157 +++++++++++++++++++++---------------- 1 file changed, 90 insertions(+), 67 deletions(-) diff --git a/src/qml/VariableEditor.qml b/src/qml/VariableEditor.qml index 587b8308d8..3fa5ad9d0a 100644 --- a/src/qml/VariableEditor.qml +++ b/src/qml/VariableEditor.qml @@ -28,17 +28,36 @@ ColumnLayout { ListView { id: table - model: ExpressionVariableModel { - currentProject: qgisProject - } flickableDirection: Flickable.VerticalFlick boundsBehavior: Flickable.StopAtBounds clip: true spacing: 1 anchors.fill: parent - anchors.margins: 3 - anchors.leftMargin: 9 - anchors.rightMargin: 5 + + model: ExpressionVariableModel { + currentProject: qgisProject + } + + section.property: "VariableScope" + section.labelPositioning: ViewSection.CurrentLabelAtStart | ViewSection.InlineLabels + section.delegate: Component { + Rectangle { + width: parent.width + height: 30 + color: Theme.controlBorderColor + + Text { + anchors { + horizontalCenter: parent.horizontalCenter + verticalCenter: parent.verticalCenter + } + font.bold: true + font.pointSize: Theme.resultFont.pointSize + color: Theme.mainTextColor + text: section == "GlobalScope" ? qsTr("Global variables") : qsTr("Project variables") + } + } + } delegate: Rectangle { id: rectangle @@ -53,14 +72,20 @@ ColumnLayout { variableNameText.forceActiveFocus(); } - Row { + Column { id: line - spacing: 5 + anchors { + left: parent.left + leftMargin: 5 + right: parent.right + rightMargin: 5 + } + spacing: 0 QfSwipeAnimator { id: variableNameTextAnimator - width: 0.35 * table.width - 10 - height: 40 + width: table.width - 10 + height: 24 shouldAutoFlick: (width < variableNameText.implicitWidth) && !dragging && !variableNameText.activeFocus contentImplicitWidth: variableNameText.implicitWidth contentWidth: variableNameText.implicitWidth @@ -68,21 +93,21 @@ ColumnLayout { TextField { id: variableNameText - topPadding: 10 - bottomPadding: 10 + topPadding: 0 + bottomPadding: 0 leftPadding: 1 rightPadding: 1 - width: variableNameTextAnimator.width + width: Math.max(table.width - 10, implicitWidth) + height: variableNameTextAnimator.height text: VariableName enabled: VariableScope == ExpressionVariableModel.GlobalScope && VariableEditable - font: Theme.tipFont + font: Theme.tinyFont + color: enabled ? variableNameText.activeFocus ? Theme.mainColor : Theme.mainTextColor : Theme.mainTextDisabledColor horizontalAlignment: TextInput.AlignLeft - placeholderText: displayText === '' ? qsTr("Enter name") : '' + verticalAlignment: TextInput.AlignVCenter + background: Rectangle { - y: variableNameText.height - height - variableNameText.bottomPadding / 2 - height: variableNameText.activeFocus ? 2 : variableNameText.enabled ? 1 : 0 - width: Math.max(variableNameTextAnimator.width, variableNameText.implicitWidth) - color: variableNameText.activeFocus ? Theme.accentColor : "transparent" + color: "transparent" } onTextChanged: { @@ -97,62 +122,60 @@ ColumnLayout { } } - QfSwipeAnimator { - id: variableValueTextAnimator - width: 0.65 * table.width - 10 - (canDelete ? deleteVariableButton.width : 0) - height: 40 - shouldAutoFlick: (width < variableValueText.implicitWidth) && !dragging && !variableValueText.activeFocus - contentImplicitWidth: variableValueText.implicitWidth - contentWidth: variableValueText.implicitWidth - duration: shouldAutoFlick ? Math.abs(variableValueText.width - width) * 100 + 10 : 10000 - - TextField { - id: variableValueText - topPadding: 10 - bottomPadding: 10 - leftPadding: 1 - rightPadding: 1 - width: variableValueTextAnimator.width - text: VariableValue - enabled: VariableEditable - font: Theme.tipFont - horizontalAlignment: TextInput.AlignLeft - placeholderText: displayText === '' ? qsTr("Enter value") : '' - background: Rectangle { - y: variableValueText.height - height - variableValueText.bottomPadding / 2 - height: variableValueText.activeFocus ? 2 : variableNameText.enabled ? 1 : 0 - width: Math.max(variableValueTextAnimator.width, variableValueText.implicitWidth) - color: variableValueText.activeFocus ? Theme.accentColor : "transparent" - } - - onTextChanged: { - if (enabled && VariableValue != text) { - VariableValue = text; - if (VariableScope == ExpressionVariableModel.ProjectScope) { - projectInfo.saveVariable(VariableName, text); + Row { + spacing: 5 + + QfSwipeAnimator { + id: variableValueTextAnimator + width: table.width - 10 - (canDelete ? deleteVariableButton.width : 0) + height: 40 + shouldAutoFlick: (width < variableValueText.implicitWidth) && !dragging && !variableValueText.activeFocus + contentImplicitWidth: variableValueText.implicitWidth + contentWidth: variableValueText.implicitWidth + duration: shouldAutoFlick ? Math.abs(variableValueText.width - width) * 100 + 10 : 10000 + + QfTextField { + id: variableValueText + topPadding: 10 + bottomPadding: 10 + leftPadding: 1 + rightPadding: 1 + width: Math.max(table.width - 10 - (canDelete ? deleteVariableButton.width : 0), implicitWidth) + text: VariableValue + enabled: VariableEditable + font: Theme.defaultFont + horizontalAlignment: TextInput.AlignLeft + placeholderText: !variableValueText.activeFocus && displayText === '' ? qsTr("Enter value") : '' + + onTextChanged: { + if (enabled && VariableValue != text) { + VariableValue = text; + if (VariableScope == ExpressionVariableModel.ProjectScope) { + projectInfo.saveVariable(VariableName, text); + } } } - } - onCursorRectangleChanged: { - variableValueTextAnimator.ensureCursorVisible(cursorRectangle); + onCursorRectangleChanged: { + variableValueTextAnimator.ensureCursorVisible(cursorRectangle); + } } } - } - QfToolButton { - id: deleteVariableButton - width: 36 - height: 36 - anchors.verticalCenter: parent.verticalCenter - visible: canDelete + QfToolButton { + id: deleteVariableButton + width: 36 + height: 36 + anchors.verticalCenter: parent.verticalCenter + visible: canDelete - iconSource: Theme.getThemeIcon('ic_delete_forever_white_24dp') - iconColor: Theme.mainTextColor - bgcolor: "transparent" + iconSource: Theme.getThemeIcon('ic_delete_forever_white_24dp') + iconColor: Theme.mainTextColor + bgcolor: "transparent" - onClicked: { - table.model.removeVariable(VariableScope, variableNameText.text); + onClicked: { + table.model.removeVariable(VariableScope, variableNameText.text); + } } } } From 81b05a7101b048fccd988e99d82b681eee90d832 Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Tue, 27 Aug 2024 17:07:30 +0700 Subject: [PATCH 6/7] Re-order variables so project come first, then editable global, then non-editable global --- src/core/expressionvariablemodel.cpp | 78 +++++++++++++++++----------- src/core/expressionvariablemodel.h | 4 +- 2 files changed, 50 insertions(+), 32 deletions(-) diff --git a/src/core/expressionvariablemodel.cpp b/src/core/expressionvariablemodel.cpp index efb4e80b26..a303997747 100644 --- a/src/core/expressionvariablemodel.cpp +++ b/src/core/expressionvariablemodel.cpp @@ -68,28 +68,42 @@ bool ExpressionVariableModel::setData( const QModelIndex &index, const QVariant return false; } -int ExpressionVariableModel::addVariable( VariableScope scope, const QString &name, const QString &value, bool editable, bool preexisting ) +void ExpressionVariableModel::appendVariable( VariableScope scope, const QString &name, const QString &value, bool editable ) { - int lastVariableInScope = rowCount(); - for ( int i = 0; i < rowCount(); ++i ) + QStandardItem *nameItem = new QStandardItem( name ); + nameItem->setData( name, VariableNameRole ); + nameItem->setData( value, VariableValueRole ); + nameItem->setData( QVariant::fromValue( scope ), VariableScopeRole ); + nameItem->setData( editable, VariableEditableRole ); + nameItem->setData( name, VariableOriginalNameRole ); + nameItem->setEditable( editable ); + + appendRow( QList() << nameItem ); +} + +int ExpressionVariableModel::addVariable( VariableScope scope, const QString &name, const QString &value ) +{ + int lastEditableVariable = 0; + while ( lastEditableVariable < rowCount() ) { - if ( item( i )->data( VariableScopeRole ).value() == scope ) + if ( !item( lastEditableVariable )->data( VariableEditableRole ).toBool() ) { - lastVariableInScope = i + 1; + break; } + lastEditableVariable++; } QStandardItem *nameItem = new QStandardItem( name ); nameItem->setData( name, VariableNameRole ); nameItem->setData( value, VariableValueRole ); nameItem->setData( QVariant::fromValue( scope ), VariableScopeRole ); - nameItem->setData( editable, VariableEditableRole ); - nameItem->setData( preexisting ? name : QString(), VariableOriginalNameRole ); - nameItem->setEditable( editable ); + nameItem->setData( true, VariableEditableRole ); + nameItem->setData( QString(), VariableOriginalNameRole ); + nameItem->setEditable( true ); - insertRow( lastVariableInScope, QList() << nameItem ); + insertRow( lastEditableVariable, QList() << nameItem ); - return lastVariableInScope; + return lastEditableVariable; } void ExpressionVariableModel::removeVariable( VariableScope scope, const QString &name ) @@ -149,38 +163,40 @@ void ExpressionVariableModel::reloadVariables() mRemovedVariables.clear(); + // First, add project variables + QVariantMap projectVariables = ExpressionContextUtils::projectVariables( mCurrentProject ); + const QStringList projectVariableKeys = projectVariables.keys(); + for ( const QString &varName : projectVariableKeys ) + { + QVariant varValue = projectVariables.value( varName ).toString(); + + appendVariable( VariableScope::ProjectScope, varName, varValue.toString(), true ); + } + std::unique_ptr scope( QgsExpressionContextUtils::globalScope() ); QStringList variableNames = scope->variableNames(); variableNames.sort(); - // First add readonly app variables - for ( const QString &varName : variableNames ) + // Second add user-provided global variables + for ( const QString &name : variableNames ) { - if ( scope->isReadOnly( varName ) ) + if ( !scope->isReadOnly( name ) ) { - QVariant varValue = scope->variable( varName ); - if ( QString::compare( varValue.toString(), QStringLiteral( "Not available" ) ) == 0 ) - varValue = QVariant( QT_TR_NOOP( "Not Available" ) ); - - addVariable( VariableScope::GlobalScope, varName, varValue.toString(), false, true ); + appendVariable( VariableScope::GlobalScope, name, scope->variable( name ).toString(), true ); } } - // Second add custom variables - for ( const QString &varName : variableNames ) + + // Finally, add read-only global variables + for ( const QString &name : variableNames ) { - if ( !scope->isReadOnly( varName ) ) + if ( scope->isReadOnly( name ) ) { - addVariable( VariableScope::GlobalScope, varName, scope->variable( varName ).toString(), true, true ); - } - } - // Finally add readonly project variables - QVariantMap projectVariables = ExpressionContextUtils::projectVariables( mCurrentProject ); - const QStringList projectVariableKeys = projectVariables.keys(); - for ( const QString &varName : projectVariableKeys ) - { - QVariant varValue = projectVariables.value( varName ).toString(); + QVariant varValue = scope->variable( name ); + if ( QString::compare( varValue.toString(), QStringLiteral( "Not available" ) ) == 0 ) + varValue = QVariant( QT_TR_NOOP( "Not Available" ) ); - addVariable( VariableScope::ProjectScope, varName, varValue.toString(), true, true ); + appendVariable( VariableScope::GlobalScope, name, varValue.toString(), false ); + } } } diff --git a/src/core/expressionvariablemodel.h b/src/core/expressionvariablemodel.h index 96e8162c8b..4d84b7ddc6 100644 --- a/src/core/expressionvariablemodel.h +++ b/src/core/expressionvariablemodel.h @@ -47,7 +47,7 @@ class ExpressionVariableModel : public QStandardItemModel bool setData( const QModelIndex &index, const QVariant &value, int role ) override; - Q_INVOKABLE int addVariable( VariableScope scope, const QString &name, const QString &value, bool editable = true, bool preexisting = false ); + Q_INVOKABLE int addVariable( VariableScope scope, const QString &name, const QString &value ); Q_INVOKABLE void removeVariable( VariableScope scope, const QString &name ); @@ -74,6 +74,8 @@ class ExpressionVariableModel : public QStandardItemModel void onDataChanged( const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles ); private: + void appendVariable( VariableScope scope, const QString &name, const QString &value, bool editable ); + QgsProject *mCurrentProject = nullptr; QList> mRemovedVariables; From 493bde8bac84589e326b29dfe7485331ca8f0eb6 Mon Sep 17 00:00:00 2001 From: Mathieu Pellerin Date: Tue, 27 Aug 2024 17:15:20 +0700 Subject: [PATCH 7/7] Add missing scrollbar in variables list, tweak padding --- src/qml/VariableEditor.qml | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/qml/VariableEditor.qml b/src/qml/VariableEditor.qml index 3fa5ad9d0a..fefa4501fd 100644 --- a/src/qml/VariableEditor.qml +++ b/src/qml/VariableEditor.qml @@ -34,6 +34,9 @@ ColumnLayout { spacing: 1 anchors.fill: parent + ScrollBar.vertical: QfScrollBar { + } + model: ExpressionVariableModel { currentProject: qgisProject } @@ -62,7 +65,7 @@ ColumnLayout { delegate: Rectangle { id: rectangle width: parent ? parent.width : 0 - height: line.height + height: line.height + 10 color: "transparent" property var itemRow: index @@ -76,15 +79,15 @@ ColumnLayout { id: line anchors { left: parent.left - leftMargin: 5 + leftMargin: 10 right: parent.right - rightMargin: 5 + rightMargin: 10 } spacing: 0 QfSwipeAnimator { id: variableNameTextAnimator - width: table.width - 10 + width: table.width - line.anchors.leftMargin * 2 height: 24 shouldAutoFlick: (width < variableNameText.implicitWidth) && !dragging && !variableNameText.activeFocus contentImplicitWidth: variableNameText.implicitWidth @@ -93,16 +96,18 @@ ColumnLayout { TextField { id: variableNameText - topPadding: 0 + topPadding: 5 bottomPadding: 0 leftPadding: 1 rightPadding: 1 - width: Math.max(table.width - 10, implicitWidth) + width: Math.max(table.width - line.anchors.leftMargin * 2, implicitWidth) height: variableNameTextAnimator.height text: VariableName enabled: VariableScope == ExpressionVariableModel.GlobalScope && VariableEditable - font: Theme.tinyFont - color: enabled ? variableNameText.activeFocus ? Theme.mainColor : Theme.mainTextColor : Theme.mainTextDisabledColor + opacity: enabled ? 1 : 0.45 + font.bold: true + font.pointSize: Theme.tinyFont.pointSize + color: variableNameText.activeFocus ? Theme.mainColor : Theme.mainTextColor horizontalAlignment: TextInput.AlignLeft verticalAlignment: TextInput.AlignVCenter @@ -127,7 +132,7 @@ ColumnLayout { QfSwipeAnimator { id: variableValueTextAnimator - width: table.width - 10 - (canDelete ? deleteVariableButton.width : 0) + width: table.width - line.anchors.leftMargin * 2 - (canDelete ? deleteVariableButton.width : 0) height: 40 shouldAutoFlick: (width < variableValueText.implicitWidth) && !dragging && !variableValueText.activeFocus contentImplicitWidth: variableValueText.implicitWidth @@ -140,7 +145,7 @@ ColumnLayout { bottomPadding: 10 leftPadding: 1 rightPadding: 1 - width: Math.max(table.width - 10 - (canDelete ? deleteVariableButton.width : 0), implicitWidth) + width: Math.max(table.width - line.anchors.leftMargin * 2 - (canDelete ? deleteVariableButton.width : 0), implicitWidth) text: VariableValue enabled: VariableEditable font: Theme.defaultFont