Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Make annotation item edit API a bit more flexible
  • Loading branch information
nyalldawson committed Sep 10, 2021
1 parent 4b245f5 commit 1228f59
Show file tree
Hide file tree
Showing 26 changed files with 122 additions and 59 deletions.
7 changes: 7 additions & 0 deletions python/core/auto_additions/qgis.py
Expand Up @@ -672,6 +672,13 @@
Qgis.AnnotationItemNodeType.__doc__ = 'Annotation item node types.\n\n.. versionadded:: 3.22\n\n' + '* ``VertexHandle``: ' + Qgis.AnnotationItemNodeType.VertexHandle.__doc__
# --
Qgis.AnnotationItemNodeType.baseClass = Qgis
# monkey patching scoped based enum
Qgis.AnnotationItemEditOperationResult.Success.__doc__ = "Item was modified successfully"
Qgis.AnnotationItemEditOperationResult.Invalid.__doc__ = "Operation has invalid parameters for the item, no change occurred"
Qgis.AnnotationItemEditOperationResult.ItemCleared.__doc__ = "The operation results in the item being cleared, and the item should be removed from the layer as a result"
Qgis.AnnotationItemEditOperationResult.__doc__ = 'Results from an edit operation on an annotation item.\n\n.. versionadded:: 3.22\n\n' + '* ``Success``: ' + Qgis.AnnotationItemEditOperationResult.Success.__doc__ + '\n' + '* ``Invalid``: ' + Qgis.AnnotationItemEditOperationResult.Invalid.__doc__ + '\n' + '* ``ItemCleared``: ' + Qgis.AnnotationItemEditOperationResult.ItemCleared.__doc__
# --
Qgis.AnnotationItemEditOperationResult.baseClass = Qgis
QgsVectorLayerTemporalProperties.TemporalMode = Qgis.VectorTemporalMode
# monkey patching scoped based enum
QgsVectorLayerTemporalProperties.ModeFixedTemporalRange = Qgis.VectorTemporalMode.FixedTemporalRange
Expand Down
Expand Up @@ -123,12 +123,10 @@ Implementations should include a call to :py:func:`~QgsAnnotationItem.readCommon
.. seealso:: :py:func:`readCommonProperties`
%End

virtual bool applyEdit( QgsAbstractAnnotationItemEditOperation *operation );
virtual Qgis::AnnotationItemEditOperationResult applyEdit( QgsAbstractAnnotationItemEditOperation *operation );
%Docstring
Applies an edit ``operation`` to the item.

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

.. versionadded:: 3.22
%End

Expand Down
Expand Up @@ -120,7 +120,7 @@ The optional ``feedback`` argument can be used to cancel the search early.
.. versionadded:: 3.22
%End

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

Expand Down
Expand Up @@ -41,7 +41,7 @@ Constructor for QgsAnnotationLineItem, with the specified ``linestring``.

virtual bool transform( const QTransform &transform );

virtual bool applyEdit( QgsAbstractAnnotationItemEditOperation *operation );
virtual Qgis::AnnotationItemEditOperationResult applyEdit( QgsAbstractAnnotationItemEditOperation *operation );

virtual QgsAnnotationItemEditOperationTransientResults *transientEditResults( QgsAbstractAnnotationItemEditOperation *operation ) /Factory/;

Expand Down
Expand Up @@ -39,7 +39,7 @@ Constructor for QgsAnnotationMarkerItem, at the specified ``point``.

virtual QList< QgsAnnotationItemNode > nodes() const;

virtual bool applyEdit( QgsAbstractAnnotationItemEditOperation *operation );
virtual Qgis::AnnotationItemEditOperationResult applyEdit( QgsAbstractAnnotationItemEditOperation *operation );

virtual QgsAnnotationItemEditOperationTransientResults *transientEditResults( QgsAbstractAnnotationItemEditOperation *operation ) /Factory/;

Expand Down
Expand Up @@ -55,7 +55,7 @@ Creates a new text at point annotation item.

virtual bool transform( const QTransform &transform );

virtual bool applyEdit( QgsAbstractAnnotationItemEditOperation *operation );
virtual Qgis::AnnotationItemEditOperationResult applyEdit( QgsAbstractAnnotationItemEditOperation *operation );

virtual QgsAnnotationItemEditOperationTransientResults *transientEditResults( QgsAbstractAnnotationItemEditOperation *operation ) /Factory/;

Expand Down
Expand Up @@ -41,7 +41,7 @@ Constructor for QgsAnnotationPolygonItem, with the specified ``polygon`` geometr

virtual bool transform( const QTransform &transform );

virtual bool applyEdit( QgsAbstractAnnotationItemEditOperation *operation );
virtual Qgis::AnnotationItemEditOperationResult applyEdit( QgsAbstractAnnotationItemEditOperation *operation );

virtual QgsAnnotationItemEditOperationTransientResults *transientEditResults( QgsAbstractAnnotationItemEditOperation *operation ) /Factory/;

Expand Down
7 changes: 7 additions & 0 deletions python/core/auto_generated/qgis.sip.in
Expand Up @@ -492,6 +492,13 @@ The development version
VertexHandle,
};

enum class AnnotationItemEditOperationResult
{
Success,
Invalid,
ItemCleared,
};

enum class VectorTemporalMode
{
FixedTemporalRange,
Expand Down
4 changes: 2 additions & 2 deletions src/core/annotations/qgsannotationitem.cpp
Expand Up @@ -23,9 +23,9 @@ Qgis::AnnotationItemFlags QgsAnnotationItem::flags() const
return Qgis::AnnotationItemFlags();
}

bool QgsAnnotationItem::applyEdit( QgsAbstractAnnotationItemEditOperation * )
Qgis::AnnotationItemEditOperationResult QgsAnnotationItem::applyEdit( QgsAbstractAnnotationItemEditOperation * )
{
return false;
return Qgis::AnnotationItemEditOperationResult::Invalid;
}

QgsAnnotationItemEditOperationTransientResults *QgsAnnotationItem::transientEditResults( QgsAbstractAnnotationItemEditOperation * )
Expand Down
4 changes: 1 addition & 3 deletions src/core/annotations/qgsannotationitem.h
Expand Up @@ -153,11 +153,9 @@ class CORE_EXPORT QgsAnnotationItem
/**
* Applies an edit \a operation to the item.
*
* Returns TRUE if the operation was successfully applied.
*
* \since QGIS 3.22
*/
virtual bool applyEdit( QgsAbstractAnnotationItemEditOperation *operation );
virtual Qgis::AnnotationItemEditOperationResult applyEdit( QgsAbstractAnnotationItemEditOperation *operation );

/**
* Retrieves the results of a transient (in progress) edit \a operation on the item.
Expand Down
24 changes: 18 additions & 6 deletions src/core/annotations/qgsannotationlayer.cpp
Expand Up @@ -232,9 +232,9 @@ QStringList QgsAnnotationLayer::itemsInBounds( const QgsRectangle &bounds, QgsRe
return res;
}

bool QgsAnnotationLayer::applyEdit( QgsAbstractAnnotationItemEditOperation *operation )
Qgis::AnnotationItemEditOperationResult QgsAnnotationLayer::applyEdit( QgsAbstractAnnotationItemEditOperation *operation )
{
bool res = false;
Qgis::AnnotationItemEditOperationResult res = Qgis::AnnotationItemEditOperationResult::Invalid;
if ( QgsAnnotationItem *targetItem = item( operation->itemId() ) )
{
// remove item from index if present
Expand All @@ -245,12 +245,24 @@ bool QgsAnnotationLayer::applyEdit( QgsAbstractAnnotationItemEditOperation *oper
}
res = targetItem->applyEdit( operation );

// and re-add to index if possible
if ( !( targetItem->flags() & Qgis::AnnotationItemFlag::ScaleDependentBoundingBox ) )
mSpatialIndex->insert( operation->itemId(), targetItem->boundingBox() );
switch ( res )
{
case Qgis::AnnotationItemEditOperationResult::Success:
case Qgis::AnnotationItemEditOperationResult::Invalid:
// re-add to index if possible
if ( !( targetItem->flags() & Qgis::AnnotationItemFlag::ScaleDependentBoundingBox ) )
mSpatialIndex->insert( operation->itemId(), targetItem->boundingBox() );
break;

case Qgis::AnnotationItemEditOperationResult::ItemCleared:
// item needs removing from layer
delete mItems.take( operation->itemId() );
mNonIndexedItems.remove( operation->itemId() );
break;
}
}

if ( res )
if ( res != Qgis::AnnotationItemEditOperationResult::Invalid )
triggerRepaint();

return res;
Expand Down
2 changes: 1 addition & 1 deletion src/core/annotations/qgsannotationlayer.h
Expand Up @@ -155,7 +155,7 @@ class CORE_EXPORT QgsAnnotationLayer : public QgsMapLayer
*
* \since QGIS 3.22
*/
bool applyEdit( QgsAbstractAnnotationItemEditOperation *operation );
Qgis::AnnotationItemEditOperationResult applyEdit( QgsAbstractAnnotationItemEditOperation *operation );

Qgis::MapLayerProperties properties() const override;
QgsAnnotationLayer *clone() const override SIP_FACTORY;
Expand Down
12 changes: 8 additions & 4 deletions src/core/annotations/qgsannotationlineitem.cpp
Expand Up @@ -103,24 +103,28 @@ bool QgsAnnotationLineItem::transform( const QTransform &transform )
return true;
}

bool QgsAnnotationLineItem::applyEdit( QgsAbstractAnnotationItemEditOperation *operation )
Qgis::AnnotationItemEditOperationResult QgsAnnotationLineItem::applyEdit( QgsAbstractAnnotationItemEditOperation *operation )
{
switch ( operation->type() )
{
case QgsAbstractAnnotationItemEditOperation::Type::MoveNode:
{
QgsAnnotationItemEditOperationMoveNode *moveOperation = qgis::down_cast< QgsAnnotationItemEditOperationMoveNode * >( operation );
return mCurve->moveVertex( moveOperation->nodeId(), QgsPoint( moveOperation->after() ) );
if ( mCurve->moveVertex( moveOperation->nodeId(), QgsPoint( moveOperation->after() ) ) )
return Qgis::AnnotationItemEditOperationResult::Success;
break;
}

case QgsAbstractAnnotationItemEditOperation::Type::DeleteNode:
{
QgsAnnotationItemEditOperationDeleteNode *deleteOperation = qgis::down_cast< QgsAnnotationItemEditOperationDeleteNode * >( operation );
return mCurve->deleteVertex( deleteOperation->nodeId() );
if ( mCurve->deleteVertex( deleteOperation->nodeId() ) )
return mCurve->isEmpty() ? Qgis::AnnotationItemEditOperationResult::ItemCleared : Qgis::AnnotationItemEditOperationResult::Success;
break;
}
}

return false;
return Qgis::AnnotationItemEditOperationResult::Invalid;
}

QgsAnnotationItemEditOperationTransientResults *QgsAnnotationLineItem::transientEditResults( QgsAbstractAnnotationItemEditOperation *operation )
Expand Down
2 changes: 1 addition & 1 deletion src/core/annotations/qgsannotationlineitem.h
Expand Up @@ -46,7 +46,7 @@ class CORE_EXPORT QgsAnnotationLineItem : public QgsAnnotationItem
QList< QgsAnnotationItemNode > nodes() const override;
QgsGeometry rubberBandGeometry() const override;
bool transform( const QTransform &transform ) override;
bool applyEdit( QgsAbstractAnnotationItemEditOperation *operation ) override;
Qgis::AnnotationItemEditOperationResult applyEdit( QgsAbstractAnnotationItemEditOperation *operation ) override;
QgsAnnotationItemEditOperationTransientResults *transientEditResults( QgsAbstractAnnotationItemEditOperation *operation ) override SIP_FACTORY;

/**
Expand Down
8 changes: 4 additions & 4 deletions src/core/annotations/qgsannotationmarkeritem.cpp
Expand Up @@ -80,24 +80,24 @@ QList<QgsAnnotationItemNode> QgsAnnotationMarkerItem::nodes() const
return { QgsAnnotationItemNode( QgsVertexId( 0, 0, 0 ), mPoint, Qgis::AnnotationItemNodeType::VertexHandle )};
}

bool QgsAnnotationMarkerItem::applyEdit( QgsAbstractAnnotationItemEditOperation *operation )
Qgis::AnnotationItemEditOperationResult QgsAnnotationMarkerItem::applyEdit( QgsAbstractAnnotationItemEditOperation *operation )
{
switch ( operation->type() )
{
case QgsAbstractAnnotationItemEditOperation::Type::MoveNode:
{
QgsAnnotationItemEditOperationMoveNode *moveOperation = qgis::down_cast< QgsAnnotationItemEditOperationMoveNode * >( operation );
mPoint = QgsPoint( moveOperation->after() );
return true;
return Qgis::AnnotationItemEditOperationResult::Success;
}

case QgsAbstractAnnotationItemEditOperation::Type::DeleteNode:
{
return false;
return Qgis::AnnotationItemEditOperationResult::ItemCleared;
}
}

return false;
return Qgis::AnnotationItemEditOperationResult::Invalid;
}

QgsAnnotationItemEditOperationTransientResults *QgsAnnotationMarkerItem::transientEditResults( QgsAbstractAnnotationItemEditOperation *operation )
Expand Down
2 changes: 1 addition & 1 deletion src/core/annotations/qgsannotationmarkeritem.h
Expand Up @@ -44,7 +44,7 @@ class CORE_EXPORT QgsAnnotationMarkerItem : public QgsAnnotationItem
bool writeXml( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const override;
Qgis::AnnotationItemFlags flags() const override;
QList< QgsAnnotationItemNode > nodes() const override;
bool applyEdit( QgsAbstractAnnotationItemEditOperation *operation ) override;
Qgis::AnnotationItemEditOperationResult applyEdit( QgsAbstractAnnotationItemEditOperation *operation ) override;
QgsAnnotationItemEditOperationTransientResults *transientEditResults( QgsAbstractAnnotationItemEditOperation *operation ) override SIP_FACTORY;

/**
Expand Down
8 changes: 4 additions & 4 deletions src/core/annotations/qgsannotationpointtextitem.cpp
Expand Up @@ -147,24 +147,24 @@ bool QgsAnnotationPointTextItem::transform( const QTransform &transform )
return true;
}

bool QgsAnnotationPointTextItem::applyEdit( QgsAbstractAnnotationItemEditOperation *operation )
Qgis::AnnotationItemEditOperationResult QgsAnnotationPointTextItem::applyEdit( QgsAbstractAnnotationItemEditOperation *operation )
{
switch ( operation->type() )
{
case QgsAbstractAnnotationItemEditOperation::Type::MoveNode:
{
QgsAnnotationItemEditOperationMoveNode *moveOperation = dynamic_cast< QgsAnnotationItemEditOperationMoveNode * >( operation );
mPoint = moveOperation->after();
return true;
return Qgis::AnnotationItemEditOperationResult::Success;
}

case QgsAbstractAnnotationItemEditOperation::Type::DeleteNode:
{
return false;
return Qgis::AnnotationItemEditOperationResult::ItemCleared;
}
}

return false;
return Qgis::AnnotationItemEditOperationResult::Invalid;
}

QgsAnnotationItemEditOperationTransientResults *QgsAnnotationPointTextItem::transientEditResults( QgsAbstractAnnotationItemEditOperation *operation )
Expand Down
2 changes: 1 addition & 1 deletion src/core/annotations/qgsannotationpointtextitem.h
Expand Up @@ -56,7 +56,7 @@ class CORE_EXPORT QgsAnnotationPointTextItem : public QgsAnnotationItem
QgsRectangle boundingBox( QgsRenderContext &context ) const override;
QList< QgsAnnotationItemNode > nodes() const override;
bool transform( const QTransform &transform ) override;
bool applyEdit( QgsAbstractAnnotationItemEditOperation *operation ) override;
Qgis::AnnotationItemEditOperationResult applyEdit( QgsAbstractAnnotationItemEditOperation *operation ) override;
QgsAnnotationItemEditOperationTransientResults *transientEditResults( QgsAbstractAnnotationItemEditOperation *operation ) override SIP_FACTORY;

/**
Expand Down
12 changes: 8 additions & 4 deletions src/core/annotations/qgsannotationpolygonitem.cpp
Expand Up @@ -133,24 +133,28 @@ bool QgsAnnotationPolygonItem::transform( const QTransform &transform )
return true;
}

bool QgsAnnotationPolygonItem::applyEdit( QgsAbstractAnnotationItemEditOperation *operation )
Qgis::AnnotationItemEditOperationResult QgsAnnotationPolygonItem::applyEdit( QgsAbstractAnnotationItemEditOperation *operation )
{
switch ( operation->type() )
{
case QgsAbstractAnnotationItemEditOperation::Type::MoveNode:
{
QgsAnnotationItemEditOperationMoveNode *moveOperation = dynamic_cast< QgsAnnotationItemEditOperationMoveNode * >( operation );
return mPolygon->moveVertex( moveOperation->nodeId(), QgsPoint( moveOperation->after() ) );
if ( mPolygon->moveVertex( moveOperation->nodeId(), QgsPoint( moveOperation->after() ) ) )
return Qgis::AnnotationItemEditOperationResult::Success;
break;
}

case QgsAbstractAnnotationItemEditOperation::Type::DeleteNode:
{
QgsAnnotationItemEditOperationDeleteNode *deleteOperation = qgis::down_cast< QgsAnnotationItemEditOperationDeleteNode * >( operation );
return mPolygon->deleteVertex( deleteOperation->nodeId() );
if ( mPolygon->deleteVertex( deleteOperation->nodeId() ) )
return mPolygon->isEmpty() ? Qgis::AnnotationItemEditOperationResult::ItemCleared : Qgis::AnnotationItemEditOperationResult::Success;
break;
}
}

return false;
return Qgis::AnnotationItemEditOperationResult::Invalid;
}

QgsAnnotationItemEditOperationTransientResults *QgsAnnotationPolygonItem::transientEditResults( QgsAbstractAnnotationItemEditOperation *operation )
Expand Down
2 changes: 1 addition & 1 deletion src/core/annotations/qgsannotationpolygonitem.h
Expand Up @@ -45,7 +45,7 @@ class CORE_EXPORT QgsAnnotationPolygonItem : public QgsAnnotationItem
QList< QgsAnnotationItemNode > nodes() const override;
QgsGeometry rubberBandGeometry() const override;
bool transform( const QTransform &transform ) override;
bool applyEdit( QgsAbstractAnnotationItemEditOperation *operation ) override;
Qgis::AnnotationItemEditOperationResult applyEdit( QgsAbstractAnnotationItemEditOperation *operation ) override;
QgsAnnotationItemEditOperationTransientResults *transientEditResults( QgsAbstractAnnotationItemEditOperation *operation ) override SIP_FACTORY;

/**
Expand Down
13 changes: 13 additions & 0 deletions src/core/qgis.h
Expand Up @@ -777,6 +777,19 @@ class CORE_EXPORT Qgis
};
Q_ENUM( AnnotationItemNodeType )

/**
* Results from an edit operation on an annotation item.
*
* \since QGIS 3.22
*/
enum class AnnotationItemEditOperationResult : int
{
Success, //!< Item was modified successfully
Invalid, //!< Operation has invalid parameters for the item, no change occurred
ItemCleared, //!< The operation results in the item being cleared, and the item should be removed from the layer as a result
};
Q_ENUM( AnnotationItemEditOperationResult )

/**
* Vector layer temporal feature modes
*
Expand Down
9 changes: 5 additions & 4 deletions tests/src/python/test_qgsannotationlayer.py
Expand Up @@ -43,7 +43,8 @@
QgsGeometry,
QgsAnnotationItemEditOperationMoveNode,
QgsVertexId,
QgsPointXY
QgsPointXY,
Qgis
)
from qgis.testing import start_app, unittest

Expand Down Expand Up @@ -279,12 +280,12 @@ def test_apply_edit(self):
self.assertCountEqual(layer.itemsInBounds(QgsRectangle(1, 1, 20, 20), rc), [polygon_item_id, linestring_item_id, marker_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), QgsPoint(14, 15), QgsPoint(19, 15))))
self.assertEqual(layer.applyEdit(QgsAnnotationItemEditOperationMoveNode('xxx', QgsVertexId(0, 0, 2), QgsPoint(14, 15), QgsPoint(19, 15))), Qgis.AnnotationItemEditOperationResult.Invalid)

# apply move to polygon
self.assertTrue(layer.applyEdit(
self.assertEqual(layer.applyEdit(
QgsAnnotationItemEditOperationMoveNode(polygon_item_id, QgsVertexId(0, 0, 2), QgsPoint(14, 15),
QgsPoint(19, 15))))
QgsPoint(19, 15))), Qgis.AnnotationItemEditOperationResult.Success)

self.assertEqual(layer.item(polygon_item_id).geometry().asWkt(), 'Polygon ((12 13, 14 13, 19 15, 12 13))')
# ensure that spatial index was updated
Expand Down

0 comments on commit 1228f59

Please sign in to comment.