Skip to content

Commit

Permalink
Merge pull request #4449 from opengisch/remember_me
Browse files Browse the repository at this point in the history
Remember project state mode (browse or digitize) and active layer across sessions
  • Loading branch information
nirvn authored Jul 16, 2023
2 parents 21d5f8c + 51833b4 commit de7faf0
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 79 deletions.
108 changes: 71 additions & 37 deletions src/core/projectinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

#include <QDateTime>
#include <QFileInfo>
#include <QSettings>
#include <QString>
#include <qgslayertree.h>
#include <qgslayertreemodel.h>
Expand Down Expand Up @@ -108,12 +107,11 @@ void ProjectInfo::saveExtent()
QFileInfo fi( mFilePath );
if ( fi.exists() )
{
QSettings settings;
const QgsRectangle extent = mMapSettings->extent();
settings.beginGroup( QStringLiteral( "/qgis/projectInfo/%1" ).arg( mFilePath ) );
settings.setValue( QStringLiteral( "filesize" ), fi.size() );
settings.setValue( QStringLiteral( "extent" ), QStringLiteral( "%1|%2|%3|%4" ).arg( qgsDoubleToString( extent.xMinimum() ), qgsDoubleToString( extent.xMaximum() ), qgsDoubleToString( extent.yMinimum() ), qgsDoubleToString( extent.yMaximum() ) ) );
settings.endGroup();
mSettings.beginGroup( QStringLiteral( "/qgis/projectInfo/%1" ).arg( mFilePath ) );
mSettings.setValue( QStringLiteral( "filesize" ), fi.size() );
mSettings.setValue( QStringLiteral( "extent" ), QStringLiteral( "%1|%2|%3|%4" ).arg( qgsDoubleToString( extent.xMinimum() ), qgsDoubleToString( extent.xMaximum() ), qgsDoubleToString( extent.yMinimum() ), qgsDoubleToString( extent.yMaximum() ) ) );
mSettings.endGroup();
}
}

Expand All @@ -130,11 +128,10 @@ void ProjectInfo::saveRotation()
QFileInfo fi( mFilePath );
if ( fi.exists() )
{
QSettings settings;
settings.beginGroup( QStringLiteral( "/qgis/projectInfo/%1" ).arg( mFilePath ) );
settings.setValue( QStringLiteral( "filesize" ), fi.size() );
settings.setValue( QStringLiteral( "rotation" ), mMapSettings->rotation() );
settings.endGroup();
mSettings.beginGroup( QStringLiteral( "/qgis/projectInfo/%1" ).arg( mFilePath ) );
mSettings.setValue( QStringLiteral( "filesize" ), fi.size() );
mSettings.setValue( QStringLiteral( "rotation" ), mMapSettings->rotation() );
mSettings.endGroup();
}
}

Expand All @@ -151,17 +148,16 @@ void ProjectInfo::saveTemporalState()
QFileInfo fi( mFilePath );
if ( fi.exists() )
{
QSettings settings;
settings.beginGroup( QStringLiteral( "/qgis/projectInfo/%1" ).arg( mFilePath ) );
settings.setValue( QStringLiteral( "filesize" ), fi.size() );
settings.setValue( QStringLiteral( "isTemporal" ), mMapSettings->isTemporal() );
settings.setValue( QStringLiteral( "StartDateTime" ), mMapSettings->temporalBegin().toTimeSpec( Qt::LocalTime ).toString( Qt::ISODateWithMs ) );
settings.setValue( QStringLiteral( "EndDateTime" ), mMapSettings->temporalEnd().toTimeSpec( Qt::LocalTime ).toString( Qt::ISODateWithMs ) );
settings.endGroup();
mSettings.beginGroup( QStringLiteral( "/qgis/projectInfo/%1" ).arg( mFilePath ) );
mSettings.setValue( QStringLiteral( "filesize" ), fi.size() );
mSettings.setValue( QStringLiteral( "isTemporal" ), mMapSettings->isTemporal() );
mSettings.setValue( QStringLiteral( "StartDateTime" ), mMapSettings->temporalBegin().toTimeSpec( Qt::LocalTime ).toString( Qt::ISODateWithMs ) );
mSettings.setValue( QStringLiteral( "EndDateTime" ), mMapSettings->temporalEnd().toTimeSpec( Qt::LocalTime ).toString( Qt::ISODateWithMs ) );
mSettings.endGroup();
}
}

void ProjectInfo::saveLayerStyle( QgsMapLayer *layer ) const
void ProjectInfo::saveLayerStyle( QgsMapLayer *layer )
{
if ( mFilePath.isEmpty() || !layer )
return;
Expand All @@ -185,14 +181,13 @@ void ProjectInfo::saveLayerStyle( QgsMapLayer *layer ) const
id += layer->id();
}

QSettings settings;
settings.beginGroup( QStringLiteral( "/qgis/projectInfo/%1/layerstyles" ).arg( mFilePath ) );
settings.setValue( id, style.xmlData() );
settings.endGroup();
mSettings.beginGroup( QStringLiteral( "/qgis/projectInfo/%1/layerstyles" ).arg( mFilePath ) );
mSettings.setValue( id, style.xmlData() );
mSettings.endGroup();
}
}

