Docs - add missing images and code, clean up sections
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmljavascriptexpression_p.h
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #ifndef QQMLJAVASCRIPTEXPRESSION_P_H
43 #define QQMLJAVASCRIPTEXPRESSION_P_H
44
45 //
46 //  W A R N I N G
47 //  -------------
48 //
49 // This file is not part of the Qt API.  It exists purely as an
50 // implementation detail.  This header file may change from version to
51 // version without notice, or even be removed.
52 //
53 // We mean it.
54 //
55
56 #include <private/qv8_p.h>
57 #include <QtCore/qglobal.h>
58 #include <QtQml/qqmlerror.h>
59 #include <private/qqmlengine_p.h>
60 #include <private/qpointervaluepair_p.h>
61
62 QT_BEGIN_NAMESPACE
63
64 class QQmlDelayedError
65 {
66 public:
67     inline QQmlDelayedError() : nextError(0), prevError(0) {}
68     inline ~QQmlDelayedError() { qPersistentDispose(m_message); removeError(); }
69
70     bool addError(QQmlEnginePrivate *);
71
72     inline void removeError() {
73         if (!prevError) return;
74         if (nextError) nextError->prevError = prevError;
75         *prevError = nextError;
76         nextError = 0;
77         prevError = 0;
78     }
79
80     inline bool isValid() const { return !m_message.IsEmpty() || m_error.isValid(); }
81     inline const QQmlError &error(QQmlEngine *engine) const { convertMessageToError(engine); return m_error; }
82     inline void clearError() { qPersistentDispose(m_message); m_error = QQmlError(); }
83
84     void setMessage(v8::Handle<v8::Message> message);
85     void setErrorLocation(const QUrl &url, quint16 line, quint16 column);
86     void setErrorDescription(const QString &description);
87
88 private:
89     void convertMessageToError(QQmlEngine *engine) const;
90
91     mutable QQmlError m_error;
92     mutable v8::Persistent<v8::Message> m_message;
93
94     QQmlDelayedError  *nextError;
95     QQmlDelayedError **prevError;
96 };
97
98 class QQmlJavaScriptExpression
99 {
100 public:
101     // Although this looks crazy, we implement our own "vtable" here, rather than relying on
102     // C++ virtuals, to save memory.  By doing it ourselves, we can overload the storage
103     // location that is use for the vtable to also store the rarely used delayed error.
104     // If we use C++ virtuals, we can't do this and it consts us an extra sizeof(void *) in
105     // memory for every expression.
106     struct VTable {
107         QString (*expressionIdentifier)(QQmlJavaScriptExpression *);
108         void (*expressionChanged)(QQmlJavaScriptExpression *);
109     };
110
111     QQmlJavaScriptExpression(VTable *vtable);
112
113     v8::Local<v8::Value> evaluate(QQmlContextData *, v8::Handle<v8::Function>,
114                                   bool *isUndefined);
115     v8::Local<v8::Value> evaluate(QQmlContextData *, v8::Handle<v8::Function>,
116                                   int argc, v8::Handle<v8::Value> args[],
117                                   bool *isUndefined);
118
119     inline bool requiresThisObject() const;
120     inline void setRequiresThisObject(bool v);
121     inline bool useSharedContext() const;
122     inline void setUseSharedContext(bool v);
123     inline bool notifyOnValueChanged() const;
124
125     void setNotifyOnValueChanged(bool v);
126     void resetNotifyOnValueChanged();
127
128     inline QObject *scopeObject() const;
129     inline void setScopeObject(QObject *v);
130
131     class DeleteWatcher {
132     public:
133         inline DeleteWatcher(QQmlJavaScriptExpression *);
134         inline ~DeleteWatcher();
135         inline bool wasDeleted() const;
136     private:
137         friend class QQmlJavaScriptExpression;
138         QObject *_c;
139         QQmlJavaScriptExpression **_w;
140         QQmlJavaScriptExpression *_s;
141     };
142
143     inline bool hasError() const;
144     inline bool hasDelayedError() const;
145     QQmlError error(QQmlEngine *) const;
146     void clearError();
147     void clearGuards();
148     QQmlDelayedError *delayedError();
149
150     static void exceptionToError(v8::Handle<v8::Message>, QQmlError &);
151     static v8::Persistent<v8::Function> evalFunction(QQmlContextData *ctxt, QObject *scope,
152                                                      const QString &code, const QString &filename,
153                                                      quint16 line,
154                                                      v8::Persistent<v8::Object> *qmlscope = 0);
155     static v8::Persistent<v8::Function> evalFunction(QQmlContextData *ctxt, QObject *scope,
156                                                      const char *code, int codeLength,
157                                                      const QString &filename, quint16 line,
158                                                      v8::Persistent<v8::Object> *qmlscope = 0);
159 protected:
160     ~QQmlJavaScriptExpression();
161
162 private:
163     typedef QQmlJavaScriptExpressionGuard Guard;
164     friend void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *, void **);
165
166     struct GuardCapture : public QQmlEnginePrivate::PropertyCapture {
167         GuardCapture(QQmlEngine *engine, QQmlJavaScriptExpression *e)
168         : engine(engine), expression(e), errorString(0) { }
169
170         ~GuardCapture()  {
171             Q_ASSERT(guards.isEmpty());
172             Q_ASSERT(errorString == 0);
173         }
174
175         virtual void captureProperty(QQmlNotifier *);
176         virtual void captureProperty(QObject *, int, int);
177
178         QQmlEngine *engine;
179         QQmlJavaScriptExpression *expression;
180         QFieldList<Guard, &Guard::next> guards;
181         QStringList *errorString;
182     };
183
184     QPointerValuePair<VTable, QQmlDelayedError> m_vtable;
185
186     // We store some flag bits in the following flag pointers.
187     //    m_scopeObject:flag1 - requiresThisObject
188     //    activeGuards:flag1  - notifyOnValueChanged
189     //    activeGuards:flag2  - useSharedContext
190     QBiPointer<QObject, DeleteWatcher> m_scopeObject;
191     QForwardFieldList<Guard, &Guard::next> activeGuards;
192 };
193
194 QQmlJavaScriptExpression::DeleteWatcher::DeleteWatcher(QQmlJavaScriptExpression *e)
195 : _c(0), _w(0), _s(e)
196 {
197     if (e->m_scopeObject.isT1()) {
198         _w = &_s;
199         _c = e->m_scopeObject.asT1();
200         e->m_scopeObject = this;
201     } else {
202         // Another watcher is already registered
203         _w = &e->m_scopeObject.asT2()->_s;
204     }
205 }
206
207 QQmlJavaScriptExpression::DeleteWatcher::~DeleteWatcher()
208 {
209     Q_ASSERT(*_w == 0 || (*_w == _s && _s->m_scopeObject.isT2()));
210     if (*_w && _s->m_scopeObject.asT2() == this)
211         _s->m_scopeObject = _c;
212 }
213
214 bool QQmlJavaScriptExpression::DeleteWatcher::wasDeleted() const
215 {
216     return *_w == 0;
217 }
218
219 bool QQmlJavaScriptExpression::requiresThisObject() const
220 {
221     return m_scopeObject.flag();
222 }
223
224 void QQmlJavaScriptExpression::setRequiresThisObject(bool v)
225 {
226     m_scopeObject.setFlagValue(v);
227 }
228
229 bool QQmlJavaScriptExpression::useSharedContext() const
230 {
231     return activeGuards.flag2();
232 }
233
234 void QQmlJavaScriptExpression::setUseSharedContext(bool v)
235 {
236     activeGuards.setFlag2Value(v);
237 }
238
239 bool QQmlJavaScriptExpression::notifyOnValueChanged() const
240 {
241     return activeGuards.flag();
242 }
243
244 QObject *QQmlJavaScriptExpression::scopeObject() const
245 {
246     if (m_scopeObject.isT1()) return m_scopeObject.asT1();
247     else return m_scopeObject.asT2()->_c;
248 }
249
250 void QQmlJavaScriptExpression::setScopeObject(QObject *v)
251 {
252     if (m_scopeObject.isT1()) m_scopeObject = v;
253     else m_scopeObject.asT2()->_c = v;
254 }
255
256 bool QQmlJavaScriptExpression::hasError() const
257 {
258     return m_vtable.hasValue() && m_vtable.constValue()->isValid();
259 }
260
261 bool QQmlJavaScriptExpression::hasDelayedError() const
262 {
263     return m_vtable.hasValue();
264 }
265
266 QQmlJavaScriptExpressionGuard::QQmlJavaScriptExpressionGuard(QQmlJavaScriptExpression *e)
267 : expression(e), next(0)
268 {
269     setCallback(QQmlNotifierEndpoint::QQmlJavaScriptExpressionGuard);
270 }
271
272 QQmlJavaScriptExpressionGuard *
273 QQmlJavaScriptExpressionGuard::New(QQmlJavaScriptExpression *e,
274                                            QQmlEngine *engine)
275 {
276     Q_ASSERT(e);
277     return QQmlEnginePrivate::get(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