1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtQml module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #ifndef QQMLJAVASCRIPTEXPRESSION_P_H |
41 | #define QQMLJAVASCRIPTEXPRESSION_P_H |
42 | |
43 | // |
44 | // W A R N I N G |
45 | // ------------- |
46 | // |
47 | // This file is not part of the Qt API. It exists purely as an |
48 | // implementation detail. This header file may change from version to |
49 | // version without notice, or even be removed. |
50 | // |
51 | // We mean it. |
52 | // |
53 | |
54 | #include <QtCore/qglobal.h> |
55 | #include <QtQml/qqmlerror.h> |
56 | #include <private/qqmlengine_p.h> |
57 | |
58 | QT_BEGIN_NAMESPACE |
59 | |
60 | struct QQmlSourceLocation; |
61 | |
62 | class QQmlDelayedError |
63 | { |
64 | public: |
65 | inline QQmlDelayedError() : nextError(nullptr), prevError(nullptr) {} |
66 | inline ~QQmlDelayedError() { (void)removeError(); } |
67 | |
68 | bool addError(QQmlEnginePrivate *); |
69 | |
70 | Q_REQUIRED_RESULT inline QQmlError removeError() { |
71 | if (prevError) { |
72 | if (nextError) nextError->prevError = prevError; |
73 | *prevError = nextError; |
74 | nextError = nullptr; |
75 | prevError = nullptr; |
76 | } |
77 | return m_error; |
78 | } |
79 | |
80 | inline bool isValid() const { return m_error.isValid(); } |
81 | inline const QQmlError &error() const { return m_error; } |
82 | inline void clearError() { m_error = QQmlError(); } |
83 | |
84 | void setErrorLocation(const QQmlSourceLocation &sourceLocation); |
85 | void setErrorDescription(const QString &description); |
86 | void setErrorObject(QObject *object); |
87 | |
88 | // Call only from catch(...) -- will re-throw if no JS exception |
89 | void catchJavaScriptException(QV4::ExecutionEngine *engine); |
90 | |
91 | private: |
92 | |
93 | mutable QQmlError m_error; |
94 | |
95 | QQmlDelayedError *nextError; |
96 | QQmlDelayedError **prevError; |
97 | }; |
98 | |
99 | class Q_QML_PRIVATE_EXPORT QQmlJavaScriptExpression |
100 | { |
101 | public: |
102 | QQmlJavaScriptExpression(); |
103 | virtual ~QQmlJavaScriptExpression(); |
104 | |
105 | virtual QString expressionIdentifier() const = 0; |
106 | virtual void expressionChanged() = 0; |
107 | |
108 | QV4::ReturnedValue evaluate(bool *isUndefined); |
109 | QV4::ReturnedValue evaluate(QV4::CallData *callData, bool *isUndefined); |
110 | |
111 | inline bool notifyOnValueChanged() const; |
112 | |
113 | void setNotifyOnValueChanged(bool v); |
114 | void resetNotifyOnValueChanged(); |
115 | |
116 | inline QObject *scopeObject() const; |
117 | inline void setScopeObject(QObject *v); |
118 | |
119 | virtual QQmlSourceLocation sourceLocation() const; |
120 | |
121 | bool isValid() const { return context() != nullptr; } |
122 | |
123 | QQmlContextData *context() const { return m_context; } |
124 | void setContext(QQmlContextData *context); |
125 | |
126 | QV4::Function *function() const; |
127 | |
128 | virtual void refresh(); |
129 | |
130 | class DeleteWatcher { |
131 | public: |
132 | inline DeleteWatcher(QQmlJavaScriptExpression *); |
133 | inline ~DeleteWatcher(); |
134 | inline bool wasDeleted() const; |
135 | private: |
136 | friend class QQmlJavaScriptExpression; |
137 | QObject *_c; |
138 | QQmlJavaScriptExpression **_w; |
139 | QQmlJavaScriptExpression *_s; |
140 | }; |
141 | |
142 | inline bool hasError() const; |
143 | inline bool hasDelayedError() const; |
144 | QQmlError error(QQmlEngine *) const; |
145 | void clearError(); |
146 | void clearActiveGuards(); |
147 | QQmlDelayedError *delayedError(); |
148 | |
149 | static QV4::ReturnedValue evalFunction(QQmlContextData *ctxt, QObject *scope, |
150 | const QString &code, const QString &filename, |
151 | quint16 line); |
152 | protected: |
153 | void createQmlBinding(QQmlContextData *ctxt, QObject *scope, const QString &code, const QString &filename, quint16 line); |
154 | |
155 | void setupFunction(QV4::ExecutionContext *qmlContext, QV4::Function *f); |
156 | void setCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit); |
157 | |
158 | // We store some flag bits in the following flag pointers. |
159 | // activeGuards:flag1 - notifyOnValueChanged |
160 | // activeGuards:flag2 - useSharedContext |
161 | QBiPointer<QObject, DeleteWatcher> m_scopeObject; |
162 | QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> activeGuards; |
163 | |
164 | void setTranslationsCaptured(bool captured) { m_error.setFlagValue(captured); } |
165 | bool translationsCaptured() const { return m_error.flag(); } |
166 | |
167 | private: |
168 | friend class QQmlContextData; |
169 | friend class QQmlPropertyCapture; |
170 | friend void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *, void **); |
171 | friend class QQmlTranslationBinding; |
172 | |
173 | // m_error:flag1 translationsCapturedDuringEvaluation |
174 | QFlagPointer<QQmlDelayedError> m_error; |
175 | |
176 | QQmlContextData *m_context; |
177 | QQmlJavaScriptExpression **m_prevExpression; |
178 | QQmlJavaScriptExpression *m_nextExpression; |
179 | |
180 | QV4::PersistentValue m_qmlScope; |
181 | QQmlRefPointer<QV4::ExecutableCompilationUnit> m_compilationUnit; |
182 | QV4::Function *m_v4Function; |
183 | }; |
184 | |
185 | class Q_QML_PRIVATE_EXPORT QQmlPropertyCapture |
186 | { |
187 | public: |
188 | QQmlPropertyCapture(QQmlEngine *engine, QQmlJavaScriptExpression *e, QQmlJavaScriptExpression::DeleteWatcher *w) |
189 | : engine(engine), expression(e), watcher(w), errorString(nullptr) { } |
190 | |
191 | ~QQmlPropertyCapture() { |
192 | Q_ASSERT(guards.isEmpty()); |
193 | Q_ASSERT(errorString == nullptr); |
194 | } |
195 | |
196 | void captureProperty(QQmlNotifier *); |
197 | void captureProperty(QObject *, int, int, bool doNotify = true); |
198 | void captureTranslation() { translationCaptured = true; } |
199 | |
200 | QQmlEngine *engine; |
201 | QQmlJavaScriptExpression *expression; |
202 | QQmlJavaScriptExpression::DeleteWatcher *watcher; |
203 | QFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> guards; |
204 | QStringList *errorString; |
205 | bool translationCaptured = false; |
206 | }; |
207 | |
208 | QQmlJavaScriptExpression::DeleteWatcher::DeleteWatcher(QQmlJavaScriptExpression *e) |
209 | : _c(nullptr), _w(nullptr), _s(e) |
210 | { |
211 | if (e->m_scopeObject.isT1()) { |
212 | _w = &_s; |
213 | _c = e->m_scopeObject.asT1(); |
214 | e->m_scopeObject = this; |
215 | } else { |
216 | // Another watcher is already registered |
217 | _w = &e->m_scopeObject.asT2()->_s; |
218 | } |
219 | } |
220 | |
221 | QQmlJavaScriptExpression::DeleteWatcher::~DeleteWatcher() |
222 | { |
223 | Q_ASSERT(*_w == nullptr || (*_w == _s && _s->m_scopeObject.isT2())); |
224 | if (*_w && _s->m_scopeObject.asT2() == this) |
225 | _s->m_scopeObject = _c; |
226 | } |
227 | |
228 | bool QQmlJavaScriptExpression::DeleteWatcher::wasDeleted() const |
229 | { |
230 | return *_w == nullptr; |
231 | } |
232 | |
233 | bool QQmlJavaScriptExpression::notifyOnValueChanged() const |
234 | { |
235 | return activeGuards.flag(); |
236 | } |
237 | |
238 | QObject *QQmlJavaScriptExpression::scopeObject() const |
239 | { |
240 | if (m_scopeObject.isT1()) return m_scopeObject.asT1(); |
241 | else return m_scopeObject.asT2()->_c; |
242 | } |
243 | |
244 | void QQmlJavaScriptExpression::setScopeObject(QObject *v) |
245 | { |
246 | if (m_scopeObject.isT1()) m_scopeObject = v; |
247 | else m_scopeObject.asT2()->_c = v; |
248 | } |
249 | |
250 | bool QQmlJavaScriptExpression::hasError() const |
251 | { |
252 | return !m_error.isNull() && m_error->isValid(); |
253 | } |
254 | |
255 | bool QQmlJavaScriptExpression::hasDelayedError() const |
256 | { |
257 | return !m_error.isNull(); |
258 | } |
259 | |
260 | inline void QQmlJavaScriptExpression::clearError() |
261 | { |
262 | delete m_error.data(); |
263 | m_error = nullptr; |
264 | } |
265 | |
266 | QQmlJavaScriptExpressionGuard::QQmlJavaScriptExpressionGuard(QQmlJavaScriptExpression *e) |
267 | : QQmlNotifierEndpoint(QQmlNotifierEndpoint::QQmlJavaScriptExpressionGuard), |
268 | expression(e), next(nullptr) |
269 | { |
270 | } |
271 | |
272 | QQmlJavaScriptExpressionGuard * |
273 | QQmlJavaScriptExpressionGuard::New(QQmlJavaScriptExpression *e, |
274 | QQmlEngine *engine) |
275 | { |
276 | Q_ASSERT(e); |
277 | return QQmlEnginePrivate::get(e: engine)->jsExpressionGuardPool.New(e); |
278 | } |
279 | |
280 | void QQmlJavaScriptExpressionGuard::Delete() |
281 | { |
282 | QRecyclePool<QQmlJavaScriptExpressionGuard>::Delete(this); |
283 | } |
284 | |
285 | |
286 | QT_END_NAMESPACE |
287 | |
288 | #endif // QQMLJAVASCRIPTEXPRESSION_P_H |
289 | |