QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
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)
int height() const
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
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
int x() const
int y() const
double y() const
Get the y value of the point.
Definition: qgspoint.h:193
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)
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
QString displayField() const
Returns the primary display field name used in the identify results dialog.
void setContextMenuPolicy(Qt::ContextMenuPolicy policy)
void setMaximumSize(const QSize &)
const QgsMapSettings & mapSettings() const
Get access to properties used for map rendering.
static QgsExpressionContextScope * mapSettingsScope(const QgsMapSettings &mapSettings)
Creates a new scope which contains variables and functions relating to a QgsMapSettings object...
int width() const
QgsPoint mapToLayerCoordinates(QgsMapLayer *theLayer, QgsPoint point) const
transform point coordinates from output CRS to layer&#39;s CRS
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...
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.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:271
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QString toString() const
QRect geometry() const
int fieldNameIndex(const QString &fieldName) const
Returns the index of a field name or -1 if the field does not exist.
double x() const
Get the x value of the point.
Definition: qgspoint.h:185
void setXMinimum(double x)
Set the minimum x value.
Definition: qgsrectangle.h:167