QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
Loading...
Searching...
No Matches
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
18
19#include "qgsattributeform.h"
22#include "qgswebframe.h"
23
24#include <QScreen>
25#include <QString>
26
27#include "moc_qgshtmlwidgetwrapper.cpp"
28
29using namespace Qt::StringLiterals;
30
32 : QgsWidgetWrapper( layer, editor, parent )
33{
34 connect( this, &QgsWidgetWrapper::contextChanged, this, &QgsHtmlWidgetWrapper::setHtmlContext );
35}
36
38{
39 return true;
40}
41
42QWidget *QgsHtmlWidgetWrapper::createWidget( QWidget *parent )
43{
44 QgsAttributeForm *form = qobject_cast<QgsAttributeForm *>( parent );
45
46 if ( form )
47 {
48 mFormFeature = form->feature();
49 connect( form, &QgsAttributeForm::widgetValueChanged, this, [this]( const QString &attribute, const QVariant &newValue, bool attributeChanged ) {
50 if ( attributeChanged )
51 {
52 if ( mRequiresFormScope )
53 {
54 mFormFeature.setAttribute( attribute, newValue );
55 setHtmlContext();
56 }
57 }
58 } );
59 }
60
61 return new QgsWebView( parent );
62}
63
64void QgsHtmlWidgetWrapper::initWidget( QWidget *editor )
65{
66 mWidget = qobject_cast<QgsWebView *>( editor );
67
68 if ( !mWidget )
69 return;
70
71 mWidget->setHtml( mHtmlCode.replace( "\n", " " ) );
72
73 checkGeometryNeeds();
74}
75
77{
78 if ( !mWidget )
79 return;
80
81 initWidget( mWidget );
82}
83
84void QgsHtmlWidgetWrapper::checkGeometryNeeds()
85{
86 if ( !mWidget )
87 return;
88
89 // initialize a temporary QgsWebView to render HTML code and check if one evaluated expression
90 // needs geometry
91 QgsWebView webView;
92 NeedsGeometryEvaluator evaluator;
93
94 const QgsAttributeEditorContext attributecontext = context();
95 if ( QgsVectorLayer *vl = layer() )
96 {
97 const QgsExpressionContext expressionContext = vl->createExpressionContext();
98 evaluator.setExpressionContext( expressionContext );
99 }
100
101 auto frame = webView.page()->mainFrame();
102 connect( frame, &QWebFrame::javaScriptWindowObjectCleared, frame, [frame, &evaluator] { frame->addToJavaScriptWindowObject( u"expression"_s, &evaluator ); } );
103
104 webView.setHtml( mHtmlCode );
105
106 mNeedsGeometry = evaluator.needsGeometry();
107}
108
109void QgsHtmlWidgetWrapper::setHtmlCode( const QString &htmlCode )
110{
111 mHtmlCode = htmlCode;
112
113 bool ok = false;
114 const thread_local QRegularExpression
115 expRe( QStringLiteral( R"re(expression.evaluate\s*\‍(\s*"(.*)"\))re" ), QRegularExpression::PatternOption::MultilineOption | QRegularExpression::PatternOption::DotMatchesEverythingOption );
116 QRegularExpressionMatchIterator matchIt = expRe.globalMatch( mHtmlCode );
117 while ( !ok && matchIt.hasNext() )
118 {
119 const QRegularExpressionMatch match = matchIt.next();
120 const QgsExpression exp = match.captured( 1 );
122 }
123 mRequiresFormScope = ok;
124
125 checkGeometryNeeds();
126}
127
128void QgsHtmlWidgetWrapper::setHtmlContext()
129{
130 if ( !mWidget )
131 return;
132
133 const QgsAttributeEditorContext attributecontext = context();
134 QgsExpressionContext expressionContext = layer()->createExpressionContext();
135 expressionContext << QgsExpressionContextUtils::formScope( mFormFeature, attributecontext.attributeFormModeString() );
136 if ( attributecontext.parentFormFeature().isValid() )
137 {
138 expressionContext << QgsExpressionContextUtils::parentFormScope( attributecontext.parentFormFeature() );
139 }
140
141 expressionContext.setFeature( mFeature );
142
143 HtmlExpression *htmlExpression = new HtmlExpression();
144 htmlExpression->setExpressionContext( expressionContext );
145 auto frame = mWidget->page()->mainFrame();
146 connect( frame, &QWebFrame::javaScriptWindowObjectCleared, frame, [frame, htmlExpression] { frame->addToJavaScriptWindowObject( u"expression"_s, htmlExpression ); } );
147
148 mWidget->setHtml( mHtmlCode );
149}
150
152{
153 if ( !mWidget )
154 return;
155
156 mFeature = feature;
157 mFormFeature = feature;
158 setHtmlContext();
159}
160
162{
163 return mNeedsGeometry;
164}
165
166
168void HtmlExpression::setExpressionContext( const QgsExpressionContext &context )
169{
170 mExpressionContext = context;
171}
172
173QString HtmlExpression::evaluate( const QString &expression ) const
174{
175 QgsExpression exp { expression };
176 exp.prepare( &mExpressionContext );
177 return exp.evaluate( &mExpressionContext ).toString();
178}
179
180void NeedsGeometryEvaluator::evaluate( const QString &expression )
181{
182 QgsExpression exp { expression };
183 exp.prepare( &mExpressionContext );
184 mNeedsGeometry |= exp.needsGeometry();
185}
186
187void NeedsGeometryEvaluator::setExpressionContext( const QgsExpressionContext &context )
188{
189 mExpressionContext = context;
190}
191
192
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.
The attribute form widget for vector layer features.
void widgetValueChanged(const QString &attribute, const QVariant &value, bool attributeChanged)
Notifies about changes of attributes.
const QgsFeature & feature() const
Returns feature of attribute form.
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.
Handles 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:60
bool isValid() const
Returns the validity of this feature.
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.
static bool expressionRequiresFormScope(const QString &expression)
Check if the expression requires a form scope (i.e.
Represents a vector layer which manages a vector based dataset.
QgsExpressionContext createExpressionContext() const final
This method needs to be reimplemented in all classes which implement this interface and return an exp...
A collection of stubs to mimic the API of QWebView on systems where the real library is not available...
Definition qgswebview.h:39
void contextChanged()
Signal when QgsAttributeEditorContext mContext changed.
QgsWidgetWrapper(QgsVectorLayer *vl, QWidget *editor=nullptr, QWidget *parent=nullptr)
Create a new widget wrapper.
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.