QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
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"
19 #include "qgsattributeeditor.h"
20 #include "qgsfeature.h"
21 #include "qgslogger.h"
22 #include "qgsmapcanvas.h"
23 #include "qgsmaplayerregistry.h"
24 #include "qgsmaptool.h"
25 #include "qgsvectorlayer.h"
26 #include <QDomElement>
27 #include <QDir>
28 #include <QFile>
29 #include <QFileInfo>
30 #include <QGraphicsProxyWidget>
31 #include <QPainter>
32 #include <QSettings>
33 #include <QUiLoader>
34 #include <QWidget>
35 
36 QgsFormAnnotationItem::QgsFormAnnotationItem( QgsMapCanvas* canvas, QgsVectorLayer* vlayer, bool hasFeature, int feature )
37  : QgsAnnotationItem( canvas )
38  , mWidgetContainer( nullptr )
39  , mDesignerWidget( nullptr )
40  , mVectorLayer( vlayer )
41  , mHasAssociatedFeature( hasFeature )
42  , mFeature( feature )
43 {
44  mWidgetContainer = new QGraphicsProxyWidget( this );
45  mWidgetContainer->setData( 0, "AnnotationItem" ); //mark embedded widget as belonging to an annotation item (composer knows it needs to be printed)
46  if ( mVectorLayer && mMapCanvas ) //default to the layers edit form
47  {
48  mDesignerForm = mVectorLayer->annotationForm();
49  QObject::connect( mVectorLayer, SIGNAL( layerModified() ), this, SLOT( setFeatureForMapPosition() ) );
50  QObject::connect( mMapCanvas, SIGNAL( renderComplete( QPainter* ) ), this, SLOT( setFeatureForMapPosition() ) );
51  QObject::connect( mMapCanvas, SIGNAL( layersChanged() ), this, SLOT( updateVisibility() ) );
52  }
53 
54  setFeatureForMapPosition();
55 }
56 
58 {
59  delete mDesignerWidget;
60 }
61 
63 {
64  mDesignerForm = uiFile;
65  mWidgetContainer->setWidget( nullptr );
66  delete mDesignerWidget;
67  mDesignerWidget = createDesignerWidget( uiFile );
68  if ( mDesignerWidget )
69  {
70  mFrameBackgroundColor = mDesignerWidget->palette().color( QPalette::Window );
71  mWidgetContainer->setWidget( mDesignerWidget );
73  }
74 }
75 
76 QWidget* QgsFormAnnotationItem::createDesignerWidget( const QString& filePath )
77 {
78  QFile file( filePath );
79  if ( !file.open( QFile::ReadOnly ) )
80  {
81  return nullptr;
82  }
83 
84  QUiLoader loader;
85  QFileInfo fi( file );
86  loader.setWorkingDirectory( fi.dir() );
87  QWidget* widget = loader.load( &file, nullptr );
88  file.close();
89 
90  //get feature and set attribute information
91  if ( mVectorLayer && mHasAssociatedFeature )
92  {
93  QgsFeature f;
94  if ( mVectorLayer->getFeatures( QgsFeatureRequest().setFilterFid( mFeature ).setFlags( QgsFeatureRequest::NoGeometry ) ).nextFeature( f ) )
95  {
96  const QgsFields& fields = mVectorLayer->fields();
97  QgsAttributes attrs = f.attributes();
98  for ( int i = 0; i < attrs.count(); ++i )
99  {
100  if ( i < fields.count() )
101  {
102  QWidget* attWidget = widget->findChild<QWidget*>( fields.at( i ).name() );
103  if ( attWidget )
104  {
105  QgsAttributeEditor::createAttributeEditor( widget, attWidget, mVectorLayer, i, attrs.at( i ) );
106  }
107  }
108  }
109  }
110  }
111  return widget;
112 }
113 
115 {
117  setFeatureForMapPosition();
118 }
119 
121 {
122  Q_UNUSED( painter );
123 }
124 
125 void QgsFormAnnotationItem::paint( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget )
126 {
127  Q_UNUSED( option );
128  Q_UNUSED( widget );
129  if ( !painter || !mWidgetContainer )
130  {
131  return;
132  }
133 
134  drawFrame( painter );
135  if ( mMapPositionFixed )
136  {
137  drawMarkerSymbol( painter );
138  }
139 
142  - mFrameBorderWidth ) );
143 
144  if ( isSelected() )
145  {
146  drawSelectionBoxes( painter );
147  }
148 }
149 
151 {
152  if ( mDesignerWidget )
153  {
154  QSizeF widgetMinSize = mDesignerWidget->minimumSize();
155  return QSizeF( 2 * mFrameBorderWidth + widgetMinSize.width(), 2 * mFrameBorderWidth + widgetMinSize.height() );
156  }
157  else
158  {
159  return QSizeF( 0, 0 );
160  }
161 }
162 
164 {
165  if ( mDesignerWidget )
166  {
167  return mDesignerWidget->sizeHint();
168  }
169  else
170  {
171  return QSizeF( 0, 0 );
172  }
173 }
174 
176 {
177  QDomElement documentElem = doc.documentElement();
178  if ( documentElem.isNull() )
179  {
180  return;
181  }
182 
183  QDomElement formAnnotationElem = doc.createElement( "FormAnnotationItem" );
184  if ( mVectorLayer )
185  {
186  formAnnotationElem.setAttribute( "vectorLayer", mVectorLayer->id() );
187  }
188  formAnnotationElem.setAttribute( "hasFeature", mHasAssociatedFeature );
189  formAnnotationElem.setAttribute( "feature", mFeature );
190  formAnnotationElem.setAttribute( "designerForm", mDesignerForm );
191  _writeXML( doc, formAnnotationElem );
192  documentElem.appendChild( formAnnotationElem );
193 }
194 
195 void QgsFormAnnotationItem::readXML( const QDomDocument& doc, const QDomElement& itemElem )
196 {
197  mVectorLayer = nullptr;
198  if ( itemElem.hasAttribute( "vectorLayer" ) )
199  {
200  mVectorLayer = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( itemElem.attribute( "vectorLayer", "" ) ) );
201  if ( mVectorLayer )
202  {
203  QObject::connect( mVectorLayer, SIGNAL( layerModified() ), this, SLOT( setFeatureForMapPosition() ) );
204  QObject::connect( mMapCanvas, SIGNAL( renderComplete( QPainter* ) ), this, SLOT( setFeatureForMapPosition() ) );
205  QObject::connect( mMapCanvas, SIGNAL( layersChanged() ), this, SLOT( updateVisibility() ) );
206  }
207  }
208  mHasAssociatedFeature = itemElem.attribute( "hasFeature", "0" ).toInt();
209  mFeature = itemElem.attribute( "feature", "0" ).toInt();
210  mDesignerForm = itemElem.attribute( "designerForm", "" );
211  QDomElement annotationElem = itemElem.firstChildElement( "AnnotationItem" );
212  if ( !annotationElem.isNull() )
213  {
214  _readXML( doc, annotationElem );
215  }
216 
217  mDesignerWidget = createDesignerWidget( mDesignerForm );
218  if ( mDesignerWidget )
219  {
220  mFrameBackgroundColor = mDesignerWidget->palette().color( QPalette::Window );
221  mWidgetContainer->setWidget( mDesignerWidget );
222  }
223  updateVisibility();
224 }
225 
226 void QgsFormAnnotationItem::setFeatureForMapPosition()
227 {
228  if ( !mVectorLayer || !mMapCanvas )
229  {
230  return;
231  }
232 
233  double halfIdentifyWidth = QgsMapTool::searchRadiusMU( mMapCanvas );
234  QgsRectangle searchRect( mMapPosition.x() - halfIdentifyWidth, mMapPosition.y() - halfIdentifyWidth,
235  mMapPosition.x() + halfIdentifyWidth, mMapPosition.y() + halfIdentifyWidth );
236 
237  QgsFeatureIterator fit = mVectorLayer->getFeatures( QgsFeatureRequest().setFilterRect( searchRect ).setFlags( QgsFeatureRequest::NoGeometry | QgsFeatureRequest::ExactIntersect ).setSubsetOfAttributes( QgsAttributeList() ) );
238 
239  QgsFeature currentFeature;
240  QgsFeatureId currentFeatureId = 0;
241  bool featureFound = false;
242 
243  while ( fit.nextFeature( currentFeature ) )
244  {
245  currentFeatureId = currentFeature.id();
246  featureFound = true;
247  break;
248  }
249 
250  mHasAssociatedFeature = featureFound;
251  mFeature = currentFeatureId;
252 
253  //create new embedded widget
254  mWidgetContainer->setWidget( nullptr );
255  delete mDesignerWidget;
256  mDesignerWidget = createDesignerWidget( mDesignerForm );
257  if ( mDesignerWidget )
258  {
259  mFrameBackgroundColor = mDesignerWidget->palette().color( QPalette::Window );
260  mWidgetContainer->setWidget( mDesignerWidget );
261  }
262 }
263 
264 void QgsFormAnnotationItem::updateVisibility()
265 {
266  bool visible = true;
267  if ( mVectorLayer && mMapCanvas )
268  {
269  visible = mMapCanvas->layers().contains( mVectorLayer );
270  }
271  setVisible( visible );
272 }
273 
274 
275 
void writeXML(QDomDocument &doc) const override
Wrapper for iterator of features from vector data provider or vector layer.
A rectangle specified with double values.
Definition: qgsrectangle.h:35
QgsAttributes attributes() const
Returns the feature&#39;s attributes.
Definition: qgsfeature.cpp:110
static double searchRadiusMU(const QgsRenderContext &context)
Get search radius in map units for given context.
Definition: qgsmaptool.cpp:219
QList< QgsMapLayer * > layers() const
return list of layers within map canvas.
QString name
Definition: qgsfield.h:52
void _readXML(const QDomDocument &doc, const QDomElement &annotationElem)
double mFrameBorderWidth
Width of the frame.
QDomNode appendChild(const QDomNode &newChild)
Use exact geometry intersection (slower) instead of bounding boxes.
QString attribute(const QString &name, const QString &defValue) const
void setData(int key, const QVariant &value)
QPointF mOffsetFromReferencePoint
Describes the shift of the item content box to the reference point.
QgsMapLayer * mapLayer(const QString &theLayerId) const
Retrieve a pointer to a registered layer by layer ID.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
void drawMarkerSymbol(QPainter *p) const
Draws the map position marker symbol to a destination painter.
Container of fields for a vector layer.
Definition: qgsfield.h:252
QDomElement documentElement() const
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:187
void setWorkingDirectory(const QDir &dir)
virtual void setGeometry(const QRectF &rect)
int count() const
Return number of items.
Definition: qgsfield.cpp:402
void setDesignerForm(const QString &uiFile)
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:109
void setFrameSize(QSizeF size)
const QgsField & at(int i) const
Get field at particular index (must be in range 0..N-1)
Definition: qgsfield.cpp:422
double y() const
Get the y value of the point.
Definition: qgspoint.h:193
QSizeF minimumFrameSize() const override
QgsFields fields() const
Returns the list of fields of this layer.
static Q_DECL_DEPRECATED QWidget * createAttributeEditor(QWidget *parent, QWidget *editor, QgsVectorLayer *vl, int idx, const QVariant &value, QMap< int, QWidget *> &proxyWidgets)
Creates or prepares a attribute editor widget.
QPointF pos() const
QSizeF preferredFrameSize() const
Returns the optimal frame size.
qreal x() const
qreal y() const
QString id() const
Get this layer&#39;s unique ID, this ID is used to access this layer from map layer registry.
virtual void setMapPosition(const QgsPoint &pos)
bool hasAttribute(const QString &name) const
void setAttribute(const QString &name, const QString &value)
bool isSelected() const
int toInt(bool *ok, int base) const
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QList< int > QgsAttributeList
void _writeXML(QDomDocument &doc, QDomElement &itemElem) const
QDir dir() const
virtual bool open(QFlags< QIODevice::OpenModeFlag > mode)
QString annotationForm() const
Get annotation form.
A class to represent a point.
Definition: qgspoint.h:117
void paint(QPainter *painter) override
function to be implemented by derived classes
QgsFeatureId id() const
Get the feature ID for this feature.
Definition: qgsfeature.cpp:65
bool contains(const T &value) const
virtual void close()
An annotation item can be either placed either on screen corrdinates or on map coordinates.
bool isNull() const
bool mMapPositionFixed
True: the item stays at the same map position, False: the item stays on same screen position...
const T & at(int i) const
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
QgsMapCanvas * mMapCanvas
pointer to map canvas
QDomElement firstChildElement(const QString &tagName) const
void readXML(const QDomDocument &doc, const QDomElement &itemElem) override
void setFlags(QFlags< QGraphicsItem::GraphicsItemFlag > flags)
int count(const T &value) const
QWidget * load(QIODevice *device, QWidget *parentWidget)
qint64 QgsFeatureId
Definition: qgsfeature.h:31
void setVisible(bool visible)
void setMapPosition(const QgsPoint &pos) override
Reimplemented from QgsAnnotationItem.
QgsFormAnnotationItem(QgsMapCanvas *canvas, QgsVectorLayer *vlayer=nullptr, bool hasFeature=false, int feature=0)
void setWidget(QWidget *widget)
QDomElement createElement(const QString &tagName)
bool nextFeature(QgsFeature &f)
qreal height() const
Geometry is not required. It may still be returned if e.g. required for a filter condition.
A vector of attributes.
Definition: qgsfeature.h:115
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
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)
qreal width() const
double x() const
Get the x value of the point.
Definition: qgspoint.h:185
void drawFrame(QPainter *p) const
Draws the annotation frame to a destination painter.
T findChild(const QString &name) const