Skip to content

Commit 6ecb17f

Browse files
authoredApr 20, 2017
Merge pull request #4380 from nyalldawson/clone_annotations
Add methods to clone annotations
2 parents 490f5f0 + dce3c88 commit 6ecb17f

19 files changed

+130
-1
lines changed
 

‎python/core/annotations/qgsannotation.sip

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ class QgsAnnotation : QObject
2525

2626
QgsAnnotation( QObject* parent /TransferThis/ = nullptr );
2727

28+
virtual QgsAnnotation *clone() const = 0 /Factory/;
29+
2830
bool isVisible() const;
2931
void setVisible( bool visible );
3032

@@ -81,4 +83,6 @@ class QgsAnnotation : QObject
8183
void _writeXml( QDomElement& itemElem, QDomDocument& doc ) const;
8284
void _readXml( const QDomElement& annotationElem, const QDomDocument& doc );
8385

86+
void copyCommonProperties( QgsAnnotation *target ) const;
87+
8488
};

‎python/core/annotations/qgsannotationmanager.sip

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,16 @@ class QgsAnnotationManager : QObject
6868
QList< QgsAnnotation * > annotations() const;
6969
%Docstring
7070
Returns a list of all annotations contained in the manager.
71+
\see cloneAnnotations()
72+
:rtype: list of QgsAnnotation
73+
%End
74+
75+
QList< QgsAnnotation * > cloneAnnotations() const /Factory/;
76+
%Docstring
77+
Returns a list containing clones of all annotations contained
78+
in the manager. The caller takes responsibility for deleting
79+
all returned annotations.
80+
\see annotations()
7181
:rtype: list of QgsAnnotation
7282
%End
7383

‎python/core/annotations/qgshtmlannotation.sip

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ class QgsHtmlAnnotation: QgsAnnotation
3131

3232
~QgsHtmlAnnotation();
3333

34+
virtual QgsHtmlAnnotation *clone() const /Factory/;
35+
3436
virtual QSizeF minimumFrameSize() const;
3537

3638
void setSourceFile( const QString &htmlFile );

‎python/core/annotations/qgssvgannotation.sip

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ class QgsSvgAnnotation: QgsAnnotation
2626
Constructor for QgsSvgAnnotation.
2727
%End
2828

29+
virtual QgsSvgAnnotation *clone() const /Factory/;
30+
2931
virtual void writeXml( QDomElement &elem, QDomDocument &doc ) const;
3032
virtual void readXml( const QDomElement &itemElem, const QDomDocument &doc );
3133

‎python/core/annotations/qgstextannotation.sip

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ class QgsTextAnnotation: QgsAnnotation
2626
Constructor for QgsTextAnnotation.
2727
%End
2828

29+
virtual QgsTextAnnotation *clone() const /Factory/;
30+
2931
const QTextDocument *document() const;
3032
%Docstring
3133
Returns the text document which will be rendered

‎python/gui/qgsformannotation.sip

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ class QgsFormAnnotation : QgsAnnotation
77

88
QgsFormAnnotation( QObject* parent /TransferThis/ = nullptr );
99

10+
virtual QgsFormAnnotation *clone() const /Factory/;
11+
1012
QSizeF minimumFrameSize() const;
1113
QSizeF preferredFrameSize() const;
1214

‎src/core/annotations/qgsannotation.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,3 +431,22 @@ void QgsAnnotation::_readXml( const QDomElement &annotationElem, const QDomDocum
431431
emit mapLayerChanged();
432432
}
433433

434+
void QgsAnnotation::copyCommonProperties( QgsAnnotation *target ) const
435+
{
436+
target->mVisible = mVisible;
437+
target->mHasFixedMapPosition = mHasFixedMapPosition;
438+
target->mMapPosition = mMapPosition;
439+
target->mMapPositionCrs = mMapPositionCrs;
440+
target->mRelativePosition = mRelativePosition;
441+
target->mOffsetFromReferencePoint = mOffsetFromReferencePoint;
442+
target->mFrameSize = mFrameSize;
443+
target->mMarkerSymbol.reset( mMarkerSymbol ? mMarkerSymbol->clone() : nullptr );
444+
target->mContentsMargins = mContentsMargins;
445+
target->mFillSymbol.reset( mFillSymbol ? mFillSymbol->clone() : nullptr );
446+
target->mBalloonSegment = mBalloonSegment;
447+
target->mBalloonSegmentPoint1 = mBalloonSegmentPoint1;
448+
target->mBalloonSegmentPoint2 = mBalloonSegmentPoint2;
449+
target->mMapLayer = mMapLayer;
450+
target->mFeature = mFeature;
451+
}
452+