void ProjectInfo::saveLayerTreeState() const
void ProjectInfo::saveLayerTreeState()
{
if ( mFilePath.isEmpty() || !mLayerTree )
return;
Expand All @@ -211,15 +206,55 @@ void ProjectInfo::saveLayerTreeState() const
document.appendChild( document.createElement( QStringLiteral( "qgis" ) ) );
mapCollection.writeXml( document );

QSettings settings;
settings.beginGroup( QStringLiteral( "/qgis/projectInfo/%1" ).arg( mFilePath ) );
settings.setValue( QStringLiteral( "filesize" ), fi.size() );
settings.setValue( QStringLiteral( "layertreestate" ), document.toString() );
settings.remove( QStringLiteral( "maptheme" ) );
settings.endGroup();
mSettings.beginGroup( QStringLiteral( "/qgis/projectInfo/%1" ).arg( mFilePath ) );
mSettings.setValue( QStringLiteral( "filesize" ), fi.size() );
mSettings.setValue( QStringLiteral( "layertreestate" ), document.toString() );
mSettings.remove( QStringLiteral( "maptheme" ) );
mSettings.endGroup();
}
}

void ProjectInfo::saveStateMode( const QString &mode )
{
if ( mFilePath.isEmpty() )
return;

QFileInfo fi( mFilePath );
if ( fi.exists() )
{
mSettings.beginGroup( QStringLiteral( "/qgis/projectInfo/%1" ).arg( mFilePath ) );
mSettings.setValue( QStringLiteral( "filesize" ), fi.size() );
mSettings.setValue( QStringLiteral( "stateMode" ), mode );
mSettings.endGroup();
}
}

QString ProjectInfo::getSavedStateMode() const
{
return mSettings.value( QStringLiteral( "/qgis/projectInfo/%1/stateMode" ).arg( mFilePath ), QStringLiteral( "browse" ) ).toString();
}

void ProjectInfo::saveActiveLayer( QgsMapLayer *layer )
{
if ( mFilePath.isEmpty() || !layer )
return;

QFileInfo fi( mFilePath );
if ( fi.exists() )
{
mSettings.beginGroup( QStringLiteral( "/qgis/projectInfo/%1" ).arg( mFilePath ) );
mSettings.setValue( QStringLiteral( "filesize" ), fi.size() );
mSettings.setValue( QStringLiteral( "activeLayer" ), layer->id() );
mSettings.endGroup();
}
}

QgsMapLayer *ProjectInfo::getSavedActiveLayer() const
{
const QString layerId = mSettings.value( QStringLiteral( "/qgis/projectInfo/%1/activeLayer" ).arg( mFilePath ) ).toString();
return !layerId.isEmpty() ? QgsProject::instance()->mapLayer( layerId ) : nullptr;
}

void ProjectInfo::mapThemeChanged()
{
if ( mFilePath.isEmpty() )
Expand All @@ -228,18 +263,17 @@ void ProjectInfo::mapThemeChanged()
QFileInfo fi( mFilePath );
if ( fi.exists() )
{
QSettings settings;
settings.beginGroup( QStringLiteral( "/qgis/projectInfo/%1" ).arg( mFilePath ) );
settings.setValue( QStringLiteral( "filesize" ), fi.size() );
mSettings.beginGroup( QStringLiteral( "/qgis/projectInfo/%1" ).arg( mFilePath ) );
mSettings.setValue( QStringLiteral( "filesize" ), fi.size() );
if ( !mLayerTree->mapTheme().isEmpty() )
{
settings.setValue( QStringLiteral( "maptheme" ), mLayerTree->mapTheme() );
settings.remove( QStringLiteral( "layertreestate" ) );
mSettings.setValue( QStringLiteral( "maptheme" ), mLayerTree->mapTheme() );
mSettings.remove( QStringLiteral( "layertreestate" ) );
}
else
{
settings.remove( QStringLiteral( "maptheme" ) );
mSettings.remove( QStringLiteral( "maptheme" ) );
}
settings.endGroup();
mSettings.endGroup();
}
}
27 changes: 25 additions & 2 deletions src/core/projectinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "qgsquickmapsettings.h"

#include <QObject>
#include <QSettings>
#include <QTimer>

/**
Expand Down Expand Up @@ -59,12 +60,33 @@ class ProjectInfo : public QObject
/**
* Saves the \a layer style to the current project information settings
*/
Q_INVOKABLE void saveLayerStyle( QgsMapLayer *layer ) const;
Q_INVOKABLE void saveLayerStyle( QgsMapLayer *layer );

/**
* Saves the current state (visibility and collapse status) of the layer tree
*/
Q_INVOKABLE void saveLayerTreeState() const;
Q_INVOKABLE void saveLayerTreeState();

/**
* Saves the state \a mode for the current project
*/
Q_INVOKABLE void saveStateMode( const QString &mode );

