QGIS API Documentation  2.14.0-Essen
qgshtmlannotationitem.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgshtmlannotationitem.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 "qgshtmlannotationitem.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 "qgsexpression.h"
28 
29 #include <QDomElement>
30 #include <QDir>
31 #include <QFile>
32 #include <QFileInfo>
33 #include <QGraphicsProxyWidget>
34 #include <QPainter>
35 #include <QSettings>
36 #include <QWidget>
37 
38 
39 QgsHtmlAnnotationItem::QgsHtmlAnnotationItem( QgsMapCanvas* canvas, QgsVectorLayer* vlayer, bool hasFeature, int feature )
40  : QgsAnnotationItem( canvas )
41  , mWidgetContainer( nullptr )
42  , mWebView( nullptr )
43  , mVectorLayer( vlayer )
44  , mHasAssociatedFeature( hasFeature )
45  , mFeatureId( feature )
46 {
47  mWebView = new QgsWebView();
48  mWebView->page()->setNetworkAccessManager( QgsNetworkAccessManager::instance() );
49 
50  mWidgetContainer = new QGraphicsProxyWidget( this );
51  mWidgetContainer->setWidget( mWebView );
52 
53  QObject::connect( mWebView->page()->mainFrame(), SIGNAL( javaScriptWindowObjectCleared() ), this, SLOT( javascript() ) );
54 
55  if ( mVectorLayer && mMapCanvas )
56  {
57  QObject::connect( mVectorLayer, SIGNAL( layerModified() ), this, SLOT( setFeatureForMapPosition() ) );
58  QObject::connect( mMapCanvas, SIGNAL( renderComplete( QPainter* ) ), this, SLOT( setFeatureForMapPosition() ) );
59  QObject::connect( mMapCanvas, SIGNAL( layersChanged() ), this, SLOT( updateVisibility() ) );
60  }
61 
62  setFeatureForMapPosition();
63 }
64 
66 {
67  delete mWebView;
68 }
69 
71 {
72  QFile file( htmlFile );
73  mHtmlFile = htmlFile;
74  if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) )
75  {
76  mHtmlSource = "";
77  }
78  else
79  {
80  QTextStream in( &file );
81  in.setCodec( "UTF-8" );
82  mHtmlSource = in.readAll();
83  }
84 
85  file.close();
86  setFeatureForMapPosition();
87 }
88 
90 {
92  setFeatureForMapPosition();
93 }
94 
96 {
97  Q_UNUSED( painter );
98 }
99 
100 void QgsHtmlAnnotationItem::paint( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget )
101 {
102  Q_UNUSED( option );
103  Q_UNUSED( widget );
104  if ( !painter || !mWidgetContainer )
105  {
106  return;
107  }
108 
109  drawFrame( painter );
110  if ( mMapPositionFixed )
111  {
112  drawMarkerSymbol( painter );
113  }
114 
117  - mFrameBorderWidth ) );
118  if ( data( 1 ).toString() == "composer" )
119  {
120  mWidgetContainer->widget()->render( painter, mOffsetFromReferencePoint.toPoint() );
121  }
122 
123  if ( isSelected() )
124  {
125  drawSelectionBoxes( painter );
126  }
127 }
128 
130 {
131  if ( mWebView )
132  {
133  QSizeF widgetMinSize = mWebView->minimumSize();
134  return QSizeF( 2 * mFrameBorderWidth + widgetMinSize.width(), 2 * mFrameBorderWidth + widgetMinSize.height() );
135  }
136  else
137  {
138  return QSizeF( 0, 0 );
139  }
140 }
141 
143 {
144  QDomElement documentElem = doc.documentElement();
145  if ( documentElem.isNull() )
146  {
147  return;
148  }
149 
150  QDomElement formAnnotationElem = doc.createElement( "HtmlAnnotationItem" );
151  if ( mVectorLayer )
152  {
153  formAnnotationElem.setAttribute( "vectorLayer", mVectorLayer->id() );
154  }
155  formAnnotationElem.setAttribute( "hasFeature", mHasAssociatedFeature );
156  formAnnotationElem.setAttribute( "feature", mFeatureId );
157  formAnnotationElem.setAttribute( "htmlfile", htmlPage() );
158 
159  _writeXML( doc, formAnnotationElem );
160  documentElem.appendChild( formAnnotationElem );
161 }
162 
163 void QgsHtmlAnnotationItem::readXML( const QDomDocument& doc, const QDomElement& itemElem )
164 {
165  mVectorLayer = nullptr;
166  if ( itemElem.hasAttribute( "vectorLayer" ) )
167  {
168  mVectorLayer = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( itemElem.attribute( "vectorLayer", "" ) ) );
169  if ( mVectorLayer )
170  {
171  QObject::connect( mVectorLayer, SIGNAL( layerModified() ), this, SLOT( setFeatureForMapPosition() ) );
172  QObject::connect( mMapCanvas, SIGNAL( renderComplete( QPainter* ) ), this, SLOT( setFeatureForMapPosition() ) );
173  QObject::connect( mMapCanvas, SIGNAL( layersChanged() ), this, SLOT( updateVisibility() ) );
174  }
175  }
176  mHasAssociatedFeature = itemElem.attribute( "hasFeature", "0" ).toInt();
177  mFeatureId = itemElem.attribute( "feature", "0" ).toInt();
178  mHtmlFile = itemElem.attribute( "htmlfile", "" );
179  QDomElement annotationElem = itemElem.firstChildElement( "AnnotationItem" );
180  if ( !annotationElem.isNull() )
181  {
182  _readXML( doc, annotationElem );
183  }
184 
185  if ( mWebView )
186  {
187  setHTMLPage( mHtmlFile );
188  }
189  updateVisibility();
190 }
191 
192 void QgsHtmlAnnotationItem::setFeatureForMapPosition()
193 {
194  if ( !mVectorLayer || !mMapCanvas )
195  {
196  return;
197  }
198 
199  QSettings settings;
200  double halfIdentifyWidth = QgsMapTool::searchRadiusMU( mMapCanvas );
201  QgsRectangle searchRect( mMapPosition.x() - halfIdentifyWidth, mMapPosition.y() - halfIdentifyWidth,
202  mMapPosition.x() + halfIdentifyWidth, mMapPosition.y() + halfIdentifyWidth );
203 
205 
206  QgsFeature currentFeature;
207  QgsFeatureId currentFeatureId = 0;
208  bool featureFound = false;
209 
210  while ( fit.nextFeature( currentFeature ) )
211  {
212  currentFeatureId = currentFeature.id();
213  featureFound = true;
214  break;
215  }
216 
217  mHasAssociatedFeature = featureFound;
218  mFeatureId = currentFeatureId;
219  mFeature = currentFeature;
220 
221  QgsExpressionContext context;
224  << QgsExpressionContextUtils::layerScope( mVectorLayer );
225  if ( mMapCanvas )
227  context.setFeature( mFeature );
228  QString newtext = QgsExpression::replaceExpressionText( mHtmlSource, &context );
229  mWebView->setHtml( newtext );
230 }
231 
232 void QgsHtmlAnnotationItem::updateVisibility()
233 {
234  bool visible = true;
235  if ( mVectorLayer && mMapCanvas )
236  {
237  visible = mMapCanvas->layers().contains( mVectorLayer );
238  }
239  setVisible( visible );
240 }
241 
242 void QgsHtmlAnnotationItem::javascript()
243 {
244  QWebFrame *frame = mWebView->page()->mainFrame();
245  frame->addToJavaScriptWindowObject( "canvas", mMapCanvas );
246  frame->addToJavaScriptWindowObject( "layer", mVectorLayer );
247 }
248 
249 
250 
QgsFeatureId id() const
Get the feature ID for this feature.
Definition: qgsfeature.cpp:65
void readXML(const QDomDocument &doc, const QDomElement &itemElem) override
void setCodec(QTextCodec *codec)
Wrapper for iterator of features from vector data provider or vector layer.
A rectangle specified with double values.
Definition: qgsrectangle.h:35
static double searchRadiusMU(const QgsRenderContext &context)
Get search radius in map units for given context.
Definition: qgsmaptool.cpp:219
The QWebFrame class is a collection of stubs to mimic the API of a QWebFrame on systems where QtWebki...
Definition: qgswebframe.h:31
QgsHtmlAnnotationItem(QgsMapCanvas *canvas, QgsVectorLayer *vlayer=nullptr, bool hasFeature=false, int feature=0)
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.
void setMapPosition(const QgsPoint &pos) override
Reimplemented from QgsAnnotationItem.
QString attribute(const QString &name, const QString &defValue) const
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
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.
const QgsMapSettings & mapSettings() const
Get access to properties used for map rendering.
QDomElement documentElement() const
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
virtual void setGeometry(const QRectF &rect)
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:105
double x() const
Get the x value of the point.
Definition: qgspoint.h:128
void drawSelectionBoxes(QPainter *p)
QgsMapLayer * mapLayer(const QString &theLayerId)
Retrieve a pointer to a loaded layer by id.
void addToJavaScriptWindowObject(const QString &name, QObject *object)
QPointF pos() const
qreal x() const
qreal y() const
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
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
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
This class wraps a request for features to a vector layer (or directly its vector data provider)...
QString id() const
Get this layer&#39;s unique ID, this ID is used to access this layer from map layer registry.
void drawMarkerSymbol(QPainter *p)
The QgsWebView class is a collection of stubs to mimic the API of QWebView on systems where the real ...
Definition: qgswebview.h:54
virtual bool open(QFlags< QIODevice::OpenModeFlag > mode)
A class to represent a point.
Definition: qgspoint.h: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...
QVariant data(int key) const
static QgsExpressionContextScope * mapSettingsScope(const QgsMapSettings &mapSettings)
Creates a new scope which contains variables and functions relating to a QgsMapSettings object...
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
QPoint toPoint() const
void _writeXML(QDomDocument &doc, QDomElement &itemElem) const
void paint(QPainter *painter) override
function to be implemented by derived classes
static QgsNetworkAccessManager * instance()
returns a pointer to the single instance
void setHTMLPage(const QString &htmlFile)
QgsMapCanvas * mMapCanvas
pointer to map canvas
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
QDomElement firstChildElement(const QString &tagName) const
void setFlags(QFlags< QGraphicsItem::GraphicsItemFlag > flags)
void drawFrame(QPainter *p)
void writeXML(QDomDocument &doc) const override
qint64 QgsFeatureId
Definition: qgsfeature.h:31
static Q_DECL_DEPRECATED QString replaceExpressionText(const QString &action, const QgsFeature *feat, QgsVectorLayer *layer, const QMap< QString, QVariant > *substitutionMap=nullptr, const QgsDistanceArea *distanceArea=nullptr)
This function currently replaces each expression between [% and %] in the string with the result of i...
QWidget * widget() const
void setVisible(bool visible)
double y() const
Get the y value of the point.
Definition: qgspoint.h:136
QSizeF minimumFrameSize() const override
void setWidget(QWidget *widget)
static QgsExpressionContextScope * projectScope()
Creates a new scope which contains variables and functions relating to the current QGIS project...
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
QDomElement createElement(const QString &tagName)
qreal height() const
Geometry is not required. It may still be returned if e.g. required for a filter condition.
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QString readAll()
Represents a vector layer which manages a vector based data sets.
QgsPoint mMapPosition
Map position (in case mMapPositionFixed is true)
QString toString() const
QSizeF mFrameSize
Size of the frame (without balloon)
qreal width() const
void render(QPaintDevice *target, const QPoint &targetOffset, const QRegion &sourceRegion, QFlags< QWidget::RenderFlag > renderFlags)