QGIS API Documentation  2.9.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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( 0 )
39  , mDesignerWidget( 0 )
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 
62 void QgsFormAnnotationItem::setDesignerForm( const QString& uiFile )
63 {
64  mDesignerForm = uiFile;
65  mWidgetContainer->setWidget( 0 );
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 0;
82  }
83 
84  QUiLoader loader;
85  QFileInfo fi( file );
86  loader.setWorkingDirectory( fi.dir() );
87  QWidget* widget = loader.load( &file, 0 );
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->pendingFields();
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[i].name() );
103  if ( attWidget )
104  {
105  QgsAttributeEditor::createAttributeEditor( widget, attWidget, mVectorLayer, i, attrs[i] );
106  }
107  }
108  }
109  }
110  }
111  return widget;
112 }
113 
115 {
117  setFeatureForMapPosition();
118 }
119 
120 void QgsFormAnnotationItem::paint( QPainter * painter )
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 
140  mWidgetContainer->setGeometry( QRectF( mOffsetFromReferencePoint.x() + mFrameBorderWidth / 2.0, mOffsetFromReferencePoint.y()
141  + mFrameBorderWidth / 2.0, mFrameSize.width() - mFrameBorderWidth, mFrameSize.height()
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 
175 void QgsFormAnnotationItem::writeXML( QDomDocument& doc ) const
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 = 0;
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( 0 );
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 
QgsFeatureId id() const
Get the feature ID for this feature.
Definition: qgsfeature.cpp:51
void writeXML(QDomDocument &doc) const override
Wrapper for iterator of features from vector data provider or vector layer.
QString annotationForm() const
get annotation form
A rectangle specified with double values.
Definition: qgsrectangle.h:35
QSizeF preferredFrameSize() const
Returns the optimal frame size.
static double searchRadiusMU(const QgsRenderContext &context)
Get search radius in map units for given context.
Definition: qgsmaptool.cpp:213
void _readXML(const QDomDocument &doc, const QDomElement &annotationElem)
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.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
QList< QgsMapLayer * > layers() const
return list of layers within map canvas.
Container of fields for a vector layer.
Definition: qgsfield.h:173
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:119
QgsFormAnnotationItem(QgsMapCanvas *canvas, QgsVectorLayer *vlayer=0, bool hasFeature=false, int feature=0)
void setDesignerForm(const QString &uiFile)
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:105
double x() const
Definition: qgspoint.h:126
void drawSelectionBoxes(QPainter *p)
QSizeF minimumFrameSize() const override
virtual void setMapPosition(const QgsPoint &pos)
QgsAttributes attributes() const
Returns the feature's attributes.
Definition: qgsfeature.cpp:90
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QList< int > QgsAttributeList
QString id() const
Get this layer's unique ID, this ID is used to access this layer from map layer registry.
Definition: qgsmaplayer.cpp:99
void drawMarkerSymbol(QPainter *p)
int count() const
Return number of items.
Definition: qgsfield.cpp:279
A class to represent a point.
Definition: qgspoint.h:63
void paint(QPainter *painter) override
function to be implemented by derived classes
An annotation item can be either placed either on screen corrdinates or on map coordinates.
QString file
Definition: qgssvgcache.cpp:76
bool mMapPositionFixed
True: the item stays at the same map position, False: the item stays on same screen position...
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.
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
void _writeXML(QDomDocument &doc, QDomElement &itemElem) const
QVector< QVariant > QgsAttributes
Definition: qgsfeature.h:106
QgsMapCanvas * mMapCanvas
pointer to map canvas
void setFrameSize(const QSizeF &size)
void readXML(const QDomDocument &doc, const QDomElement &itemElem) override
void drawFrame(QPainter *p)
qint64 QgsFeatureId
Definition: qgsfeature.h:31
double y() const
Definition: qgspoint.h:134
void setMapPosition(const QgsPoint &pos) override
Reimplemented from QgsAnnotationItem.
QgsMapLayer * mapLayer(QString theLayerId)
Retrieve a pointer to a loaded layer by id.
const QgsFields & pendingFields() const
returns field list in the to-be-committed state
bool nextFeature(QgsFeature &f)
Geometry is not required. It may still be returned if e.g. required for a filter condition.
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)