/**
* Returns the saved state mode for the current project
*/
Q_INVOKABLE QString getSavedStateMode() const;

/**
* Saves the active \a layer within the current project
*/
Q_INVOKABLE void saveActiveLayer( QgsMapLayer *layer );

/**
* Returns the saved active layer for the current project
* or nullptr if active layer was not saved or isn't present
*/
Q_INVOKABLE QgsMapLayer *getSavedActiveLayer() const;

signals:

Expand All @@ -89,6 +111,7 @@ class ProjectInfo : public QObject
void saveRotation();
void saveTemporalState();

QSettings mSettings;
QString mFilePath;

QgsQuickMapSettings *mMapSettings = nullptr;
Expand Down
29 changes: 21 additions & 8 deletions src/qml/DashBoard.qml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Drawer {
signal showCloudMenu

property alias allowLayerChange: legend.enabled
property alias currentLayer: legend.currentLayer
property alias activeLayer: legend.activeLayer
property alias layerTree: legend.model
property MapSettings mapSettings

Expand All @@ -41,9 +41,21 @@ Drawer {
onShowMenu: mainMenu.popup(settingsButton.x + 2, mainWindow.sceneTopMargin + settingsButton.y + 2)
onShowCloudMenu: cloudPopup.show()

onCurrentLayerChanged: {
if ( currentLayer && currentLayer.readOnly && stateMachine.state == "digitize" )
displayToast( qsTr( "The layer %1 is read only." ).arg( currentLayer.name ) )
onActiveLayerChanged: {
if (activeLayer && activeLayer.readOnly && stateMachine.state == "digitize")
displayToast(qsTr("The layer %1 is read only.").arg(activeLayer.name))
}

Connections {
target: stateMachine

function onStateChanged() {
if (stateMachine.state === "measure") {
return
}

modeSwitch.checked = stateMachine.state === "digitize"
}
}

ColumnLayout {
Expand Down Expand Up @@ -146,7 +158,7 @@ Drawer {


Switch {
id: modeswitch
id: modeSwitch
visible: projectInfo.insertRights
height: 56
width: ( 56 + 36 )
Expand All @@ -155,7 +167,7 @@ Drawer {
indicator: Rectangle {
implicitHeight: 36
implicitWidth: 36 * 2
x: modeswitch.leftPadding
x: modeSwitch.leftPadding
radius: 4
color: "#66212121"
border.color: "#44FFFFFF"
Expand Down Expand Up @@ -183,7 +195,7 @@ Drawer {
opacity: 0.4
}
Rectangle {
x: modeswitch.checked ? parent.width - width : 0
x: modeSwitch.checked ? parent.width - width : 0
width: 36
height: 36
radius: 4
Expand All @@ -193,7 +205,7 @@ Drawer {
width: 28
height: 28
anchors.centerIn: parent
source: modeswitch.checked ? Theme.getThemeVectorIcon( 'ic_create_white_24dp' ) : Theme.getThemeVectorIcon( 'ic_map_white_24dp' )
source: modeSwitch.checked ? Theme.getThemeVectorIcon( 'ic_create_white_24dp' ) : Theme.getThemeVectorIcon( 'ic_map_white_24dp' )
sourceSize.width: parent.height * screen.devicePixelRatio
sourceSize.height: parent.width * screen.devicePixelRatio
}
Expand All @@ -205,6 +217,7 @@ Drawer {
}
}
}

onPositionChanged: {
if ( checked ) {
changeMode( "digitize" )
Expand Down
9 changes: 5 additions & 4 deletions src/qml/Legend.qml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ ListView {
id: legend

property bool isVisible: false
property VectorLayer currentLayer
property VectorLayer activeLayer

model: flatLayerTree
flickableDirection: Flickable.VerticalFlick
Expand All @@ -28,7 +28,7 @@ ListView {
property int itemPadding: 5 + ( 5 + 24 ) * TreeLevel
property string itemType: Type
property string layerType: LayerType
property bool isSelectedLayer: ( itemType === "layer" && vectorLayer != null && vectorLayer == currentLayer )
property bool isSelectedLayer: ( itemType === "layer" && vectorLayer != null && vectorLayer == activeLayer )
property bool isPressed: false

id: rectangle
Expand Down Expand Up @@ -141,7 +141,7 @@ ListView {
text: Name
horizontalAlignment: Text.AlignLeft
font.pointSize: Theme.tipFont.pointSize
font.bold: itemType === "group" || (itemType === "layer" && vectorLayer != null && vectorLayer == currentLayer) ? true : false
font.bold: itemType === "group" || (itemType === "layer" && vectorLayer != null && vectorLayer == activeLayer) ? true : false
color: {
if ( isSelectedLayer )
return Theme.light;
Expand Down Expand Up @@ -233,7 +233,8 @@ ListView {

if (item) {
if (item.vectorLayer && item.vectorLayer.isValid) {
currentLayer = item.vectorLayer
activeLayer = item.vectorLayer
projectInfo.saveActiveLayer(activeLayer)
}
}
}
Expand Down
Loading

1 comment on commit de7faf0

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