QGIS API Documentation  2.99.0-Master (e077efd)
qgsformannotationitem.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsformannotationitem.h
3  ------------------------
4  begin : February 26, 2010
5  copyright : (C) 2010 by Marco Hugentobler
6  email : marco dot hugentobler at hugis dot net
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgsformannotationitem.h"
21 #include "qgseditorwidgetwrapper.h"
22 #include "qgsfeature.h"
23 #include "qgsfeatureiterator.h"
24 #include "qgslogger.h"
25 #include "qgsmapcanvas.h"
26 #include "qgsmaplayerregistry.h"
27 #include "qgsmaptool.h"
28 #include "qgsvectorlayer.h"
29 #include <QDomElement>
30 #include <QDir>
31 #include <QFile>
32 #include <QFileInfo>
33 #include <QGraphicsProxyWidget>
34 #include <QPainter>
35 #include <QSettings>
36 #include <QUiLoader>
37 #include <QWidget>
38 
39 QgsFormAnnotationItem::QgsFormAnnotationItem( QgsMapCanvas* canvas, QgsVectorLayer* vlayer, bool hasFeature, int feature )
40  : QgsAnnotationItem( canvas )
41  , mWidgetContainer( nullptr )
42  , mDesignerWidget( nullptr )
43  , mVectorLayer( vlayer )
44  , mHasAssociatedFeature( hasFeature )
45  , mFeature( feature )
46 {
47  mWidgetContainer = new QGraphicsProxyWidget( this );
48  mWidgetContainer->setData( 0, "AnnotationItem" ); //mark embedded widget as belonging to an annotation item (composer knows it needs to be printed)
49  if ( mVectorLayer && mMapCanvas ) //default to the layers edit form
50  {
51  mDesignerForm = mVectorLayer->annotationForm();
52  QObject::connect( mVectorLayer, SIGNAL( layerModified() ), this, SLOT( setFeatureForMapPosition() ) );
53  QObject::connect( mMapCanvas, SIGNAL( renderComplete( QPainter* ) ), this, SLOT( setFeatureForMapPosition() ) );
54  QObject::connect( mMapCanvas, SIGNAL( layersChanged() ), this, SLOT( updateVisibility() ) );
55  }
56 
57  setFeatureForMapPosition();
58 }
59 
61 {
62  delete mDesignerWidget;
63 }
64 
65 void QgsFormAnnotationItem::setDesignerForm( const QString& uiFile )
66 {
67  mDesignerForm = uiFile;
68  mWidgetContainer->setWidget( nullptr );
69  delete mDesignerWidget;
70  mDesignerWidget = createDesignerWidget( uiFile );
71  if ( mDesignerWidget )
72  {
73  mFrameBackgroundColor = mDesignerWidget->palette().color( QPalette::Window );
74  mWidgetContainer->setWidget( mDesignerWidget );
76  }
77 }
78 
79 QWidget* QgsFormAnnotationItem::createDesignerWidget( const QString& filePath )
80 {
81  QFile file( filePath );
82  if ( !file.open( QFile::ReadOnly ) )
83  {
84  return nullptr;
85  }
86 
87  QUiLoader loader;
88  QFileInfo fi( file );
89  loader.setWorkingDirectory( fi.dir() );
90  QWidget* widget = loader.load( &file, nullptr );
91  file.close();
92 
93  //get feature and set attribute information
95  if ( mVectorLayer && mHasAssociatedFeature )
96  {
97  QgsFeature f;
98  if ( mVectorLayer->getFeatures( QgsFeatureRequest().setFilterFid( mFeature ).setFlags( QgsFeatureRequest::NoGeometry ) ).nextFeature( f ) )
99  {
100  const QgsFields& fields = mVectorLayer->fields();
101  QgsAttributes attrs = f.attributes();
102  for ( int i = 0; i < attrs.count(); ++i )
103  {
104  if ( i < fields.count() )
105  {
106  QWidget* attWidget = widget->findChild<QWidget*>( fields.at( i ).name() );
107  if ( attWidget )
108  {
109  QgsEditorWidgetWrapper* eww = QgsEditorWidgetRegistry::instance()->create( mVectorLayer, i, attWidget, widget, context );
110  if ( eww )
111  {
112  eww->setValue( attrs.at( i ) );
113  }
114  }
115  }
116  }
117  }
118  }
119  return widget;
120 }
121 
123 {
125  setFeatureForMapPosition();
126 }
127 
128 void QgsFormAnnotationItem::paint( QPainter * painter )
129 {
130  Q_UNUSED( painter );
131 }
132 
133 void QgsFormAnnotationItem::paint( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget )
134 {
135  Q_UNUSED( option );
136  Q_UNUSED( widget );
137  if ( !painter || !mWidgetContainer )
138  {
139  return;
140  }
141 
142  drawFrame( painter );
143  if ( mMapPositionFixed )
144  {
145  drawMarkerSymbol( painter );
146  }
147 
148  mWidgetContainer->setGeometry( QRectF( mOffsetFromReferencePoint.x() + mFrameBorderWidth / 2.0, mOffsetFromReferencePoint.y()
149  + mFrameBorderWidth / 2.0, mFrameSize.width() - mFrameBorderWidth, mFrameSize.height()
150  - mFrameBorderWidth ) );
151 
152  if ( isSelected() )
153  {
154  drawSelectionBoxes( painter );
155  }
156 }
157 
159 {
160  if ( mDesignerWidget )
161  {
162  QSizeF widgetMinSize = mDesignerWidget->minimumSize();
163  return QSizeF( 2 * mFrameBorderWidth + widgetMinSize.width(), 2 * mFrameBorderWidth + widgetMinSize.height() );
164  }
165  else
166  {
167  return QSizeF( 0, 0 );
168  }
169 }
170 
172 {
173  if ( mDesignerWidget )
174  {
175  return mDesignerWidget->sizeHint();
176  }
177  else
178  {
179  return QSizeF( 0, 0 );
180  }
181 }
182 
183 void QgsFormAnnotationItem::writeXml( QDomDocument& doc ) const
184 {
185  QDomElement documentElem = doc.documentElement();
186  if ( documentElem.isNull() )
187  {
188  return;
189  }
190 
191  QDomElement formAnnotationElem = doc.createElement( QStringLiteral( "FormAnnotationItem" ) );
192  if ( mVectorLayer )
193  {
194  formAnnotationElem.setAttribute( QStringLiteral( "vectorLayer" ), mVectorLayer->id() );
195  }
196  formAnnotationElem.setAttribute( QStringLiteral( "hasFeature" ), mHasAssociatedFeature );
197  formAnnotationElem.setAttribute( QStringLiteral( "feature" ), mFeature );
198  formAnnotationElem.setAttribute( QStringLiteral( "designerForm" ), mDesignerForm );
199  _writeXml( doc, formAnnotationElem );
200  documentElem.appendChild( formAnnotationElem );
201 }
202 
203 void QgsFormAnnotationItem::readXml( const QDomDocument& doc, const QDomElement& itemElem )
204 {
205  mVectorLayer = nullptr;
206  if ( itemElem.hasAttribute( QStringLiteral( "vectorLayer" ) ) )
207  {
208  mVectorLayer = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( itemElem.attribute( QStringLiteral( "vectorLayer" ), QLatin1String( "" ) ) ) );
209  if ( mVectorLayer )
210  {
211  QObject::connect( mVectorLayer, SIGNAL( layerModified() ), this, SLOT( setFeatureForMapPosition() ) );
212  QObject::connect( mMapCanvas, SIGNAL( renderComplete( QPainter* ) ), this, SLOT( setFeatureForMapPosition() ) );
213  QObject::connect( mMapCanvas, SIGNAL( layersChanged() ), this, SLOT( updateVisibility() ) );
214  }
215  }
216  mHasAssociatedFeature = itemElem.attribute( QStringLiteral( "hasFeature" ), QStringLiteral( "0" ) ).toInt();
217  mFeature = itemElem.attribute( QStringLiteral( "feature" ), QStringLiteral( "0" ) ).toInt();
218  mDesignerForm = itemElem.attribute( QStringLiteral( "designerForm" ), QLatin1String( "" ) );
219  QDomElement annotationElem = itemElem.firstChildElement( QStringLiteral( "AnnotationItem" ) );
220  if ( !annotationElem.isNull() )
221  {
222  _readXml( doc, annotationElem );
223  }
224 
225  mDesignerWidget = createDesignerWidget( mDesignerForm );
226  if ( mDesignerWidget )
227  {
228  mFrameBackgroundColor = mDesignerWidget->palette().color( QPalette::Window );
229  mWidgetContainer->setWidget( mDesignerWidget );
230  }
231  updateVisibility();
232 }
233 
234 void QgsFormAnnotationItem::setFeatureForMapPosition()
235 {
236  if ( !mVectorLayer || !mMapCanvas )
237  {
238  return;
239  }
240 
241  double halfIdentifyWidth = QgsMapTool::searchRadiusMU( mMapCanvas );
242  QgsRectangle searchRect( mMapPosition.x() - halfIdentifyWidth, mMapPosition.y() - halfIdentifyWidth,
243  mMapPosition.x() + halfIdentifyWidth, mMapPosition.y() + halfIdentifyWidth );
244 
245  QgsFeatureIterator fit = mVectorLayer->getFeatures( QgsFeatureRequest().setFilterRect( searchRect ).setFlags( QgsFeatureRequest::NoGeometry | QgsFeatureRequest::ExactIntersect ).setSubsetOfAttributes( QgsAttributeList() ) );
246 
247  QgsFeature currentFeature;
248  QgsFeatureId currentFeatureId = 0;
249  bool featureFound = false;
250 
251  while ( fit.nextFeature( currentFeature ) )
252  {
253  currentFeatureId = currentFeature.id();
254  featureFound = true;
255  break;
256  }
257 
258  mHasAssociatedFeature = featureFound;
259  mFeature = currentFeatureId;
260 
261  //create new embedded widget
262  mWidgetContainer->setWidget( nullptr );
263  delete mDesignerWidget;
264  mDesignerWidget = createDesignerWidget( mDesignerForm );
265  if ( mDesignerWidget )
266  {
267  mFrameBackgroundColor = mDesignerWidget->palette().color( QPalette::Window );
268  mWidgetContainer->setWidget( mDesignerWidget );
269  }
270 }
271 
272 void QgsFormAnnotationItem::updateVisibility()
273 {
274  bool visible = true;
275  if ( mVectorLayer && mMapCanvas )
276  {
277  visible = mMapCanvas->layers().contains( mVectorLayer );
278  }
279  setVisible( visible );
280 }
281 
282 
283 
QgsFeatureId id
Definition: qgsfeature.h:139
Wrapper for iterator of features from vector data provider or vector layer.
void writeXml(QDomDocument &doc) const override
Serialize to XML.
A rectangle specified with double values.
Definition: qgsrectangle.h:35
double y
Definition: qgspoint.h:116
static double searchRadiusMU(const QgsRenderContext &context)
Get search radius in map units for given context.
Definition: qgsmaptool.cpp:204
QList< QgsMapLayer * > layers() const
return list of layers within map canvas.
QString name
Definition: qgsfield.h:55
double mFrameBorderWidth
Width of the frame.
Use exact geometry intersection (slower) instead of bounding boxes.
QPointF mOffsetFromReferencePoint
Describes the shift of the item content box to the reference point.
This class contains context information for attribute editor widgets.
Manages an editor widget Widget and wrapper share the same parent.
QgsMapLayer * mapLayer(const QString &theLayerId) const
Retrieve a pointer to a registered layer by layer ID.
void drawMarkerSymbol(QPainter *p) const
Draws the map position marker symbol to a destination painter.
Container of fields for a vector layer.
Definition: qgsfields.h:36
void drawSelectionBoxes(QPainter *p) const
Draws selection handles around the item.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:135
static QgsEditorWidgetRegistry * instance()
This class is a singleton and has therefore to be accessed with this method instead of a constructor...
int count() const
Return number of items.
Definition: qgsfields.cpp:117
void setDesignerForm(const QString &uiFile)
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:106
void setFrameSize(QSizeF size)
QSizeF minimumFrameSize() const override
QgsFields fields() const
Returns the list of fields of this layer.
QgsField at(int i) const
Get field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:137
QSizeF preferredFrameSize() const
Returns the optimal frame size.
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsMapLayerRegistry.
virtual void setMapPosition(const QgsPoint &pos)
QgsEditorWidgetWrapper * create(const QString &widgetId, QgsVectorLayer *vl, int fieldIdx, const QgsEditorWidgetConfig &config, QWidget *editor, QWidget *parent, const QgsAttributeEditorContext &context=QgsAttributeEditorContext())
Create an attribute editor widget wrapper of a given type for a given field.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const
Query the layer for features specified in request.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QList< int > QgsAttributeList
virtual void setValue(const QVariant &value)=0
Is called, when the value of the widget needs to be changed.
QString annotationForm() const
Get annotation form.
A class to represent a point.
Definition: qgspoint.h:111
void paint(QPainter *painter) override
function to be implemented by derived classes
void readXml(const QDomDocument &doc, const QDomElement &itemElem) override
Deserialize from XML.
An annotation item can be either placed either on screen corrdinates or on map coordinates.
bool mMapPositionFixed
True: the item stays at the same map position, False: the item stays on same screen position...
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
void _writeXml(QDomDocument &doc, QDomElement &itemElem) const
Serialize to XML.
QgsMapCanvas * mMapCanvas
pointer to map canvas
qint64 QgsFeatureId
Definition: qgsfeature.h:32
void setMapPosition(const QgsPoint &pos) override
Reimplemented from QgsAnnotationItem.
QgsFormAnnotationItem(QgsMapCanvas *canvas, QgsVectorLayer *vlayer=nullptr, bool hasFeature=false, int feature=0)
bool nextFeature(QgsFeature &f)
Geometry is not required. It may still be returned if e.g. required for a filter condition.
A vector of attributes.
Definition: qgsfeature.h:55
Represents a vector layer which manages a vector based data sets.
QgsPoint mMapPosition
Map position (in case mMapPositionFixed is true)
QSizeF mFrameSize
Size of the frame (without balloon)
QgsAttributes attributes
Definition: qgsfeature.h:140
void drawFrame(QPainter *p) const
Draws the annotation frame to a destination painter.
void _readXml(const QDomDocument &doc, const QDomElement &annotationElem)
Deserialize from XML.
double x
Definition: qgspoint.h:115