Remove "All rights reserved" line from license headers.
[profile/ivi/qtdeclarative.git] / src / declarative / qml / qdeclarativevmemetaobject.cpp
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 QtDeclarative 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 #include "qdeclarativevmemetaobject_p.h"
43
44
45 #include "qdeclarative.h"
46 #include <private/qdeclarativerefcount_p.h>
47 #include "qdeclarativeexpression.h"
48 #include "qdeclarativeexpression_p.h"
49 #include "qdeclarativecontext_p.h"
50 #include "qdeclarativebinding_p.h"
51 #include "qdeclarativepropertyvalueinterceptor_p.h"
52
53 #include <private/qv8variantresource_p.h>
54
55 Q_DECLARE_METATYPE(QJSValue);
56
57 QT_BEGIN_NAMESPACE
58
59 class QDeclarativeVMEVariant
60 {
61 public:
62     inline QDeclarativeVMEVariant();
63     inline ~QDeclarativeVMEVariant();
64
65     inline const void *dataPtr() const;
66     inline void *dataPtr();
67     inline int dataType() const;
68
69     inline QObject *asQObject();
70     inline const QVariant &asQVariant();
71     inline int asInt();
72     inline bool asBool();
73     inline double asDouble();
74     inline const QString &asQString();
75     inline const QUrl &asQUrl();
76     inline const QColor &asQColor();
77     inline const QTime &asQTime();
78     inline const QDate &asQDate();
79     inline const QDateTime &asQDateTime();
80     inline const QJSValue &asQJSValue();
81
82     inline void setValue(QObject *);
83     inline void setValue(const QVariant &);
84     inline void setValue(int);
85     inline void setValue(bool);
86     inline void setValue(double);
87     inline void setValue(const QString &);
88     inline void setValue(const QUrl &);
89     inline void setValue(const QColor &);
90     inline void setValue(const QTime &);
91     inline void setValue(const QDate &);
92     inline void setValue(const QDateTime &);
93     inline void setValue(const QJSValue &);
94 private:
95     int type;
96     void *data[4]; // Large enough to hold all types
97
98     inline void cleanup();
99 };
100
101 class QDeclarativeVMEMetaObjectEndpoint : public QDeclarativeNotifierEndpoint
102 {
103 public:
104     QDeclarativeVMEMetaObjectEndpoint();
105     static void vmecallback(QDeclarativeNotifierEndpoint *);
106     void tryConnect();
107
108     QFlagPointer<QDeclarativeVMEMetaObject> metaObject;
109 };
110
111
112 QDeclarativeVMEVariant::QDeclarativeVMEVariant()
113 : type(QVariant::Invalid)
114 {
115 }
116
117 QDeclarativeVMEVariant::~QDeclarativeVMEVariant()
118 {
119     cleanup();
120 }
121
122 void QDeclarativeVMEVariant::cleanup()
123 {
124     if (type == QVariant::Invalid) {
125     } else if (type == QMetaType::Int ||
126                type == QMetaType::Bool ||
127                type == QMetaType::Double) {
128         type = QVariant::Invalid;
129     } else if (type == QMetaType::QObjectStar) {
130         ((QDeclarativeGuard<QObject>*)dataPtr())->~QDeclarativeGuard<QObject>();
131         type = QVariant::Invalid;
132     } else if (type == QMetaType::QString) {
133         ((QString *)dataPtr())->~QString();
134         type = QVariant::Invalid;
135     } else if (type == QMetaType::QUrl) {
136         ((QUrl *)dataPtr())->~QUrl();
137         type = QVariant::Invalid;
138     } else if (type == QMetaType::QColor) {
139         ((QColor *)dataPtr())->~QColor();
140         type = QVariant::Invalid;
141     } else if (type == QMetaType::QTime) {
142         ((QTime *)dataPtr())->~QTime();
143         type = QVariant::Invalid;
144     } else if (type == QMetaType::QDate) {
145         ((QDate *)dataPtr())->~QDate();
146         type = QVariant::Invalid;
147     } else if (type == QMetaType::QDateTime) {
148         ((QDateTime *)dataPtr())->~QDateTime();
149         type = QVariant::Invalid;
150     } else if (type == qMetaTypeId<QVariant>()) {
151         ((QVariant *)dataPtr())->~QVariant();
152         type = QVariant::Invalid;
153     } else if (type == qMetaTypeId<QJSValue>()) {
154         ((QJSValue *)dataPtr())->~QJSValue();
155         type = QVariant::Invalid;
156     }
157
158 }
159
160 int QDeclarativeVMEVariant::dataType() const
161 {
162     return type;
163 }
164
165 const void *QDeclarativeVMEVariant::dataPtr() const
166 {
167     return &data;
168 }
169
170 void *QDeclarativeVMEVariant::dataPtr() 
171 {
172     return &data;
173 }
174
175 QObject *QDeclarativeVMEVariant::asQObject() 
176 {
177     if (type != QMetaType::QObjectStar) 
178         setValue((QObject *)0);
179
180     return *(QDeclarativeGuard<QObject> *)(dataPtr());
181 }
182
183 const QVariant &QDeclarativeVMEVariant::asQVariant() 
184 {
185     if (type != QMetaType::QVariant)
186         setValue(QVariant());
187
188     return *(QVariant *)(dataPtr());
189 }
190
191 int QDeclarativeVMEVariant::asInt() 
192 {
193     if (type != QMetaType::Int)
194         setValue(int(0));
195
196     return *(int *)(dataPtr());
197 }
198
199 bool QDeclarativeVMEVariant::asBool() 
200 {
201     if (type != QMetaType::Bool)
202         setValue(bool(false));
203
204     return *(bool *)(dataPtr());
205 }
206
207 double QDeclarativeVMEVariant::asDouble() 
208 {
209     if (type != QMetaType::Double)
210         setValue(double(0));
211
212     return *(double *)(dataPtr());
213 }
214
215 const QString &QDeclarativeVMEVariant::asQString() 
216 {
217     if (type != QMetaType::QString)
218         setValue(QString());
219
220     return *(QString *)(dataPtr());
221 }
222
223 const QUrl &QDeclarativeVMEVariant::asQUrl() 
224 {
225     if (type != QMetaType::QUrl)
226         setValue(QUrl());
227
228     return *(QUrl *)(dataPtr());
229 }
230
231 const QColor &QDeclarativeVMEVariant::asQColor() 
232 {
233     if (type != QMetaType::QColor)
234         setValue(QColor());
235
236     return *(QColor *)(dataPtr());
237 }
238
239 const QTime &QDeclarativeVMEVariant::asQTime() 
240 {
241     if (type != QMetaType::QTime)
242         setValue(QTime());
243
244     return *(QTime *)(dataPtr());
245 }
246
247 const QDate &QDeclarativeVMEVariant::asQDate() 
248 {
249     if (type != QMetaType::QDate)
250         setValue(QDate());
251
252     return *(QDate *)(dataPtr());
253 }
254
255 const QDateTime &QDeclarativeVMEVariant::asQDateTime() 
256 {
257     if (type != QMetaType::QDateTime)
258         setValue(QDateTime());
259
260     return *(QDateTime *)(dataPtr());
261 }
262
263 const QJSValue &QDeclarativeVMEVariant::asQJSValue()
264 {
265     if (type != qMetaTypeId<QJSValue>())
266         setValue(QJSValue());
267
268     return *(QJSValue *)(dataPtr());
269 }
270
271 void QDeclarativeVMEVariant::setValue(QObject *v)
272 {
273     if (type != QMetaType::QObjectStar) {
274         cleanup();
275         type = QMetaType::QObjectStar;
276         new (dataPtr()) QDeclarativeGuard<QObject>();
277     }
278     *(QDeclarativeGuard<QObject>*)(dataPtr()) = v;
279 }
280
281 void QDeclarativeVMEVariant::setValue(const QVariant &v)
282 {
283     if (type != qMetaTypeId<QVariant>()) {
284         cleanup();
285         type = qMetaTypeId<QVariant>();
286         new (dataPtr()) QVariant(v);
287     } else {
288         *(QVariant *)(dataPtr()) = v;
289     }
290 }
291
292 void QDeclarativeVMEVariant::setValue(int v)
293 {
294     if (type != QMetaType::Int) {
295         cleanup();
296         type = QMetaType::Int;
297     }
298     *(int *)(dataPtr()) = v;
299 }
300
301 void QDeclarativeVMEVariant::setValue(bool v)
302 {
303     if (type != QMetaType::Bool) {
304         cleanup();
305         type = QMetaType::Bool;
306     }
307     *(bool *)(dataPtr()) = v;
308 }
309
310 void QDeclarativeVMEVariant::setValue(double v)
311 {
312     if (type != QMetaType::Double) {
313         cleanup();
314         type = QMetaType::Double;
315     }
316     *(double *)(dataPtr()) = v;
317 }
318
319 void QDeclarativeVMEVariant::setValue(const QString &v)
320 {
321     if (type != QMetaType::QString) {
322         cleanup();
323         type = QMetaType::QString;
324         new (dataPtr()) QString(v);
325     } else {
326         *(QString *)(dataPtr()) = v;
327     }
328 }
329
330 void QDeclarativeVMEVariant::setValue(const QUrl &v)
331 {
332     if (type != QMetaType::QUrl) {
333         cleanup();
334         type = QMetaType::QUrl;
335         new (dataPtr()) QUrl(v);
336     } else {
337         *(QUrl *)(dataPtr()) = v;
338     }
339 }
340
341 void QDeclarativeVMEVariant::setValue(const QColor &v)
342 {
343     if (type != QMetaType::QColor) {
344         cleanup();
345         type = QMetaType::QColor;
346         new (dataPtr()) QColor(v);
347     } else {
348         *(QColor *)(dataPtr()) = v;
349     }
350 }
351
352 void QDeclarativeVMEVariant::setValue(const QTime &v)
353 {
354     if (type != QMetaType::QTime) {
355         cleanup();
356         type = QMetaType::QTime;
357         new (dataPtr()) QTime(v);
358     } else {
359         *(QTime *)(dataPtr()) = v;
360     }
361 }
362
363 void QDeclarativeVMEVariant::setValue(const QDate &v)
364 {
365     if (type != QMetaType::QDate) {
366         cleanup();
367         type = QMetaType::QDate;
368         new (dataPtr()) QDate(v);
369     } else {
370         *(QDate *)(dataPtr()) = v;
371     }
372 }
373
374 void QDeclarativeVMEVariant::setValue(const QDateTime &v)
375 {
376     if (type != QMetaType::QDateTime) {
377         cleanup();
378         type = QMetaType::QDateTime;
379         new (dataPtr()) QDateTime(v);
380     } else {
381         *(QDateTime *)(dataPtr()) = v;
382     }
383 }
384
385 void QDeclarativeVMEVariant::setValue(const QJSValue &v)
386 {
387     if (type != qMetaTypeId<QJSValue>()) {
388         cleanup();
389         type = qMetaTypeId<QJSValue>();
390         new (dataPtr()) QJSValue(v);
391     } else {
392         *(QJSValue *)(dataPtr()) = v;
393     }
394 }
395
396 QDeclarativeVMEMetaObjectEndpoint::QDeclarativeVMEMetaObjectEndpoint()
397 {
398     callback = &vmecallback;
399 }
400
401 void QDeclarativeVMEMetaObjectEndpoint::vmecallback(QDeclarativeNotifierEndpoint *e)
402 {
403     QDeclarativeVMEMetaObjectEndpoint *vmee = static_cast<QDeclarativeVMEMetaObjectEndpoint*>(e);
404     vmee->tryConnect();
405 }
406
407 void QDeclarativeVMEMetaObjectEndpoint::tryConnect()
408 {
409     if (metaObject.flag())
410         return;
411
412     int aliasId = this - metaObject->aliasEndpoints;
413
414     QDeclarativeVMEMetaData::AliasData *d = metaObject->metaData->aliasData() + aliasId;
415     if (!d->isObjectAlias()) {
416         QDeclarativeContextData *ctxt = metaObject->ctxt;
417         QObject *target = ctxt->idValues[d->contextIdx].data();
418         if (!target)
419             return;
420
421         QMetaProperty prop = target->metaObject()->property(d->propertyIndex());
422         if (prop.hasNotifySignal()) {
423             int sigIdx = metaObject->methodOffset + aliasId + metaObject->metaData->propertyCount;
424             QDeclarativePropertyPrivate::connect(target, prop.notifySignalIndex(),
425                                                  metaObject->object, sigIdx);
426         }
427     }
428
429     metaObject.setFlag();
430 }
431
432 QDeclarativeVMEMetaObject::QDeclarativeVMEMetaObject(QObject *obj,
433                                                      const QMetaObject *other, 
434                                                      const QDeclarativeVMEMetaData *meta,
435                                                      QDeclarativeCompiledData *cdata)
436 : QV8GCCallback::Node(GcPrologueCallback), object(obj), compiledData(cdata),
437   ctxt(QDeclarativeData::get(obj, true)->outerContext), metaData(meta), data(0),
438   aliasEndpoints(0), firstVarPropertyIndex(-1), varPropertiesInitialized(false),
439   v8methods(0), parent(0)
440 {
441     compiledData->addref();
442
443     *static_cast<QMetaObject *>(this) = *other;
444     this->d.superdata = obj->metaObject();
445
446     QObjectPrivate *op = QObjectPrivate::get(obj);
447     if (op->metaObject)
448         parent = static_cast<QAbstractDynamicMetaObject*>(op->metaObject);
449     op->metaObject = this;
450
451     propOffset = QAbstractDynamicMetaObject::propertyOffset();
452     methodOffset = QAbstractDynamicMetaObject::methodOffset();
453
454     data = new QDeclarativeVMEVariant[metaData->propertyCount - metaData->varPropertyCount];
455
456     aConnected.resize(metaData->aliasCount);
457     int list_type = qMetaTypeId<QDeclarativeListProperty<QObject> >();
458
459     // ### Optimize
460     for (int ii = 0; ii < metaData->propertyCount - metaData->varPropertyCount; ++ii) {
461         int t = (metaData->propertyData() + ii)->propertyType;
462         if (t == list_type) {
463             listProperties.append(List(methodOffset + ii));
464             data[ii].setValue(listProperties.count() - 1);
465         } 
466     }
467
468     firstVarPropertyIndex = metaData->propertyCount - metaData->varPropertyCount;
469     if (metaData->varPropertyCount)
470         QV8GCCallback::addGcCallbackNode(this);
471 }
472
473 QDeclarativeVMEMetaObject::~QDeclarativeVMEMetaObject()
474 {
475     compiledData->release();
476     delete parent;
477     delete [] data;
478     delete [] aliasEndpoints;
479
480     for (int ii = 0; v8methods && ii < metaData->methodCount; ++ii) {
481         qPersistentDispose(v8methods[ii]);
482     }
483
484     if (metaData->varPropertyCount)
485         qPersistentDispose(varProperties); // if not weak, will not have been cleaned up by the callback.
486 }
487
488 int QDeclarativeVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
489 {
490     int id = _id;
491     if(c == QMetaObject::WriteProperty) {
492         int flags = *reinterpret_cast<int*>(a[3]);
493         if (!(flags & QDeclarativePropertyPrivate::BypassInterceptor)
494             && !aInterceptors.isEmpty()
495             && aInterceptors.testBit(id)) {
496             QPair<int, QDeclarativePropertyValueInterceptor*> pair = interceptors.value(id);
497             int valueIndex = pair.first;
498             QDeclarativePropertyValueInterceptor *vi = pair.second;
499             int type = property(id).userType();
500
501             if (type != QVariant::Invalid) {
502                 if (valueIndex != -1) {
503                     QDeclarativeEnginePrivate *ep = ctxt?QDeclarativeEnginePrivate::get(ctxt->engine):0;
504                     QDeclarativeValueType *valueType = 0;
505                     if (ep) valueType = ep->valueTypes[type];
506                     else valueType = QDeclarativeValueTypeFactory::valueType(type);
507                     Q_ASSERT(valueType);
508
509                     valueType->setValue(QVariant(type, a[0]));
510                     QMetaProperty valueProp = valueType->metaObject()->property(valueIndex);
511                     vi->write(valueProp.read(valueType));
512
513                     if (!ep) delete valueType;
514                     return -1;
515                 } else {
516                     vi->write(QVariant(type, a[0]));
517                     return -1;
518                 }
519             }
520         }
521     }
522     if (c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty || c == QMetaObject::ResetProperty) {
523         if (id >= propOffset) {
524             id -= propOffset;
525
526             if (id < metaData->propertyCount) {
527                int t = (metaData->propertyData() + id)->propertyType;
528                 bool needActivate = false;
529
530                 if (id >= firstVarPropertyIndex) {
531                     Q_ASSERT(t == QMetaType::QVariant);
532                     // the context can be null if accessing var properties from cpp after re-parenting an item.
533                     QDeclarativeEnginePrivate *ep = (ctxt == 0 || ctxt->engine == 0) ? 0 : QDeclarativeEnginePrivate::get(ctxt->engine);
534                     QV8Engine *v8e = (ep == 0) ? 0 : ep->v8engine();
535                     if (v8e) {
536                         v8::HandleScope handleScope;
537                         v8::Context::Scope contextScope(v8e->context());
538                         if (c == QMetaObject::ReadProperty) {
539                             *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id);
540                         } else if (c == QMetaObject::WriteProperty) {
541                             writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
542                         }
543                     } else if (c == QMetaObject::ReadProperty) {
544                         // if the context was disposed, we just return an invalid variant from read.
545                         *reinterpret_cast<QVariant *>(a[0]) = QVariant();
546                     }
547
548                 } else {
549
550                     if (c == QMetaObject::ReadProperty) {
551                         switch(t) {
552                         case QVariant::Int:
553                             *reinterpret_cast<int *>(a[0]) = data[id].asInt();
554                             break;
555                         case QVariant::Bool:
556                             *reinterpret_cast<bool *>(a[0]) = data[id].asBool();
557                             break;
558                         case QVariant::Double:
559                             *reinterpret_cast<double *>(a[0]) = data[id].asDouble();
560                             break;
561                         case QVariant::String:
562                             *reinterpret_cast<QString *>(a[0]) = data[id].asQString();
563                             break;
564                         case QVariant::Url:
565                             *reinterpret_cast<QUrl *>(a[0]) = data[id].asQUrl();
566                             break;
567                         case QVariant::Color:
568                             *reinterpret_cast<QColor *>(a[0]) = data[id].asQColor();
569                             break;
570                         case QVariant::Date:
571                             *reinterpret_cast<QDate *>(a[0]) = data[id].asQDate();
572                             break;
573                         case QVariant::DateTime:
574                             *reinterpret_cast<QDateTime *>(a[0]) = data[id].asQDateTime();
575                             break;
576                         case QMetaType::QObjectStar:
577                             *reinterpret_cast<QObject **>(a[0]) = data[id].asQObject();
578                             break;
579                         case QMetaType::QVariant:
580                             *reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id);
581                             break;
582                         default:
583                             break;
584                         }
585                         if (t == qMetaTypeId<QDeclarativeListProperty<QObject> >()) {
586                             int listIndex = data[id].asInt();
587                             const List *list = &listProperties.at(listIndex);
588                             *reinterpret_cast<QDeclarativeListProperty<QObject> *>(a[0]) = 
589                                 QDeclarativeListProperty<QObject>(object, (void *)list,
590                                                                   list_append, list_count, list_at, 
591                                                                   list_clear);
592                         }
593
594                     } else if (c == QMetaObject::WriteProperty) {
595
596                         switch(t) {
597                         case QVariant::Int:
598                             needActivate = *reinterpret_cast<int *>(a[0]) != data[id].asInt();
599                             data[id].setValue(*reinterpret_cast<int *>(a[0]));
600                             break;
601                         case QVariant::Bool:
602                             needActivate = *reinterpret_cast<bool *>(a[0]) != data[id].asBool();
603                             data[id].setValue(*reinterpret_cast<bool *>(a[0]));
604                             break;
605                         case QVariant::Double:
606                             needActivate = *reinterpret_cast<double *>(a[0]) != data[id].asDouble();
607                             data[id].setValue(*reinterpret_cast<double *>(a[0]));
608                             break;
609                         case QVariant::String:
610                             needActivate = *reinterpret_cast<QString *>(a[0]) != data[id].asQString();
611                             data[id].setValue(*reinterpret_cast<QString *>(a[0]));
612                             break;
613                         case QVariant::Url:
614                             needActivate = *reinterpret_cast<QUrl *>(a[0]) != data[id].asQUrl();
615                             data[id].setValue(*reinterpret_cast<QUrl *>(a[0]));
616                             break;
617                         case QVariant::Color:
618                             needActivate = *reinterpret_cast<QColor *>(a[0]) != data[id].asQColor();
619                             data[id].setValue(*reinterpret_cast<QColor *>(a[0]));
620                             break;
621                         case QVariant::Date:
622                             needActivate = *reinterpret_cast<QDate *>(a[0]) != data[id].asQDate();
623                             data[id].setValue(*reinterpret_cast<QDate *>(a[0]));
624                             break;
625                         case QVariant::DateTime:
626                             needActivate = *reinterpret_cast<QDateTime *>(a[0]) != data[id].asQDateTime();
627                             data[id].setValue(*reinterpret_cast<QDateTime *>(a[0]));
628                             break;
629                         case QMetaType::QObjectStar:
630                             needActivate = *reinterpret_cast<QObject **>(a[0]) != data[id].asQObject();
631                             data[id].setValue(*reinterpret_cast<QObject **>(a[0]));
632                             break;
633                         case QMetaType::QVariant:
634                             writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
635                             break;
636                         default:
637                             break;
638                         }
639                     }
640
641                 }
642
643                 if (c == QMetaObject::WriteProperty && needActivate) {
644                     activate(object, methodOffset + id, 0);
645                 }
646
647                 return -1;
648             }
649
650             id -= metaData->propertyCount;
651
652             if (id < metaData->aliasCount) {
653
654                 QDeclarativeVMEMetaData::AliasData *d = metaData->aliasData() + id;
655
656                 if (d->flags & QML_ALIAS_FLAG_PTR && c == QMetaObject::ReadProperty) 
657                         *reinterpret_cast<void **>(a[0]) = 0;
658
659                 if (!ctxt) return -1;
660
661                 QDeclarativeContext *context = ctxt->asQDeclarativeContext();
662                 QDeclarativeContextPrivate *ctxtPriv = QDeclarativeContextPrivate::get(context);
663
664                 QObject *target = ctxtPriv->data->idValues[d->contextIdx].data();
665                 if (!target) 
666                     return -1;
667
668                 connectAlias(id);
669
670                 if (d->isObjectAlias()) {
671                     *reinterpret_cast<QObject **>(a[0]) = target;
672                     return -1;
673                 } 
674                 
675                 // Remove binding (if any) on write
676                 if(c == QMetaObject::WriteProperty) {
677                     int flags = *reinterpret_cast<int*>(a[3]);
678                     if (flags & QDeclarativePropertyPrivate::RemoveBindingOnAliasWrite) {
679                         QDeclarativeData *targetData = QDeclarativeData::get(target);
680                         if (targetData && targetData->hasBindingBit(d->propertyIndex())) {
681                             QDeclarativeAbstractBinding *binding = QDeclarativePropertyPrivate::setBinding(target, d->propertyIndex(), d->isValueTypeAlias()?d->valueTypeIndex():-1, 0);
682                             if (binding) binding->destroy();
683                         }
684                     }
685                 }
686                 
687                 if (d->isValueTypeAlias()) {
688                     // Value type property
689                     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(ctxt->engine);
690
691                     QDeclarativeValueType *valueType = ep->valueTypes[d->valueType()];
692                     Q_ASSERT(valueType);
693
694                     valueType->read(target, d->propertyIndex());
695                     int rv = QMetaObject::metacall(valueType, c, d->valueTypeIndex(), a);
696                     
697                     if (c == QMetaObject::WriteProperty)
698                         valueType->write(target, d->propertyIndex(), 0x00);
699
700                     return rv;
701
702                 } else {
703                     return QMetaObject::metacall(target, c, d->propertyIndex(), a);
704                 }
705
706             }
707             return -1;
708
709         }
710
711     } else if(c == QMetaObject::InvokeMetaMethod) {
712
713         if (id >= methodOffset) {
714
715             id -= methodOffset;
716             int plainSignals = metaData->signalCount + metaData->propertyCount +
717                                metaData->aliasCount;
718             if (id < plainSignals) {
719                 QMetaObject::activate(object, _id, a);
720                 return -1;
721             }
722
723             id -= plainSignals;
724
725             if (id < metaData->methodCount) {
726                 if (!ctxt->engine)
727                     return -1; // We can't run the method
728
729                 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(ctxt->engine);
730                 ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
731
732                 v8::Handle<v8::Function> function = method(id);
733                 QDeclarativeVMEMetaData::MethodData *data = metaData->methodData() + id;
734
735                 v8::HandleScope handle_scope;
736                 v8::Context::Scope scope(ep->v8engine()->context());
737                 v8::Handle<v8::Value> *args = 0;
738
739                 if (data->parameterCount) {
740                     args = new v8::Handle<v8::Value>[data->parameterCount];
741                     for (int ii = 0; ii < data->parameterCount; ++ii) 
742                         args[ii] = ep->v8engine()->fromVariant(*(QVariant *)a[ii + 1]);
743                 }
744
745                 v8::TryCatch try_catch;
746
747                 v8::Local<v8::Value> result = function->Call(ep->v8engine()->global(), data->parameterCount, args);
748
749                 QVariant rv;
750                 if (try_catch.HasCaught()) {
751                     QDeclarativeError error;
752                     QDeclarativeExpressionPrivate::exceptionToError(try_catch.Message(), error);
753                     if (error.isValid())
754                         ep->warning(error);
755                     if (a[0]) *(QVariant *)a[0] = QVariant();
756                 } else {
757                     if (a[0]) *(QVariant *)a[0] = ep->v8engine()->toVariant(result, 0);
758                 }
759
760                 ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
761                 return -1;
762             }
763             return -1;
764         }
765     }
766
767     if (parent)
768         return parent->metaCall(c, _id, a);
769     else
770         return object->qt_metacall(c, _id, a);
771 }
772
773 v8::Handle<v8::Function> QDeclarativeVMEMetaObject::method(int index)
774 {
775     if (!v8methods) 
776         v8methods = new v8::Persistent<v8::Function>[metaData->methodCount];
777
778     if (v8methods[index].IsEmpty()) {
779         QDeclarativeVMEMetaData::MethodData *data = metaData->methodData() + index;
780
781         const QChar *body = 
782             (const QChar *)(((const char*)metaData) + data->bodyOffset);
783
784         QString code = QString::fromRawData(body, data->bodyLength);
785
786         // XXX We should evaluate all methods in a single big script block to 
787         // improve the call time between dynamic methods defined on the same
788         // object
789         v8methods[index] = QDeclarativeExpressionPrivate::evalFunction(ctxt, object, code, ctxt->url.toString(),
790                                                                        data->lineNumber);
791     }
792
793     return v8methods[index];
794 }
795
796 v8::Handle<v8::Value> QDeclarativeVMEMetaObject::readVarProperty(int id)
797 {
798     Q_ASSERT(id >= firstVarPropertyIndex);
799
800     ensureVarPropertiesAllocated();
801     return varProperties->Get(id - firstVarPropertyIndex);
802 }
803
804 QVariant QDeclarativeVMEMetaObject::readPropertyAsVariant(int id)
805 {
806     if (id >= firstVarPropertyIndex) {
807         ensureVarPropertiesAllocated();
808         return QDeclarativeEnginePrivate::get(ctxt->engine)->v8engine()->toVariant(varProperties->Get(id - firstVarPropertyIndex), -1);
809     } else {
810         if (data[id].dataType() == QMetaType::QObjectStar) {
811             return QVariant::fromValue(data[id].asQObject());
812         } else {
813             return data[id].asQVariant();
814         }
815     }
816 }
817
818 void QDeclarativeVMEMetaObject::writeVarProperty(int id, v8::Handle<v8::Value> value)
819 {
820     Q_ASSERT(id >= firstVarPropertyIndex);
821     ensureVarPropertiesAllocated();
822
823     // Importantly, if the current value is a scarce resource, we need to ensure that it
824     // gets automatically released by the engine if no other references to it exist.
825     v8::Local<v8::Value> oldv = varProperties->Get(id - firstVarPropertyIndex);
826     if (oldv->IsObject()) {
827         QV8VariantResource *r = v8_resource_cast<QV8VariantResource>(v8::Handle<v8::Object>::Cast(oldv));
828         if (r) {
829             r->removeVmePropertyReference();
830         }
831     }
832
833     // And, if the new value is a scarce resource, we need to ensure that it does not get
834     // automatically released by the engine until no other references to it exist.
835     if (value->IsObject()) {
836         QV8VariantResource *r = v8_resource_cast<QV8VariantResource>(v8::Handle<v8::Object>::Cast(value));
837         if (r) {
838             r->addVmePropertyReference();
839         }
840     }
841
842     // Write the value and emit change signal as appropriate.
843     varProperties->Set(id - firstVarPropertyIndex, value);
844     activate(object, methodOffset + id, 0);
845 }
846
847 void QDeclarativeVMEMetaObject::writeProperty(int id, const QVariant &value)
848 {
849     if (id >= firstVarPropertyIndex) {
850         ensureVarPropertiesAllocated();
851
852         // Importantly, if the current value is a scarce resource, we need to ensure that it
853         // gets automatically released by the engine if no other references to it exist.
854         v8::Local<v8::Value> oldv = varProperties->Get(id - firstVarPropertyIndex);
855         if (oldv->IsObject()) {
856             QV8VariantResource *r = v8_resource_cast<QV8VariantResource>(v8::Handle<v8::Object>::Cast(oldv));
857             if (r) {
858                 r->removeVmePropertyReference();
859             }
860         }
861
862         // And, if the new value is a scarce resource, we need to ensure that it does not get
863         // automatically released by the engine until no other references to it exist.
864         v8::Handle<v8::Value> newv = QDeclarativeEnginePrivate::get(ctxt->engine)->v8engine()->fromVariant(value);
865         if (newv->IsObject()) {
866             QV8VariantResource *r = v8_resource_cast<QV8VariantResource>(v8::Handle<v8::Object>::Cast(newv));
867             if (r) {
868                 r->addVmePropertyReference();
869             }
870         }
871
872         // Write the value and emit change signal as appropriate.
873         QVariant currentValue = readPropertyAsVariant(id);
874         varProperties->Set(id - firstVarPropertyIndex, newv);
875         if ((currentValue.userType() != value.userType() || currentValue != value))
876             activate(object, methodOffset + id, 0);
877     } else {
878         bool needActivate = false;
879         if (value.userType() == QMetaType::QObjectStar) {
880             QObject *o = qvariant_cast<QObject *>(value);
881             needActivate = (data[id].dataType() != QMetaType::QObjectStar || data[id].asQObject() != o);
882             data[id].setValue(qvariant_cast<QObject *>(value));
883         } else {
884             needActivate = (data[id].dataType() != qMetaTypeId<QVariant>() ||
885                             data[id].asQVariant().userType() != value.userType() ||
886                             data[id].asQVariant() != value);
887             data[id].setValue(value);
888         }
889
890         if (needActivate)
891             activate(object, methodOffset + id, 0);
892     }
893 }
894
895 void QDeclarativeVMEMetaObject::listChanged(int id)
896 {
897     activate(object, methodOffset + id, 0);
898 }
899
900 void QDeclarativeVMEMetaObject::list_append(QDeclarativeListProperty<QObject> *prop, QObject *o)
901 {
902     List *list = static_cast<List *>(prop->data);
903     list->append(o);
904     QMetaObject::activate(prop->object, list->notifyIndex, 0);
905 }
906
907 int QDeclarativeVMEMetaObject::list_count(QDeclarativeListProperty<QObject> *prop)
908 {
909     return static_cast<List *>(prop->data)->count();
910 }
911
912 QObject *QDeclarativeVMEMetaObject::list_at(QDeclarativeListProperty<QObject> *prop, int index)
913 {
914     return static_cast<List *>(prop->data)->at(index);
915 }
916
917 void QDeclarativeVMEMetaObject::list_clear(QDeclarativeListProperty<QObject> *prop)
918 {
919     List *list = static_cast<List *>(prop->data);
920     list->clear();
921     QMetaObject::activate(prop->object, list->notifyIndex, 0);
922 }
923
924 void QDeclarativeVMEMetaObject::registerInterceptor(int index, int valueIndex, QDeclarativePropertyValueInterceptor *interceptor)
925 {
926     if (aInterceptors.isEmpty())
927         aInterceptors.resize(propertyCount() + metaData->propertyCount);
928     aInterceptors.setBit(index);
929     interceptors.insert(index, qMakePair(valueIndex, interceptor));
930 }
931
932 int QDeclarativeVMEMetaObject::vmeMethodLineNumber(int index)
933 {
934     if (index < methodOffset) {
935         Q_ASSERT(parent);
936         return static_cast<QDeclarativeVMEMetaObject *>(parent)->vmeMethodLineNumber(index);
937     }
938
939     int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
940     Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount));
941
942     int rawIndex = index - methodOffset - plainSignals;
943
944     QDeclarativeVMEMetaData::MethodData *data = metaData->methodData() + rawIndex;
945     return data->lineNumber;
946 }
947
948 v8::Handle<v8::Function> QDeclarativeVMEMetaObject::vmeMethod(int index)
949 {
950     if (index < methodOffset) {
951         Q_ASSERT(parent);
952         return static_cast<QDeclarativeVMEMetaObject *>(parent)->vmeMethod(index);
953     }
954     int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
955     Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount));
956     return method(index - methodOffset - plainSignals);
957 }
958
959 // Used by debugger
960 void QDeclarativeVMEMetaObject::setVmeMethod(int index, v8::Persistent<v8::Function> value)
961 {
962     if (index < methodOffset) {
963         Q_ASSERT(parent);
964         return static_cast<QDeclarativeVMEMetaObject *>(parent)->setVmeMethod(index, value);
965     }
966     int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
967     Q_ASSERT(index >= (methodOffset + plainSignals) && index < (methodOffset + plainSignals + metaData->methodCount));
968
969     if (!v8methods) 
970         v8methods = new v8::Persistent<v8::Function>[metaData->methodCount];
971
972     int methodIndex = index - methodOffset - plainSignals;
973     if (!v8methods[methodIndex].IsEmpty()) 
974         qPersistentDispose(v8methods[methodIndex]);
975     v8methods[methodIndex] = value;
976 }
977
978 v8::Handle<v8::Value> QDeclarativeVMEMetaObject::vmeProperty(int index)
979 {
980     if (index < propOffset) {
981         Q_ASSERT(parent);
982         return static_cast<QDeclarativeVMEMetaObject *>(parent)->vmeProperty(index);
983     }
984     return readVarProperty(index - propOffset);
985 }
986
987 void QDeclarativeVMEMetaObject::setVMEProperty(int index, v8::Handle<v8::Value> v)
988 {
989     if (index < propOffset) {
990         Q_ASSERT(parent);
991         static_cast<QDeclarativeVMEMetaObject *>(parent)->setVMEProperty(index, v);
992         return;
993     }
994     return writeVarProperty(index - propOffset, v);
995 }
996
997 void QDeclarativeVMEMetaObject::ensureVarPropertiesAllocated()
998 {
999     if (!varPropertiesInitialized)
1000         allocateVarPropertiesArray();
1001 }
1002
1003 // see also: QV8GCCallback::garbageCollectorPrologueCallback()
1004 void QDeclarativeVMEMetaObject::allocateVarPropertiesArray()
1005 {
1006     v8::HandleScope handleScope;
1007     v8::Context::Scope cs(QDeclarativeEnginePrivate::get(ctxt->engine)->v8engine()->context());
1008     varProperties = qPersistentNew(v8::Array::New(metaData->varPropertyCount));
1009     varProperties.MakeWeak(static_cast<void*>(this), VarPropertiesWeakReferenceCallback);
1010     varPropertiesInitialized = true;
1011 }
1012
1013 /*
1014    The "var" properties are stored in a v8::Array which will be strong persistent if the object has cpp-ownership
1015    and the root QObject in the parent chain does not have JS-ownership.  In the weak persistent handle case,
1016    this callback will dispose the handle when the v8object which owns the lifetime of the var properties array
1017    is cleared as a result of all other handles to that v8object being released.
1018    See QV8GCCallback::garbageCollectorPrologueCallback() for more information.
1019  */
1020 void QDeclarativeVMEMetaObject::VarPropertiesWeakReferenceCallback(v8::Persistent<v8::Value> object, void* parameter)
1021 {
1022     QDeclarativeVMEMetaObject *vmemo = static_cast<QDeclarativeVMEMetaObject*>(parameter);
1023     Q_ASSERT(vmemo);
1024     qPersistentDispose(object);
1025     vmemo->varProperties.Clear();
1026 }
1027
1028 void QDeclarativeVMEMetaObject::GcPrologueCallback(QV8GCCallback::Node *node)
1029 {
1030     QDeclarativeVMEMetaObject *vmemo = static_cast<QDeclarativeVMEMetaObject*>(node);
1031     Q_ASSERT(vmemo);
1032     if (!vmemo->varPropertiesInitialized || vmemo->varProperties.IsEmpty() || !vmemo->ctxt || !vmemo->ctxt->engine)
1033         return;
1034     QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(vmemo->ctxt->engine);
1035     ep->v8engine()->addRelationshipForGC(vmemo->object, vmemo->varProperties);
1036 }
1037
1038 bool QDeclarativeVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const
1039 {
1040     Q_ASSERT(index >= propOffset + metaData->propertyCount);
1041
1042     *target = 0;
1043     *coreIndex = -1;
1044     *valueTypeIndex = -1;
1045
1046     if (!ctxt)
1047         return false;
1048
1049     QDeclarativeVMEMetaData::AliasData *d = metaData->aliasData() + (index - propOffset - metaData->propertyCount);
1050     QDeclarativeContext *context = ctxt->asQDeclarativeContext();
1051     QDeclarativeContextPrivate *ctxtPriv = QDeclarativeContextPrivate::get(context);
1052
1053     *target = ctxtPriv->data->idValues[d->contextIdx].data();
1054     if (!*target)
1055         return false;
1056
1057     if (d->isObjectAlias()) {
1058     } else if (d->isValueTypeAlias()) {
1059         *coreIndex = d->propertyIndex();
1060         *valueTypeIndex = d->valueTypeIndex();
1061     } else {
1062         *coreIndex = d->propertyIndex();
1063     }
1064
1065     return true;
1066 }
1067
1068 void QDeclarativeVMEMetaObject::connectAlias(int aliasId)
1069 {
1070     if (!aConnected.testBit(aliasId)) {
1071
1072         if (!aliasEndpoints)
1073             aliasEndpoints = new QDeclarativeVMEMetaObjectEndpoint[metaData->aliasCount];
1074
1075         aConnected.setBit(aliasId);
1076
1077         QDeclarativeVMEMetaData::AliasData *d = metaData->aliasData() + aliasId;
1078
1079         QDeclarativeVMEMetaObjectEndpoint *endpoint = aliasEndpoints + aliasId;
1080         endpoint->metaObject = this;
1081
1082         endpoint->connect(&ctxt->idValues[d->contextIdx].bindings);
1083
1084         endpoint->tryConnect();
1085     }
1086 }
1087
1088 void QDeclarativeVMEMetaObject::connectAliasSignal(int index)
1089 {
1090     int aliasId = (index - methodOffset) - metaData->propertyCount;
1091     if (aliasId < 0 || aliasId >= metaData->aliasCount)
1092         return;
1093
1094     connectAlias(aliasId);
1095 }
1096
1097 QT_END_NAMESPACE