Use an edit operation for annotation item translation, instead of

transform

Will make it easier to add undo/redo support in future
This commit is contained in:
Nyall Dawson 2021-09-10 11:37:27 +10:00
parent f76b262ac0
commit a7d299df92
26 changed files with 255 additions and 165 deletions

View File

@ -2,5 +2,6 @@
# monkey patching scoped based enum
QgsAbstractAnnotationItemEditOperation.Type.MoveNode.__doc__ = "Move a node"
QgsAbstractAnnotationItemEditOperation.Type.DeleteNode.__doc__ = "Delete a node"
QgsAbstractAnnotationItemEditOperation.Type.__doc__ = 'Operation type\n\n' + '* ``MoveNode``: ' + QgsAbstractAnnotationItemEditOperation.Type.MoveNode.__doc__ + '\n' + '* ``DeleteNode``: ' + QgsAbstractAnnotationItemEditOperation.Type.DeleteNode.__doc__
QgsAbstractAnnotationItemEditOperation.Type.TranslateItem.__doc__ = "Translate (move) an item"
QgsAbstractAnnotationItemEditOperation.Type.__doc__ = 'Operation type\n\n' + '* ``MoveNode``: ' + QgsAbstractAnnotationItemEditOperation.Type.MoveNode.__doc__ + '\n' + '* ``DeleteNode``: ' + QgsAbstractAnnotationItemEditOperation.Type.DeleteNode.__doc__ + '\n' + '* ``TranslateItem``: ' + QgsAbstractAnnotationItemEditOperation.Type.TranslateItem.__doc__
# --

View File

@ -82,15 +82,6 @@ Returns the bounding box of the item's geographic location, in the parent layer'
virtual QgsRectangle boundingBox( QgsRenderContext &context ) const;
%Docstring
Returns the bounding box of the item's geographic location, in the parent layer's coordinate reference system.
%End
virtual bool transform( const QTransform &transform ) = 0;
%Docstring
Transforms the item's geometry using the specified ``transform``.
Returns ``True`` if the transformation was successful.
.. versionadded:: 3.22
%End
virtual void render( QgsRenderContext &context, QgsFeedback *feedback ) = 0;
@ -212,16 +203,6 @@ exactly 2mm thick when a map is rendered at 1:1000, or 1mm thick when rendered a
.. seealso:: :py:func:`symbologyReferenceScale`
.. seealso:: :py:func:`setUseSymbologyReferenceScale`
%End
virtual QgsGeometry rubberBandGeometry() const;
%Docstring
Returns the geometry to use as a rubber band for map tools which manipulate the item.
The default implementation returns a null geometry, which indicates that the item bounds should
be used as the rubber band.
.. versionadded:: 3.22
%End
protected:

View File

