QGIS API Documentation 3.41.0-Master (3440c17df1d)
Loading...
Searching...
No Matches
qgsqmlwidgetwrapper.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsqmlwidgetwrapper.cpp
3
4 ---------------------
5 begin : 25.6.2018
6 copyright : (C) 2018 by Matthias Kuhn
7 email : matthias@opengis.ch
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 "qgsqmlwidgetwrapper.h"
18#include "moc_qgsqmlwidgetwrapper.cpp"
19#include "qgsattributeform.h"
20#include "qgsmessagelog.h"
23
24#include <QQmlContext>
25#include <QQmlEngine>
26#include <QUrl>
27
28QgsQmlWidgetWrapper::QgsQmlWidgetWrapper( QgsVectorLayer *layer, QWidget *editor, QWidget *parent )
29 : QgsWidgetWrapper( layer, editor, parent )
30{
31 connect( this, &QgsWidgetWrapper::contextChanged, this, &QgsQmlWidgetWrapper::setQmlContext );
32}
33
35{
36 return true;
37}
38
39QWidget *QgsQmlWidgetWrapper::createWidget( QWidget *parent )
40{
41 QgsAttributeForm *form = qobject_cast<QgsAttributeForm *>( parent );
42
43 if ( form )
44 {
45 mFormFeature = form->feature();
46 connect( form, &QgsAttributeForm::widgetValueChanged, this, [ = ]( const QString & attribute, const QVariant & newValue, bool attributeChanged )
47 {
48 if ( attributeChanged )
49 {
50 if ( mRequiresFormScope )
51 {
52 mFormFeature.setAttribute( attribute, newValue );
53 setQmlContext();
54 }
55 }
56 } );
57 }
58
59 return new QQuickWidget( parent );
60}
61
62void QgsQmlWidgetWrapper::initWidget( QWidget *editor )
63{
64 mWidget = qobject_cast<QQuickWidget *>( editor );
65
66 if ( !mWidget )
67 return;
68
69
70 if ( !mQmlFile.open() )
71 {
72 QgsMessageLog::logMessage( tr( "Failed to open temporary QML file" ) );
73 return;
74 }
75
76 mWidget->setSource( QUrl::fromLocalFile( mQmlFile.fileName() ) );
77
78 mQmlFile.close();
79}
80
81
83{
84 if ( !mWidget )
85 return;
86
87 mWidget->engine()->clearComponentCache();
88
89 initWidget( mWidget );
90}
91
92void QgsQmlWidgetWrapper::setQmlCode( const QString &qmlCode )
93{
94 if ( mQmlCode == qmlCode )
95 {
96 return;
97 }
98
99 mQmlCode = qmlCode;
100
101 bool ok = false;
102 const thread_local QRegularExpression expRe( QStringLiteral( R"re(expression.evaluate\s*\‍(\s*"(.*)"\))re" ), QRegularExpression::PatternOption::MultilineOption | QRegularExpression::PatternOption::DotMatchesEverythingOption );
103 QRegularExpressionMatchIterator matchIt = expRe.globalMatch( mQmlCode );
104 while ( !ok && matchIt.hasNext() )
105 {
106 const QRegularExpressionMatch match = matchIt.next();
107 const QgsExpression exp = match.captured( 1 );
109 }
110 mRequiresFormScope = ok;
111
112 if ( !mQmlFile.open() )
113 {
114 QgsMessageLog::logMessage( tr( "Failed to open temporary QML file" ) );
115 return;
116 }
117
118 mQmlFile.resize( 0 );
119 mQmlFile.write( mQmlCode.toUtf8() );
120
121 mQmlFile.close();
122}
123
124void QgsQmlWidgetWrapper::setQmlContext( )
125{
126 if ( !mWidget )
127 return;
128
129 const QgsAttributeEditorContext attributecontext = context();
130 QgsExpressionContext expressionContext = layer()->createExpressionContext();
131 expressionContext << QgsExpressionContextUtils::formScope( mFormFeature, attributecontext.attributeFormModeString() );
132 if ( attributecontext.parentFormFeature().isValid() )
133 {
134 expressionContext << QgsExpressionContextUtils::parentFormScope( attributecontext.parentFormFeature() );
135 }
136
137 expressionContext.setFeature( mFeature );
138
139 QmlExpression *qmlExpression = new QmlExpression();
140 qmlExpression->setExpressionContext( expressionContext );
141
142 mWidget->rootContext()->setContextProperty( "expression", qmlExpression );
143}
144
146{
147 if ( !mWidget )
148 return;
149
150 mFeature = feature;
151 mFormFeature = feature;
152
153 setQmlContext();
154}
155
157void QmlExpression::setExpressionContext( const QgsExpressionContext &context )
158{
159 mExpressionContext = context;
160}
161
162QVariant QmlExpression::evaluate( const QString &expression ) const
163{
164 QgsExpression exp = QgsExpression( expression );
165 exp.prepare( &mExpressionContext );
166 return exp.evaluate( &mExpressionContext );
167}
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.
void widgetValueChanged(const QString &attribute, const QVariant &value, bool attributeChanged)
Notifies about changes of attributes.
const QgsFeature & feature()
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.
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:58
Q_INVOKABLE bool setAttribute(int field, const QVariant &attr)
Sets an attribute's value by field index.
bool isValid() const
Returns the validity of this feature.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
QWidget * createWidget(QWidget *parent) override
This method should create a new widget with the provided parent.
void initWidget(QWidget *editor) override
This method should initialize the editor widget with runtime data.
bool valid() const override
Returns true if the widget has been properly initialized.
void setFeature(const QgsFeature &feature) override
void reinitWidget()
Clears the content and makes new initialization.
void setQmlCode(const QString &qmlCode)
writes the qmlCode into a temporary file
QgsQmlWidgetWrapper(QgsVectorLayer *layer, QWidget *editor, QWidget *parent)
Create a qml widget wrapper.
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 data sets.
QgsExpressionContext createExpressionContext() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
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.