Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add method to apply a annotation item edit operation directly
onto a QgsAnnotationLayer
  • Loading branch information
nyalldawson committed Sep 10, 2021
1 parent 6313432 commit 1fe8743
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 1 deletion.
10 changes: 10 additions & 0 deletions python/core/auto_generated/annotations/qgsannotationlayer.sip.in
Expand Up @@ -11,6 +11,7 @@




class QgsAnnotationLayer : QgsMapLayer
{
%Docstring(signature="appended")
Expand Down Expand Up @@ -116,6 +117,15 @@ rendered using the given render ``context``.

The optional ``feedback`` argument can be used to cancel the search early.

.. versionadded:: 3.22
%End

bool applyEdit( QgsAbstractAnnotationItemEditOperation *operation );
%Docstring
Applies an edit ``operation`` to the layer.

Returns ``True`` if the operation was successfully applied.

.. versionadded:: 3.22
%End

Expand Down
25 changes: 25 additions & 0 deletions src/core/annotations/qgsannotationlayer.cpp
Expand Up @@ -23,6 +23,7 @@
#include "qgspainting.h"
#include "qgsmaplayerfactory.h"
#include "qgsfeedback.h"
#include "qgsannotationitemeditoperation.h"
#include <QUuid>
#include "RTree.h"

Expand Down Expand Up @@ -231,6 +232,30 @@ QStringList QgsAnnotationLayer::itemsInBounds( const QgsRectangle &bounds, QgsRe
return res;
}

bool QgsAnnotationLayer::applyEdit( QgsAbstractAnnotationItemEditOperation *operation )
{
bool res = false;
if ( QgsAnnotationItem *targetItem = item( operation->itemId() ) )
{
// remove item from index if present
auto it = mNonIndexedItems.find( operation->itemId() );
if ( it == mNonIndexedItems.end() )
{
mSpatialIndex->remove( operation->itemId(), targetItem->boundingBox() );
}
res = targetItem->applyEdit( operation );

// and re-add to index if possible
if ( !( targetItem->flags() & Qgis::AnnotationItemFlag::ScaleDependentBoundingBox ) )
mSpatialIndex->insert( operation->itemId(), targetItem->boundingBox() );
}

if ( res )
triggerRepaint();

return res;
}

Qgis::MapLayerProperties QgsAnnotationLayer::properties() const
{
// annotation layers are always editable
Expand Down
11 changes: 11 additions & 0 deletions src/core/annotations/qgsannotationlayer.h
Expand Up @@ -24,6 +24,8 @@


class QgsAnnotationItem;
class QgsAbstractAnnotationItemEditOperation;

///@cond PRIVATE
class QgsAnnotationLayerSpatialIndex;
///@endcond
Expand Down Expand Up @@ -146,6 +148,15 @@ class CORE_EXPORT QgsAnnotationLayer : public QgsMapLayer
*/
QStringList itemsInBounds( const QgsRectangle &bounds, QgsRenderContext &context, QgsFeedback *feedback = nullptr ) const;

/**
* Applies an edit \a operation to the layer.
*
* Returns TRUE if the operation was successfully applied.
*
* \since QGIS 3.22
*/
bool applyEdit( QgsAbstractAnnotationItemEditOperation *operation );

Qgis::MapLayerProperties properties() const override;
QgsAnnotationLayer *clone() const override SIP_FACTORY;
QgsMapLayerRenderer *createMapRenderer( QgsRenderContext &rendererContext ) override SIP_FACTORY;
Expand Down
37 changes: 36 additions & 1 deletion tests/src/python/test_qgsannotationlayer.py
Expand Up @@ -40,7 +40,11 @@
QgsMarkerSymbol,
QgsMapRendererSequentialJob,
QgsMapRendererParallelJob,
QgsGeometry
QgsGeometry,
QgsAbstractAnnotationItemEditOperation,
QgsAnnotationItemEditOperationMoveNode,
QgsVertexId,
QgsPointXY
)
from qgis.testing import start_app, unittest

Expand Down Expand Up @@ -259,6 +263,37 @@ def testProjectMainAnnotationLayer(self):
self.assertIsInstance(p2.mainAnnotationLayer().items()[linestring_item_id], QgsAnnotationLineItem)
self.assertIsInstance(p2.mainAnnotationLayer().items()[marker_item_id], QgsAnnotationMarkerItem)

def test_apply_edit(self):
"""
Test applying edits to a layer
"""
layer = QgsAnnotationLayer('test', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()))
self.assertTrue(layer.isValid())

polygon_item_id = layer.addItem(QgsAnnotationPolygonItem(
QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)]))))
linestring_item_id = layer.addItem(
QgsAnnotationLineItem(QgsLineString([QgsPoint(11, 13), QgsPoint(12, 13), QgsPoint(12, 15)])))
marker_item_id = layer.addItem(QgsAnnotationMarkerItem(QgsPoint(12, 13)))

rc = QgsRenderContext()
self.assertCountEqual(layer.itemsInBounds(QgsRectangle(1, 1, 20, 20), rc), [polygon_item_id, linestring_item_id, marker_item_id])

# can't apply the abstract operation to a layer
self.assertFalse(layer.applyEdit(QgsAbstractAnnotationItemEditOperation(polygon_item_id)))

# can't apply a move to an item which doesn't exist in the layer
self.assertFalse(layer.applyEdit(QgsAnnotationItemEditOperationMoveNode('xxx', QgsVertexId(0, 0, 2), QgsPointXY(14, 15), QgsPointXY(19, 15))))

# apply move to polygon
self.assertTrue(layer.applyEdit(
QgsAnnotationItemEditOperationMoveNode(polygon_item_id, QgsVertexId(0, 0, 2), QgsPointXY(14, 15),
QgsPointXY(19, 15))))

self.assertEqual(layer.item(polygon_item_id).geometry().asWkt(), 'Polygon ((12 13, 14 13, 19 15, 12 13))')
# ensure that spatial index was updated
self.assertCountEqual(layer.itemsInBounds(QgsRectangle(18, 1, 20, 16), rc), [polygon_item_id])

def testRenderLayer(self):
layer = QgsAnnotationLayer('test', QgsAnnotationLayer.LayerOptions(QgsProject.instance().transformContext()))
layer.setCrs(QgsCoordinateReferenceSystem('EPSG:4326'))
Expand Down

0 comments on commit 1fe8743

Please sign in to comment.