QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
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.replace( "\n", "\\n" ) );
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, &QgsHtmlWidgetWrapper::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 
QgsExpressionContext
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Definition: qgsexpressioncontext.h:406
qgsexpressioncontextutils.h
QgsWidgetWrapper
Manages an editor widget Widget and wrapper share the same parent.
Definition: qgswidgetwrapper.h:52
qgswebframe.h
QgsExpressionContextUtils::formScope
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...
Definition: qgsexpressioncontextutils.cpp:270
QgsWidgetWrapper::context
const QgsAttributeEditorContext & context() const
Returns information about the context in which this widget is shown.
Definition: qgswidgetwrapper.cpp:87
QWebPage
The QWebPage class is a collection of stubs to mimic the API of a QWebPage on systems where QtWebkit ...
Definition: qgswebpage.h:103
QgsHtmlWidgetWrapper::QgsHtmlWidgetWrapper
QgsHtmlWidgetWrapper(QgsVectorLayer *layer, QWidget *editor, QWidget *parent)
Create a html widget wrapper.
Definition: qgshtmlwidgetwrapper.cpp:24
qgsapplication.h
QgsWidgetWrapper::contextChanged
void contextChanged()
Signal when QgsAttributeEditorContext mContext changed.
QgsWidgetWrapper::layer
QgsVectorLayer * layer() const
Returns the vector layer associated with the widget.
Definition: qgswidgetwrapper.cpp:92
QgsFeature::isValid
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:216
QgsExpressionContextUtils::parentFormScope
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...
Definition: qgsexpressioncontextutils.cpp:281
QgsAttributeEditorContext::parentFormFeature
QgsFeature parentFormFeature() const
Returns the feature of the currently edited parent form in its actual state.
Definition: qgsattributeeditorcontext.h:251
QgsExpression::prepare
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
Definition: qgsexpression.cpp:327
QgsExpression::evaluate
QVariant evaluate()
Evaluate the feature and return the result.
Definition: qgsexpression.cpp:350
QgsHtmlWidgetWrapper::setHtmlCode
void setHtmlCode(const QString &htmlCode)
Sets the HTML code to htmlCode.
Definition: qgshtmlwidgetwrapper.cpp:96
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:391
QgsHtmlWidgetWrapper::createWidget
QWidget * createWidget(QWidget *parent) override
This method should create a new widget with the provided parent.
Definition: qgshtmlwidgetwrapper.cpp:35
QgsHtmlWidgetWrapper::valid
bool valid() const override
Returns true if the widget has been properly initialized.
Definition: qgshtmlwidgetwrapper.cpp:30
QgsExpression::needsGeometry
bool needsGeometry() const
Returns true if the expression uses feature geometry for some computation.
Definition: qgsexpression.cpp:270
QgsHtmlWidgetWrapper::needsGeometry
bool needsGeometry() const
Returns true if the widget needs feature geometry.
Definition: qgshtmlwidgetwrapper.cpp:145
QgsFeature
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:55
QgsHtmlWidgetWrapper::setFeature
void setFeature(const QgsFeature &feature) override
Definition: qgshtmlwidgetwrapper.cpp:136
QgsVectorLayer::createExpressionContext
QgsExpressionContext createExpressionContext() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
Definition: qgsvectorlayer.cpp:5203
QgsExpression
Class for parsing and evaluation of expressions (formerly called "search strings")....
Definition: qgsexpression.h:102
QgsAttributeEditorContext
This class contains context information for attribute editor widgets. It will be passed to embedded w...
Definition: qgsattributeeditorcontext.h:40
qgshtmlwidgetwrapper.h
QgsHtmlWidgetWrapper::reinitWidget
void reinitWidget()
Clears the content and makes new initialization.
Definition: qgshtmlwidgetwrapper.cpp:63
QgsHtmlWidgetWrapper::initWidget
void initWidget(QWidget *editor) override
This method should initialize the editor widget with runtime data.
Definition: qgshtmlwidgetwrapper.cpp:40
QgsAttributeEditorContext::attributeFormModeString
QString attributeFormModeString() const
Returns given attributeFormMode as string.
Definition: qgsattributeeditorcontext.h:276
QgsWebView
The QgsWebView class is a collection of stubs to mimic the API of QWebView on systems where the real ...
Definition: qgswebview.h:65
qgsmessagelog.h
QgsExpressionContext::setFeature
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
Definition: qgsexpressioncontext.cpp:525