Skip to content
Permalink
Browse files
[feature] Pressing delete/backspace will delete the current node
when editing an annotation item
  • Loading branch information
nyalldawson committed Sep 10, 2021
1 parent 1228f59 commit f76b262ac08a32b675c7b1be6d4cc4f4c6f5803b
Showing with 126 additions and 6 deletions.
  1. +47 −6 src/gui/annotations/qgsmaptoolmodifyannotation.cpp
  2. +79 −0 tests/src/app/testqgsmaptooleditannotation.cpp
@@ -219,7 +219,7 @@ void QgsMapToolModifyAnnotation::cadCanvasMoveEvent( QgsMapMouseEvent *event )
{
QgsAnnotationLayer *layer = annotationLayerFromId( mSelectedItemLayerId );
const QgsPointXY endPointLayer = toLayerCoordinates( layer, event->mapPoint() );
QgsAnnotationItemEditOperationMoveNode operation( mSelectedItemId, mTargetNode.id(), mTargetNode.point(), endPointLayer );
QgsAnnotationItemEditOperationMoveNode operation( mSelectedItemId, mTargetNode.id(), QgsPoint( mTargetNode.point() ), QgsPoint( endPointLayer ) );
std::unique_ptr< QgsAnnotationItemEditOperationTransientResults > operationResults( item->transientEditResults( &operation ) );
if ( operationResults )
{
@@ -373,10 +373,18 @@ void QgsMapToolModifyAnnotation::cadCanvasPressEvent( QgsMapMouseEvent *event )
if ( QgsAnnotationLayer *layer = annotationLayerFromId( mSelectedItemLayerId ) )
{
const QgsPointXY endPointLayer = toLayerCoordinates( layer, event->mapPoint() );
QgsAnnotationItemEditOperationMoveNode operation( mSelectedItemId, mTargetNode.id(), mTargetNode.point(), endPointLayer );
if ( layer->applyEdit( &operation ) )
QgsProject::instance()->setDirty( true );
mRefreshSelectedItemAfterRedraw = true;
QgsAnnotationItemEditOperationMoveNode operation( mSelectedItemId, mTargetNode.id(), QgsPoint( mTargetNode.point() ), QgsPoint( endPointLayer ) );
switch ( layer->applyEdit( &operation ) )
{
case Qgis::AnnotationItemEditOperationResult::Success:
QgsProject::instance()->setDirty( true );
mRefreshSelectedItemAfterRedraw = true;
break;

case Qgis::AnnotationItemEditOperationResult::Invalid:
case Qgis::AnnotationItemEditOperationResult::ItemCleared:
break;
}
}

mTemporaryRubberBand.reset();
@@ -431,9 +439,42 @@ void QgsMapToolModifyAnnotation::keyPressEvent( QKeyEvent *event )
break;
}

case Action::MoveItem:
case Action::MoveNode:
{
if ( event->key() == Qt::Key_Delete || event->key() == Qt::Key_Backspace )
{
if ( QgsAnnotationLayer *layer = annotationLayerFromId( mSelectedItemLayerId ) )
{
QgsAnnotationItemEditOperationDeleteNode operation( mSelectedItemId, mTargetNode.id(), QgsPoint( mTargetNode.point() ) );
switch ( layer->applyEdit( &operation ) )
{
case Qgis::AnnotationItemEditOperationResult::Success:
QgsProject::instance()->setDirty( true );
mRefreshSelectedItemAfterRedraw = true;
break;
case Qgis::AnnotationItemEditOperationResult::Invalid:
break;
case Qgis::AnnotationItemEditOperationResult::ItemCleared:
QgsProject::instance()->setDirty( true );
break;
}
}

mTemporaryRubberBand.reset();
mHoveredItemNodeRubberBands.clear();
mHoveredItemNodes.clear();
mTemporaryRubberBand.reset();
mCurrentAction = Action::NoAction;
setCursor( Qt::ArrowCursor );
event->ignore(); // disable default shortcut handling (delete vector feature)
break;
}
FALLTHROUGH
}

case Action::MoveItem:
{
// warning -- fallthrough above!
if ( event->key() == Qt::Key_Escape )
{
mCurrentAction = Action::NoAction;
@@ -49,6 +49,7 @@ class TestQgsMapToolEditAnnotation : public QObject
void testDeleteItem();
void testMoveItem();
void testMoveNode();
void testDeleteNode();

};

@@ -418,6 +419,84 @@ void TestQgsMapToolEditAnnotation::testMoveNode()
QCOMPARE( qgis::down_cast< QgsAnnotationPolygonItem * >( layer->item( i1id ) )->geometry()->asWkt( 1 ), QStringLiteral( "Polygon ((1 1, 5.5 1.5, 4.5 4.5, 1 5, 1 1))" ) );
}

void TestQgsMapToolEditAnnotation::testDeleteNode()
{
QgsProject::instance()->clear();
QgsMapCanvas canvas;
canvas.setDestinationCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) );
canvas.setFrameStyle( QFrame::NoFrame );
canvas.resize( 600, 600 );
canvas.setExtent( QgsRectangle( 0, 0, 10, 10 ) );
canvas.show(); // to make the canvas resize

