Skip to content

Commit

Permalink
Merge pull request #5593 from opengisch/variable_editor_fixes
Browse files Browse the repository at this point in the history
Save/restore edited project variables
  • Loading branch information
nirvn authored Aug 28, 2024
2 parents f04e472 + 493bde8 commit ccf7464
Show file tree
Hide file tree
Showing 6 changed files with 240 additions and 140 deletions.
172 changes: 107 additions & 65 deletions src/core/expressionvariablemodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,42 +32,91 @@ 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:
default:
break;
}

return false;
}

int ExpressionVariableModel::addVariable( VariableScope scope, const QString &name, const QString &value, bool editable )
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<QStandardItem *>() << nameItem );
}

int ExpressionVariableModel::addVariable( VariableScope scope, const QString &name, const QString &value )
{
int lastEditableVariable = 0;
while ( lastEditableVariable < rowCount() )
{
if ( item( i )->data( VariableScopeRole ).value<VariableScope>() == scope )
if ( !item( lastEditableVariable )->data( VariableEditableRole ).toBool() )
{
lastVariableInScope = i + 1;
break;
}
lastEditableVariable++;
}

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->setEditable( editable );
nameItem->setData( true, VariableEditableRole );
nameItem->setData( QString(), VariableOriginalNameRole );
nameItem->setEditable( true );

insertRow( lastVariableInScope, QList<QStandardItem *>() << nameItem );
insertRow( lastEditableVariable, QList<QStandardItem *>() << nameItem );

return lastVariableInScope;
return lastEditableVariable;
}

void ExpressionVariableModel::removeVariable( VariableScope scope, const QString &name )
{
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<VariableScope>();

if ( variableName == name && variableScope == scope )
{
mRemovedVariables << QPair<VariableScope, QString>( variableScope, variableName );
removeRow( i );
return;
}
Expand All @@ -76,15 +125,29 @@ void ExpressionVariableModel::removeVariable( VariableScope scope, const QString

void ExpressionVariableModel::save()
{
for ( const QPair<VariableScope, QString> &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<VariableScope>();
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 )
Expand All @@ -98,75 +161,54 @@ void ExpressionVariableModel::reloadVariables()
{
clear();

std::unique_ptr<QgsExpressionContextScope> scope( QgsExpressionContextUtils::globalScope() );

QStringList variableNames = scope->variableNames();
variableNames.sort();

// First add readonly app variables
for ( const QString &varName : variableNames )
{
if ( scope->isReadOnly( varName ) )
{
QVariant varValue = scope->variable( varName );
if ( QString::compare( varValue.toString(), QStringLiteral( "Not available" ) ) == 0 )
varValue = QVariant( QT_TR_NOOP( "Not Available" ) );
mRemovedVariables.clear();

addVariable( VariableScope::GlobalScope, varName, varValue.toString(), false );
}
}
// Second add custom variables
for ( const QString &varName : variableNames )
{
if ( !scope->isReadOnly( varName ) )
{
addVariable( VariableScope::GlobalScope, varName, scope->variable( varName ).toString() );
}
}
// Finally add readonly project variables
// 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();

addVariable( VariableScope::ProjectScope, varName, varValue.toString() );
appendVariable( VariableScope::ProjectScope, varName, varValue.toString(), true );
}
}

void ExpressionVariableModel::setName( int row, const QString &name )
{
QStandardItem *rowItem = item( row );
std::unique_ptr<QgsExpressionContextScope> scope( QgsExpressionContextUtils::globalScope() );
QStringList variableNames = scope->variableNames();
variableNames.sort();

if ( !rowItem )
return;
// Second add user-provided global variables
for ( const QString &name : variableNames )
{
if ( !scope->isReadOnly( name ) )
{
appendVariable( VariableScope::GlobalScope, name, scope->variable( name ).toString(), true );
}
}

if ( rowItem->data( VariableName ).toString() == name )
return;
// Finally, add read-only global variables
for ( const QString &name : variableNames )
{
if ( scope->isReadOnly( name ) )
{
QVariant varValue = scope->variable( name );
if ( QString::compare( varValue.toString(), QStringLiteral( "Not available" ) ) == 0 )
varValue = QVariant( QT_TR_NOOP( "Not Available" ) );

rowItem->setData( name, VariableName );
appendVariable( VariableScope::GlobalScope, name, varValue.toString(), false );
}
}
}

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<int, QByteArray> ExpressionVariableModel::roleNames() const
{
QHash<int, QByteArray> 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;
}

Expand Down
19 changes: 10 additions & 9 deletions src/core/expressionvariablemodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -46,18 +47,14 @@ 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 );

Q_INVOKABLE void removeVariable( VariableScope scope, const QString &name );

Q_INVOKABLE void save();

Q_INVOKABLE void reloadVariables();

Q_INVOKABLE void setName( int row, const QString &name );

Q_INVOKABLE void setValue( int row, const QString &value );

QHash<int, QByteArray> roleNames() const override;

/**
Expand All @@ -77,7 +74,11 @@ class ExpressionVariableModel : public QStandardItemModel
void onDataChanged( const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles );

private:
void appendVariable( VariableScope scope, const QString &name, const QString &value, bool editable );

QgsProject *mCurrentProject = nullptr;

QList<QPair<VariableScope, QString>> mRemovedVariables;
};

#endif // EXPRESSIONVARIABLEMODEL_H
16 changes: 16 additions & 0 deletions src/core/projectinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
***************************************************************************/


#include "expressioncontextutils.h"
#include "projectinfo.h"

#include <QDateTime>
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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()
Expand Down
2 changes: 2 additions & 0 deletions src/core/projectinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 );

Expand Down
1 change: 1 addition & 0 deletions src/core/utils/expressioncontextutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 )
Expand Down
Loading

1 comment on commit ccf7464

@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.