QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
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  QString newText;
195  if ( mVectorLayer && mMapCanvas )
196  {
197  double halfIdentifyWidth = QgsMapTool::searchRadiusMU( mMapCanvas );
198  QgsRectangle searchRect( mMapPosition.x() - halfIdentifyWidth, mMapPosition.y() - halfIdentifyWidth,
199  mMapPosition.x() + halfIdentifyWidth, mMapPosition.y() + halfIdentifyWidth );
200 
202 
203  QgsFeature currentFeature;
204  QgsFeatureId currentFeatureId = 0;
205  bool featureFound = false;
206 
207  while ( fit.nextFeature( currentFeature ) )
208  {
209  currentFeatureId = currentFeature.id();
210  featureFound = true;
211  break;
212  }
213 
214  mHasAssociatedFeature = featureFound;
215  mFeatureId = currentFeatureId;
216  mFeature = currentFeature;
217 
218  QgsExpressionContext context;
221  << QgsExpressionContextUtils::layerScope( mVectorLayer );
222  if ( mMapCanvas )
224  context.setFeature( mFeature );
225  newText = QgsExpression::replaceExpressionText( mHtmlSource, &context );
226  }
227  else
228  {
229  newText = mHtmlSource;
230  }
231  mWebView->setHtml( newText );
232 }
233 
234 void QgsHtmlAnnotationItem::updateVisibility()
235 {
236  bool visible = true;
237  if ( mVectorLayer && mMapCanvas )
238  {
239  visible = mMapCanvas->layers().contains( mVectorLayer );
240  }
241  setVisible( visible );
242 }
243 
244 void QgsHtmlAnnotationItem::javascript()
245 {
246  QWebFrame *frame = mWebView->page()->mainFrame();
247  frame->addToJavaScriptWindowObject( "canvas", mMapCanvas );
248  frame->addToJavaScriptWindowObject( "layer", mVectorLayer );
249 }
250 
251 
252 
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:32
QList< QgsMapLayer * > layers() const
return list of layers within map canvas.
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.
QgsMapLayer * mapLayer(const QString &theLayerId) const
Retrieve a pointer to a registered layer by layer ID.
void setHtml(const QString &text)
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.
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
virtual void setGeometry(const QRectF &rect)
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:109
double y() const
Get the y value of the point.
Definition: qgspoint.h:193
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...
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
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)...
void _writeXML(QDomDocument &doc, QDomElement &itemElem) const
The QgsWebView class is a collection of stubs to mimic the API of QWebView on systems where the real ...
Definition: qgswebview.h:57
virtual bool open(QFlags< QIODevice::OpenModeFlag > mode)
A class to represent a point.
Definition: qgspoint.h:117
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
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...
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 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 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)
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
double x() const
Get the x value of the point.
Definition: qgspoint.h:185
void render(QPaintDevice *target, const QPoint &targetOffset, const QRegion &sourceRegion, QFlags< QWidget::RenderFlag > renderFlags)
void drawFrame(QPainter *p) const
Draws the annotation frame to a destination painter.