Skip to content

Commit aa14926

Browse files
committedJan 29, 2017
Move map layer association for annotations to QgsAnnotation
Previously only some annotations had (incomplete) support for attaching to a particular vector layer and synchronising their visibility with the layer's visibility. This handling has all been moved up to QgsAnnotation, so that all annotation types can be attached to layers. This will allow selective annotation visibility based on the visible layers of a particular canvas, eg in multi-canvas environments. Additionally: - show the attached layer in the annotation properties dialog, and allow it to be cleared to always show the annotation - allow attaching annotations to non-vector layers - add unit tests for visibility
1 parent c853f4f commit aa14926

17 files changed

+188
-176
lines changed
 

‎python/core/annotations/qgsannotation.sip

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ class QgsAnnotation : QObject
4545
void setMarkerSymbol( QgsMarkerSymbol* symbol /Transfer/ );
4646
QgsMarkerSymbol* markerSymbol() const;
4747

48+
QgsMapLayer* mapLayer() const;
49+
void setMapLayer( QgsMapLayer* layer );
50+
4851
signals:
4952

5053
void appearanceChanged();

‎python/core/annotations/qgshtmlannotation.sip

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ class QgsHtmlAnnotation : QgsAnnotation
55
%End
66
public:
77

8-
QgsHtmlAnnotation( QObject* parent /TransferThis/ = nullptr, QgsVectorLayer* vlayer = nullptr, bool hasFeature = false, int feature = 0 );
8+
QgsHtmlAnnotation( QObject* parent /TransferThis/ = nullptr );
99

1010
~QgsHtmlAnnotation();
1111

@@ -17,8 +17,6 @@ class QgsHtmlAnnotation : QgsAnnotation
1717
virtual void writeXml( QDomElement& elem, QDomDocument & doc ) const;
1818
virtual void readXml( const QDomElement& itemElem, const QDomDocument& doc );
1919

20-
QgsVectorLayer* vectorLayer() const;
21-
2220
protected:
2321

2422
void renderAnnotation( QgsRenderContext& context, QSizeF size ) const;

