Skip to content

Commit 8ce6d28

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. (cherry-picked from 0dc1a61)
1 parent 7d67897 commit 8ce6d28

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
@@ -5142,7 +5142,7 @@ void QgisApp::fileExit()
51425142
return;
51435143
}
51445144

5145-
if ( checkUnsavedLayerEdits() && saveDirty() )
5145+
if ( checkUnsavedLayerEdits() && checkMemoryLayers() && saveDirty() )
51465146
{
51475147
closeProject();
51485148
userProfileManager()->setDefaultFromActive();
@@ -5177,7 +5177,7 @@ bool QgisApp::fileNew( bool promptToSaveFlag, bool forceBlank )
51775177

51785178
if ( promptToSaveFlag )
51795179
{
5180-
if ( !checkUnsavedLayerEdits() || !saveDirty() )
5180+
if ( !checkUnsavedLayerEdits() || !checkMemoryLayers() || !saveDirty() )
51815181
{
51825182
return false; //cancel pressed
51835183
}
@@ -5271,7 +5271,7 @@ bool QgisApp::fileNewFromTemplate( const QString &fileName )
52715271
if ( checkTasksDependOnProject() )
52725272
return false;
52735273

5274-
if ( !checkUnsavedLayerEdits() || !saveDirty() )
5274+
if ( !checkUnsavedLayerEdits() || !checkMemoryLayers() || !saveDirty() )
52755275
{
52765276
return false; //cancel pressed
52775277
}
@@ -5570,7 +5570,7 @@ void QgisApp::fileOpen()
55705570
return;
55715571

55725572
// possibly save any pending work before opening a new project
5573-
if ( checkUnsavedLayerEdits() && saveDirty() )
5573+
if ( checkUnsavedLayerEdits() && checkMemoryLayers() && saveDirty() )
55745574
{
55755575
// Retrieve last used project dir from persistent settings
55765576
QgsSettings settings;
@@ -5604,7 +5604,7 @@ void QgisApp::fileRevert()
56045604
QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) == QMessageBox::No )
56055605
return;
56065606

5607-
if ( !checkUnsavedLayerEdits() )
5607+
if ( !checkUnsavedLayerEdits() || !checkMemoryLayers() )
56085608
return;
56095609

56105610
// re-open the current project
@@ -6034,7 +6034,7 @@ void QgisApp::openProject( QAction *action )
60346034
return;
60356035

60366036
QString debugme = action->data().toString();
6037-
if ( checkUnsavedLayerEdits() && saveDirty() )
6037+
if ( checkUnsavedLayerEdits() && checkMemoryLayers() && saveDirty() )
60386038
addProject( debugme );
60396039
}
60406040

@@ -6060,7 +6060,7 @@ void QgisApp::openProject( const QString &fileName )
60606060
return;
60616061

60626062
// possibly save any pending work before opening a different project
6063-
if ( checkUnsavedLayerEdits() && saveDirty() )
6063+
if ( checkUnsavedLayerEdits() && checkMemoryLayers() && saveDirty() )
60646064
{
60656065
// error handling and reporting is in addProject() function
60666066
addProject( fileName );
@@ -10777,7 +10777,9 @@ bool QgisApp::saveDirty()
1077710777
for ( QMap<QString, QgsMapLayer *>::iterator it = layers.begin(); it != layers.end(); ++it )
1077810778
{
1077910779
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( it.value() );
10780-
if ( !vl )
10780+
// note that we skip the unsaved edits check for memory layers -- it's misleading, because their contents aren't actually
10781+
// saved if this is part of a project close operation. Instead we let these get picked up by checkMemoryLayers().
10782+
if ( !vl || vl->dataProvider()->name() == QLatin1String( "memory" ) )
1078110783
{
1078210784
continue;
1078310785
}
@@ -10831,7 +10833,27 @@ bool QgisApp::saveDirty()
1083110833

1083210834
freezeCanvases( false );
1083310835

10834-
return answer != QMessageBox::Cancel;
10836+
if ( answer == QMessageBox::Cancel )
10837+
return false;
10838+
10839+
// for memory layers, we discard all unsaved changes manually. Users have already been warned about
10840+
// these by an earlier call to checkMemoryLayers(), and we don't want duplicate "unsaved changes" prompts
10841+
// and anyway, saving the changes to a memory layer here won't actually save ANYTHING!
10842+
// we do this at the very end here, because if the user opted to cancel above then ALL unsaved
10843+
// changes in memory layers should still exist for them.
10844+
const QMap<QString, QgsMapLayer *> layers = QgsProject::instance()->mapLayers();
10845+
for ( auto it = layers.begin(); it != layers.end(); ++it )
10846+
{
10847+
if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( it.value() ) )
10848+
{
10849+
if ( vl->dataProvider()->name() == QLatin1String( "memory" ) && vl->isEditable() && vl->isModified() )
10850+
{
10851+
vl->rollBack();
10852+
}
10853+
}
10854+
}
10855+
10856+
return true;
1083510857
}
1083610858