@ -26,6 +26,7 @@ Abstract base class for annotation item edit operations
{
MoveNode,
DeleteNode,
TranslateItem,
};
QgsAbstractAnnotationItemEditOperation( const QString &itemId );
@ -128,6 +129,50 @@ Returns the node position before the delete occurred (in layer coordinates).
};
class QgsAnnotationItemEditOperationTranslateItem : QgsAbstractAnnotationItemEditOperation
{
%Docstring(signature="appended")
Annotation item edit operation consisting of translating (moving) an item
.. versionadded:: 3.22
%End
%TypeHeaderCode
#include "qgsannotationitemeditoperation.h"
%End
public:
QgsAnnotationItemEditOperationTranslateItem( const QString &itemId, double translateX, double translateY );
%Docstring
Constructor for QgsAnnotationItemEditOperationTranslateItem, where the node with the specified ``id`` and translation
(in map units)
%End
virtual Type type() const;
QgsVertexId nodeId() const;
%Docstring
Returns the deleted node ID.
%End
double translationX() const;
%Docstring
Returns the x-axis translation, in layer units.
\since :py:func:`~QgsAnnotationItemEditOperationTranslateItem.translationY`
%End
double translationY() const;
%Docstring
Returns the y-axis translation, in layer units.
\since :py:func:`~QgsAnnotationItemEditOperationTranslateItem.translationX`
%End
};
class QgsAnnotationItemEditOperationTransientResults
{
%Docstring(signature="appended")

View File

@ -37,10 +37,6 @@ Constructor for QgsAnnotationLineItem, with the specified ``linestring``.
virtual QList< QgsAnnotationItemNode > nodes() const;
virtual QgsGeometry rubberBandGeometry() const;
virtual bool transform( const QTransform &transform );
virtual Qgis::AnnotationItemEditOperationResult applyEdit( QgsAbstractAnnotationItemEditOperation *operation );
virtual QgsAnnotationItemEditOperationTransientResults *transientEditResults( QgsAbstractAnnotationItemEditOperation *operation ) /Factory/;

View File

@ -57,8 +57,6 @@ Creates a new marker annotation item.
virtual QgsRectangle boundingBox( QgsRenderContext &context ) const;
virtual bool transform( const QTransform &transform );
QgsPointXY geometry() const;
%Docstring

View File

@ -53,8 +53,6 @@ Creates a new text at point annotation item.
virtual QList< QgsAnnotationItemNode > nodes() const;
virtual bool transform( const QTransform &transform );
virtual Qgis::AnnotationItemEditOperationResult applyEdit( QgsAbstractAnnotationItemEditOperation *operation );
virtual QgsAnnotationItemEditOperationTransientResults *transientEditResults( QgsAbstractAnnotationItemEditOperation *operation ) /Factory/;

View File

@ -37,10 +37,6 @@ Constructor for QgsAnnotationPolygonItem, with the specified ``polygon`` geometr
virtual QList< QgsAnnotationItemNode > nodes() const;
virtual QgsGeometry rubberBandGeometry() const;
virtual bool transform( const QTransform &transform );
virtual Qgis::AnnotationItemEditOperationResult applyEdit( QgsAbstractAnnotationItemEditOperation *operation );
virtual QgsAnnotationItemEditOperationTransientResults *transientEditResults( QgsAbstractAnnotationItemEditOperation *operation ) /Factory/;

View File

@ -60,8 +60,3 @@ bool QgsAnnotationItem::readCommonProperties( const QDomElement &element, const
setSymbologyReferenceScale( element.attribute( QStringLiteral( "referenceScale" ) ).toDouble() );
return true;
}
QgsGeometry QgsAnnotationItem::rubberBandGeometry() const
{
return QgsGeometry();
}

View File

@ -113,15 +113,6 @@ class CORE_EXPORT QgsAnnotationItem
*/
virtual QgsRectangle boundingBox( QgsRenderContext &context ) const { Q_UNUSED( context ) return boundingBox();}
/**
* Transforms the item's geometry using the specified \a transform.
*
* Returns TRUE if the transformation was successful.
*
* \since QGIS 3.22
*/
virtual bool transform( const QTransform &transform ) = 0;
/**
* Renders the item to the specified render \a context.
*
@ -237,16 +228,6 @@ class CORE_EXPORT QgsAnnotationItem
*/
void setSymbologyReferenceScale( double scale ) { mReferenceScale = scale; }
/**
* Returns the geometry to use as a rubber band for map tools which manipulate the item.
*
* The default implementation returns a null geometry, which indicates that the item bounds should
* be used as the rubber band.
*
* \since QGIS 3.22
*/
virtual QgsGeometry rubberBandGeometry() const;
protected:
/**

View File

@ -62,3 +62,20 @@ QgsAbstractAnnotationItemEditOperation::Type QgsAnnotationItemEditOperationDelet
{
return Type::DeleteNode;
}
//
// QgsAnnotationItemEditOperationTranslateItem
//
QgsAnnotationItemEditOperationTranslateItem::QgsAnnotationItemEditOperationTranslateItem( const QString &itemId, double translateX, double translateY )
: QgsAbstractAnnotationItemEditOperation( itemId )
, mTranslateX( translateX )
, mTranslateY( translateY )
{
}
QgsAbstractAnnotationItemEditOperation::Type QgsAnnotationItemEditOperationTranslateItem::type() const
{
return Type::TranslateItem;
}

View File

@ -40,6 +40,7 @@ class CORE_EXPORT QgsAbstractAnnotationItemEditOperation
{
MoveNode, //!< Move a node
DeleteNode, //!< Delete a node
TranslateItem, //!< Translate (move) an item
};
/**
@ -144,6 +145,52 @@ class CORE_EXPORT QgsAnnotationItemEditOperationDeleteNode : public QgsAbstractA
};
/**
* \ingroup core
* \brief Annotation item edit operation consisting of translating (moving) an item
* \since QGIS 3.22
*/
class CORE_EXPORT QgsAnnotationItemEditOperationTranslateItem : public QgsAbstractAnnotationItemEditOperation
{
public:
/**
* Constructor for QgsAnnotationItemEditOperationTranslateItem, where the node with the specified \a id and translation
* (in map units)
*/
QgsAnnotationItemEditOperationTranslateItem( const QString &itemId, double translateX, double translateY );
Type type() const override;
/**
* Returns the deleted node ID.
*/
QgsVertexId nodeId() const { return mNodeId; }
/**
* Returns the x-axis translation, in layer units.
*
* \since translationY()
*/
double translationX() const { return mTranslateX; }
/**
* Returns the y-axis translation, in layer units.
*
* \since translationX()
*/
double translationY() const { return mTranslateY; }
private:
QgsVertexId mNodeId;
double mTranslateX = 0;
double mTranslateY = 0;
};
/**
* \ingroup core
* \brief Encapsulates the transient results of an in-progress annotation edit operation.

View File

@ -92,17 +92,6 @@ QList<QgsAnnotationItemNode> QgsAnnotationLineItem::nodes() const
return res;
}
QgsGeometry QgsAnnotationLineItem::rubberBandGeometry() const
{
return QgsGeometry( mCurve->clone() );
}
bool QgsAnnotationLineItem::transform( const QTransform &transform )
{
mCurve->transform( transform );
return true;
}
Qgis::AnnotationItemEditOperationResult QgsAnnotationLineItem::applyEdit( QgsAbstractAnnotationItemEditOperation *operation )
{
switch ( operation->type() )
@ -122,6 +111,14 @@ Qgis::AnnotationItemEditOperationResult QgsAnnotationLineItem::applyEdit( QgsAbs
return mCurve->isEmpty() ? Qgis::AnnotationItemEditOperationResult::ItemCleared : Qgis::AnnotationItemEditOperationResult::Success;
break;
}
case QgsAbstractAnnotationItemEditOperation::Type::TranslateItem:
{
QgsAnnotationItemEditOperationTranslateItem *moveOperation = qgis::down_cast< QgsAnnotationItemEditOperationTranslateItem * >( operation );
const QTransform transform = QTransform::fromTranslate( moveOperation->translationX(), moveOperation->translationY() );
mCurve->transform( transform );
return Qgis::AnnotationItemEditOperationResult::Success;
}
}
return Qgis::AnnotationItemEditOperationResult::Invalid;
@ -142,6 +139,15 @@ QgsAnnotationItemEditOperationTransientResults *QgsAnnotationLineItem::transient
break;
}
case QgsAbstractAnnotationItemEditOperation::Type::TranslateItem:
{
QgsAnnotationItemEditOperationTranslateItem *moveOperation = qgis::down_cast< QgsAnnotationItemEditOperationTranslateItem * >( operation );
const QTransform transform = QTransform::fromTranslate( moveOperation->translationX(), moveOperation->translationY() );
std::unique_ptr< QgsCurve > modifiedCurve( mCurve->clone() );
modifiedCurve->transform( transform );
return new QgsAnnotationItemEditOperationTransientResults( QgsGeometry( std::move( modifiedCurve ) ) );
}
case QgsAbstractAnnotationItemEditOperation::Type::DeleteNode:
break;
}

View File

@ -44,8 +44,6 @@ class CORE_EXPORT QgsAnnotationLineItem : public QgsAnnotationItem
void render( QgsRenderContext &context, QgsFeedback *feedback ) override;
bool writeXml( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const override;
QList< QgsAnnotationItemNode > nodes() const override;
QgsGeometry rubberBandGeometry() const override;
bool transform( const QTransform &transform ) override;
Qgis::AnnotationItemEditOperationResult applyEdit( QgsAbstractAnnotationItemEditOperation *operation ) override;
QgsAnnotationItemEditOperationTransientResults *transientEditResults( QgsAbstractAnnotationItemEditOperation *operation ) override SIP_FACTORY;

View File

@ -95,6 +95,14 @@ Qgis::AnnotationItemEditOperationResult QgsAnnotationMarkerItem::applyEdit( QgsA
{
return Qgis::AnnotationItemEditOperationResult::ItemCleared;
}
case QgsAbstractAnnotationItemEditOperation::Type::TranslateItem:
{
QgsAnnotationItemEditOperationTranslateItem *moveOperation = qgis::down_cast< QgsAnnotationItemEditOperationTranslateItem * >( operation );
mPoint.setX( mPoint.x() + moveOperation->translationX() );
mPoint.setY( mPoint.y() + moveOperation->translationY() );
return Qgis::AnnotationItemEditOperationResult::Success;
}
}
return Qgis::AnnotationItemEditOperationResult::Invalid;
@ -110,6 +118,12 @@ QgsAnnotationItemEditOperationTransientResults *QgsAnnotationMarkerItem::transie
return new QgsAnnotationItemEditOperationTransientResults( QgsGeometry( moveOperation->after().clone() ) );
}
case QgsAbstractAnnotationItemEditOperation::Type::TranslateItem:
{
QgsAnnotationItemEditOperationTranslateItem *moveOperation = qgis::down_cast< QgsAnnotationItemEditOperationTranslateItem * >( operation );
return new QgsAnnotationItemEditOperationTransientResults( QgsGeometry( new QgsPoint( mPoint.x() + moveOperation->translationX(), mPoint.y() + moveOperation->translationY() ) ) );
}
case QgsAbstractAnnotationItemEditOperation::Type::DeleteNode:
break;
}
@ -177,12 +191,6 @@ QgsRectangle QgsAnnotationMarkerItem::boundingBox( QgsRenderContext &context ) c
return context.coordinateTransform().transformBoundingBox( boundsMapUnits, QgsCoordinateTransform::ReverseTransform );
}
bool QgsAnnotationMarkerItem::transform( const QTransform &transform )
{
mPoint.transform( transform );
return true;
}
const QgsMarkerSymbol *QgsAnnotationMarkerItem::symbol() const
{
return mSymbol.get();

View File

@ -56,7 +56,6 @@ class CORE_EXPORT QgsAnnotationMarkerItem : public QgsAnnotationItem
QgsAnnotationMarkerItem *clone() override SIP_FACTORY;
QgsRectangle boundingBox() const override;
QgsRectangle boundingBox( QgsRenderContext &context ) const override;
bool transform( const QTransform &transform ) override;
/**
* Returns the point geometry of the marker.

View File

@ -138,15 +138,6 @@ QList<QgsAnnotationItemNode> QgsAnnotationPointTextItem::nodes() const
return { QgsAnnotationItemNode( QgsVertexId( 0, 0, 0 ), mPoint, Qgis::AnnotationItemNodeType::VertexHandle )};
}
bool QgsAnnotationPointTextItem::transform( const QTransform &transform )
{
double x = mPoint.x();
double y = mPoint.y();
transform.map( mPoint.x(), mPoint.y(), &x, &y );
mPoint.set( x, y );
return true;
}
Qgis::AnnotationItemEditOperationResult QgsAnnotationPointTextItem::applyEdit( QgsAbstractAnnotationItemEditOperation *operation )
{
switch ( operation->type() )
@ -162,6 +153,14 @@ Qgis::AnnotationItemEditOperationResult QgsAnnotationPointTextItem::applyEdit( Q
{
return Qgis::AnnotationItemEditOperationResult::ItemCleared;
}
case QgsAbstractAnnotationItemEditOperation::Type::TranslateItem:
{
QgsAnnotationItemEditOperationTranslateItem *moveOperation = qgis::down_cast< QgsAnnotationItemEditOperationTranslateItem * >( operation );
mPoint.setX( mPoint.x() + moveOperation->translationX() );
mPoint.setY( mPoint.y() + moveOperation->translationY() );
return Qgis::AnnotationItemEditOperationResult::Success;
}
}
return Qgis::AnnotationItemEditOperationResult::Invalid;
@ -177,6 +176,12 @@ QgsAnnotationItemEditOperationTransientResults *QgsAnnotationPointTextItem::tran
return new QgsAnnotationItemEditOperationTransientResults( QgsGeometry( moveOperation->after().clone() ) );
}
case QgsAbstractAnnotationItemEditOperation::Type::TranslateItem:
{
QgsAnnotationItemEditOperationTranslateItem *moveOperation = qgis::down_cast< QgsAnnotationItemEditOperationTranslateItem * >( operation );
return new QgsAnnotationItemEditOperationTransientResults( QgsGeometry( new QgsPoint( mPoint.x() + moveOperation->translationX(), mPoint.y() + moveOperation->translationY() ) ) );
}
case QgsAbstractAnnotationItemEditOperation::Type::DeleteNode:
break;
}

View File

@ -55,7 +55,6 @@ class CORE_EXPORT QgsAnnotationPointTextItem : public QgsAnnotationItem
QgsRectangle boundingBox() const override;
QgsRectangle boundingBox( QgsRenderContext &context ) const override;
QList< QgsAnnotationItemNode > nodes() const override;
bool transform( const QTransform &transform ) override;
Qgis::AnnotationItemEditOperationResult applyEdit( QgsAbstractAnnotationItemEditOperation *operation ) override;
QgsAnnotationItemEditOperationTransientResults *transientEditResults( QgsAbstractAnnotationItemEditOperation *operation ) override SIP_FACTORY;

View File

@ -122,17 +122,6 @@ QList<QgsAnnotationItemNode> QgsAnnotationPolygonItem::nodes() const
return res;
}
QgsGeometry QgsAnnotationPolygonItem::rubberBandGeometry() const
{
return QgsGeometry( mPolygon->clone() );
}
bool QgsAnnotationPolygonItem::transform( const QTransform &transform )
{
mPolygon->transform( transform );
return true;
}
Qgis::AnnotationItemEditOperationResult QgsAnnotationPolygonItem::applyEdit( QgsAbstractAnnotationItemEditOperation *operation )
{
switch ( operation->type() )
@ -152,6 +141,14 @@ Qgis::AnnotationItemEditOperationResult QgsAnnotationPolygonItem::applyEdit( Qgs
return mPolygon->isEmpty() ? Qgis::AnnotationItemEditOperationResult::ItemCleared : Qgis::AnnotationItemEditOperationResult::Success;
break;
}
case QgsAbstractAnnotationItemEditOperation::Type::TranslateItem:
{
QgsAnnotationItemEditOperationTranslateItem *moveOperation = qgis::down_cast< QgsAnnotationItemEditOperationTranslateItem * >( operation );
const QTransform transform = QTransform::fromTranslate( moveOperation->translationX(), moveOperation->translationY() );
mPolygon->transform( transform );
return Qgis::AnnotationItemEditOperationResult::Success;
}
}
return Qgis::AnnotationItemEditOperationResult::Invalid;
@ -172,6 +169,15 @@ QgsAnnotationItemEditOperationTransientResults *QgsAnnotationPolygonItem::transi
break;
}
case QgsAbstractAnnotationItemEditOperation::Type::TranslateItem:
{
QgsAnnotationItemEditOperationTranslateItem *moveOperation = qgis::down_cast< QgsAnnotationItemEditOperationTranslateItem * >( operation );
const QTransform transform = QTransform::fromTranslate( moveOperation->translationX(), moveOperation->translationY() );
std::unique_ptr< QgsCurvePolygon > modifiedPolygon( mPolygon->clone() );
modifiedPolygon->transform( transform );
return new QgsAnnotationItemEditOperationTransientResults( QgsGeometry( std::move( modifiedPolygon ) ) );
}
case QgsAbstractAnnotationItemEditOperation::Type::DeleteNode:
break;
}

View File

@ -43,8 +43,6 @@ class CORE_EXPORT QgsAnnotationPolygonItem : public QgsAnnotationItem
void render( QgsRenderContext &context, QgsFeedback *feedback ) override;
bool writeXml( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const override;
QList< QgsAnnotationItemNode > nodes() const override;
QgsGeometry rubberBandGeometry() const override;
bool transform( const QTransform &transform ) override;
Qgis::AnnotationItemEditOperationResult applyEdit( QgsAbstractAnnotationItemEditOperation *operation ) override;
QgsAnnotationItemEditOperationTransientResults *transientEditResults( QgsAbstractAnnotationItemEditOperation *operation ) override SIP_FACTORY;

View File

@ -197,18 +197,28 @@ void QgsMapToolModifyAnnotation::cadCanvasMoveEvent( QgsMapMouseEvent *event )
case Action::MoveItem:
{
#if 0
const QgsVector delta = event->mapPoint() - mMoveStartPointCanvasCrs;
if ( mTemporaryRubberBand )
#endif
if ( QgsAnnotationItem *item = annotationItemFromId( mSelectedItemLayerId, mSelectedItemId ) )
{
mTemporaryRubberBand->setTranslationOffset( delta.x(), delta.y() );
mTemporaryRubberBand->updatePosition();
mTemporaryRubberBand->update();
}
for ( QgsRubberBand *band : mHoveredItemNodeRubberBands )
{
band->setTranslationOffset( delta.x(), delta.y() );
band->updatePosition();
band->update();
QgsAnnotationLayer *layer = annotationLayerFromId( mSelectedItemLayerId );
const QgsVector delta = toLayerCoordinates( layer, event->mapPoint() ) - mMoveStartPointLayerCrs;
QgsAnnotationItemEditOperationTranslateItem operation( mSelectedItemId, delta.x(), delta.y() );
std::unique_ptr< QgsAnnotationItemEditOperationTransientResults > operationResults( item->transientEditResults( &operation ) );
if ( operationResults )
{
mTemporaryRubberBand.reset( new QgsRubberBand( mCanvas, operationResults->representativeGeometry().type() ) );
const double scaleFactor = canvas()->fontMetrics().xHeight() * .2;
mTemporaryRubberBand->setWidth( scaleFactor );
mTemporaryRubberBand->setToGeometry( operationResults->representativeGeometry(), layer->crs() );
}
else
{
mTemporaryRubberBand.reset();
}
}
break;
}
@ -285,16 +295,6 @@ void QgsMapToolModifyAnnotation::cadCanvasPressEvent( QgsMapMouseEvent *event )
if ( hoveredNode.point().isEmpty() )
{
mCurrentAction = Action::MoveItem;
QgsAnnotationItem *item = annotationItemFromId( mSelectedItemLayerId, mSelectedItemId );
QgsGeometry rubberBandGeom = item->rubberBandGeometry();
if ( rubberBandGeom.isNull() )
rubberBandGeom = mSelectedRubberBand->asGeometry();
mTemporaryRubberBand.reset( new QgsRubberBand( mCanvas, rubberBandGeom.type() ) );
const double scaleFactor = canvas()->fontMetrics().xHeight() * .2;
mTemporaryRubberBand->setWidth( scaleFactor );
mTemporaryRubberBand->setToGeometry( rubberBandGeom, layer->crs() );
}
else
{
@ -339,16 +339,21 @@ void QgsMapToolModifyAnnotation::cadCanvasPressEvent( QgsMapMouseEvent *event )
else if ( event->button() == Qt::LeftButton )
{
// apply move
if ( QgsAnnotationItem *item = annotationItemFromId( mSelectedItemLayerId, mSelectedItemId ) )
if ( QgsAnnotationLayer *layer = annotationLayerFromId( mSelectedItemLayerId ) )
{
QgsAnnotationLayer *layer = annotationLayerFromId( mSelectedItemLayerId );
const QgsVector delta = toLayerCoordinates( layer, event->mapPoint() ) - mMoveStartPointLayerCrs;
const QTransform transform = QTransform::fromTranslate( delta.x(), delta.y() );
std::unique_ptr< QgsAnnotationItem > transformedItem( item->clone() );
transformedItem->transform( transform );
layer->replaceItem( mSelectedItemId, transformedItem.release() );
mRefreshSelectedItemAfterRedraw = true;
QgsAnnotationItemEditOperationTranslateItem operation( mSelectedItemId, delta.x(), delta.y() );
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();
@ -422,18 +427,22 @@ void QgsMapToolModifyAnnotation::keyPressEvent( QKeyEvent *event )
|| event->key() == Qt::Key_Down )
{
QgsAnnotationLayer *layer = annotationLayerFromId( mSelectedItemLayerId );
QgsAnnotationItem *annotationItem = annotationItemFromId( mSelectedItemLayerId, mSelectedItemId );
if ( !layer || !annotationItem )
if ( !layer )
return;
const QSizeF deltaLayerCoordinates = deltaForKeyEvent( layer, mSelectedRubberBand->asGeometry().centroid().asPoint(), event );
const QTransform transform = QTransform::fromTranslate( deltaLayerCoordinates.width(), deltaLayerCoordinates.height() );
std::unique_ptr< QgsAnnotationItem > transformedItem( annotationItem->clone() );
transformedItem->transform( transform );
layer->replaceItem( mSelectedItemId, transformedItem.release() );
mRefreshSelectedItemAfterRedraw = true;
QgsAnnotationItemEditOperationTranslateItem operation( mSelectedItemId, deltaLayerCoordinates.width(), deltaLayerCoordinates.height() );
switch ( layer->applyEdit( &operation ) )
{
case Qgis::AnnotationItemEditOperationResult::Success:
QgsProject::instance()->setDirty( true );
mRefreshSelectedItemAfterRedraw = true;
break;
case Qgis::AnnotationItemEditOperationResult::Invalid:
case Qgis::AnnotationItemEditOperationResult::ItemCleared:
break;
}
event->ignore(); // disable default shortcut handling (move map)
}
break;

View File

@ -52,11 +52,6 @@ class TestItem : public QgsAnnotationItem
return new TestItem();
}
bool transform( const QTransform & ) override
{
return true;
}
bool writeXml( QDomElement &, QDomDocument &, const QgsReadWriteContext & ) const override
{
return true;

View File

@ -68,7 +68,6 @@ class TestItem : public QgsAnnotationItem // clazy:exclude=missing-qobject-macro
void render( QgsRenderContext &, QgsFeedback * ) override {}
bool writeXml( QDomElement &, QDomDocument &, const QgsReadWriteContext & ) const override { return true; }
bool readXml( const QDomElement &, const QgsReadWriteContext & ) override { return true; }
bool transform( const QTransform & ) override { return true; }
};
class TestItemWidget: public QgsAnnotationItemBaseWidget

View File

@ -38,7 +38,8 @@ from qgis.core import (QgsMapSettings,
Qgis,
QgsVertexId,
QgsAnnotationItemEditOperationMoveNode,
QgsAnnotationItemEditOperationDeleteNode
QgsAnnotationItemEditOperationDeleteNode,
QgsAnnotationItemEditOperationTranslateItem
)
from qgis.PyQt.QtXml import QDomDocument
@ -87,8 +88,7 @@ class TestQgsAnnotationLineItem(unittest.TestCase):
item = QgsAnnotationLineItem(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15)]))
self.assertEqual(item.geometry().asWkt(), 'LineString (12 13, 14 13, 14 15)')
transform = QTransform.fromTranslate(100, 200)
item.transform(transform)
self.assertEqual(item.applyEdit(QgsAnnotationItemEditOperationTranslateItem('', 100, 200)), Qgis.AnnotationItemEditOperationResult.Success)
self.assertEqual(item.geometry().asWkt(), 'LineString (112 213, 114 213, 114 215)')
def test_apply_move_node_edit(self):
@ -122,13 +122,12 @@ class TestQgsAnnotationLineItem(unittest.TestCase):
res = item.transientEditResults(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 1), QgsPoint(14, 13), QgsPoint(17, 18)))
self.assertEqual(res.representativeGeometry().asWkt(), 'LineString (12 13, 17 18, 14 15)')
def test_rubberbandgeometry(self):
"""
Test creating rubber band geometry
"""
def test_transient_translate_operation(self):
item = QgsAnnotationLineItem(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15)]))
band = item.rubberBandGeometry()
self.assertEqual(band.asWkt(), 'LineString (12 13, 14 13, 14 15)')
self.assertEqual(item.geometry().asWkt(), 'LineString (12 13, 14 13, 14 15)')
res = item.transientEditResults(QgsAnnotationItemEditOperationTranslateItem('', 100, 200))
self.assertEqual(res.representativeGeometry().asWkt(), 'LineString (112 213, 114 213, 114 215)')
def testReadWriteXml(self):
doc = QDomDocument("testdoc")

View File

@ -36,7 +36,8 @@ from qgis.core import (QgsMapSettings,
QgsPointXY,
QgsVertexId,
QgsAnnotationItemEditOperationMoveNode,
QgsAnnotationItemEditOperationDeleteNode
QgsAnnotationItemEditOperationDeleteNode,
QgsAnnotationItemEditOperationTranslateItem
)
from qgis.PyQt.QtXml import QDomDocument
@ -85,8 +86,7 @@ class TestQgsAnnotationMarkerItem(unittest.TestCase):
item = QgsAnnotationMarkerItem(QgsPoint(12, 13))
self.assertEqual(item.geometry().asWkt(), 'POINT(12 13)')
transform = QTransform.fromTranslate(100, 200)
item.transform(transform)
self.assertEqual(item.applyEdit(QgsAnnotationItemEditOperationTranslateItem('', 100, 200)), Qgis.AnnotationItemEditOperationResult.Success)
self.assertEqual(item.geometry().asWkt(), 'POINT(112 213)')
def test_apply_move_node_edit(self):
@ -109,6 +109,13 @@ class TestQgsAnnotationMarkerItem(unittest.TestCase):
res = item.transientEditResults(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 0), QgsPoint(12, 13), QgsPoint(17, 18)))
self.assertEqual(res.representativeGeometry().asWkt(), 'Point (17 18)')
def test_transient_translate_operation(self):
item = QgsAnnotationMarkerItem(QgsPoint(12, 13))
self.assertEqual(item.geometry().asWkt(), 'POINT(12 13)')
res = item.transientEditResults(QgsAnnotationItemEditOperationTranslateItem('', 100, 200))
self.assertEqual(res.representativeGeometry().asWkt(), 'Point (112 213)')
def testReadWriteXml(self):
doc = QDomDocument("testdoc")
elem = doc.createElement('test')

View File

@ -38,6 +38,7 @@ from qgis.core import (QgsMapSettings,
QgsVertexId,
QgsAnnotationItemEditOperationMoveNode,
QgsAnnotationItemEditOperationDeleteNode,
QgsAnnotationItemEditOperationTranslateItem,
QgsPoint
)
from qgis.PyQt.QtXml import QDomDocument
@ -97,8 +98,7 @@ class TestQgsAnnotationPointTextItem(unittest.TestCase):
item = QgsAnnotationPointTextItem('my text', QgsPointXY(12, 13))
self.assertEqual(item.point().asWkt(), 'POINT(12 13)')
transform = QTransform.fromTranslate(100, 200)
item.transform(transform)
self.assertEqual(item.applyEdit(QgsAnnotationItemEditOperationTranslateItem('', 100, 200)), Qgis.AnnotationItemEditOperationResult.Success)
self.assertEqual(item.point().asWkt(), 'POINT(112 213)')
def test_apply_move_node_edit(self):
@ -115,6 +115,13 @@ class TestQgsAnnotationPointTextItem(unittest.TestCase):
res = item.transientEditResults(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 0), QgsPoint(12, 13), QgsPoint(17, 18)))
self.assertEqual(res.representativeGeometry().asWkt(), 'Point (17 18)')
def test_transient_translate_operation(self):
item = QgsAnnotationPointTextItem('my text', QgsPointXY(12, 13))
self.assertEqual(item.point().asWkt(), 'POINT(12 13)')
res = item.transientEditResults(QgsAnnotationItemEditOperationTranslateItem('', 100, 200))
self.assertEqual(res.representativeGeometry().asWkt(), 'Point (112 213)')
def test_apply_delete_node_edit(self):
item = QgsAnnotationPointTextItem('my text', QgsPointXY(12, 13))
self.assertEqual(item.point().asWkt(), 'POINT(12 13)')

View File

@ -40,7 +40,8 @@ from qgis.core import (QgsMapSettings,
QgsPointXY,
QgsVertexId,
QgsAnnotationItemEditOperationMoveNode,
QgsAnnotationItemEditOperationDeleteNode
QgsAnnotationItemEditOperationDeleteNode,
QgsAnnotationItemEditOperationTranslateItem
)
from qgis.PyQt.QtXml import QDomDocument
@ -86,20 +87,11 @@ class TestQgsAnnotationPolygonItem(unittest.TestCase):
QgsAnnotationItemNode(QgsVertexId(0, 0, 1), QgsPointXY(14, 13), Qgis.AnnotationItemNodeType.VertexHandle),
QgsAnnotationItemNode(QgsVertexId(0, 0, 2), QgsPointXY(14, 15), Qgis.AnnotationItemNodeType.VertexHandle)])
def test_rubberbandgeometry(self):
"""
Test creating rubber band geometry
"""
item = QgsAnnotationPolygonItem(QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)])))
band = item.rubberBandGeometry()
self.assertEqual(band.asWkt(), 'Polygon ((12 13, 14 13, 14 15, 12 13))')
def test_transform(self):
item = QgsAnnotationPolygonItem(QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)])))
self.assertEqual(item.geometry().asWkt(), 'Polygon ((12 13, 14 13, 14 15, 12 13))')
transform = QTransform.fromTranslate(100, 200)
item.transform(transform)
self.assertEqual(item.applyEdit(QgsAnnotationItemEditOperationTranslateItem('', 100, 200)), Qgis.AnnotationItemEditOperationResult.Success)
self.assertEqual(item.geometry().asWkt(), 'Polygon ((112 213, 114 213, 114 215, 112 213))')
def test_apply_move_node_edit(self):
@ -137,6 +129,14 @@ class TestQgsAnnotationPolygonItem(unittest.TestCase):
res = item.transientEditResults(QgsAnnotationItemEditOperationMoveNode('', QgsVertexId(0, 0, 1), QgsPoint(14, 13), QgsPoint(17, 18)))
self.assertEqual(res.representativeGeometry().asWkt(), 'Polygon ((12 13, 17 18, 14 15, 12 13))')
def test_transient_translate_operation(self):
item = QgsAnnotationPolygonItem(
QgsPolygon(QgsLineString([QgsPoint(12, 13), QgsPoint(14, 13), QgsPoint(14, 15), QgsPoint(12, 13)])))
self.assertEqual(item.geometry().asWkt(), 'Polygon ((12 13, 14 13, 14 15, 12 13))')
res = item.transientEditResults(QgsAnnotationItemEditOperationTranslateItem('', 100, 200))
self.assertEqual(res.representativeGeometry().asWkt(), 'Polygon ((112 213, 114 213, 114 215, 112 213))')
def testReadWriteXml(self):
doc = QDomDocument("testdoc")
elem = doc.createElement('test')