‎src/core/annotations/qgsannotation.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ class CORE_EXPORT QgsAnnotation : public QObject
5757
*/
5858
QgsAnnotation( QObject *parent = nullptr );
5959

60+
/**
61+
* Clones the annotation, returning a new copy of the annotation
62+
* reflecting the annotation's current state.
63+
*/
64+
virtual QgsAnnotation *clone() const = 0;
65+
6066
/**
6167
* Returns true if the annotation is visible and should be rendered.
6268
* \see setVisible()
@@ -293,6 +299,14 @@ class CORE_EXPORT QgsAnnotation : public QObject
293299
*/
294300
void _readXml( const QDomElement &annotationElem, const QDomDocument &doc );
295301

302+
/**
303+
* Copies common annotation properties to the \a targe
304+
* annotation.
305+
* Can be used within QgsAnnotation::clone() implementations
306+
* to assist with creating copies.
307+
*/
308+
void copyCommonProperties( QgsAnnotation *target ) const;
309+
296310
private:
297311

298312
//! Check where to attach the balloon connection between frame and map point

‎src/core/annotations/qgsannotationmanager.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,16 @@ QList<QgsAnnotation *> QgsAnnotationManager::annotations() const
7373
return mAnnotations;
7474
}
7575

76+
QList<QgsAnnotation *> QgsAnnotationManager::cloneAnnotations() const
77+
{
78+
QList<QgsAnnotation *> results;
79+
Q_FOREACH ( const QgsAnnotation *a, mAnnotations )
80+
{
81+
results << a->clone();
82+
}
83+
return results;
84+
}
85+
7686
bool QgsAnnotationManager::readXml( const QDomElement &element, const QDomDocument &doc )
7787
{
7888
clear();

‎src/core/annotations/qgsannotationmanager.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,18 @@ class CORE_EXPORT QgsAnnotationManager : public QObject
7979

8080
/**
8181
* Returns a list of all annotations contained in the manager.
82+
* \see cloneAnnotations()
8283
*/
8384
QList< QgsAnnotation * > annotations() const;
8485

86+
/**
87+
* Returns a list containing clones of all annotations contained
88+
* in the manager. The caller takes responsibility for deleting
89+
* all returned annotations.
90+
* \see annotations()
91+
*/
92+
QList< QgsAnnotation * > cloneAnnotations() const SIP_FACTORY;
93+
8594
/**
8695
* Reads the manager's state from a DOM element, restoring all annotations
8796
* present in the XML document.

‎src/core/annotations/qgshtmlannotation.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@ QgsHtmlAnnotation::QgsHtmlAnnotation( QObject *parent )
4747
connect( mWebPage->mainFrame(), &QWebFrame::javaScriptWindowObjectCleared, this, &QgsHtmlAnnotation::javascript );
4848
}
4949

50+
QgsHtmlAnnotation *QgsHtmlAnnotation::clone() const
51+
{
52+
std::unique_ptr< QgsHtmlAnnotation > c( new QgsHtmlAnnotation() );
53+
copyCommonProperties( c.get() );
54+
c->setSourceFile( mHtmlFile );
55+
return c.release();
56+
}
57+
5058
void QgsHtmlAnnotation::setSourceFile( const QString &htmlFile )
5159
{
5260
QFile file( htmlFile );

‎src/core/annotations/qgshtmlannotation.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ class CORE_EXPORT QgsHtmlAnnotation: public QgsAnnotation
4444

4545
~QgsHtmlAnnotation() = default;
4646

47+
QgsHtmlAnnotation *clone() const override SIP_FACTORY;
48+
4749
QSizeF minimumFrameSize() const override;
4850

4951
/**

‎src/core/annotations/qgssvgannotation.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ QgsSvgAnnotation::QgsSvgAnnotation( QObject *parent )
2727

2828
}
2929

30+
QgsSvgAnnotation *QgsSvgAnnotation::clone() const
31+
{
32+
std::unique_ptr< QgsSvgAnnotation > c( new QgsSvgAnnotation() );
33+
copyCommonProperties( c.get() );
34+
c->setFilePath( mFilePath );
35+
return c.release();
36+
}
37+
3038
void QgsSvgAnnotation::writeXml( QDomElement &elem, QDomDocument &doc ) const
3139
{
3240
QDomElement svgAnnotationElem = doc.createElement( QStringLiteral( "SVGAnnotationItem" ) );

‎src/core/annotations/qgssvgannotation.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ class CORE_EXPORT QgsSvgAnnotation: public QgsAnnotation
3939
*/
4040
QgsSvgAnnotation( QObject *parent SIP_TRANSFERTHIS = nullptr );
4141

42+
QgsSvgAnnotation *clone() const override SIP_FACTORY;
43+
4244
virtual void writeXml( QDomElement &elem, QDomDocument &doc ) const override;
4345
virtual void readXml( const QDomElement &itemElem, const QDomDocument &doc ) override;
4446

‎src/core/annotations/qgstextannotation.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ QgsTextAnnotation::QgsTextAnnotation( QObject *parent )
2626
mDocument->setUseDesignMetrics( true );
2727
}
2828

