QGIS API Documentation  2.99.0-Master (6a61179)
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 "qgsfeature.h"
20 #include "qgsfeatureiterator.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 #include "qgswebview.h"
29 #include "qgswebframe.h"
30 
31 #include <QDomElement>
32 #include <QDir>
33 #include <QFile>
34 #include <QFileInfo>
35 #include <QGraphicsProxyWidget>
36 #include <QPainter>
37 #include <QSettings>
38 #include <QWidget>
39 
40 
41 QgsHtmlAnnotationItem::QgsHtmlAnnotationItem( QgsMapCanvas* canvas, QgsVectorLayer* vlayer, bool hasFeature, int feature )
42  : QgsAnnotationItem( canvas )
43  , mWidgetContainer( nullptr )
44  , mWebView( nullptr )
45  , mVectorLayer( vlayer )
46  , mHasAssociatedFeature( hasFeature )
47  , mFeatureId( feature )
48 {
49  mWebView = new QgsWebView();
50  mWebView->page()->setNetworkAccessManager( QgsNetworkAccessManager::instance() );
51 
52  mWidgetContainer = new QGraphicsProxyWidget( this );
53  mWidgetContainer->setWidget( mWebView );
54 
55  QObject::connect( mWebView->page()->mainFrame(), SIGNAL( javaScriptWindowObjectCleared() ), this, SLOT( javascript() ) );
56 
57  if ( mVectorLayer && mMapCanvas )
58  {
59  QObject::connect( mVectorLayer, SIGNAL( layerModified() ), this, SLOT( setFeatureForMapPosition() ) );
60  QObject::connect( mMapCanvas, SIGNAL( renderComplete( QPainter* ) ), this, SLOT( setFeatureForMapPosition() ) );
61  QObject::connect( mMapCanvas, SIGNAL( layersChanged() ), this, SLOT( updateVisibility() ) );
62  }
63 
64  setFeatureForMapPosition();
65 }
66 
68 {
69  delete mWebView;
70 }
71 
72 void QgsHtmlAnnotationItem::setHTMLPage( const QString& htmlFile )
73 {
74  QFile file( htmlFile );
75  mHtmlFile = htmlFile;
76  if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) )
77  {
78  mHtmlSource = QLatin1String( "" );
79  }
80  else
81  {
82  QTextStream in( &file );
83  in.setCodec( "UTF-8" );
84  mHtmlSource = in.readAll();
85  }
86 
87  file.close();
88  setFeatureForMapPosition();
89 }
90 
92 {
94  setFeatureForMapPosition();
95 }
96 
97 void QgsHtmlAnnotationItem::paint( QPainter * painter )
98 {
99  Q_UNUSED( painter );
100 }
101 
102 void QgsHtmlAnnotationItem::paint( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget )
103 {
104  Q_UNUSED( option );
105  Q_UNUSED( widget );
106  if ( !painter || !mWidgetContainer )
107  {
108  return;
109  }
110 
111  drawFrame( painter );
112  if ( mMapPositionFixed )
113  {
114  drawMarkerSymbol( painter );
115  }
116 
117  mWidgetContainer->setGeometry( QRectF( mOffsetFromReferencePoint.x() + mFrameBorderWidth / 2.0, mOffsetFromReferencePoint.y()
118  + mFrameBorderWidth / 2.0, mFrameSize.width() - mFrameBorderWidth, mFrameSize.height()
119  - mFrameBorderWidth ) );
120  if ( data( 1 ).toString() == QLatin1String( "composer" ) )
121  {
122  mWidgetContainer->widget()->render( painter, mOffsetFromReferencePoint.toPoint() );
123  }
124 
125  if ( isSelected() )
126  {
127  drawSelectionBoxes( painter );
128  }
129 }
130 
132 {
133  if ( mWebView )
134  {
135  QSizeF widgetMinSize = mWebView->minimumSize();
136  return QSizeF( 2 * mFrameBorderWidth + widgetMinSize.width(), 2 * mFrameBorderWidth + widgetMinSize.height() );
137  }
138  else
139  {
140  return QSizeF( 0, 0 );
141  }
142 }
143 
144 void QgsHtmlAnnotationItem::writeXml( QDomDocument& doc ) const
145 {
146  QDomElement documentElem = doc.documentElement();
147  if ( documentElem.isNull() )
148  {
149  return;
150  }
151 
152  QDomElement formAnnotationElem = doc.createElement( QStringLiteral( "HtmlAnnotationItem" ) );
153  if ( mVectorLayer )
154  {
155  formAnnotationElem.setAttribute( QStringLiteral( "vectorLayer" ), mVectorLayer->id() );
156  }
157  formAnnotationElem.setAttribute( QStringLiteral( "hasFeature" ), mHasAssociatedFeature );
158  formAnnotationElem.setAttribute( QStringLiteral( "feature" ), mFeatureId );
159  formAnnotationElem.setAttribute( QStringLiteral( "htmlfile" ), htmlPage() );
160 
161  _writeXml( doc, formAnnotationElem );
162  documentElem.appendChild( formAnnotationElem );
163 }
164 
165 void QgsHtmlAnnotationItem::readXml( const QDomDocument& doc, const QDomElement& itemElem )
166 {
167  mVectorLayer = nullptr;
168  if ( itemElem.hasAttribute( QStringLiteral( "vectorLayer" ) ) )
169  {
170  mVectorLayer = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( itemElem.attribute( QStringLiteral( "vectorLayer" ), QLatin1String( "" ) ) ) );
171  if ( mVectorLayer )
172  {
173  QObject::connect( mVectorLayer, SIGNAL( layerModified() ), this, SLOT( setFeatureForMapPosition() ) );
174  QObject::connect( mMapCanvas, SIGNAL( renderComplete( QPainter* ) ), this, SLOT( setFeatureForMapPosition() ) );
175  QObject::connect( mMapCanvas, SIGNAL( layersChanged() ), this, SLOT( updateVisibility() ) );
176  }
177  }
178  mHasAssociatedFeature = itemElem.attribute( QStringLiteral( "hasFeature" ), QStringLiteral( "0" ) ).toInt();
179  mFeatureId = itemElem.attribute( QStringLiteral( "feature" ), QStringLiteral( "0" ) ).toInt();
180  mHtmlFile = itemElem.attribute( QStringLiteral( "htmlfile" ), QLatin1String( "" ) );
181  QDomElement annotationElem = itemElem.firstChildElement( QStringLiteral( "AnnotationItem" ) );
182  if ( !annotationElem.isNull() )
183  {
184  _readXml( doc, annotationElem );
185  }
186 
187  if ( mWebView )
188  {
189  setHTMLPage( mHtmlFile );
190  }
191  updateVisibility();
192 }
193 
194 void QgsHtmlAnnotationItem::setFeatureForMapPosition()
195 {
196  QString newText;
197  if ( mVectorLayer && mMapCanvas )
198  {
199  double halfIdentifyWidth = QgsMapTool::searchRadiusMU( mMapCanvas );
200  QgsRectangle searchRect( mMapPosition.x() - halfIdentifyWidth, mMapPosition.y() - halfIdentifyWidth,
201  mMapPosition.x() + halfIdentifyWidth, mMapPosition.y() + halfIdentifyWidth );
202 
203  QgsFeatureIterator fit = mVectorLayer->getFeatures( QgsFeatureRequest().setFilterRect( searchRect ).setFlags( QgsFeatureRequest::NoGeometry | QgsFeatureRequest::ExactIntersect ) );
204 
205  QgsFeature currentFeature;
206  QgsFeatureId currentFeatureId = 0;
207  bool featureFound = false;
208 
209  while ( fit.nextFeature( currentFeature ) )
210  {
211  currentFeatureId = currentFeature.id();
212  featureFound = true;
213  break;
214  }
215 
216  mHasAssociatedFeature = featureFound;
217  mFeatureId = currentFeatureId;
218  mFeature = currentFeature;
219 
220  QgsExpressionContext context;
223  << QgsExpressionContextUtils::layerScope( mVectorLayer );
224  if ( mMapCanvas )
226  context.setFeature( mFeature );
227  newText = QgsExpression::replaceExpressionText( mHtmlSource, &context );
228  }
229  else
230  {
231  newText = mHtmlSource;
232  }
233  mWebView->setHtml( newText );
234 }
235 
236 void QgsHtmlAnnotationItem::updateVisibility()
237 {
238  bool visible = true;
239  if ( mVectorLayer && mMapCanvas )
240  {
241  visible = mMapCanvas->layers().contains( mVectorLayer );
242  }
243  setVisible( visible );
244 }
245 
246 void QgsHtmlAnnotationItem::javascript()
247 {
248  QWebFrame *frame = mWebView->page()->mainFrame();
249  frame->addToJavaScriptWindowObject( QStringLiteral( "canvas" ), mMapCanvas );
250  frame->addToJavaScriptWindowObject( QStringLiteral( "layer" ), mVectorLayer );
251 }
252 
253 
254 
QgsFeatureId id
Definition: qgsfeature.h:139
Wrapper for iterator of features from vector data provider or vector layer.
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.
QgsHtmlAnnotationItem(QgsMapCanvas *canvas, QgsVectorLayer *vlayer=nullptr, bool hasFeature=false, int feature=0)
double mFrameBorderWidth
Width of the frame.
Use exact geometry intersection (slower) instead of bounding boxes.
void setMapPosition(const QgsPoint &pos) override
Reimplemented from QgsAnnotationItem.
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.
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.
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
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:106
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
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)
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
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)...
The QgsWebView class is a collection of stubs to mimic the API of QWebView on systems where the real ...
Definition: qgswebview.h:57
A class to represent a point.
Definition: qgspoint.h:111
An annotation item can be either placed either on screen corrdinates or on map coordinates.
const QgsMapSettings & mapSettings() const
Get access to properties used for map rendering.
bool mMapPositionFixed
True: the item stays at the same map position, False: the item stays on same screen position...
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.
void paint(QPainter *painter) override
function to be implemented by derived classes
static QgsNetworkAccessManager * instance()
returns a pointer to the single instance
void _writeXml(QDomDocument &doc, QDomElement &itemElem) const
Serialize to XML.
void setHTMLPage(const QString &htmlFile)
QgsMapCanvas * mMapCanvas
pointer to map canvas
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
qint64 QgsFeatureId
Definition: qgsfeature.h:32
QSizeF minimumFrameSize() const override
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.
Geometry is not required. It may still be returned if e.g. required for a filter condition.
void writeXml(QDomDocument &doc) const override
Serialize to XML.
Represents a vector layer which manages a vector based data sets.
QgsPoint mMapPosition
Map position (in case mMapPositionFixed is true)
void readXml(const QDomDocument &doc, const QDomElement &itemElem) override
Deserialize from XML.
QSizeF mFrameSize
Size of the frame (without balloon)
The QWebFrame class is a collection of stubs to mimic the API of a QWebFrame on systems where QtWebki...
Definition: qgswebframe.h:32
void drawFrame(QPainter *p) const
Draws the annotation frame to a destination painter.
static QString replaceExpressionText(const QString &action, const QgsExpressionContext *context, const QgsDistanceArea *distanceArea=nullptr)
This function replaces each expression between [% and %] in the string with the result of its evaluat...
void _readXml(const QDomDocument &doc, const QDomElement &annotationElem)
Deserialize from XML.
double x
Definition: qgspoint.h:115