QGIS API Documentation  3.23.0-Master (c716e02dd3)
qgshtmlwidgetwrapper.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgshtmlwidgetwrapper.h
3 
4  ---------------------
5  begin : 23.03.2019
6  copyright : (C) 2019 by Alessandro Pasotti
7  email : elpaso at itopen dot it
8  ***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 
17 #include "qgshtmlwidgetwrapper.h"
18 #include "qgsmessagelog.h"
20 #include "qgsapplication.h"
21 #include "qgswebframe.h"
22 #include <QScreen>
23 
24 QgsHtmlWidgetWrapper::QgsHtmlWidgetWrapper( QgsVectorLayer *layer, QWidget *editor, QWidget *parent )
25  : QgsWidgetWrapper( layer, editor, parent )
26 {
27  connect( this, &QgsWidgetWrapper::contextChanged, this, &QgsHtmlWidgetWrapper::setHtmlContext );
28 }
29 
31 {
32  return true;
33 }
34 
35 QWidget *QgsHtmlWidgetWrapper::createWidget( QWidget *parent )
36 {
37  return new QgsWebView( parent );
38 }
39 
40 void QgsHtmlWidgetWrapper::initWidget( QWidget *editor )
41 {
42  mWidget = qobject_cast<QgsWebView *>( editor );
43 
44  if ( !mWidget )
45  return;
46 
47  mWidget->setHtml( mHtmlCode );
48 #ifdef WITH_QTWEBKIT
49 
50  const int horizontalDpi = mWidget->logicalDpiX();
51 
52  mWidget->setZoomFactor( horizontalDpi / 96.0 );
53 
54  QWebPage *page = mWidget->page();
55  connect( page, &QWebPage::contentsChanged, this, &QgsHtmlWidgetWrapper::fixHeight, Qt::ConnectionType::UniqueConnection );
56  connect( page, &QWebPage::loadFinished, this, [ = ]( bool ) { fixHeight(); }, Qt::ConnectionType::UniqueConnection );
57 
58 #endif
59 
60  checkGeometryNeeds();
61 }
62 
64 {
65  if ( !mWidget )
66  return;
67 
68  initWidget( mWidget );
69 }
70 
71 void QgsHtmlWidgetWrapper::checkGeometryNeeds()
72 {
73  if ( !mWidget )
74  return;
75 
76  // initialize a temporary QgsWebView to render HTML code and check if one evaluated expression
77  // needs geometry
78  QgsWebView webView;
79  NeedsGeometryEvaluator evaluator;
80 
81  const QgsAttributeEditorContext attributecontext = context();
82  const QgsExpressionContext expressionContext = layer()->createExpressionContext();
83  evaluator.setExpressionContext( expressionContext );
84 
85  auto frame = webView.page()->mainFrame();
86  connect( frame, &QWebFrame::javaScriptWindowObjectCleared, frame, [ frame, &evaluator ]
87  {
88  frame->addToJavaScriptWindowObject( QStringLiteral( "expression" ), &evaluator );
89  } );
90 
91  webView.setHtml( mHtmlCode );
92 
93  mNeedsGeometry = evaluator.needsGeometry();
94 }
95 
96 void QgsHtmlWidgetWrapper::setHtmlCode( const QString &htmlCode )
97 {
98  mHtmlCode = htmlCode;
99  checkGeometryNeeds();
100 }
101 
102 void QgsHtmlWidgetWrapper::setHtmlContext( )
103 {
104  if ( !mWidget )
105  return;
106 
107  const QgsAttributeEditorContext attributecontext = context();
108  QgsExpressionContext expressionContext = layer()->createExpressionContext();
109  expressionContext << QgsExpressionContextUtils::formScope( mFeature, attributecontext.attributeFormModeString() );
110  if ( attributecontext.parentFormFeature().isValid() )
111  {
112  expressionContext << QgsExpressionContextUtils::parentFormScope( attributecontext.parentFormFeature() );
113  }
114  expressionContext.setFeature( mFeature );
115 
116  HtmlExpression *htmlExpression = new HtmlExpression();
117  htmlExpression->setExpressionContext( expressionContext );
118  auto frame = mWidget->page()->mainFrame();
119  connect( frame, &QWebFrame::javaScriptWindowObjectCleared, frame, [ = ]
120  {
121  frame->addToJavaScriptWindowObject( QStringLiteral( "expression" ), htmlExpression );
122  } );
123 
124  mWidget->setHtml( mHtmlCode );
125 }
126 
127 #ifdef WITH_QTWEBKIT
128 void QgsHtmlWidgetWrapper::fixHeight()
129 {
130  QWebPage *page = mWidget->page();
131  const int docHeight { page->mainFrame()->contentsSize().height() };
132  mWidget->setFixedHeight( docHeight );
133 }
134 #endif
135 
137 {
138  if ( !mWidget )
139  return;
140 
141  mFeature = feature;
142  setHtmlContext();
143 }
144 
146 {
147  return mNeedsGeometry;
148 }
149 
150 
152 void HtmlExpression::setExpressionContext( const QgsExpressionContext &context )
153 {
154  mExpressionContext = context;
155 }
156 
157 QString HtmlExpression::evaluate( const QString &expression ) const
158 {
159  QgsExpression exp = QgsExpression( expression );
160  exp.prepare( &mExpressionContext );
161  return exp.evaluate( &mExpressionContext ).toString();
162 }
163 
164 void NeedsGeometryEvaluator::evaluate( const QString &expression )
165 {
166  QgsExpression exp = QgsExpression( expression );
167  exp.prepare( &mExpressionContext );
168  mNeedsGeometry |= exp.needsGeometry();
169 }
170 
171 void NeedsGeometryEvaluator::setExpressionContext( const QgsExpressionContext &context )
172 {
173  mExpressionContext = context;
174 }
175 
176 
The QWebPage class is a collection of stubs to mimic the API of a QWebPage on systems where QtWebkit ...
Definition: qgswebpage.h:104
This class contains context information for attribute editor widgets.
QString attributeFormModeString() const
Returns given attributeFormMode as string.
QgsFeature parentFormFeature() const
Returns the feature of the currently edited parent form in its actual state.
static QgsExpressionContextScope * parentFormScope(const QgsFeature &formFeature=QgsFeature(), const QString &formMode=QString())
Creates a new scope which contains functions and variables from the current parent attribute form/tab...
static QgsExpressionContextScope * formScope(const QgsFeature &formFeature=QgsFeature(), const QString &formMode=QString())
Creates a new scope which contains functions and variables from the current attribute form/table form...
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
Class for parsing and evaluation of expressions (formerly called "search strings").
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
QVariant evaluate()
Evaluate the feature and return the result.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:209
void reinitWidget()
Clears the content and makes new initialization.
void initWidget(QWidget *editor) override
This method should initialize the editor widget with runtime data.
QWidget * createWidget(QWidget *parent) override
This method should create a new widget with the provided parent.
QgsHtmlWidgetWrapper(QgsVectorLayer *layer, QWidget *editor, QWidget *parent)
Create a html widget wrapper.
void setHtmlCode(const QString &htmlCode)
Sets the HTML code to htmlCode.
bool valid() const override
Returns true if the widget has been properly initialized.
void setFeature(const QgsFeature &feature) override
bool needsGeometry() const
Returns true if the widget needs feature geometry.
Represents a vector layer which manages a vector based data sets.
QgsExpressionContext createExpressionContext() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
The QgsWebView class is a collection of stubs to mimic the API of QWebView on systems where the real ...
Definition: qgswebview.h:66
Manages an editor widget Widget and wrapper share the same parent.
void contextChanged()
Signal when QgsAttributeEditorContext mContext changed.
const QgsAttributeEditorContext & context() const
Returns information about the context in which this widget is shown.
QgsVectorLayer * layer() const
Returns the vector layer associated with the widget.