29+
QgsTextAnnotation *QgsTextAnnotation::clone() const
30+
{
31+
std::unique_ptr< QgsTextAnnotation > c( new QgsTextAnnotation() );
32+
copyCommonProperties( c.get() );
33+
c->setDocument( mDocument ? mDocument->clone() : nullptr );
34+
return c.release();
35+
}
36+
2937
const QTextDocument *QgsTextAnnotation::document() const
3038
{
3139
return mDocument.get();

‎src/core/annotations/qgstextannotation.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ class CORE_EXPORT QgsTextAnnotation: public QgsAnnotation
3939
*/
4040
QgsTextAnnotation( QObject *parent SIP_TRANSFERTHIS = nullptr );
4141

42+
QgsTextAnnotation *clone() const override SIP_FACTORY;
43+
4244
/**
4345
* Returns the text document which will be rendered
4446
* within the annotation.

‎src/gui/qgsformannotation.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ QgsFormAnnotation::QgsFormAnnotation( QObject *parent )
4040
: QgsAnnotation( parent )
4141
{}
4242

43+
QgsFormAnnotation *QgsFormAnnotation::clone() const
44+
{
45+
std::unique_ptr< QgsFormAnnotation > c( new QgsFormAnnotation() );
46+
copyCommonProperties( c.get() );
47+
c->setDesignerForm( mDesignerForm );
48+
return c.release();
49+
}
50+
4351
void QgsFormAnnotation::setDesignerForm( const QString &uiFile )
4452
{
4553
mDesignerForm = uiFile;

‎src/gui/qgsformannotation.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ class GUI_EXPORT QgsFormAnnotation: public QgsAnnotation
3939
*/
4040
QgsFormAnnotation( QObject *parent = nullptr );
4141

42+
QgsFormAnnotation *clone() const override SIP_FACTORY;
43+
4244
QSizeF minimumFrameSize() const override;
4345
//! Returns the optimal frame size
4446
QSizeF preferredFrameSize() const;
@@ -63,7 +65,7 @@ class GUI_EXPORT QgsFormAnnotation: public QgsAnnotation
6365
/**
6466
* Returns a new QgsFormAnnotation object.
6567
*/
66-
static QgsFormAnnotation *create() { return new QgsFormAnnotation(); }
68+
static QgsFormAnnotation *create() SIP_FACTORY { return new QgsFormAnnotation(); }
6769

6870
protected:
6971

‎tests/src/python/test_qgsannotation.py

100644100755
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ def testTextAnnotation(self):
6363
im = self.renderAnnotation(a, QPointF(20, 30))
6464
self.assertTrue(self.imageCheck('text_annotation', 'text_annotation', im))
6565

66+
# check clone
67+
clone = a.clone()
68+
im = self.renderAnnotation(a, QPointF(20, 30))
69+
self.assertTrue(self.imageCheck('text_annotation', 'text_annotation', im))
70+
6671
def testSvgAnnotation(self):
6772
""" test rendering a svg annotation"""
6873
a = QgsSvgAnnotation()
@@ -73,6 +78,11 @@ def testSvgAnnotation(self):
7378
im = self.renderAnnotation(a, QPointF(20, 30))
7479
self.assertTrue(self.imageCheck('svg_annotation', 'svg_annotation', im))
7580

81+
# check clone
82+
clone = a.clone()
83+
im = self.renderAnnotation(a, QPointF(20, 30))
84+
self.assertTrue(self.imageCheck('svg_annotation', 'svg_annotation', im))
85+
7686
def testHtmlAnnotation(self):
7787
""" test rendering a html annotation"""
7888
a = QgsHtmlAnnotation()
@@ -83,6 +93,11 @@ def testHtmlAnnotation(self):
8393
im = self.renderAnnotation(a, QPointF(20, 30))
8494
self.assertTrue(self.imageCheck('html_annotation', 'html_annotation', im))
8595

96+
# check clone
97+
clone = a.clone()
98+
im = self.renderAnnotation(a, QPointF(20, 30))
99+
self.assertTrue(self.imageCheck('html_annotation', 'html_annotation', im))
100+
86101
def testHtmlAnnotationWithFeature(self):
87102
""" test rendering a html annotation with a feature"""
88103
layer = QgsVectorLayer("Point?crs=EPSG:3111&field=station:string&field=suburb:string",

0 commit comments

Comments
 (0)
Please sign in to comment.