1083710859
bool QgisApp::checkUnsavedLayerEdits()
@@ -10845,6 +10867,11 @@ bool QgisApp::checkUnsavedLayerEdits()
1084510867
{
1084610868
if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( it.value() ) )
1084710869
{
10870+
// note that we skip the unsaved edits check for memory layers -- it's misleading, because their contents aren't actually
10871+
// saved if this is part of a project close operation. Instead we let these get picked up by checkMemoryLayers()
10872+
if ( vl->dataProvider()->name() == QLatin1String( "memory" ) )
10873+
continue;
10874+
1084810875
const bool hasUnsavedEdits = ( vl->isEditable() && vl->isModified() );
1084910876
if ( !hasUnsavedEdits )
1085010877
continue;
@@ -10858,6 +10885,38 @@ bool QgisApp::checkUnsavedLayerEdits()
1085810885
return true;
1085910886
}
1086010887

10888+
bool QgisApp::checkMemoryLayers()
10889+
{
10890+
// check to see if there are any memory layers present (with features)
10891+
bool hasMemoryLayers = false;
10892+
const QMap<QString, QgsMapLayer *> layers = QgsProject::instance()->mapLayers();
10893+
for ( auto it = layers.begin(); it != layers.end(); ++it )
10894+
{
10895+
if ( it.value() && it.value()->dataProvider()->name() == QLatin1String( "memory" ) )
10896+
{
10897+
QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( it.value() );
10898+
if ( vl && vl->featureCount() != 0 )
10899+
{
10900+
hasMemoryLayers = true;
10901+
break;
10902+
}
10903+
}
10904+
}
10905+
10906+
if ( hasMemoryLayers )
10907+
{
10908+
if ( QMessageBox::warning( this,
10909+
tr( "Close Project" ),
10910+
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?" ),
10911+
QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel ) == QMessageBox::Yes )
10912+
return true;
10913+
else
10914+
return false;
10915+
}
10916+
else
10917+
return true;
10918+
}
10919+
1086110920
bool QgisApp::checkTasksDependOnProject()
1086210921
{
1086310922
QSet< QString > activeTaskDescriptions;

‎src/app/qgisapp.h

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

1793+
/**
1794+
* Checks whether memory layers (with features) exist in the project, and if so
1795+
* shows a warning to users that their contents will be lost on
1796+
* project unload.
1797+
*
1798+
* Returns true if there are no memory layers present, or if the
1799+
* user opted to discard their contents. Returns false if there
1800+
* are memory layers present and the user clicked 'Cancel' on
1801+
* the warning dialog.
1802+
*/
1803+
bool checkMemoryLayers();
1804+
17931805
//! Checks for running tasks dependent on the open project
17941806
bool checkTasksDependOnProject();
17951807

0 commit comments

Comments
 (0)
Please sign in to comment.