Skip to content

Commit 0dc1a61

Browse files
committedAug 3, 2018
Warn users on closing projects with populated memory layers present
Adds a warning (with a cancel option!) when users start to close a project containing any memory layers with features. These layers are temporary only and their contents will be permanently lost if the project is closed. The warning allows users to cancel the close operation (that's the default action!) so that they can then save these layers out to a permanent location.
1 parent 02bd1cc commit 0dc1a61

File tree

2 files changed

+80
-9
lines changed

2 files changed

+80
-9
lines changed
 

‎src/app/qgisapp.cpp

Lines changed: 68 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5218,7 +5218,7 @@ void QgisApp::fileExit()
52185218
return;
52195219
}
52205220

5221-
if ( checkUnsavedLayerEdits() && saveDirty() )
5221+
if ( checkUnsavedLayerEdits() && checkMemoryLayers() && saveDirty() )
52225222
{
52235223
closeProject();
52245224
userProfileManager()->setDefaultFromActive();
@@ -5253,7 +5253,7 @@ bool QgisApp::fileNew( bool promptToSaveFlag, bool forceBlank )
52535253

52545254
if ( promptToSaveFlag )
52555255
{
5256-
if ( !checkUnsavedLayerEdits() || !saveDirty() )
5256+
if ( !checkUnsavedLayerEdits() || !checkMemoryLayers() || !saveDirty() )
52575257
{
52585258
return false; //cancel pressed
52595259
}
@@ -5347,7 +5347,7 @@ bool QgisApp::fileNewFromTemplate( const QString &fileName )
53475347
if ( checkTasksDependOnProject() )
53485348
return false;
53495349

5350-
if ( !checkUnsavedLayerEdits() || !saveDirty() )
5350+
if ( !checkUnsavedLayerEdits() || !checkMemoryLayers() || !saveDirty() )
53515351
{
53525352
return false; //cancel pressed
53535353
}
@@ -5646,7 +5646,7 @@ void QgisApp::fileOpen()
56465646
return;
56475647

56485648
// possibly save any pending work before opening a new project
5649-
if ( checkUnsavedLayerEdits() && saveDirty() )
5649+
if ( checkUnsavedLayerEdits() && checkMemoryLayers() && saveDirty() )
56505650
{
56515651
// Retrieve last used project dir from persistent settings
56525652
QgsSettings settings;
@@ -5680,7 +5680,7 @@ void QgisApp::fileRevert()
56805680
QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) == QMessageBox::No )
56815681
return;
56825682

5683-
if ( !checkUnsavedLayerEdits() )
5683+
if ( !checkUnsavedLayerEdits() || !checkMemoryLayers() )
56845684
return;
56855685

56865686
// re-open the current project
@@ -6110,7 +6110,7 @@ void QgisApp::openProject( QAction *action )
61106110
return;
61116111

61126112
QString debugme = action->data().toString();
6113-
if ( checkUnsavedLayerEdits() && saveDirty() )
6113+
if ( checkUnsavedLayerEdits() && checkMemoryLayers() && saveDirty() )
61146114
addProject( debugme );
61156115
}
61166116

@@ -6136,7 +6136,7 @@ void QgisApp::openProject( const QString &fileName )
61366136
return;
61376137

