Skip to content
Permalink
Browse files
Make annotation item edit API a bit more flexible
  • Loading branch information
nyalldawson committed Sep 10, 2021
1 parent 4b245f5 commit 1228f59bff158dcf8f29955e36ef23fee1c026a2
Showing with 122 additions and 59 deletions.
  1. +7 −0 python/core/auto_additions/qgis.py
  2. +1 −3 python/core/auto_generated/annotations/qgsannotationitem.sip.in
  3. +1 −1 python/core/auto_generated/annotations/qgsannotationlayer.sip.in
  4. +1 −1 python/core/auto_generated/annotations/qgsannotationlineitem.sip.in
  5. +1 −1 python/core/auto_generated/annotations/qgsannotationmarkeritem.sip.in
  6. +1 −1 python/core/auto_generated/annotations/qgsannotationpointtextitem.sip.in
  7. +1 −1 python/core/auto_generated/annotations/qgsannotationpolygonitem.sip.in
  8. +7 −0 python/core/auto_generated/qgis.sip.in
  9. +2 −2 src/core/annotations/qgsannotationitem.cpp
  10. +1 −3 src/core/annotations/qgsannotationitem.h
  11. +18 −6 src/core/annotations/qgsannotationlayer.cpp
  12. +1 −1 src/core/annotations/qgsannotationlayer.h
  13. +8 −4 src/core/annotations/qgsannotationlineitem.cpp
  14. +1 −1 src/core/annotations/qgsannotationlineitem.h
  15. +4 −4 src/core/annotations/qgsannotationmarkeritem.cpp
  16. +1 −1 src/core/annotations/qgsannotationmarkeritem.h
  17. +4 −4 src/core/annotations/qgsannotationpointtextitem.cpp
  18. +1 −1 src/core/annotations/qgsannotationpointtextitem.h
  19. +8 −4 src/core/annotations/qgsannotationpolygonitem.cpp
  20. +1 −1 src/core/annotations/qgsannotationpolygonitem.h
  21. +13 −0 src/core/qgis.h
  22. +5 −4 tests/src/python/test_qgsannotationlayer.py
  23. +8 −6 tests/src/python/test_qgsannotationlineitem.py
  24. +9 −2 tests/src/python/test_qgsannotationmarkeritem.py
  25. +8 −1 tests/src/python/test_qgsannotationpointtextitem.py
  26. +9 −6 tests/src/python/test_qgsannotationpolygonitem.py
@@ -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
@@ -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

@@ -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.

@@ -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/;

@@ -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/;

@@ -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/;

@@ -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/;

@@ -492,6 +492,13 @@ The development version
VertexHandle,
};

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

enum class VectorTemporalMode
{
FixedTemporalRange,
@@ -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 * )
@@ -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.
@@ -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
@@ -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;
@@ -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;
@@ -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 )
@@ -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;

/**
@@ -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 )
@@ -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;

/**
@@ -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 )
@@ -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;

/**
@@ -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 )
@@ -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;

/**
@@ -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
*
@@ -43,7 +43,8 @@
QgsGeometry,
QgsAnnotationItemEditOperationMoveNode,
QgsVertexId,
QgsPointXY
QgsPointXY,
Qgis
)
from qgis.testing import start_app, unittest

@@ -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

0 comments on commit 1228f59

Please sign in to comment.