QGIS API Documentation  2.17.0-Master (06698cd)
qgsmaptip.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmaptips.cpp - Query a layer and show a maptip on the canvas
3  ---------------------
4  begin : October 2007
5  copyright : (C) 2007 by Gary Sherman
6  email : sherman @ mrcc dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 // QGIS includes
16 #include "qgsmapcanvas.h"
17 #include "qgsmaptool.h"
18 #include "qgsvectorlayer.h"
19 #include "qgsexpression.h"
20 #include "qgslogger.h"
21 #include "qgswebview.h"
22 #include "qgswebframe.h"
23 
24 // Qt includes
25 #include <QPoint>
26 #include <QToolTip>
27 #include <QSettings>
28 #include <QLabel>
29 #include <QDesktopServices>
30 #if WITH_QTWEBKIT
31 #include <QWebElement>
32 #endif
33 #include <QHBoxLayout>
34 
35 
36 #include "qgsmaptip.h"
37 
39  : mWidget( nullptr ), mWebView( nullptr )
40 {
41  // init the visible flag
42  mMapTipVisible = false;
43 }
44 
46 {
47 
48 }
49 
51  QgsPoint & mapPosition,
52  QPoint & thePixelPosition,
53  QgsMapCanvas *pMapCanvas )
54 {
55  // Do the search using the active layer and the preferred label field for the
56  // layer. The label field must be defined in the layer configuration
57  // file/database. The code required to do this is similar to identify, except
58  // we only want the first qualifying feature and we will only display the
59  // field defined as the label field in the layer configuration file/database
60 
61  // Show the maptip on the canvas
62  QString tipText, lastTipText, tipHtml, bodyStyle, containerStyle,
63  backgroundColor, borderColor;
64 
65  delete mWidget;
66  mWidget = new QWidget( pMapCanvas );
67  mWebView = new QgsWebView( mWidget );
68 
69 
70 #if WITH_QTWEBKIT
71  mWebView->page()->setLinkDelegationPolicy( QWebPage::DelegateAllLinks );//Handle link clicks by yourself
72  mWebView->setContextMenuPolicy( Qt::NoContextMenu ); //No context menu is allowed if you don't need it
73  connect( mWebView, SIGNAL( linkClicked( QUrl ) ), this, SLOT( onLinkClicked( QUrl ) ) );
74 #endif
75 
76  mWebView->page()->settings()->setAttribute(
77  QWebSettings::DeveloperExtrasEnabled, true );
78  mWebView->page()->settings()->setAttribute(
79  QWebSettings::JavascriptEnabled, true );
80 
82  layout->addWidget( mWebView );
83 
84  mWidget->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
85  mWidget->setLayout( layout );
86 
87  //assure the map tip is never larger than half the map canvas
88  const int MAX_WIDTH = pMapCanvas->geometry().width() / 2;
89  const int MAX_HEIGHT = pMapCanvas->geometry().height() / 2;
90  mWidget->setMaximumSize( MAX_WIDTH, MAX_HEIGHT );
91 
92  // start with 0 size,
93  // the content will automatically make it grow up to MaximumSize
94  mWidget->resize( 0, 0 );
95 
96  backgroundColor = mWidget->palette().base().color().name();
97  borderColor = mWidget->palette().shadow().color().name();
98  mWidget->setStyleSheet( QString(
99  ".QWidget{"
100  "border: 1px solid %1;"
101  "background-color: %2;}" ).arg(
102  borderColor, backgroundColor ) );
103 
104  tipText = fetchFeature( pLayer, mapPosition, pMapCanvas );
105 
106  mMapTipVisible = !tipText.isEmpty();
107  if ( !mMapTipVisible )
108  {
109  clear();
110  return;
111  }
112 
113  if ( tipText == lastTipText )
114  {
115  return;
116  }
117 
118  bodyStyle = QString(
119  "background-color: %1;"
120  "margin: 0;" ).arg( backgroundColor );
121 
122  containerStyle = QString(
123  "display: inline-block;"
124  "margin: 0px" );
125 
126  tipHtml = QString(
127  "<html>"
128  "<body style='%1'>"
129  "<div id='QgsWebViewContainer' style='%2'>%3</div>"
130  "</body>"
131  "</html>" ).arg( bodyStyle, containerStyle, tipText );
132 
133  mWidget->move( thePixelPosition.x(),
134  thePixelPosition.y() );
135 
136  mWebView->setHtml( tipHtml );
137  lastTipText = tipText;
138 
139  mWidget->show();
140 
141 #if WITH_QTWEBKIT
142  int scrollbarWidth = mWebView->page()->mainFrame()->scrollBarGeometry(
143  Qt::Vertical ).width();
144  int scrollbarHeight = mWebView->page()->mainFrame()->scrollBarGeometry(
145  Qt::Horizontal ).height();
146 
147  if ( scrollbarWidth > 0 || scrollbarHeight > 0 )
148  {
149  // Get the content size
150  QWebElement container = mWebView->page()->mainFrame()->findFirstElement(
151  "#QgsWebViewContainer" );
152  int width = container.geometry().width() + 5 + scrollbarWidth;
153  int height = container.geometry().height() + 5 + scrollbarHeight;
154 
155  mWidget->resize( width, height );
156  }
157 #endif
158 }
159 
161 {
162  if ( !mMapTipVisible )
163  return;
164 
165  mWebView->setHtml( QString() );
166  mWidget->hide();
167 
168  // reset the visible flag
169  mMapTipVisible = false;
170 }
171 
172 QString QgsMapTip::fetchFeature( QgsMapLayer *layer, QgsPoint &mapPosition, QgsMapCanvas *mpMapCanvas )
173 {
174  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
175  if ( !vlayer )
176  return QString();
177 
178  double searchRadius = QgsMapTool::searchRadiusMU( mpMapCanvas );
179 
180  QgsRectangle r;
181  r.setXMinimum( mapPosition.x() - searchRadius );
182  r.setYMinimum( mapPosition.y() - searchRadius );
183  r.setXMaximum( mapPosition.x() + searchRadius );
184  r.setYMaximum( mapPosition.y() + searchRadius );
185 
186  r = mpMapCanvas->mapSettings().mapToLayerCoordinates( layer, r );
187 
188  QgsFeature feature;
189 
190  if ( !vlayer->getFeatures( QgsFeatureRequest().setFilterRect( r ).setFlags( QgsFeatureRequest::ExactIntersect ) ).nextFeature( feature ) )
191  return QString();
192 
193  int idx = vlayer->fieldNameIndex( vlayer->displayField() );
194  if ( idx < 0 )
195  {
196  QgsExpressionContext context;
200  if ( mpMapCanvas )
202 
203  context.setFeature( feature );
204  return QgsExpression::replaceExpressionText( vlayer->displayField(), &context );
205  }
206  else
207  {
208  return feature.attribute( idx ).toString();
209  }
210 }
211 
212 //This slot handles all clicks
213 void QgsMapTip::onLinkClicked( const QUrl &url )
214 {
216 }
QLayout * layout() const
void setStyleSheet(const QString &styleSheet)
A rectangle specified with double values.
Definition: qgsrectangle.h:35
Base class for all map layer types.
Definition: qgsmaplayer.h:49
static double searchRadiusMU(const QgsRenderContext &context)
Get search radius in map units for given context.
Definition: qgsmaptool.cpp:219
void setXMaximum(double x)
Set the maximum x value.
Definition: qgsrectangle.h:172
Use exact geometry intersection (slower) instead of bounding boxes.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
void setHtml(const QString &text)
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
void setAttribute(Qt::WidgetAttribute attribute, bool on)
const QgsMapSettings & mapSettings() const
Get access to properties used for map rendering.
int height() const
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
QgsPoint mapToLayerCoordinates(QgsMapLayer *theLayer, QgsPoint point) const
transform point coordinates from output CRS to layer&#39;s CRS
virtual ~QgsMapTip()
Destructor.
Definition: qgsmaptip.cpp:45
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:109
double x() const
Get the x value of the point.
Definition: qgspoint.h:185
int x() const
int y() const
void resize(int w, int h)
void addWidget(QWidget *widget, int stretch, QFlags< Qt::AlignmentFlag > alignment)
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
void setLayout(QLayout *layout)
void setYMinimum(double y)
Set the minimum y value.
Definition: qgsrectangle.h:177
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
bool isEmpty() const
void clear(QgsMapCanvas *mpMapCanvas=nullptr)
Clear the current maptip if it exists.
Definition: qgsmaptip.cpp:160
void showMapTip(QgsMapLayer *thepLayer, QgsPoint &theMapPosition, QPoint &thePixelPosition, QgsMapCanvas *mpMapCanvas)
Show a maptip at a given point on the map canvas.
Definition: qgsmaptip.cpp:50
This class wraps a request for features to a vector layer (or directly its vector data provider)...
void move(int x, int y)
const QString displayField() const
Returns the primary display field name used in the identify results dialog.
The QgsWebView class is a collection of stubs to mimic the API of QWebView on systems where the real ...
Definition: qgswebview.h:57
void hide()
void setSizePolicy(QSizePolicy)
A class to represent a point.
Definition: qgspoint.h:117
void setContextMenuPolicy(Qt::ContextMenuPolicy policy)
void setMaximumSize(const QSize &)
static QgsExpressionContextScope * mapSettingsScope(const QgsMapSettings &mapSettings)
Creates a new scope which contains variables and functions relating to a QgsMapSettings object...
int width() const
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:271
void setYMaximum(double y)
Set the maximum y value.
Definition: qgsrectangle.h:182
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
QWidget(QWidget *parent, QFlags< Qt::WindowType > f)
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...
double y() const
Get the y value of the point.
Definition: qgspoint.h:193
void show()
QgsMapTip()
Default constructor.
Definition: qgsmaptip.cpp:38
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.
bool nextFeature(QgsFeature &f)
bool openUrl(const QUrl &url)
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.
int fieldNameIndex(const QString &fieldName) const
Returns the index of a field name or -1 if the field does not exist.
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QString toString() const
QRect geometry() const
void setXMinimum(double x)
Set the minimum x value.
Definition: qgsrectangle.h:167