61386138
// possibly save any pending work before opening a different project
6139-
if ( checkUnsavedLayerEdits() && saveDirty() )
6139+
if ( checkUnsavedLayerEdits() && checkMemoryLayers() && saveDirty() )
61406140
{
61416141
// error handling and reporting is in addProject() function
61426142
addProject( fileName );
@@ -10863,7 +10863,9 @@ bool QgisApp::saveDirty()
1086310863
for ( QMap<QString, QgsMapLayer *>::iterator it = layers.begin(); it != layers.end(); ++it )
1086410864
{
1086510865
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( it.value() );
10866-
if ( !vl )
10866+
// note that we skip the unsaved edits check for memory layers -- it's misleading, because their contents aren't actually
10867+
// saved if this is part of a project close operation. Instead we let these get picked up by checkMemoryLayers().
10868+
if ( !vl || vl->dataProvider()->name() == QLatin1String( "memory" ) )
1086710869
{
1086810870
continue;
1086910871
}
@@ -10917,7 +10919,27 @@ bool QgisApp::saveDirty()
1091710919

1091810920
freezeCanvases( false );
1091910921

10920-
return answer != QMessageBox::Cancel;
10922+
if ( answer == QMessageBox::Cancel )
10923+
return false;
10924+
10925+
// for memory layers, we discard all unsaved changes manually. Users have already been warned about
10926+
// these by an earlier call to checkMemoryLayers(), and we don't want duplicate "unsaved changes" prompts
10927+
// and anyway, saving the changes to a memory layer here won't actually save ANYTHING!
10928+
// we do this at the very end here, because if the user opted to cancel above then ALL unsaved
10929+
// changes in memory layers should still exist for them.
10930+
const QMap<QString, QgsMapLayer *> layers = QgsProject::instance()->mapLayers();
10931+
for ( auto it = layers.begin(); it != layers.end(); ++it )
10932+
{
10933+
if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( it.value() ) )
10934+
{
10935+
if ( vl->dataProvider()->name() == QLatin1String( "memory" ) && vl->isEditable() && vl->isModified() )
10936+
{
10937+
vl->rollBack();
10938+
}
10939+
}
10940+
}
10941+
10942+
return true;
1092110943
}
1092210944

1092310945
bool QgisApp::checkUnsavedLayerEdits()
@@ -10931,6 +10953,11 @@ bool QgisApp::checkUnsavedLayerEdits()
1093110953
{
1093210954
if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( it.value() ) )
1093310955
{
10956+
// note that we skip the unsaved edits check for memory layers -- it's misleading, because their contents aren't actually
10957+
// saved if this is part of a project close operation. Instead we let these get picked up by checkMemoryLayers()
10958+
if ( vl->dataProvider()->name() == QLatin1String( "memory" ) )
10959+
continue;
10960+
1093410961
const bool hasUnsavedEdits = ( vl->isEditable() && vl->isModified() );
1093510962
if ( !hasUnsavedEdits )
1093610963
continue;
@@ -10944,6 +10971,38 @@ bool QgisApp::checkUnsavedLayerEdits()
1094410971
return true;
1094510972
}
1094610973

10974+
bool QgisApp::checkMemoryLayers()
10975+
{
10976+
// check to see if there are any memory layers present (with features)
10977+
bool hasMemoryLayers = false;
10978+
const QMap<QString, QgsMapLayer *> layers = QgsProject::instance()->mapLayers();
10979+
for ( auto it = layers.begin(); it != layers.end(); ++it )
10980+
{
10981+
if ( it.value() && it.value()->dataProvider()->name() == QLatin1String( "memory" ) )
10982+
{
10983+
QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( it.value() );
10984+
if ( vl && vl->featureCount() != 0 )
10985+
{
10986+
hasMemoryLayers = true;
10987+
break;
10988+
}
10989+
}
10990+
}
10991+
10992+
if ( hasMemoryLayers )
10993+
{
10994+
if ( QMessageBox::warning( this,
10995+
tr( "Close Project" ),
10996+
tr( "This project includes one or more temporary scratch layers. These layers are not saved to disk and their contents will be permanently lost. Are you sure you want to proceed?" ),
10997+
QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel ) == QMessageBox::Yes )
10998+
return true;
10999+
else
11000+
return false;
11001+
}
11002+
else
11003+
return true;
11004+
}
11005+
1094711006
bool QgisApp::checkTasksDependOnProject()
1094811007
{
1094911008
QSet< QString > activeTaskDescriptions;

‎src/app/qgisapp.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1798,6 +1798,18 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
17981798
*/
17991799
bool checkUnsavedLayerEdits();
18001800

1801+
/**
1802+
* Checks whether memory layers (with features) exist in the project, and if so
1803+
* shows a warning to users that their contents will be lost on
1804+
* project unload.
1805+
*
1806+
* Returns true if there are no memory layers present, or if the
1807+
* user opted to discard their contents. Returns false if there
1808+
* are memory layers present and the user clicked 'Cancel' on
1809+
* the warning dialog.
1810+
*/
1811+
bool checkMemoryLayers();
1812+
18011813
//! Checks for running tasks dependent on the open project
18021814
bool checkTasksDependOnProject();
18031815

0 commit comments

Comments
 (0)
Please sign in to comment.