Merge branch 'kinetic-declarativeui' of scm.dev.nokia.troll.no:qt/kinetic into kineti...
[qt:qt-palm-pre.git] / src / script / bridge / qscriptdeclarativeclass.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL-ONLY$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser
12 ** General Public License version 2.1 as published by the Free Software
13 ** Foundation and appearing in the file LICENSE.LGPL included in the
14 ** packaging of this file.  Please review the following information to
15 ** ensure the GNU Lesser General Public License version 2.1 requirements
16 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** If you have questions regarding the use of this file, please contact
19 ** Nokia at qt-info@nokia.com.
20 ** $QT_END_LICENSE$
21 **
22 ****************************************************************************/
23
24 #include "qscriptdeclarativeclass_p.h"
25 #include "qscriptdeclarativeobject_p.h"
26 #include "qscriptobject_p.h"
27 #include <QtScript/qscriptstring.h>
28 #include <QtScript/qscriptengine.h>
29 #include <QtScript/qscriptengineagent.h>
30 #include <private/qscriptengine_p.h>
31 #include <private/qscriptvalue_p.h>
32 #include <private/qscriptqobject_p.h>
33 #include <private/qscriptactivationobject_p.h>
34 #include <QtCore/qstringlist.h>
35
36 QT_BEGIN_NAMESPACE
37
38 /*!
39 \class QScriptDeclarativeClass::Value
40 \internal
41 \brief The QScriptDeclarativeClass::Value class acts as a container for JavaScript data types.
42
43 QScriptDeclarativeClass::Value class is similar to QScriptValue, but it is slightly faster.  
44 Unlike QScriptValue, however, Value instances cannot be stored as they may not survive garbage 
45 collection.  If you need to store a Value, convert it to a QScriptValue and store that.
46 */
47
48 QScriptDeclarativeClass::Value::Value()
49 {
50     new (this) JSC::JSValue(JSC::jsUndefined());
51 }
52
53 QScriptDeclarativeClass::Value::Value(const Value &other)
54 {
55     new (this) JSC::JSValue((JSC::JSValue &)other);
56 }
57
58 static QScriptDeclarativeClass::Value jscToValue(const JSC::JSValue &val)
59 {
60     return QScriptDeclarativeClass::Value((QScriptDeclarativeClass::Value &)val);
61 }
62
63 QScriptDeclarativeClass::Value::Value(QScriptContext *ctxt, int value)
64 {
65     new (this) JSC::JSValue(QScriptEnginePrivate::frameForContext(ctxt), value);
66 }
67
68 QScriptDeclarativeClass::Value::Value(QScriptContext *ctxt, uint value)
69 {
70     new (this) JSC::JSValue(QScriptEnginePrivate::frameForContext(ctxt), value);
71 }
72
73 QScriptDeclarativeClass::Value::Value(QScriptContext *ctxt, bool value)
74 {
75     new (this) JSC::JSValue(QScriptEnginePrivate::frameForContext(ctxt), value);
76 }
77
78 QScriptDeclarativeClass::Value::Value(QScriptContext *ctxt, double value)
79 {
80     new (this) JSC::JSValue(QScriptEnginePrivate::frameForContext(ctxt), value);
81 }
82
83 QScriptDeclarativeClass::Value::Value(QScriptContext *ctxt, float value)
84 {
85     new (this) JSC::JSValue(QScriptEnginePrivate::frameForContext(ctxt), value);
86 }
87
88 QScriptDeclarativeClass::Value::Value(QScriptContext *ctxt, const QString &value)
89 {
90     new (this) JSC::JSValue(JSC::jsString(QScriptEnginePrivate::frameForContext(ctxt), value));
91 }
92
93 QScriptDeclarativeClass::Value::Value(QScriptEngine *eng, int value)
94 {
95     new (this) JSC::JSValue(QScriptEnginePrivate::get(eng)->currentFrame, value);
96 }
97
98 QScriptDeclarativeClass::Value::Value(QScriptEngine *eng, uint value)
99 {
100     new (this) JSC::JSValue(QScriptEnginePrivate::get(eng)->currentFrame, value);
101 }
102
103 QScriptDeclarativeClass::Value::Value(QScriptEngine *eng, bool value)
104 {
105     new (this) JSC::JSValue(QScriptEnginePrivate::get(eng)->currentFrame, value);
106 }
107
108 QScriptDeclarativeClass::Value::Value(QScriptEngine *eng, double value)
109 {
110     new (this) JSC::JSValue(QScriptEnginePrivate::get(eng)->currentFrame, value);
111 }
112
113 QScriptDeclarativeClass::Value::Value(QScriptEngine *eng, float value)
114 {
115     new (this) JSC::JSValue(QScriptEnginePrivate::get(eng)->currentFrame, value);
116 }
117
118 QScriptDeclarativeClass::Value::Value(QScriptEngine *eng, const QString &value)
119 {
120     new (this) JSC::JSValue(JSC::jsString(QScriptEnginePrivate::get(eng)->currentFrame, value));
121 }
122
123 QScriptDeclarativeClass::Value::Value(const QScriptValue &value)
124 {
125     new (this) JSC::JSValue(QScriptValuePrivate::get(&value)->engine->scriptValueToJSCValue(value));
126 }
127
128
129 QScriptDeclarativeClass::Value::~Value()
130 {
131     ((JSC::JSValue *)(this))->~JSValue();
132 }
133
134 QScriptValue QScriptDeclarativeClass::Value::toScriptValue(QScriptEngine *engine) const
135 {
136     return QScriptEnginePrivate::get(engine)->scriptValueFromJSCValue((JSC::JSValue &)*this);
137 }
138
139 QScriptDeclarativeClass::PersistentIdentifier::PersistentIdentifier()
140 : identifier(0)
141 {
142     new (&d) JSC::Identifier();
143 }
144
145 QScriptDeclarativeClass::PersistentIdentifier::~PersistentIdentifier()
146 {
147     ((JSC::Identifier &)d).JSC::Identifier::~Identifier();
148 }
149
150 QScriptDeclarativeClass::PersistentIdentifier::PersistentIdentifier(const PersistentIdentifier &other)
151 {
152     identifier = other.identifier;
153     new (&d) JSC::Identifier((JSC::Identifier &)(other.d));
154 }
155
156 QScriptDeclarativeClass::PersistentIdentifier &
157 QScriptDeclarativeClass::PersistentIdentifier::operator=(const PersistentIdentifier &other)
158 {
159     identifier = other.identifier;
160     ((JSC::Identifier &)d) = (JSC::Identifier &)(other.d);
161     return *this;
162 }
163
164 QScriptDeclarativeClass::QScriptDeclarativeClass(QScriptEngine *engine)
165 : d_ptr(new QScriptDeclarativeClassPrivate)
166 {
167     Q_ASSERT(sizeof(void*) == sizeof(JSC::Identifier));
168     d_ptr->q_ptr = this;
169     d_ptr->engine = engine;
170 }
171
172 QScriptValue QScriptDeclarativeClass::newObject(QScriptEngine *engine, 
173                                                 QScriptDeclarativeClass *scriptClass, 
174                                                 Object *object)
175 {
176     Q_ASSERT(engine);
177     Q_ASSERT(scriptClass);
178
179     QScriptEnginePrivate *p = static_cast<QScriptEnginePrivate *>(QObjectPrivate::get(engine)); 
180
181     JSC::ExecState* exec = p->currentFrame;
182     QScriptObject *result = new (exec) QScriptObject(p->scriptObjectStructure);
183     result->setDelegate(new QScript::DeclarativeObjectDelegate(scriptClass, object));
184     return p->scriptValueFromJSCValue(result);
185 }
186
187 QScriptDeclarativeClass::Value 
188 QScriptDeclarativeClass::newObjectValue(QScriptEngine *engine, 
189                                         QScriptDeclarativeClass *scriptClass, 
190                                         Object *object)
191 {
192     Q_ASSERT(engine);
193     Q_ASSERT(scriptClass);
194
195     QScriptEnginePrivate *p = static_cast<QScriptEnginePrivate *>(QObjectPrivate::get(engine)); 
196
197     JSC::ExecState* exec = p->currentFrame;
198     QScriptObject *result = new (exec) QScriptObject(p->scriptObjectStructure);
199     result->setDelegate(new QScript::DeclarativeObjectDelegate(scriptClass, object));
200     return jscToValue(JSC::JSValue(result));
201 }
202
203 QScriptDeclarativeClass *QScriptDeclarativeClass::scriptClass(const QScriptValue &v)
204 {
205     QScriptValuePrivate *d = QScriptValuePrivate::get(v);
206     if (!d || !d->isJSC() || !d->jscValue.inherits(&QScriptObject::info))
207         return 0;
208     QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(d->jscValue));
209     QScriptObjectDelegate *delegate = scriptObject->delegate();
210     if (!delegate || (delegate->type() != QScriptObjectDelegate::DeclarativeClassObject))
211         return 0;
212     return static_cast<QScript::DeclarativeObjectDelegate*>(delegate)->scriptClass();
213 }
214
215 QScriptDeclarativeClass::Object *QScriptDeclarativeClass::object(const QScriptValue &v)
216 {
217     QScriptValuePrivate *d = QScriptValuePrivate::get(v);
218     if (!d || !d->isJSC() || !d->jscValue.inherits(&QScriptObject::info))
219         return 0;
220     QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(d->jscValue));
221     QScriptObjectDelegate *delegate = scriptObject->delegate();
222     if (!delegate || (delegate->type() != QScriptObjectDelegate::DeclarativeClassObject))
223         return 0;
224     return static_cast<QScript::DeclarativeObjectDelegate*>(delegate)->object();
225 }
226
227 QScriptValue QScriptDeclarativeClass::function(const QScriptValue &v, const Identifier &name)
228 {
229     QScriptValuePrivate *d = QScriptValuePrivate::get(v);
230
231     if (!d->isObject())
232         return QScriptValue();
233
234     JSC::ExecState *exec = d->engine->currentFrame;
235     JSC::JSObject *object = d->jscValue.getObject();
236     JSC::PropertySlot slot(const_cast<JSC::JSObject*>(object));
237     JSC::JSValue result;
238
239     JSC::Identifier id(exec, (JSC::UString::Rep *)name);
240
241     if (const_cast<JSC::JSObject*>(object)->getOwnPropertySlot(exec, id, slot)) {
242         result = slot.getValue(exec, id);
243         if (QScript::isFunction(result))
244             return d->engine->scriptValueFromJSCValue(result);
245     }
246
247     return QScriptValue();
248 }
249
250 QScriptValue QScriptDeclarativeClass::property(const QScriptValue &v, const Identifier &name)
251 {
252     QScriptValuePrivate *d = QScriptValuePrivate::get(v);
253
254     if (!d->isObject())
255         return QScriptValue();
256
257     JSC::ExecState *exec = d->engine->currentFrame;
258     JSC::JSObject *object = d->jscValue.getObject();
259     JSC::PropertySlot slot(const_cast<JSC::JSObject*>(object));
260     JSC::JSValue result;
261
262     JSC::Identifier id(exec, (JSC::UString::Rep *)name);
263
264     if (const_cast<JSC::JSObject*>(object)->getOwnPropertySlot(exec, id, slot)) {
265         result = slot.getValue(exec, id);
266         return d->engine->scriptValueFromJSCValue(result);
267     }
268
269     return QScriptValue();
270 }
271
272 QScriptDeclarativeClass::Value
273 QScriptDeclarativeClass::functionValue(const QScriptValue &v, const Identifier &name)
274 {
275     QScriptValuePrivate *d = QScriptValuePrivate::get(v);
276
277     if (!d->isObject())
278         return Value();
279
280     JSC::ExecState *exec = d->engine->currentFrame;
281     JSC::JSObject *object = d->jscValue.getObject();
282     JSC::PropertySlot slot(const_cast<JSC::JSObject*>(object));
283     JSC::JSValue result;
284
285     JSC::Identifier id(exec, (JSC::UString::Rep *)name);
286
287     if (const_cast<JSC::JSObject*>(object)->getOwnPropertySlot(exec, id, slot)) {
288         result = slot.getValue(exec, id);
289         if (QScript::isFunction(result))
290             return jscToValue(result);
291     }
292
293     return Value();
294 }
295
296 QScriptDeclarativeClass::Value
297 QScriptDeclarativeClass::propertyValue(const QScriptValue &v, const Identifier &name)
298 {
299     QScriptValuePrivate *d = QScriptValuePrivate::get(v);
300
301     if (!d->isObject())
302         return Value();
303
304     JSC::ExecState *exec = d->engine->currentFrame;
305     JSC::JSObject *object = d->jscValue.getObject();
306     JSC::PropertySlot slot(const_cast<JSC::JSObject*>(object));
307     JSC::JSValue result;
308
309     JSC::Identifier id(exec, (JSC::UString::Rep *)name);
310
311     if (const_cast<JSC::JSObject*>(object)->getOwnPropertySlot(exec, id, slot)) {
312         result = slot.getValue(exec, id);
313         return jscToValue(result);
314     }
315
316     return Value();
317 }
318
319 /*
320 Returns the scope chain entry at \a index.  If index is less than 0, returns
321 entries starting at the end.  For example, scopeChainValue(context, -1) will return
322 the value last in the scope chain.
323 */
324 QScriptValue QScriptDeclarativeClass::scopeChainValue(QScriptContext *context, int index)
325 {
326     context->activationObject(); //ensure the creation of the normal scope for native context
327     const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(context);
328     QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(frame);
329
330     JSC::ScopeChainNode *node = frame->scopeChain();
331     JSC::ScopeChainIterator it(node);
332
333     if (index < 0) {
334         int count = 0;
335         for (it = node->begin(); it != node->end(); ++it) 
336             ++count;
337
338         index = qAbs(index);
339         if (index > count)
340             return QScriptValue();
341         else
342             index = count - index;
343     }
344
345     for (it = node->begin(); it != node->end(); ++it) {
346
347         if (index == 0) {
348
349             JSC::JSObject *object = *it;
350             if (!object) return QScriptValue();
351
352             if (object->inherits(&QScript::QScriptActivationObject::info)
353                     && (static_cast<QScript::QScriptActivationObject*>(object)->delegate() != 0)) {
354                 // Return the object that property access is being delegated to
355                 object = static_cast<QScript::QScriptActivationObject*>(object)->delegate();
356             }
357             return engine->scriptValueFromJSCValue(object);
358
359         } else {
360             --index;
361         }
362
363     }
364
365     return QScriptValue();
366 }
367
368 /*!
369   Enters a new execution context and returns the associated
370   QScriptContext object.
371
372   Once you are done with the context, you should call popContext() to
373   restore the old context.
374
375   By default, the `this' object of the new context is the Global Object.
376   The context's \l{QScriptContext::callee()}{callee}() will be invalid.
377
378   Unlike pushContext(), the default scope chain is reset to include
379   only the global object and the QScriptContext's activation object.
380
381   \sa QScriptEngine::popContext()
382 */
383 QScriptContext * QScriptDeclarativeClass::pushCleanContext(QScriptEngine *engine)
384 {
385     if (!engine)
386         return 0;
387
388     QScriptEnginePrivate *d = QScriptEnginePrivate::get(engine);
389
390     JSC::CallFrame* newFrame = d->pushContext(d->currentFrame, 
391                                               d->currentFrame->globalData().dynamicGlobalObject,
392                                               JSC::ArgList(), /*callee = */0, false, true);
393
394     if (engine->agent())
395         engine->agent()->contextPush();
396
397     return d->contextForFrame(newFrame);
398 }
399
400 QScriptDeclarativeClass::~QScriptDeclarativeClass()
401 {
402 }
403
404 QScriptEngine *QScriptDeclarativeClass::engine() const
405 {
406     return d_ptr->engine;
407 }
408
409 bool QScriptDeclarativeClass::supportsCall() const
410 {
411     return d_ptr->supportsCall;
412 }
413
414 void QScriptDeclarativeClass::setSupportsCall(bool c)
415 {
416     d_ptr->supportsCall = c;
417 }
418
419 QScriptDeclarativeClass::PersistentIdentifier 
420 QScriptDeclarativeClass::createPersistentIdentifier(const QString &str)
421 {
422     QScriptEnginePrivate *p = 
423         static_cast<QScriptEnginePrivate *>(QObjectPrivate::get(d_ptr->engine)); 
424     JSC::ExecState* exec = p->currentFrame;
425
426     PersistentIdentifier rv(true);
427     new (&rv.d) JSC::Identifier(exec, (UChar *)str.constData(), str.size());
428     rv.identifier = (void *)((JSC::Identifier &)rv.d).ustring().rep();
429     return rv;
430 }
431
432 QScriptDeclarativeClass::PersistentIdentifier 
433 QScriptDeclarativeClass::createPersistentIdentifier(const Identifier &id)
434 {
435     QScriptEnginePrivate *p = 
436         static_cast<QScriptEnginePrivate *>(QObjectPrivate::get(d_ptr->engine)); 
437     JSC::ExecState* exec = p->currentFrame;
438
439     PersistentIdentifier rv(true);
440     new (&rv.d) JSC::Identifier(exec, (JSC::UString::Rep *)id);
441     rv.identifier = (void *)((JSC::Identifier &)rv.d).ustring().rep();
442     return rv;
443 }
444
445 QString QScriptDeclarativeClass::toString(const Identifier &identifier)
446 {
447     JSC::UString::Rep *r = (JSC::UString::Rep *)identifier;
448     return QString((QChar *)r->data(), r->size());
449 }
450
451 quint32 QScriptDeclarativeClass::toArrayIndex(const Identifier &identifier, bool *ok)
452 {
453     JSC::UString::Rep *r = (JSC::UString::Rep *)identifier;
454     JSC::UString s(r);
455     return s.toArrayIndex(ok);
456 }
457
458 QScriptClass::QueryFlags 
459 QScriptDeclarativeClass::queryProperty(Object *object, const Identifier &name, 
460                                        QScriptClass::QueryFlags flags)
461 {
462     Q_UNUSED(object);
463     Q_UNUSED(name);
464     Q_UNUSED(flags);
465     return 0;
466 }
467
468 QScriptDeclarativeClass::Value
469 QScriptDeclarativeClass::property(Object *object, const Identifier &name)
470 {
471     Q_UNUSED(object);
472     Q_UNUSED(name);
473     return Value();
474 }
475
476 void QScriptDeclarativeClass::setProperty(Object *object, const Identifier &name, 
477                                           const QScriptValue &value)
478 {
479     Q_UNUSED(object);
480     Q_UNUSED(name);
481     Q_UNUSED(value);
482 }
483
484 QScriptValue::PropertyFlags 
485 QScriptDeclarativeClass::propertyFlags(Object *object, const Identifier &name)
486 {
487     Q_UNUSED(object);
488     Q_UNUSED(name);
489     return 0;
490 }
491
492 QScriptDeclarativeClass::Value QScriptDeclarativeClass::call(Object *object, 
493                                                              QScriptContext *ctxt)
494 {
495     Q_UNUSED(object);
496     Q_UNUSED(ctxt);
497     return Value();
498 }
499
500 QStringList QScriptDeclarativeClass::propertyNames(Object *object)
501 {
502     Q_UNUSED(object);
503     return QStringList();
504 }
505
506 bool QScriptDeclarativeClass::isQObject() const
507 {
508     return false;
509 }
510
511 QObject *QScriptDeclarativeClass::toQObject(Object *, bool *ok)
512 {
513     if (ok) *ok = false;
514     return 0;
515 }
516
517 QVariant QScriptDeclarativeClass::toVariant(Object *, bool *ok)
518 {
519     if (ok) *ok = false;
520     return QVariant();
521 }
522
523 QScriptContext *QScriptDeclarativeClass::context() const
524 {
525     return d_ptr->context;
526 }
527
528 QT_END_NAMESPACE