‎src/app/qgsannotationwidget.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ QgsAnnotationWidget::QgsAnnotationWidget( QgsMapCanvasAnnotationItem* item, QWid
3131
, mMarkerSymbol( nullptr )
3232
{
3333
setupUi( this );
34+
mLayerComboBox->setAllowEmptyLayer( true );
3435

3536
if ( mItem && mItem->annotation() )
3637
{
@@ -59,6 +60,8 @@ QgsAnnotationWidget::QgsAnnotationWidget( QgsMapCanvasAnnotationItem* item, QWid
5960
mBackgroundColorButton->setNoColorString( tr( "Transparent" ) );
6061
mBackgroundColorButton->setShowNoColor( true );
6162

63+
mLayerComboBox->setLayer( annotation->mapLayer() );
64+
6265
connect( mBackgroundColorButton, &QgsColorButton::colorChanged, this, &QgsAnnotationWidget::backgroundColorChanged );
6366

6467
const QgsMarkerSymbol* symbol = annotation->markerSymbol();
@@ -88,6 +91,7 @@ void QgsAnnotationWidget::apply()
8891
annotation->setFrameColor( mFrameColorButton->color() );
8992
annotation->setFrameBackgroundColor( mBackgroundColorButton->color() );
9093
annotation->setMarkerSymbol( mMarkerSymbol->clone() );
94+
annotation->setMapLayer( mLayerComboBox->currentLayer() );
9195
}
9296
mItem->update();
9397
}
@@ -99,6 +103,7 @@ void QgsAnnotationWidget::blockAllSignals( bool block )
99103
mMapMarkerButton->blockSignals( block );
100104
mFrameWidthSpinBox->blockSignals( block );
101105
mFrameColorButton->blockSignals( block );
106+
mLayerComboBox->blockSignals( block );
102107
}
103108

104109
void QgsAnnotationWidget::on_mMapMarkerButton_clicked()

‎src/app/qgsformannotationdialog.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ void QgsFormAnnotationDialog::applySettingsToItem()
6060
{
6161
QgsFormAnnotation* annotation = static_cast< QgsFormAnnotation* >( mItem->annotation() );
6262
annotation->setDesignerForm( mFileLineEdit->text() );
63-
QgsVectorLayer* layer = annotation->vectorLayer();
63+
QgsVectorLayer* layer = qobject_cast< QgsVectorLayer* >( annotation->mapLayer() );
6464
if ( layer )
6565
{
6666
//set last used annotation form as default for the layer

‎src/app/qgshtmlannotationdialog.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,6 @@ void QgsHtmlAnnotationDialog::applySettingsToItem()
6161
{
6262
QgsHtmlAnnotation* annotation = static_cast< QgsHtmlAnnotation* >( mItem->annotation() );
6363
annotation->setSourceFile( mFileLineEdit->text() );
64-
QgsVectorLayer* layer = annotation->vectorLayer();
65-
if ( layer )
66-
{
67-
//set last used annotation form as default for the layer
68-
//layer->setAnnotationForm( mFileLineEdit->text() );
69-
}
7064
mItem->update();
7165
}
7266
}

‎src/app/qgsmaptoolformannotation.cpp

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,6 @@ QgsMapToolFormAnnotation::~QgsMapToolFormAnnotation()
3434

3535
QgsAnnotation* QgsMapToolFormAnnotation::createItem() const
3636
{
37-
//try to associate the current vector layer and a feature to the form item
38-
QgsVectorLayer* currentVectorLayer = nullptr;
39-
if ( mCanvas )
40-
{
41-
QgsMapLayer* mLayer = mCanvas->currentLayer();
42-
if ( mLayer )
43-
{
44-
currentVectorLayer = dynamic_cast<QgsVectorLayer*>( mLayer );
45-
}
46-
}
47-
48-
return new QgsFormAnnotation( currentVectorLayer );
37+
return new QgsFormAnnotation();
4938
}
5039

‎src/app/qgsmaptoolhtmlannotation.cpp

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,6 @@ QgsMapToolHtmlAnnotation::~QgsMapToolHtmlAnnotation()
3434

3535
QgsAnnotation* QgsMapToolHtmlAnnotation::createItem() const
3636
{
37-
//try to associate the current vector layer and a feature to the form item
38-
QgsVectorLayer* currentVectorLayer = nullptr;
39-
if ( mCanvas )
40-
{
41-
QgsMapLayer* mLayer = mCanvas->currentLayer();
42-
if ( mLayer )
43-
{
44-
currentVectorLayer = dynamic_cast<QgsVectorLayer*>( mLayer );
45-
}
46-
}
47-
48-
return new QgsHtmlAnnotation( nullptr, currentVectorLayer );
37+
return new QgsHtmlAnnotation();
4938
}
5039

‎src/core/annotations/qgsannotation.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
#include "qgsannotation.h"
1919
#include "qgssymbollayerutils.h"
20+
#include "qgsmaplayer.h"
21+
#include "qgsproject.h"
2022
#include <QPen>
2123
#include <QPainter>
2224

@@ -135,6 +137,12 @@ void QgsAnnotation::setMarkerSymbol( QgsMarkerSymbol* symbol )
135137
emit appearanceChanged();
136138
}
137139

140+
void QgsAnnotation::setMapLayer( QgsMapLayer* layer )
141+
{
142+
mMapLayer = layer;
143+
emit mapLayerChanged();
144+
}
145+
138146
void QgsAnnotation::updateBalloon()
139147
{
140148
//first test if the point is in the frame. In that case we don't need a balloon.
@@ -313,6 +321,10 @@ void QgsAnnotation::_writeXml( QDomElement& itemElem, QDomDocument& doc ) const
313321
annotationElem.setAttribute( QStringLiteral( "frameBackgroundColor" ), mFrameBackgroundColor.name() );
314322
annotationElem.setAttribute( QStringLiteral( "frameBackgroundColorAlpha" ), mFrameBackgroundColor.alpha() );
315323
annotationElem.setAttribute( QStringLiteral( "visible" ), isVisible() );
324+
if ( mMapLayer )
325+
{
326+
annotationElem.setAttribute( QStringLiteral( "mapLayer" ), mMapLayer->id() );
327+
}
316328
if ( mMarkerSymbol )
317329
{
318330
QDomElement symbolElem = QgsSymbolLayerUtils::saveSymbol( QStringLiteral( "marker symbol" ), mMarkerSymbol.data(), doc );
@@ -356,6 +368,10 @@ void QgsAnnotation::_readXml( const QDomElement& annotationElem, const QDomDocum
356368
mOffsetFromReferencePoint.setY( annotationElem.attribute( QStringLiteral( "offsetY" ), QStringLiteral( "0" ) ).toDouble() );
357369
mHasFixedMapPosition = annotationElem.attribute( QStringLiteral( "mapPositionFixed" ), QStringLiteral( "1" ) ).toInt();
358370
mVisible = annotationElem.attribute( QStringLiteral( "visible" ), QStringLiteral( "1" ) ).toInt();
371+
if ( annotationElem.hasAttribute( QStringLiteral( "mapLayer" ) ) )
372+
{
373+
mMapLayer = QgsProject::instance()->mapLayer( annotationElem.attribute( QStringLiteral( "mapLayer" ) ) );
374+
}
359375

360376
//marker symbol
361377
QDomElement symbolElem = annotationElem.firstChildElement( QStringLiteral( "symbol" ) );
@@ -369,5 +385,6 @@ void QgsAnnotation::_readXml( const QDomElement& annotationElem, const QDomDocum
369385
}
370386

371387
updateBalloon();
388+
emit mapLayerChanged();
372389
}
373390

‎src/core/annotations/qgsannotation.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "qgscoordinatereferencesystem.h"
2424
#include "qgsrendercontext.h"
2525
#include "qgssymbol.h"
26+
#include "qgsmaplayer.h"
2627

2728
/** \ingroup core
2829
* \class QgsAnnotation
@@ -225,6 +226,22 @@ class CORE_EXPORT QgsAnnotation : public QObject
225226
*/
226227
QgsMarkerSymbol* markerSymbol() const { return mMarkerSymbol.data(); }
227228

229+
/**
230+
* Returns the map layer associated with the annotation. Annotations can be
231+
* associated with a map layer if their visibility should be synchronized
232+
* with the layer's visibility.
233+
* @see setMapLayer()
234+
*/
235+
QgsMapLayer* mapLayer() const { return mMapLayer.data(); }
236+
237+
/**
238+
* Sets the map layer associated with the annotation. Annotations can be
239+
* associated with a map layer if their visibility should be synchronized
240+
* with the layer's visibility.
241+
* @see mapLayer()
242+
*/
243+
void setMapLayer( QgsMapLayer* layer );
244+
228245
signals:
229246

230247
//! Emitted whenever the annotation's appearance changes
@@ -236,6 +253,11 @@ class CORE_EXPORT QgsAnnotation : public QObject
236253
*/
237254
void moved();
238255

256+
/**
257+
* Emitted when the map layer associated with the annotation changes.
258+
*/
259+
void mapLayerChanged();
260+
239261
protected:
240262

241263
virtual void renderAnnotation( QgsRenderContext& context, QSizeF size ) const = 0;
@@ -320,6 +342,9 @@ class CORE_EXPORT QgsAnnotation : public QObject
320342
//! Second segment point for drawing the balloon connection (ccw direction)
321343
QPointF mBalloonSegmentPoint2;
322344

345+
//! Associated layer (or nullptr if not attached to a layer)
346+
QPointer<QgsMapLayer> mMapLayer;
347+
323348
};
324349

325350
#endif // QGSANNOTATION_H

‎src/core/annotations/qgshtmlannotation.cpp

Lines changed: 13 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,11 @@
3636
#include <QWidget>
3737

3838

39-
QgsHtmlAnnotation::QgsHtmlAnnotation(QObject* parent, QgsVectorLayer* vlayer, bool hasFeature, int feature )
39+
QgsHtmlAnnotation::QgsHtmlAnnotation( QObject* parent )
4040
: QgsAnnotation( parent )
4141
, mWebPage( nullptr )
42-
, mVectorLayer( vlayer )
43-
, mHasAssociatedFeature( hasFeature )
44-
, mFeatureId( feature )
42+
, mHasAssociatedFeature( false )
43+
, mFeatureId( -1 )
4544
{
4645
mWebPage = new QgsWebPage();
4746
mWebPage->mainFrame()->setScrollBarPolicy( Qt::Horizontal, Qt::ScrollBarAlwaysOff );
@@ -50,15 +49,6 @@ QgsHtmlAnnotation::QgsHtmlAnnotation(QObject* parent, QgsVectorLayer* vlayer, bo
5049

5150
connect( mWebPage->mainFrame(), &QWebFrame::javaScriptWindowObjectCleared, this, &QgsHtmlAnnotation::javascript );
5251

53-
if ( mVectorLayer )
54-
{
55-
connect( mVectorLayer, SIGNAL( layerModified() ), this, SLOT( setFeatureForMapPosition() ) );
56-
#if 0
57-
QObject::connect( mMapCanvas, SIGNAL( renderComplete( QPainter* ) ), this, SLOT( setFeatureForMapPosition() ) );
58-
QObject::connect( mMapCanvas, SIGNAL( layersChanged() ), this, SLOT( updateVisibility() ) );
59-
#endif
60-
}
61-
6252
setFeatureForMapPosition();
6353
}
6454

@@ -118,10 +108,6 @@ QSizeF QgsHtmlAnnotation::minimumFrameSize() const
118108
void QgsHtmlAnnotation::writeXml( QDomElement& elem, QDomDocument & doc ) const
119109
{
120110
QDomElement formAnnotationElem = doc.createElement( QStringLiteral( "HtmlAnnotationItem" ) );
121-
if ( mVectorLayer )
122-
{
123-
formAnnotationElem.setAttribute( QStringLiteral( "vectorLayer" ), mVectorLayer->id() );
124-
}
125111
formAnnotationElem.setAttribute( QStringLiteral( "hasFeature" ), mHasAssociatedFeature );
126112
formAnnotationElem.setAttribute( QStringLiteral( "feature" ), mFeatureId );
127113
formAnnotationElem.setAttribute( QStringLiteral( "htmlfile" ), sourceFile() );
@@ -132,19 +118,6 @@ void QgsHtmlAnnotation::writeXml( QDomElement& elem, QDomDocument & doc ) const
132118

133119
void QgsHtmlAnnotation::readXml( const QDomElement& itemElem, const QDomDocument& doc )
134120
{
135-
mVectorLayer = nullptr;
136-
if ( itemElem.hasAttribute( QStringLiteral( "vectorLayer" ) ) )
137-
{
138-
mVectorLayer = dynamic_cast<QgsVectorLayer*>( QgsProject::instance()->mapLayer( itemElem.attribute( QStringLiteral( "vectorLayer" ), QLatin1String( "" ) ) ) );
139-
if ( mVectorLayer )
140-
{
141-
connect( mVectorLayer, SIGNAL( layerModified() ), this, SLOT( setFeatureForMapPosition() ) );
142-
#if 0
143-
QObject::connect( mMapCanvas, SIGNAL( renderComplete( QPainter* ) ), this, SLOT( setFeatureForMapPosition() ) );
144-
QObject::connect( mMapCanvas, SIGNAL( layersChanged() ), this, SLOT( updateVisibility() ) );
145-
#endif
146-
}
147-
}
148121
mHasAssociatedFeature = itemElem.attribute( QStringLiteral( "hasFeature" ), QStringLiteral( "0" ) ).toInt();
149122
mFeatureId = itemElem.attribute( QStringLiteral( "feature" ), QStringLiteral( "0" ) ).toInt();
150123
mHtmlFile = itemElem.attribute( QStringLiteral( "htmlfile" ), QLatin1String( "" ) );
@@ -154,23 +127,28 @@ void QgsHtmlAnnotation::readXml( const QDomElement& itemElem, const QDomDocument
154127
_readXml( annotationElem, doc );
155128
}
156129

130+
// upgrade old layer
131+
if ( !mapLayer() && itemElem.hasAttribute( QStringLiteral( "vectorLayer" ) ) )
132+
{
133+
setMapLayer( QgsProject::instance()->mapLayer( itemElem.attribute( QStringLiteral( "vectorLayer" ) ) ) );
134+
}
135+
157136
if ( mWebPage )
158137
{
159138
setSourceFile( mHtmlFile );
160139
}
161-
updateVisibility();
162140
}
163141

164142
void QgsHtmlAnnotation::setFeatureForMapPosition()
165143
{
166144
QString newText;
167-
if ( mVectorLayer )
145+
if ( QgsVectorLayer* vectorLayer = qobject_cast< QgsVectorLayer* >( mapLayer() ) )
168146
{
169147
double halfIdentifyWidth = 0; // QgsMapTool::searchRadiusMU( mMapCanvas );
170148
QgsRectangle searchRect( mapPosition().x() - halfIdentifyWidth, mapPosition().y() - halfIdentifyWidth,
171149
mapPosition().x() + halfIdentifyWidth, mapPosition().y() + halfIdentifyWidth );
172150

173-
QgsFeatureIterator fit = mVectorLayer->getFeatures( QgsFeatureRequest().setFilterRect( searchRect ).setFlags( QgsFeatureRequest::NoGeometry | QgsFeatureRequest::ExactIntersect ) );
151+
QgsFeatureIterator fit = vectorLayer->getFeatures( QgsFeatureRequest().setFilterRect( searchRect ).setFlags( QgsFeatureRequest::NoGeometry | QgsFeatureRequest::ExactIntersect ) );
174152

175153
QgsFeature currentFeature;
176154
QgsFeatureId currentFeatureId = 0;
@@ -187,7 +165,7 @@ void QgsHtmlAnnotation::setFeatureForMapPosition()
187165
mFeatureId = currentFeatureId;
188166
mFeature = currentFeature;
189167

190-
QgsExpressionContext context( QgsExpressionContextUtils::globalProjectLayerScopes( mVectorLayer ) );
168+
QgsExpressionContext context( QgsExpressionContextUtils::globalProjectLayerScopes( vectorLayer ) );
191169
context.setFeature( mFeature );
192170
newText = QgsExpression::replaceExpressionText( mHtmlSource, &context );
193171
}
@@ -199,22 +177,10 @@ void QgsHtmlAnnotation::setFeatureForMapPosition()
199177
emit appearanceChanged();
200178
}
201179

202-
void QgsHtmlAnnotation::updateVisibility()
203-
{
204-
bool visible = true;
205-
#if 0
206-
if ( mVectorLayer && mMapCanvas )
207-
{
208-
visible = mMapCanvas->layers().contains( mVectorLayer );
209-
}
210-
#endif
211-
setVisible( visible );
212-
}
213-
214180
void QgsHtmlAnnotation::javascript()
215181
{
216182
QWebFrame *frame = mWebPage->mainFrame();
217-
frame->addToJavaScriptWindowObject( QStringLiteral( "layer" ), mVectorLayer );
183+
frame->addToJavaScriptWindowObject( QStringLiteral( "layer" ), mapLayer() );
218184
}
219185

220186

‎src/core/annotations/qgshtmlannotation.h

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class CORE_EXPORT QgsHtmlAnnotation: public QgsAnnotation
4040
/**
4141
* Constructor for QgsHtmlAnnotation.
4242
*/
43-
QgsHtmlAnnotation( QObject* parent = nullptr, QgsVectorLayer* vlayer = nullptr, bool hasFeature = false, int feature = 0 );
43+
QgsHtmlAnnotation( QObject* parent = nullptr );
4444

4545
~QgsHtmlAnnotation();
4646

@@ -64,27 +64,18 @@ class CORE_EXPORT QgsHtmlAnnotation: public QgsAnnotation
6464
virtual void writeXml( QDomElement& elem, QDomDocument & doc ) const override;
6565
virtual void readXml( const QDomElement& itemElem, const QDomDocument& doc ) override;
6666

67-
/**
68-
* Returns the vector layer associated with the annotation.
69-
*/
70-
QgsVectorLayer* vectorLayer() const { return mVectorLayer; }
71-
7267
protected:
7368

7469
void renderAnnotation( QgsRenderContext& context, QSizeF size ) const override;
7570

7671
private slots:
7772
//! Sets a feature for the current map position and updates the dialog
7873
void setFeatureForMapPosition();
79-
//! Sets visibility status based on mVectorLayer visibility
80-
void updateVisibility();
8174

8275
void javascript();
8376

8477
private:
8578
QgsWebPage* mWebPage;
86-
//! Associated vectorlayer (or 0 if attributes are not supposed to be replaced)
87-
QgsVectorLayer* mVectorLayer;
8879
//! True if the item is related to a vector feature
8980
bool mHasAssociatedFeature;
9081
//! Associated feature

‎src/gui/qgsformannotation.cpp

Lines changed: 17 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -36,23 +36,12 @@
3636
#include <QUiLoader>
3737
#include <QWidget>
3838

39-
QgsFormAnnotation::QgsFormAnnotation(QgsVectorLayer* vlayer, bool hasFeature, int feature )
40-
: QgsAnnotation()
39+
QgsFormAnnotation::QgsFormAnnotation( QObject* parent )
40+
: QgsAnnotation( parent )
4141
, mDesignerWidget( nullptr )
42-
, mVectorLayer( vlayer )
43-
, mHasAssociatedFeature( hasFeature )
44-
, mFeature( feature )
42+
, mHasAssociatedFeature( false )
43+
, mFeature( -1 )
4544
{
46-
if ( mVectorLayer ) //default to the layers edit form
47-
{
48-
mDesignerForm = mVectorLayer->annotationForm();
49-
QObject::connect( mVectorLayer, SIGNAL( layerModified() ), this, SLOT( setFeatureForMapPosition() ) );
50-
#if 0
51-
QObject::connect( mMapCanvas, SIGNAL( renderComplete( QPainter* ) ), this, SLOT( setFeatureForMapPosition() ) );
52-
QObject::connect( mMapCanvas, SIGNAL( layersChanged() ), this, SLOT( updateVisibility() ) );
53-
#endif
54-
}
55-
5645
setFeatureForMapPosition();
5746
}
5847

@@ -91,12 +80,13 @@ QWidget* QgsFormAnnotation::createDesignerWidget( const QString& filePath )
9180

9281
//get feature and set attribute information
9382
QgsAttributeEditorContext context;
94-
if ( mVectorLayer && mHasAssociatedFeature )
83+
QgsVectorLayer* vectorLayer = qobject_cast< QgsVectorLayer* >( mapLayer() );
84+
if ( vectorLayer && mHasAssociatedFeature )
9585
{
9686
QgsFeature f;
97-
if ( mVectorLayer->getFeatures( QgsFeatureRequest().setFilterFid( mFeature ).setFlags( QgsFeatureRequest::NoGeometry ) ).nextFeature( f ) )
87+
if ( vectorLayer->getFeatures( QgsFeatureRequest().setFilterFid( mFeature ).setFlags( QgsFeatureRequest::NoGeometry ) ).nextFeature( f ) )
9888
{
99-
const QgsFields& fields = mVectorLayer->fields();
89+
const QgsFields& fields = vectorLayer->fields();
10090
QgsAttributes attrs = f.attributes();
10191
for ( int i = 0; i < attrs.count(); ++i )
10292
{
@@ -105,7 +95,7 @@ QWidget* QgsFormAnnotation::createDesignerWidget( const QString& filePath )
10595
QWidget* attWidget = widget->findChild<QWidget*>( fields.at( i ).name() );
10696
if ( attWidget )
10797
{
108-
QgsEditorWidgetWrapper* eww = QgsEditorWidgetRegistry::instance()->create( mVectorLayer, i, attWidget, widget, context );
98+
QgsEditorWidgetWrapper* eww = QgsEditorWidgetRegistry::instance()->create( vectorLayer, i, attWidget, widget, context );
10999
if ( eww )
110100
{
111101
eww->setValue( attrs.at( i ) );
@@ -165,10 +155,6 @@ QSizeF QgsFormAnnotation::preferredFrameSize() const
165155
void QgsFormAnnotation::writeXml( QDomElement& elem, QDomDocument & doc ) const
166156
{
167157
QDomElement formAnnotationElem = doc.createElement( QStringLiteral( "FormAnnotationItem" ) );
168-
if ( mVectorLayer )
169-
{
170-
formAnnotationElem.setAttribute( QStringLiteral( "vectorLayer" ), mVectorLayer->id() );
171-
}
172158
formAnnotationElem.setAttribute( QStringLiteral( "hasFeature" ), mHasAssociatedFeature );
173159
formAnnotationElem.setAttribute( QStringLiteral( "feature" ), mFeature );
174160
formAnnotationElem.setAttribute( QStringLiteral( "designerForm" ), mDesignerForm );
@@ -178,19 +164,6 @@ void QgsFormAnnotation::writeXml( QDomElement& elem, QDomDocument & doc ) const
178164

179165
void QgsFormAnnotation::readXml( const QDomElement& itemElem, const QDomDocument& doc )
180166
{
181-
mVectorLayer = nullptr;
182-
if ( itemElem.hasAttribute( QStringLiteral( "vectorLayer" ) ) )
183-
{
184-
mVectorLayer = dynamic_cast<QgsVectorLayer*>( QgsProject::instance()->mapLayer( itemElem.attribute( QStringLiteral( "vectorLayer" ), QLatin1String( "" ) ) ) );
185-
if ( mVectorLayer )
186-
{
187-
QObject::connect( mVectorLayer, SIGNAL( layerModified() ), this, SLOT( setFeatureForMapPosition() ) );
188-
#if 0
189-
QObject::connect( mMapCanvas, SIGNAL( renderComplete( QPainter* ) ), this, SLOT( setFeatureForMapPosition() ) );
190-
QObject::connect( mMapCanvas, SIGNAL( layersChanged() ), this, SLOT( updateVisibility() ) );
191-
#endif
192-
}
193-
}
194167
mHasAssociatedFeature = itemElem.attribute( QStringLiteral( "hasFeature" ), QStringLiteral( "0" ) ).toInt();
195168
mFeature = itemElem.attribute( QStringLiteral( "feature" ), QStringLiteral( "0" ) ).toInt();
196169
mDesignerForm = itemElem.attribute( QStringLiteral( "designerForm" ), QLatin1String( "" ) );
@@ -199,18 +172,23 @@ void QgsFormAnnotation::readXml( const QDomElement& itemElem, const QDomDocument
199172
{
200173
_readXml( annotationElem, doc );
201174
}
175+
// upgrade old layer
176+
if ( !mapLayer() && itemElem.hasAttribute( QStringLiteral( "vectorLayer" ) ) )
177+
{
178+
setMapLayer( QgsProject::instance()->mapLayer( itemElem.attribute( QStringLiteral( "vectorLayer" ) ) ) );
179+
}
202180

203181
mDesignerWidget = createDesignerWidget( mDesignerForm );
204182
if ( mDesignerWidget )
205183
{
206184
setFrameBackgroundColor( mDesignerWidget->palette().color( QPalette::Window ) );
207185
}
208-
updateVisibility();
209186
}
210187

211188
void QgsFormAnnotation::setFeatureForMapPosition()
212189
{
213-
if ( !mVectorLayer)
190+
QgsVectorLayer* vectorLayer = qobject_cast< QgsVectorLayer* >( mapLayer() );
191+
if ( !vectorLayer )
214192
{
215193
return;
216194
}
@@ -219,7 +197,7 @@ void QgsFormAnnotation::setFeatureForMapPosition()
219197
QgsRectangle searchRect( mapPosition().x() - halfIdentifyWidth, mapPosition().y() - halfIdentifyWidth,
220198
mapPosition().x() + halfIdentifyWidth, mapPosition().y() + halfIdentifyWidth );
221199

222-
QgsFeatureIterator fit = mVectorLayer->getFeatures( QgsFeatureRequest().setFilterRect( searchRect ).setFlags( QgsFeatureRequest::NoGeometry | QgsFeatureRequest::ExactIntersect ).setSubsetOfAttributes( QgsAttributeList() ) );
200+
QgsFeatureIterator fit = vectorLayer->getFeatures( QgsFeatureRequest().setFilterRect( searchRect ).setFlags( QgsFeatureRequest::NoGeometry | QgsFeatureRequest::ExactIntersect ).setSubsetOfAttributes( QgsAttributeList() ) );
223201

224202
QgsFeature currentFeature;
225203
QgsFeatureId currentFeatureId = 0;
@@ -245,17 +223,5 @@ void QgsFormAnnotation::setFeatureForMapPosition()
245223
emit appearanceChanged();
246224
}
247225

248-
void QgsFormAnnotation::updateVisibility()
249-
{
250-
bool visible = true;
251-
#if 0
252-
if ( mVectorLayer && mMapCanvas )
253-
{
254-
visible = mMapCanvas->layers().contains( mVectorLayer );
255-
}
256-
#endif
257-
setVisible( visible );
258-
}
259-
260226

261227

‎src/gui/qgsformannotation.h

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class GUI_EXPORT QgsFormAnnotation: public QgsAnnotation
3030
{
3131
Q_OBJECT
3232
public:
33-
QgsFormAnnotation( QgsVectorLayer* vlayer = nullptr, bool hasFeature = false, int feature = 0 );
33+
QgsFormAnnotation( QObject* parent = nullptr );
3434
~QgsFormAnnotation();
3535

3636
QSizeF minimumFrameSize() const override;
@@ -45,24 +45,18 @@ class GUI_EXPORT QgsFormAnnotation: public QgsAnnotation
4545
virtual void writeXml( QDomElement& elem, QDomDocument & doc ) const override;
4646
virtual void readXml( const QDomElement& itemElem, const QDomDocument& doc ) override;
4747

48-
QgsVectorLayer* vectorLayer() const { return mVectorLayer; }
49-
5048
protected:
5149

5250
void renderAnnotation( QgsRenderContext& context, QSizeF size ) const override;
5351

5452
private slots:
5553
//! Sets a feature for the current map position and updates the dialog
5654
void setFeatureForMapPosition();
57-
//! Sets visibility status based on mVectorLayer visibility
58-
void updateVisibility();
5955

6056
private:
6157

6258
QWidget* mDesignerWidget;
6359
QSize mMinimumSize;
64-
//! Associated vectorlayer (or 0 if attributes are not supposed to be replaced)
65-
QgsVectorLayer* mVectorLayer;
6660
//! True if the item is related to a vector feature
6761
bool mHasAssociatedFeature;
6862
//! Associated feature

‎src/gui/qgsmapcanvasannotationitem.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ QgsMapCanvasAnnotationItem::QgsMapCanvasAnnotationItem( QgsAnnotation* annotatio
3030
connect( mAnnotation, &QgsAnnotation::moved, this, [this] { updatePosition(); } );
3131
connect( mAnnotation, &QgsAnnotation::appearanceChanged, this, &QgsMapCanvasAnnotationItem::updateBoundingRect );
3232

33+
connect( mMapCanvas, &QgsMapCanvas::layersChanged, this, &QgsMapCanvasAnnotationItem::onCanvasLayersChanged );
34+
connect( mAnnotation, &QgsAnnotation::mapLayerChanged, this, &QgsMapCanvasAnnotationItem::onCanvasLayersChanged );
3335
updatePosition();
3436
}
3537

@@ -92,6 +94,18 @@ void QgsMapCanvasAnnotationItem::updateBoundingRect()
9294
}
9395
}
9496

97+
void QgsMapCanvasAnnotationItem::onCanvasLayersChanged()
98+
{
99+
if ( !mAnnotation->mapLayer() )
100+
{
101+
setVisible( true );
102+
}
103+
else
104+
{
105+
setVisible( mMapCanvas->mapSettings().layers().contains( mAnnotation->mapLayer() ) );
106+
}
107+
}
108+
95109
void QgsMapCanvasAnnotationItem::drawSelectionBoxes( QPainter* p ) const
96110
{
97111
if ( !p )

‎src/gui/qgsmapcanvasannotationitem.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ class GUI_EXPORT QgsMapCanvasAnnotationItem: public QObject, public QgsMapCanvas
8888

8989
void updateBoundingRect();
9090

91+
void onCanvasLayersChanged();
92+
9193
private:
9294

9395
//! Draws selection handles around the item

‎src/ui/qgsannotationwidgetbase.ui

Lines changed: 69 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,14 @@
77
<x>0</x>
88
<y>0</y>
99
<width>319</width>
10-
<height>172</height>
10+
<height>203</height>
1111
</rect>
1212
</property>
1313
<property name="windowTitle">
1414
<string>Form</string>
1515
</property>
1616
<layout class="QGridLayout" name="gridLayout">
17-
<item row="0" column="0" colspan="2">
18-
<widget class="QCheckBox" name="mMapPositionFixedCheckBox">
19-
<property name="text">
20-
<string>Fixed map position</string>
21-
</property>
22-
</widget>
23-
</item>
24-
<item row="1" column="0">
17+
<item row="2" column="0">
2518
<widget class="QLabel" name="mMapMarkerLabel">
2619
<property name="text">
2720
<string>Map marker</string>
@@ -31,34 +24,48 @@
3124
</property>
3225
</widget>
3326
</item>
34-
<item row="1" column="1">
27+
<item row="4" column="0">
28+
<widget class="QLabel" name="mBackgroundColorLabel">
29+
<property name="text">
30+
<string>Background color</string>
31+
</property>
32+
</widget>
33+
</item>
34+
<item row="3" column="1">
35+
<widget class="QDoubleSpinBox" name="mFrameWidthSpinBox"/>
36+
</item>
37+
<item row="5" column="0">
38+
<widget class="QLabel" name="mFrameColorLabel">
39+
<property name="text">
40+
<string>Frame color</string>
41+
</property>
42+
</widget>
43+
</item>
44+
<item row="2" column="1">
3545
<widget class="QPushButton" name="mMapMarkerButton">
3646
<property name="text">
3747
<string/>
3848
</property>
3949
</widget>
4050
</item>
41-
<item row="2" column="0">
42-
<widget class="QLabel" name="mFrameWidthLabel">
51+
<item row="1" column="0">
52+
<widget class="QLabel" name="mMapMarkerLabel_2">
4353
<property name="text">
44-
<string>Frame width</string>
54+
<string>Linked layer</string>
4555
</property>
4656
<property name="buddy">
47-
<cstring>mFrameWidthSpinBox</cstring>
57+
<cstring>mMapMarkerButton</cstring>
4858
</property>
4959
</widget>
5060
</item>
51-
<item row="2" column="1">
52-
<widget class="QDoubleSpinBox" name="mFrameWidthSpinBox"/>
53-
</item>
54-
<item row="3" column="0">
55-
<widget class="QLabel" name="mBackgroundColorLabel">
56-
<property name="text">
57-
<string>Background color</string>
61+
<item row="1" column="1">
62+
<widget class="QgsMapLayerComboBox" name="mLayerComboBox">
63+
<property name="toolTip">
64+
<string>Allows the annotation to be associated with a map layer. If set, the annotation will only be visible when the layer is visible.</string>
5865
</property>
5966
</widget>
6067
</item>
61-
<item row="3" column="1">
68+
<item row="4" column="1">
6269
<layout class="QHBoxLayout" name="horizontalLayout_2">
6370
<item>
6471
<widget class="QgsColorButton" name="mBackgroundColorButton">
@@ -94,14 +101,14 @@
94101
</item>
95102
</layout>
96103
</item>
97-
<item row="4" column="0">
98-
<widget class="QLabel" name="mFrameColorLabel">
104+
<item row="0" column="0" colspan="2">
105+
<widget class="QCheckBox" name="mMapPositionFixedCheckBox">
99106
<property name="text">
100-
<string>Frame color</string>
107+
<string>Fixed map position</string>
101108
</property>
102109
</widget>
103110
</item>
104-
<item row="4" column="1">
111+
<item row="5" column="1">
105112
<layout class="QHBoxLayout" name="horizontalLayout">
106113
<item>
107114
<widget class="QgsColorButton" name="mFrameColorButton">
@@ -137,6 +144,29 @@
137144
</item>
138145
</layout>
139146
</item>
147+
<item row="3" column="0">
148+
<widget class="QLabel" name="mFrameWidthLabel">
149+
<property name="text">
150+
<string>Frame width</string>
151+
</property>
152+
<property name="buddy">
153+
<cstring>mFrameWidthSpinBox</cstring>
154+
</property>
155+
</widget>
156+
</item>
157+
<item row="6" column="1">
158+
<spacer name="verticalSpacer">
159+
<property name="orientation">
160+
<enum>Qt::Vertical</enum>
161+
</property>
162+
<property name="sizeHint" stdset="0">
163+
<size>
164+
<width>20</width>
165+
<height>40</height>
166+
</size>
167+
</property>
168+
</spacer>
169+
</item>
140170
</layout>
141171
</widget>
142172
<customwidgets>
@@ -145,7 +175,20 @@
145175
<extends>QToolButton</extends>
146176
<header>qgscolorbutton.h</header>
147177
</customwidget>
178+
<customwidget>
179+
<class>QgsMapLayerComboBox</class>
180+
<extends>QComboBox</extends>
181+
<header location="global">qgsmaplayercombobox.h</header>
182+
</customwidget>
148183
</customwidgets>
184+
<tabstops>
185+
<tabstop>mMapPositionFixedCheckBox</tabstop>
186+
<tabstop>mLayerComboBox</tabstop>
187+
<tabstop>mMapMarkerButton</tabstop>
188+
<tabstop>mFrameWidthSpinBox</tabstop>
189+
<tabstop>mBackgroundColorButton</tabstop>
190+
<tabstop>mFrameColorButton</tabstop>
191+
</tabstops>
149192
<resources/>
150193
<connections/>
151194
</ui>

‎tests/src/python/test_qgsmapcanvasannotationitem.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
QgsMapSettings,
1919
QgsCoordinateReferenceSystem,
2020
QgsRectangle,
21-
QgsPoint)
21+
QgsPoint,
22+
QgsVectorLayer)
2223
from qgis.gui import (QgsMapCanvas,
2324
QgsMapCanvasAnnotationItem)
2425

@@ -105,6 +106,21 @@ def testSize(self):
105106
self.assertAlmostEqual(i.boundingRect().width(), 310, -1)
106107
self.assertAlmostEqual(i.boundingRect().height(), 220, -1)
107108

109+
def testVisibility(self):
110+
""" test that map canvas annotation item visibility follows layer"""
111+
a = QgsTextAnnotation()
112+
canvas = QgsMapCanvas()
113+
i = QgsMapCanvasAnnotationItem(a, canvas)
114+
115+
self.assertTrue(i.isVisible())
116+
117+
layer = QgsVectorLayer("Point?crs=EPSG:3111&field=fldtxt:string",
118+
'test', "memory")
119+
a.setMapLayer(layer)
120+
self.assertFalse(i.isVisible())
121+
canvas.setLayers([layer])
122+
self.assertTrue(i.isVisible())
123+
108124

109125
if __name__ == '__main__':
110126
unittest.main()

0 commit comments

Comments
 (0)
Please sign in to comment.