QgsAnnotationLayer *layer = new QgsAnnotationLayer( QStringLiteral( "test" ), QgsAnnotationLayer::LayerOptions( QgsProject::instance()->transformContext() ) );
QVERIFY( layer->isValid() );
QgsProject::instance()->addMapLayers( { layer } );

QgsAnnotationPolygonItem *item1 = new QgsAnnotationPolygonItem( new QgsPolygon( new QgsLineString( QVector<QgsPoint> { QgsPoint( 1, 1 ), QgsPoint( 5, 1 ), QgsPoint( 5, 5 ), QgsPoint( 1, 5 ), QgsPoint( 1, 1 ) } ) ) );
item1->setZIndex( 1 );
const QString i1id = layer->addItem( item1 );
QCOMPARE( qgis::down_cast< QgsAnnotationPolygonItem * >( layer->item( i1id ) )->geometry()->asWkt(), QStringLiteral( "Polygon ((1 1, 5 1, 5 5, 1 5, 1 1))" ) );

layer->setCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) );

canvas.setLayers( { layer } );
while ( !canvas.isDrawing() )
{
QgsApplication::processEvents();
}
canvas.waitWhileRendering();
QCOMPARE( canvas.renderedItemResults()->renderedItems().size(), 1 );

QgsAdvancedDigitizingDockWidget cadDock( &canvas );
QgsMapToolModifyAnnotation tool( &canvas, &cadDock );
canvas.setMapTool( &tool );

QSignalSpy spy( &tool, &QgsMapToolModifyAnnotation::itemSelected );
TestQgsMapToolUtils utils( &tool );

// click on item
utils.mouseMove( 1.5, 1.5 );
utils.mouseClick( 1.5, 1.5, Qt::LeftButton, Qt::KeyboardModifiers(), true );
QCOMPARE( spy.count(), 1 );
QCOMPARE( spy.at( 0 ).at( 1 ).toString(), i1id );

// click on a node
utils.mouseMove( 5, 5 );
utils.mouseClick( 5, 5, Qt::LeftButton, Qt::KeyboardModifiers(), true );
// second click isn't selecting an item, so no new signals should be emitted
QCOMPARE( spy.count(), 1 );

// delete node
utils.keyClick( Qt::Key_Delete );
while ( !canvas.isDrawing() )
{
QgsApplication::processEvents();
}
canvas.waitWhileRendering();
QCOMPARE( canvas.renderedItemResults()->renderedItems().size(), 1 );

// check that node was deleted
QCOMPARE( qgis::down_cast< QgsAnnotationPolygonItem * >( layer->item( i1id ) )->geometry()->asWkt(), QStringLiteral( "Polygon ((1 1, 5 1, 1 5, 1 1))" ) );

// start a new delete node
// click on item -- it should already be selected, so this will start a new move, not emit the itemSelected signal
utils.mouseMove( 5, 1 );
utils.mouseClick( 5, 1, Qt::LeftButton, Qt::KeyboardModifiers(), true );
QCOMPARE( spy.count(), 1 );

utils.keyClick( Qt::Key_Delete );
while ( !canvas.isDrawing() )
{
QgsApplication::processEvents();
}
canvas.waitWhileRendering();

// check that node was deleted -- this should delete the whole item, as its geometry was cleared
QCOMPARE( canvas.renderedItemResults()->renderedItems().size(), 0 );
QVERIFY( !layer->item( i1id ) );
}


QGSTEST_MAIN( TestQgsMapToolEditAnnotation )
#include "testqgsmaptooleditannotation.moc"

0 comments on commit f76b262

Please sign in to comment.