Skip to content
Permalink
Browse files

Warn user when trying to move or delete selected features outside of …

…map view (#6092)

Sometimes users may inadvertently move/delete features they are not aware
of being selected. If that is the case, extra warning message box will be shown
for confirmation.

Does not apply for deletion from attribute table - it is assumed that features
do not need to be visible when deleting from attribute table.

In QgisApp::deleteSelected() method the last argument was not used anymore,
so I have replaced it by the "checkFeaturesVisible" argument.
  • Loading branch information
wonder-sk committed Feb 20, 2018
1 parent 1582073 commit 348b0cf8847f7b91635a00a313e9ce54ecb09a4c
Showing with 51 additions and 6 deletions.
  1. +27 −5 src/app/qgisapp.cpp
  2. +1 −1 src/app/qgisapp.h
  3. +23 −0 src/app/qgsmaptoolmovefeature.cpp
@@ -1902,7 +1902,7 @@ void QgisApp::createActions()
connect( mActionReshapeFeatures, &QAction::triggered, this, &QgisApp::reshapeFeatures );
connect( mActionSplitFeatures, &QAction::triggered, this, &QgisApp::splitFeatures );
connect( mActionSplitParts, &QAction::triggered, this, &QgisApp::splitParts );
connect( mActionDeleteSelected, &QAction::triggered, this, [ = ] { deleteSelected(); } );
connect( mActionDeleteSelected, &QAction::triggered, this, [ = ] { deleteSelected( nullptr, nullptr, true ); } );
connect( mActionAddRing, &QAction::triggered, this, &QgisApp::addRing );
connect( mActionFillRing, &QAction::triggered, this, &QgisApp::fillRing );
connect( mActionAddPart, &QAction::triggered, this, &QgisApp::addPart );
@@ -7090,7 +7090,7 @@ void QgisApp::layerProperties()
showLayerProperties( activeLayer() );
}

void QgisApp::deleteSelected( QgsMapLayer *layer, QWidget *parent, bool promptConfirmation )
void QgisApp::deleteSelected( QgsMapLayer *layer, QWidget *parent, bool checkFeaturesVisible )
{
if ( !layer )
{
@@ -7145,9 +7145,31 @@ void QgisApp::deleteSelected( QgsMapLayer *layer, QWidget *parent, bool promptCo
return;
}
//display a warning
if ( promptConfirmation && QMessageBox::warning( parent, tr( "Delete Features" ), tr( "Delete %n feature(s)?", "number of features to delete", numberOfSelectedFeatures ), QMessageBox::Ok | QMessageBox::Cancel ) == QMessageBox::Cancel )
if ( checkFeaturesVisible )
{
return;
QgsFeature feat;
QgsFeatureIterator it = vlayer->getSelectedFeatures( QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() ) );
bool allFeaturesInView = true;
QgsRectangle viewRect = mMapCanvas->mapSettings().mapToLayerCoordinates( vlayer, mMapCanvas->extent() );

while ( it.nextFeature( feat ) )
{
if ( allFeaturesInView && !viewRect.intersects( feat.geometry().boundingBox() ) )
{
allFeaturesInView = false;
break;
}
}

if ( !allFeaturesInView )
{
// for extra safety to make sure we are not removing geometries by accident
int res = QMessageBox::warning( mMapCanvas, tr( "Delete features" ),
tr( "Some of the selected features are outside of the current map view. Would you still like to continue?" ),
QMessageBox::Yes | QMessageBox::No );
if ( res != QMessageBox::Yes )
return;
}
}

vlayer->beginEditCommand( tr( "Features deleted" ) );
@@ -12272,7 +12294,7 @@ void QgisApp::mapCanvas_keyPressed( QKeyEvent *e )
// Delete selected features when it is possible and KeyEvent was not managed by current MapTool
if ( ( e->key() == Qt::Key_Backspace || e->key() == Qt::Key_Delete ) && e->isAccepted() )
{
deleteSelected();
deleteSelected( nullptr, nullptr, true );
}
}

@@ -821,7 +821,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
void loadGDALSublayers( const QString &uri, const QStringList &list );

//! Deletes the selected attributes for the currently selected vector layer
void deleteSelected( QgsMapLayer *layer = nullptr, QWidget *parent = nullptr, bool promptConfirmation = false );
void deleteSelected( QgsMapLayer *layer = nullptr, QWidget *parent = nullptr, bool checkFeaturesVisible = false );

//! project was written
void writeProject( QDomDocument & );
@@ -26,6 +26,7 @@
#include "qgsvectorlayertools.h"


#include <QMessageBox>
#include <QMouseEvent>
#include <QSettings>
#include <limits>
@@ -128,9 +129,31 @@ void QgsMapToolMoveFeature::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
QgsFeature feat;
QgsFeatureIterator it = vlayer->getSelectedFeatures( QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() ) );

bool allFeaturesInView = true;
QgsRectangle viewRect = mCanvas->mapSettings().mapToLayerCoordinates( vlayer, mCanvas->extent() );

while ( it.nextFeature( feat ) )
{
mRubberBand->addGeometry( feat.geometry(), vlayer );

if ( allFeaturesInView && !viewRect.intersects( feat.geometry().boundingBox() ) )
allFeaturesInView = false;
}

if ( !allFeaturesInView )
{
// for extra safety to make sure we are not modifying geometries by accident

int res = QMessageBox::warning( mCanvas, tr( "Move features" ),
tr( "Some of the selected features are outside of the current map view. Would you still like to continue?" ),
QMessageBox::Yes | QMessageBox::No );
if ( res != QMessageBox::Yes )
{
mMovedFeatures.clear();
delete mRubberBand;
mRubberBand = nullptr;
return;
}
}
}

0 comments on commit 348b0cf

Please sign in to comment.
You can’t perform that action at this time.