d922b9942a68bd8fe69620b0725d33a4af068f95
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmlpropertycache.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 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 #include "qqmlpropertycache_p.h"
43
44 #include "qqmlengine_p.h"
45 #include "qqmlbinding_p.h"
46 #include <private/qv8engine_p.h>
47
48 #include <private/qmetaobject_p.h>
49 #include <private/qqmlaccessors_p.h>
50 #include <private/qmetaobjectbuilder_p.h>
51
52 #include <QtCore/qdebug.h>
53
54 #include <ctype.h> // for toupper
55
56 #ifdef Q_CC_MSVC
57 // nonstandard extension used : zero-sized array in struct/union.
58 #  pragma warning( disable : 4200 )
59 #endif
60
61 Q_DECLARE_METATYPE(QJSValue)
62 Q_DECLARE_METATYPE(QQmlV8Handle);
63
64 QT_BEGIN_NAMESPACE
65
66 #define Q_INT16_MAX 32767
67
68 class QQmlPropertyCacheMethodArguments 
69 {
70 public:
71     QQmlPropertyCacheMethodArguments *next;
72
73     QList<QByteArray> *names;
74     int arguments[0];
75 };
76
77 // Flags that do *NOT* depend on the property's QMetaProperty::userType() and thus are quick
78 // to load
79 static QQmlPropertyData::Flags fastFlagsForProperty(const QMetaProperty &p)
80 {
81     QQmlPropertyData::Flags flags;
82
83     if (p.isConstant())
84         flags |= QQmlPropertyData::IsConstant;
85     if (p.isWritable())
86         flags |= QQmlPropertyData::IsWritable;
87     if (p.isResettable())
88         flags |= QQmlPropertyData::IsResettable;
89     if (p.isFinal())
90         flags |= QQmlPropertyData::IsFinal;
91     if (p.isEnumType())
92         flags |= QQmlPropertyData::IsEnumType;
93
94     return flags;
95 }
96
97 // Flags that do depend on the property's QMetaProperty::userType() and thus are slow to 
98 // load
99 static QQmlPropertyData::Flags flagsForPropertyType(int propType, QQmlEngine *engine)
100 {
101     Q_ASSERT(propType != -1);
102
103     QQmlPropertyData::Flags flags;
104
105     if (propType == QMetaType::QObjectStar || propType == QMetaType::QWidgetStar) {
106         flags |= QQmlPropertyData::IsQObjectDerived;
107     } else if (propType == QMetaType::QVariant) {
108         flags |= QQmlPropertyData::IsQVariant;
109     } else if (propType < (int)QVariant::UserType) {
110     } else if (propType == qMetaTypeId<QQmlBinding *>()) {
111         flags |= QQmlPropertyData::IsQmlBinding;
112     } else if (propType == qMetaTypeId<QJSValue>()) {
113         flags |= QQmlPropertyData::IsQJSValue;
114     } else if (propType == qMetaTypeId<QQmlV8Handle>()) {
115         flags |= QQmlPropertyData::IsV8Handle;
116     } else {
117         QQmlMetaType::TypeCategory cat = 
118             engine ? QQmlEnginePrivate::get(engine)->typeCategory(propType)
119                    : QQmlMetaType::typeCategory(propType);
120
121         if (cat == QQmlMetaType::Object)
122             flags |= QQmlPropertyData::IsQObjectDerived;
123         else if (cat == QQmlMetaType::List)
124             flags |= QQmlPropertyData::IsQList;
125     }
126
127     return flags;
128 }
129
130 static int metaObjectSignalCount(const QMetaObject *metaObject)
131 {
132     int signalCount = 0;
133     for (const QMetaObject *obj = metaObject; obj; obj = obj->superClass())
134         signalCount += QMetaObjectPrivate::get(obj)->signalCount;
135     return signalCount;
136 }
137
138 QQmlPropertyData::Flags
139 QQmlPropertyData::flagsForProperty(const QMetaProperty &p, QQmlEngine *engine)
140 {
141     return fastFlagsForProperty(p) | flagsForPropertyType(p.userType(), engine);
142 }
143
144 void QQmlPropertyData::lazyLoad(const QMetaProperty &p, QQmlEngine *engine)
145 {
146     Q_UNUSED(engine);
147
148     coreIndex = p.propertyIndex();
149     notifyIndex = QMetaObjectPrivate::signalIndex(p.notifySignal());
150     Q_ASSERT(p.revision() <= Q_INT16_MAX);
151     revision = p.revision();
152
153     flags = fastFlagsForProperty(p);
154
155     int type = p.type();
156     if (type == QMetaType::QObjectStar || type == QMetaType::QWidgetStar) {
157         propType = type;
158         flags |= QQmlPropertyData::IsQObjectDerived;
159     } else if (type == QMetaType::QVariant) {
160         propType = type;
161         flags |= QQmlPropertyData::IsQVariant;
162     } else if (type == QVariant::UserType || type == -1) {
163         propTypeName = p.typeName();
164         flags |= QQmlPropertyData::NotFullyResolved;
165     } else {
166         propType = type;
167     }
168 }
169
170 void QQmlPropertyData::load(const QMetaProperty &p, QQmlEngine *engine)
171 {
172     propType = p.userType();
173     coreIndex = p.propertyIndex();
174     notifyIndex = QMetaObjectPrivate::signalIndex(p.notifySignal());
175     flags = fastFlagsForProperty(p) | flagsForPropertyType(propType, engine);
176     Q_ASSERT(p.revision() <= Q_INT16_MAX);
177     revision = p.revision();
178 }
179
180 void QQmlPropertyData::load(const QMetaMethod &m)
181 {
182     coreIndex = m.methodIndex();
183     arguments = 0;
184     flags |= IsFunction;
185     if (m.methodType() == QMetaMethod::Signal)
186         flags |= IsSignal;
187     propType = m.returnType();
188
189     if (m.parameterCount()) {
190         flags |= HasArguments;
191         if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV8Function*")) {
192             flags |= IsV8Function;
193         }
194     }
195
196     if (m.attributes() & QMetaMethod::Cloned)
197         flags |= IsCloned;
198
199     Q_ASSERT(m.revision() <= Q_INT16_MAX);
200     revision = m.revision();
201 }
202
203 void QQmlPropertyData::lazyLoad(const QMetaMethod &m)
204 {
205     coreIndex = m.methodIndex();
206     arguments = 0;
207     flags |= IsFunction;
208     if (m.methodType() == QMetaMethod::Signal)
209         flags |= IsSignal;
210     propType = QMetaType::Void;
211
212     const char *returnType = m.typeName();
213     if (!returnType)
214         returnType = "\0";
215     if ((*returnType != 'v') || (qstrcmp(returnType+1, "oid") != 0)) {
216         propTypeName = returnType;
217         flags |= NotFullyResolved;
218     }
219
220     if (m.parameterCount()) {
221         flags |= HasArguments;
222         if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV8Function*")) {
223             flags |= IsV8Function;
224         }
225     }
226
227     if (m.attributes() & QMetaMethod::Cloned)
228         flags |= IsCloned;
229
230     Q_ASSERT(m.revision() <= Q_INT16_MAX);
231     revision = m.revision();
232 }
233
234 /*!
235 Creates a new empty QQmlPropertyCache.
236 */
237 QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e)
238 : engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
239   signalHandlerIndexCacheStart(0), _ownMetaObject(false), _metaObject(0), argumentsCache(0)
240 {
241     Q_ASSERT(engine);
242 }
243
244 /*!
245 Creates a new QQmlPropertyCache of \a metaObject.
246 */
247 QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e, const QMetaObject *metaObject)
248 : engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
249   signalHandlerIndexCacheStart(0), _ownMetaObject(false), _metaObject(0), argumentsCache(0)
250 {
251     Q_ASSERT(engine);
252     Q_ASSERT(metaObject);
253
254     update(engine, metaObject);
255 }
256
257 QQmlPropertyCache::~QQmlPropertyCache()
258 {
259     clear();
260
261     QQmlPropertyCacheMethodArguments *args = argumentsCache;
262     while (args) {
263         QQmlPropertyCacheMethodArguments *next = args->next;
264         if (args->names) delete args->names;
265         free(args);
266         args = next;
267     }
268
269     // We must clear this prior to releasing the parent incase it is a
270     // linked hash
271     stringCache.clear();
272     if (_parent) _parent->release();
273
274     if (_ownMetaObject) free((void *)_metaObject);
275     _metaObject = 0;
276     _parent = 0;
277     engine = 0;
278 }
279
280 void QQmlPropertyCache::destroy()
281 {
282     Q_ASSERT(engine || constructor.IsEmpty());
283     if (constructor.IsEmpty())
284         delete this;
285     else
286         QQmlEnginePrivate::deleteInEngineThread(engine, this);
287 }
288
289 // This is inherited from QQmlCleanup, so it should only clear the things
290 // that are tied to the specific QQmlEngine.
291 void QQmlPropertyCache::clear()
292 {
293     qPersistentDispose(constructor);
294     engine = 0;
295 }
296
297 QQmlPropertyCache *QQmlPropertyCache::copy(int reserve)
298 {
299     QQmlPropertyCache *cache = new QQmlPropertyCache(engine);
300     cache->_parent = this;
301     cache->_parent->addref();
302     cache->propertyIndexCacheStart = propertyIndexCache.count() + propertyIndexCacheStart;
303     cache->methodIndexCacheStart = methodIndexCache.count() + methodIndexCacheStart;
304     cache->signalHandlerIndexCacheStart = signalHandlerIndexCache.count() + signalHandlerIndexCacheStart;
305     cache->stringCache.linkAndReserve(stringCache, reserve);
306     cache->allowedRevisionCache = allowedRevisionCache;
307     cache->_metaObject = _metaObject;
308     cache->_defaultPropertyName = _defaultPropertyName;
309
310     // We specifically do *NOT* copy the constructor
311
312     return cache;
313 }
314
315 QQmlPropertyCache *QQmlPropertyCache::copy()
316 {
317     return copy(0);
318 }
319
320 QQmlPropertyCache *QQmlPropertyCache::copyAndReserve(QQmlEngine *, int propertyCount, int methodCount,
321                                                      int signalCount)
322 {
323     QQmlPropertyCache *rv = copy(propertyCount + methodCount + signalCount);
324     rv->propertyIndexCache.reserve(propertyCount);
325     rv->methodIndexCache.reserve(methodCount);
326     rv->signalHandlerIndexCache.reserve(signalCount);
327     rv->_metaObject = 0;
328
329     return rv;
330 }
331
332 /*! \internal
333
334     \a notifyIndex MUST be in the signal index range (see QObjectPrivate::signalIndex()).
335     This is different from QMetaMethod::methodIndex().
336 */
337 void QQmlPropertyCache::appendProperty(const QString &name,
338                                        quint32 flags, int coreIndex, int propType, int notifyIndex)
339 {
340     QQmlPropertyData data;
341     data.propType = propType;
342     data.coreIndex = coreIndex;
343     data.notifyIndex = notifyIndex;
344     data.flags = flags;
345
346     QHashedString string(name);
347     if (QQmlPropertyData **old = stringCache.value(string)) {
348         data.overrideIndexIsProperty = !(*old)->isFunction();
349         data.overrideIndex = (*old)->coreIndex;
350     }
351
352     propertyIndexCache.append(data);
353
354     stringCache.insert(string, propertyIndexCache.data() + propertyIndexCache.count() - 1);
355 }
356
357 void QQmlPropertyCache::appendProperty(const QHashedCStringRef &name,
358                                        quint32 flags, int coreIndex, int propType, int notifyIndex)
359 {
360     QQmlPropertyData data;
361     data.propType = propType;
362     data.coreIndex = coreIndex;
363     data.notifyIndex = notifyIndex;
364     data.flags = flags;
365
366     if (QQmlPropertyData **old = stringCache.value(name)) {
367         data.overrideIndexIsProperty = !(*old)->isFunction();
368         data.overrideIndex = (*old)->coreIndex;
369     }
370
371     propertyIndexCache.append(data);
372
373     stringCache.insert(name, propertyIndexCache.data() + propertyIndexCache.count() - 1);
374 }
375
376 void QQmlPropertyCache::appendSignal(const QString &name, quint32 flags, int coreIndex,
377                                      const int *types, const QList<QByteArray> &names)
378 {
379     QQmlPropertyData data;
380     data.propType = QVariant::Invalid;
381     data.coreIndex = coreIndex;
382     data.flags = flags;
383     data.arguments = 0;
384
385     QQmlPropertyData handler = data;
386     handler.flags |= QQmlPropertyData::IsSignalHandler;
387
388     if (types) {
389         int argumentCount = *types;
390         typedef QQmlPropertyCacheMethodArguments A;
391         A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
392         ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int));
393         args->names = new QList<QByteArray>(names);
394         args->next = argumentsCache;
395         argumentsCache = args;
396         data.arguments = args;
397     }
398
399     QString handlerName = QLatin1String("on") + name;
400     handlerName[2] = handlerName[2].toUpper();
401
402     QHashedString string(name);
403     if (QQmlPropertyData **old = stringCache.value(string)) {
404         data.overrideIndexIsProperty = !(*old)->isFunction();
405         data.overrideIndex = (*old)->coreIndex;
406     }
407
408     methodIndexCache.append(data);
409     signalHandlerIndexCache.append(handler);
410
411     stringCache.insert(string, methodIndexCache.data() + methodIndexCache.count() - 1);
412     stringCache.insert(handlerName, signalHandlerIndexCache.data() + signalHandlerIndexCache.count() - 1);
413 }
414
415 void QQmlPropertyCache::appendSignal(const QHashedCStringRef &name, quint32 flags, int coreIndex,
416                                      const int *types, const QList<QByteArray> &names)
417 {
418     QQmlPropertyData data;
419     data.propType = QVariant::Invalid;
420     data.coreIndex = coreIndex;
421     data.flags = flags;
422     data.arguments = 0;
423
424     QQmlPropertyData handler = data;
425     handler.flags |= QQmlPropertyData::IsSignalHandler;
426
427     if (types) {
428         int argumentCount = *types;
429         typedef QQmlPropertyCacheMethodArguments A;
430         A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
431         ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int));
432         args->names = new QList<QByteArray>(names);
433         args->next = argumentsCache;
434         argumentsCache = args;
435         data.arguments = args;
436     }
437
438     QString handlerName = QLatin1String("on") + name.toUtf16();
439     handlerName[2] = handlerName[2].toUpper();
440
441     if (QQmlPropertyData **old = stringCache.value(name)) {
442         data.overrideIndexIsProperty = !(*old)->isFunction();
443         data.overrideIndex = (*old)->coreIndex;
444     }
445
446     methodIndexCache.append(data);
447     signalHandlerIndexCache.append(handler);
448
449     stringCache.insert(name, methodIndexCache.data() + methodIndexCache.count() - 1);
450     stringCache.insert(handlerName, signalHandlerIndexCache.data() + signalHandlerIndexCache.count() - 1);
451 }
452
453 void QQmlPropertyCache::appendMethod(const QString &name, quint32 flags, int coreIndex,
454                                      const QList<QByteArray> &names)
455 {
456     int argumentCount = names.count();
457
458     QQmlPropertyData data;
459     data.propType = QMetaType::QVariant;
460     data.coreIndex = coreIndex;
461
462     typedef QQmlPropertyCacheMethodArguments A;
463     A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
464     args->arguments[0] = argumentCount;
465     for (int ii = 0; ii < argumentCount; ++ii)
466         args->arguments[ii + 1] = QMetaType::QVariant;
467     args->names = 0;
468     if (argumentCount)
469         args->names = new QList<QByteArray>(names);
470     args->next = argumentsCache;
471     argumentsCache = args;
472     data.arguments = args;
473
474     data.flags = flags;
475
476     QHashedString string(name);
477     if (QQmlPropertyData **old = stringCache.value(string)) {
478         data.overrideIndexIsProperty = !(*old)->isFunction();
479         data.overrideIndex = (*old)->coreIndex;
480     }
481
482     methodIndexCache.append(data);
483
484     stringCache.insert(string, methodIndexCache.data() + methodIndexCache.count() - 1);
485 }
486
487 void QQmlPropertyCache::appendMethod(const QHashedCStringRef &name, quint32 flags, int coreIndex,
488                                      const QList<QByteArray> &names)
489 {
490     int argumentCount = names.count();
491
492     QQmlPropertyData data;
493     data.propType = QMetaType::QVariant;
494     data.coreIndex = coreIndex;
495
496     typedef QQmlPropertyCacheMethodArguments A;
497     A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
498     args->arguments[0] = argumentCount;
499     for (int ii = 0; ii < argumentCount; ++ii)
500         args->arguments[ii + 1] = QMetaType::QVariant;
501     args->names = 0;
502     if (argumentCount)
503         args->names = new QList<QByteArray>(names);
504     args->next = argumentsCache;
505     argumentsCache = args;
506     data.arguments = args;
507
508     data.flags = flags;
509
510     if (QQmlPropertyData **old = stringCache.value(name)) {
511         data.overrideIndexIsProperty = !(*old)->isFunction();
512         data.overrideIndex = (*old)->coreIndex;
513     }
514
515     methodIndexCache.append(data);
516
517     stringCache.insert(name, methodIndexCache.data() + methodIndexCache.count() - 1);
518 }
519
520 // Returns this property cache's metaObject.  May be null if it hasn't been created yet.
521 const QMetaObject *QQmlPropertyCache::metaObject() const
522 {
523     return _metaObject;
524 }
525
526 // Returns this property cache's metaObject, creating it if necessary.
527 const QMetaObject *QQmlPropertyCache::createMetaObject()
528 {
529     if (!_metaObject) {
530         _ownMetaObject = true;
531
532         QMetaObjectBuilder builder;
533         toMetaObjectBuilder(builder);
534         builder.setSuperClass(_parent->createMetaObject());
535         _metaObject = builder.toMetaObject();
536     }
537
538     return _metaObject;
539 }
540
541 // Returns the name of the default property for this cache
542 QString QQmlPropertyCache::defaultPropertyName() const
543 {
544     return _defaultPropertyName;
545 }
546
547 QQmlPropertyData *QQmlPropertyCache::defaultProperty() const
548 {
549     return property(defaultPropertyName());
550 }
551
552 QQmlPropertyCache *QQmlPropertyCache::parent() const
553 {
554     return _parent;
555 }
556
557 // Returns the first C++ type's QMetaObject - that is, the first QMetaObject not created by
558 // QML
559 const QMetaObject *QQmlPropertyCache::firstCppMetaObject() const
560 {
561     while (_parent && (_metaObject == 0 || _ownMetaObject))
562         return _parent->firstCppMetaObject();
563     return _metaObject;
564 }
565
566 QQmlPropertyCache *
567 QQmlPropertyCache::copyAndAppend(QQmlEngine *engine, const QMetaObject *metaObject,
568                                          QQmlPropertyData::Flag propertyFlags,
569                                          QQmlPropertyData::Flag methodFlags,
570                                          QQmlPropertyData::Flag signalFlags)
571 {
572     return copyAndAppend(engine, metaObject, -1, propertyFlags, methodFlags, signalFlags);
573 }
574
575 QQmlPropertyCache *
576 QQmlPropertyCache::copyAndAppend(QQmlEngine *engine, const QMetaObject *metaObject,
577                                          int revision,
578                                          QQmlPropertyData::Flag propertyFlags,
579                                          QQmlPropertyData::Flag methodFlags,
580                                          QQmlPropertyData::Flag signalFlags)
581 {
582     Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
583
584     // Reserve enough space in the name hash for all the methods (including signals), all the
585     // signal handlers and all the properties.  This assumes no name clashes, but this is the
586     // common case.
587     QQmlPropertyCache *rv = copy(QMetaObjectPrivate::get(metaObject)->methodCount +
588                                          QMetaObjectPrivate::get(metaObject)->signalCount +
589                                          QMetaObjectPrivate::get(metaObject)->propertyCount);
590
591     rv->append(engine, metaObject, revision, propertyFlags, methodFlags, signalFlags);
592
593     return rv;
594 }
595
596 void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject, 
597                                        int revision, 
598                                        QQmlPropertyData::Flag propertyFlags,
599                                        QQmlPropertyData::Flag methodFlags,
600                                        QQmlPropertyData::Flag signalFlags)
601 {
602     Q_UNUSED(revision);
603     Q_ASSERT(constructor.IsEmpty()); // We should not be appending to an in-use property cache
604
605     _metaObject = metaObject;
606
607     bool dynamicMetaObject = isDynamicMetaObject(metaObject);
608
609     allowedRevisionCache.append(0);
610
611     int methodCount = metaObject->methodCount();
612     Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
613     int signalCount = metaObjectSignalCount(metaObject);
614     int classInfoCount = QMetaObjectPrivate::get(metaObject)->classInfoCount;
615
616     QQmlAccessorProperties::Properties accessorProperties;
617
618     if (classInfoCount) {
619         int classInfoOffset = metaObject->classInfoOffset();
620         bool hasFastProperty = false;
621         for (int ii = 0; ii < classInfoCount; ++ii) {
622             int idx = ii + classInfoOffset;
623
624             if (0 == qstrcmp(metaObject->classInfo(idx).name(), "qt_HasQmlAccessors")) {
625                 hasFastProperty = true;
626             } else if (0 == qstrcmp(metaObject->classInfo(idx).name(), "DefaultProperty")) {
627                 _defaultPropertyName = QString::fromUtf8(metaObject->classInfo(idx).value());
628             }
629         }
630
631         if (hasFastProperty) {
632             accessorProperties = QQmlAccessorProperties::properties(metaObject);
633             if (accessorProperties.count == 0)
634                 qFatal("QQmlPropertyCache: %s has FastProperty class info, but has not "
635                        "installed property accessors", metaObject->className());
636         } else {
637 #ifndef QT_NO_DEBUG
638             accessorProperties = QQmlAccessorProperties::properties(metaObject);
639             if (accessorProperties.count != 0)
640                 qFatal("QQmlPropertyCache: %s has fast property accessors, but is missing "
641                        "FastProperty class info", metaObject->className());
642 #endif
643         }
644     }
645
646     //Used to block access to QObject::destroyed() and QObject::deleteLater() from QML
647     static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
648     static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()");
649     static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()");
650
651     int methodOffset = metaObject->methodOffset();
652     int signalOffset = signalCount - QMetaObjectPrivate::get(metaObject)->signalCount;
653
654     // update() should have reserved enough space in the vector that this doesn't cause a realloc
655     // and invalidate the stringCache.
656     methodIndexCache.resize(methodCount - methodIndexCacheStart);
657     signalHandlerIndexCache.resize(signalCount - signalHandlerIndexCacheStart);
658     int signalHandlerIndex = signalOffset;
659     for (int ii = methodOffset; ii < methodCount; ++ii) {
660         if (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx)
661             continue;
662         QMetaMethod m = metaObject->method(ii);
663         if (m.access() == QMetaMethod::Private) 
664             continue;
665
666         // Extract method name
667         // It's safe to keep the raw name pointer
668         Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 7);
669         const char *rawName = m.name().constData();
670         const char *cptr = rawName;
671         char utf8 = 0;
672         while (*cptr) {
673             utf8 |= *cptr & 0x80;
674             ++cptr;
675         }
676
677         QQmlPropertyData *data = &methodIndexCache[ii - methodIndexCacheStart];
678         QQmlPropertyData *sigdata = 0;
679
680         data->lazyLoad(m);
681
682         if (data->isSignal())
683             data->flags |= signalFlags;
684         else
685             data->flags |= methodFlags;
686
687         if (!dynamicMetaObject)
688             data->flags |= QQmlPropertyData::IsDirect;
689
690         Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
691         data->metaObjectOffset = allowedRevisionCache.count() - 1;
692
693         if (data->isSignal()) {
694             sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHandlerIndexCacheStart];
695             *sigdata = *data;
696             sigdata->flags |= QQmlPropertyData::IsSignalHandler;
697         }
698
699         QQmlPropertyData *old = 0;
700
701         if (utf8) {
702             QHashedString methodName(QString::fromUtf8(rawName, cptr - rawName));
703             if (QQmlPropertyData **it = stringCache.value(methodName))
704                 old = *it;
705             stringCache.insert(methodName, data);
706
707             if (data->isSignal()) {
708                 QHashedString on(QStringLiteral("on") % methodName.at(0).toUpper() % methodName.midRef(1));
709                 stringCache.insert(on, sigdata);
710                 ++signalHandlerIndex;
711             }
712         } else {
713             QHashedCStringRef methodName(rawName, cptr - rawName);
714             if (QQmlPropertyData **it = stringCache.value(methodName))
715                 old = *it;
716             stringCache.insert(methodName, data);
717
718             if (data->isSignal()) {
719                 int length = methodName.length();
720
721                 QVarLengthArray<char, 128> str(length+3);
722                 str[0] = 'o';
723                 str[1] = 'n';
724                 str[2] = toupper(rawName[0]);
725                 if (length > 1)
726                     memcpy(&str[3], &rawName[1], length - 1);
727                 str[length + 2] = '\0';
728
729                 QHashedString on(QString::fromLatin1(str.data()));
730                 stringCache.insert(on, sigdata);
731                 ++signalHandlerIndex;
732             }
733         }
734
735         if (old) {
736             // We only overload methods in the same class, exactly like C++
737             if (old->isFunction() && old->coreIndex >= methodOffset)
738                 data->flags |= QQmlPropertyData::IsOverload;
739             data->overrideIndexIsProperty = !old->isFunction();
740             data->overrideIndex = old->coreIndex;
741         }
742     }
743
744     int propCount = metaObject->propertyCount();
745     int propOffset = metaObject->propertyOffset();
746
747     // update() should have reserved enough space in the vector that this doesn't cause a realloc
748     // and invalidate the stringCache.
749     propertyIndexCache.resize(propCount - propertyIndexCacheStart);
750     for (int ii = propOffset; ii < propCount; ++ii) {
751         QMetaProperty p = metaObject->property(ii);
752         if (!p.isScriptable())
753             continue;
754
755         const char *str = p.name();
756         char utf8 = 0;
757         const char *cptr = str;
758         while (*cptr != 0) {
759             utf8 |= *cptr & 0x80;
760             ++cptr;
761         }
762
763         QQmlPropertyData *data = &propertyIndexCache[ii - propertyIndexCacheStart];
764
765         data->lazyLoad(p, engine);
766         data->flags |= propertyFlags;
767
768         if (!dynamicMetaObject) 
769             data->flags |= QQmlPropertyData::IsDirect;
770
771         Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
772         data->metaObjectOffset = allowedRevisionCache.count() - 1;
773
774         QQmlPropertyData *old = 0;
775
776         if (utf8) {
777             QHashedString propName(QString::fromUtf8(str, cptr - str));
778             if (QQmlPropertyData **it = stringCache.value(propName))
779                 old = *it;
780             stringCache.insert(propName, data);
781         } else {
782             QHashedCStringRef propName(str, cptr - str);
783             if (QQmlPropertyData **it = stringCache.value(propName))
784                 old = *it;
785             stringCache.insert(propName, data);
786         }
787
788         QQmlAccessorProperties::Property *accessorProperty = accessorProperties.property(str);
789
790         // Fast properties may not be overrides or revisioned
791         Q_ASSERT(accessorProperty == 0 || (old == 0 && data->revision == 0));
792
793         if (accessorProperty) {
794             data->flags |= QQmlPropertyData::HasAccessors;
795             data->accessors = accessorProperty->accessors;
796             data->accessorData = accessorProperty->data;
797         } else if (old) {
798             data->overrideIndexIsProperty = !old->isFunction();
799             data->overrideIndex = old->coreIndex;
800         }
801     }
802 }
803
804 void QQmlPropertyCache::resolve(QQmlPropertyData *data) const
805 {
806     Q_ASSERT(data->notFullyResolved());
807
808     data->propType = QMetaType::type(data->propTypeName);
809
810     if (!data->isFunction())
811         data->flags |= flagsForPropertyType(data->propType, engine);
812
813     data->flags &= ~QQmlPropertyData::NotFullyResolved;
814 }
815
816 void QQmlPropertyCache::updateRecur(QQmlEngine *engine, const QMetaObject *metaObject)
817 {
818     if (!metaObject)
819         return;
820
821     updateRecur(engine, metaObject->superClass());
822
823     append(engine, metaObject, -1);
824 }
825
826 void QQmlPropertyCache::update(QQmlEngine *engine, const QMetaObject *metaObject)
827 {
828     Q_ASSERT(engine);
829     Q_ASSERT(metaObject);
830     Q_ASSERT(stringCache.isEmpty());
831
832     // Preallocate enough space in the index caches for all the properties/methods/signals that
833     // are not cached in a parent cache so that the caches never need to be reallocated as this
834     // would invalidate pointers stored in the stringCache.
835     int pc = metaObject->propertyCount();
836     int mc = metaObject->methodCount();
837     int sc = metaObjectSignalCount(metaObject);
838     propertyIndexCache.reserve(pc - propertyIndexCacheStart);
839     methodIndexCache.reserve(mc - methodIndexCacheStart);
840     signalHandlerIndexCache.reserve(sc - signalHandlerIndexCacheStart);
841
842     // Reserve enough space in the stringCache for all properties/methods/signals including those
843     // cached in a parent cache.
844     stringCache.reserve(pc + mc + sc);
845
846     updateRecur(engine,metaObject);
847 }
848
849 /*! \internal
850     \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
851     This is different from QMetaMethod::methodIndex().
852 */
853 QQmlPropertyData *
854 QQmlPropertyCache::signal(int index) const
855 {
856     if (index < 0 || index >= (signalHandlerIndexCacheStart + signalHandlerIndexCache.count()))
857         return 0;
858
859     if (index < signalHandlerIndexCacheStart)
860         return _parent->signal(index);
861
862     QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - signalHandlerIndexCacheStart));
863     if (rv->notFullyResolved()) resolve(rv);
864     Q_ASSERT(rv->isSignal() || rv->coreIndex == -1);
865     return rv;
866 }
867
868 int QQmlPropertyCache::methodIndexToSignalIndex(int index) const
869 {
870     if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
871         return index;
872
873     if (index < methodIndexCacheStart)
874         return _parent->methodIndexToSignalIndex(index);
875
876     return index - methodIndexCacheStart + signalHandlerIndexCacheStart;
877 }
878
879 QQmlPropertyData *
880 QQmlPropertyCache::property(int index) const
881 {
882     if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count()))
883         return 0;
884     
885     if (index < propertyIndexCacheStart)
886         return _parent->property(index);
887
888     QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
889     if (rv->notFullyResolved()) resolve(rv);
890     return rv;
891 }
892
893 QQmlPropertyData *
894 QQmlPropertyCache::method(int index) const
895 {
896     if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
897         return 0;
898
899     if (index < methodIndexCacheStart)
900         return _parent->method(index);
901
902     QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
903     if (rv->notFullyResolved()) resolve(rv);
904     return rv;
905 }
906
907 QQmlPropertyData *
908 QQmlPropertyCache::property(const QHashedStringRef &str) const
909 {
910     QQmlPropertyData **rv = stringCache.value(str);
911     if (rv && (*rv)->notFullyResolved()) resolve(*rv);
912     return rv?*rv:0;
913 }
914
915 QQmlPropertyData *
916 QQmlPropertyCache::property(const QHashedCStringRef &str) const
917 {
918     QQmlPropertyData **rv = stringCache.value(str);
919     if (rv && (*rv)->notFullyResolved()) resolve(*rv);
920     return rv?*rv:0;
921 }
922
923 QQmlPropertyData *
924 QQmlPropertyCache::property(const QString &str) const
925 {
926     QQmlPropertyData **rv = stringCache.value(str);
927     if (rv && (*rv)->notFullyResolved()) resolve(*rv);
928     return rv?*rv:0;
929 }
930
931 QString QQmlPropertyData::name(QObject *object)
932 {
933     if (!object)
934         return QString();
935
936     return name(object->metaObject());
937 }
938
939 QString QQmlPropertyData::name(const QMetaObject *metaObject)
940 {
941     if (!metaObject || coreIndex == -1)
942         return QString();
943
944     if (flags & IsFunction) {
945         QMetaMethod m = metaObject->method(coreIndex);
946
947         return QString::fromUtf8(m.name().constData());
948     } else {
949         QMetaProperty p = metaObject->property(coreIndex);
950         return QString::fromUtf8(p.name());
951     }
952 }
953
954 QStringList QQmlPropertyCache::propertyNames() const
955 {
956     QStringList keys;
957     for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) 
958         keys.append(iter.key());
959     return keys;
960 }
961
962 struct StaticQtMetaObject : public QObject
963 {
964     static const QMetaObject *get()
965         { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
966 };
967
968 static int EnumType(const QMetaObject *metaobj, const QByteArray &str, int type)
969 {
970     QByteArray scope;
971     QByteArray name;
972     int scopeIdx = str.lastIndexOf("::");
973     if (scopeIdx != -1) {
974         scope = str.left(scopeIdx);
975         name = str.mid(scopeIdx + 2);
976     } else { 
977         name = str;
978     }
979     const QMetaObject *meta;
980     if (scope == "Qt")
981         meta = StaticQtMetaObject::get();
982     else
983         meta = metaobj;
984     for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
985         QMetaEnum m = meta->enumerator(i);
986         if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
987             return QVariant::Int;
988     }
989     return type;
990 }
991
992 /*! \internal
993     \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
994     This is different from QMetaMethod::methodIndex().
995 */
996 QList<QByteArray> QQmlPropertyCache::signalParameterNames(QObject *object, int index)
997 {
998     QQmlData *data = QQmlData::get(object, false);
999     if (data->propertyCache) {
1000         QQmlPropertyData *p = data->propertyCache->signal(index);
1001         if (!p->hasArguments())
1002             return QList<QByteArray>();
1003     }
1004
1005     return QMetaObjectPrivate::signal(object->metaObject(), index).parameterNames();
1006 }
1007
1008 // Returns an array of the arguments for method \a index.  The first entry in the array
1009 // is the number of arguments.
1010 int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index, 
1011                                                      QVarLengthArray<int, 9> &dummy,
1012                                                      QByteArray *unknownTypeError)
1013 {
1014     Q_ASSERT(object && index >= 0);
1015
1016     QQmlData *ddata = QQmlData::get(object, false);
1017
1018     if (ddata && ddata->propertyCache) {
1019         typedef QQmlPropertyCacheMethodArguments A;
1020
1021         QQmlPropertyCache *c = ddata->propertyCache;
1022         Q_ASSERT(index < c->methodIndexCacheStart + c->methodIndexCache.count());
1023
1024         while (index < c->methodIndexCacheStart)
1025             c = c->_parent;
1026
1027         QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&c->methodIndexCache.at(index - c->methodIndexCacheStart));
1028
1029         if (rv->arguments)  
1030             return static_cast<A *>(rv->arguments)->arguments;
1031
1032         const QMetaObject *metaObject = c->createMetaObject();
1033         Q_ASSERT(metaObject);
1034         QMetaMethod m = metaObject->method(index);
1035
1036         int argc = m.parameterCount();
1037         A *args = static_cast<A *>(malloc(sizeof(A) + (argc + 1) * sizeof(int)));
1038         args->arguments[0] = argc;
1039         args->names = 0;
1040         QList<QByteArray> argTypeNames; // Only loaded if needed
1041
1042         for (int ii = 0; ii < argc; ++ii) {
1043             int type = m.parameterType(ii);
1044             QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
1045             if (flags & QMetaType::IsEnumeration)
1046                 type = QVariant::Int;
1047             else if (type == QMetaType::UnknownType ||
1048                      (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
1049                       type != qMetaTypeId<QJSValue>())) {
1050                 //the UserType clause is to catch registered QFlags
1051                 if (argTypeNames.isEmpty())
1052                     argTypeNames = m.parameterTypes();
1053                 type = EnumType(object->metaObject(), argTypeNames.at(ii), type);
1054             }
1055             if (type == QMetaType::UnknownType) {
1056                 if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
1057                 free(args);
1058                 return 0;
1059             }
1060             args->arguments[ii + 1] = type;
1061         }
1062
1063         rv->arguments = args;
1064         args->next = c->argumentsCache;
1065         c->argumentsCache = args;
1066         return static_cast<A *>(rv->arguments)->arguments;
1067
1068     } else {
1069         QMetaMethod m = object->metaObject()->method(index);
1070         int argc = m.parameterCount();
1071         dummy.resize(argc + 1);
1072         dummy[0] = argc;
1073         QList<QByteArray> argTypeNames; // Only loaded if needed
1074
1075         for (int ii = 0; ii < argc; ++ii) {
1076             int type = m.parameterType(ii);
1077             QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
1078             if (flags & QMetaType::IsEnumeration)
1079                 type = QVariant::Int;
1080             else if (type == QMetaType::UnknownType ||
1081                      (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
1082                       type != qMetaTypeId<QJSValue>())) {
1083                 //the UserType clause is to catch registered QFlags)
1084                 if (argTypeNames.isEmpty())
1085                     argTypeNames = m.parameterTypes();
1086                 type = EnumType(object->metaObject(), argTypeNames.at(ii), type);
1087             }
1088             if (type == QMetaType::UnknownType) {
1089                 if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
1090                 return 0;
1091             }
1092             dummy[ii + 1] = type;
1093         }
1094
1095         return dummy.data();
1096     }
1097 }
1098
1099 // Returns the return type of the method.
1100 int QQmlPropertyCache::methodReturnType(QObject *object, const QQmlPropertyData &data,
1101                                         QByteArray *unknownTypeError)
1102 {
1103     Q_ASSERT(object && data.coreIndex >= 0);
1104
1105     int type = data.propType;
1106
1107     const char *propTypeName = 0;
1108
1109     if (type == QMetaType::UnknownType) {
1110         // Find the return type name from the method info
1111         QMetaMethod m;
1112
1113         QQmlData *ddata = QQmlData::get(object, false);
1114         if (ddata && ddata->propertyCache) {
1115             QQmlPropertyCache *c = ddata->propertyCache;
1116             Q_ASSERT(data.coreIndex < c->methodIndexCacheStart + c->methodIndexCache.count());
1117
1118             while (data.coreIndex < c->methodIndexCacheStart)
1119                 c = c->_parent;
1120
1121             const QMetaObject *metaObject = c->createMetaObject();
1122             Q_ASSERT(metaObject);
1123             m = metaObject->method(data.coreIndex);
1124         } else {
1125             m = object->metaObject()->method(data.coreIndex);
1126         }
1127
1128         type = m.returnType();
1129         propTypeName = m.typeName();
1130     }
1131
1132     QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
1133     if (flags & QMetaType::IsEnumeration) {
1134         type = QVariant::Int;
1135     } else if (type == QMetaType::UnknownType ||
1136                (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
1137                type != qMetaTypeId<QJSValue>())) {
1138         //the UserType clause is to catch registered QFlags
1139         type = EnumType(object->metaObject(), propTypeName, type);
1140     }
1141
1142     if (type == QMetaType::UnknownType) {
1143         if (unknownTypeError) *unknownTypeError = propTypeName;
1144     }
1145
1146     return type;
1147 }
1148
1149 QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject, const QString &property)
1150 {
1151     Q_ASSERT(metaObject);
1152
1153     QQmlPropertyData rv;
1154     {
1155         const QMetaObject *cmo = metaObject;
1156         const QByteArray propertyName = property.toUtf8();
1157         while (cmo) {
1158             int idx = cmo->indexOfProperty(propertyName);
1159             if (idx != -1) {
1160                 QMetaProperty p = cmo->property(idx);
1161                 if (p.isScriptable()) {
1162                     rv.load(p);
1163                     return rv;
1164                 } else {
1165                     while (cmo && cmo->propertyOffset() >= idx)
1166                         cmo = cmo->superClass();
1167                 }
1168             } else {
1169                 cmo = 0;
1170             }
1171         }
1172     }
1173
1174     //Used to block access to QObject::destroyed() and QObject::deleteLater() from QML
1175     static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
1176     static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()");
1177     static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()");
1178
1179     int methodCount = metaObject->methodCount();
1180     for (int ii = methodCount - 1; ii >= 0; --ii) {
1181         if (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx)
1182             continue;
1183         QMetaMethod m = metaObject->method(ii);
1184         if (m.access() == QMetaMethod::Private)
1185             continue;
1186         QString methodName = QString::fromUtf8(m.name().constData());
1187
1188         if (methodName == property) {
1189             rv.load(m);
1190             return rv;
1191         }
1192     }
1193
1194     return rv;
1195 }
1196
1197 inline const QString &qQmlPropertyCacheToString(const QString &string)
1198 {
1199     return string;
1200 }
1201
1202 inline QString qQmlPropertyCacheToString(const QHashedV8String &string)
1203 {
1204     return QV8Engine::toStringStatic(string.string());
1205 }
1206
1207 template<typename T>
1208 QQmlPropertyData *
1209 qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, const T &name, QQmlPropertyData &local)
1210 {
1211     QQmlPropertyCache *cache = 0;
1212
1213     QQmlData *ddata = QQmlData::get(obj, false);
1214
1215     if (ddata && ddata->propertyCache) {
1216         cache = ddata->propertyCache;
1217     } else if (engine) {
1218         QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
1219         cache = ep->cache(obj);
1220         if (cache) {
1221             ddata = QQmlData::get(obj, true);
1222             cache->addref();
1223             ddata->propertyCache = cache;
1224         }
1225     }
1226
1227     QQmlPropertyData *rv = 0;
1228
1229     if (cache) {
1230         rv = cache->property(name);
1231     } else {
1232         local = qQmlPropertyCacheCreate(obj->metaObject(), qQmlPropertyCacheToString(name));
1233         if (local.isValid())
1234             rv = &local;
1235     }
1236
1237     return rv;
1238 }
1239
1240 QQmlPropertyData *
1241 QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj, 
1242                                     const QHashedV8String &name, QQmlPropertyData &local)
1243 {
1244     return qQmlPropertyCacheProperty<QHashedV8String>(engine, obj, name, local);
1245 }
1246
1247 QQmlPropertyData *
1248 QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj,
1249                                     const QString &name, QQmlPropertyData &local)
1250 {
1251     return qQmlPropertyCacheProperty<QString>(engine, obj, name, local);
1252 }
1253
1254 static inline const QMetaObjectPrivate *priv(const uint* data)
1255 { return reinterpret_cast<const QMetaObjectPrivate*>(data); }
1256
1257 bool QQmlPropertyCache::isDynamicMetaObject(const QMetaObject *mo)
1258 {
1259     return priv(mo->d.data)->revision >= 3 && priv(mo->d.data)->flags & DynamicMetaObject;
1260 }
1261
1262 const char *QQmlPropertyCache::className() const
1263 {
1264     if (!_ownMetaObject && _metaObject)
1265         return _metaObject->className();
1266     else
1267         return _dynamicClassName.constData();
1268 }
1269
1270 void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
1271 {
1272     struct Sort { static bool lt(const QPair<QString, QQmlPropertyData *> &lhs,
1273                                  const QPair<QString, QQmlPropertyData *> &rhs) {
1274         return lhs.second->coreIndex < rhs.second->coreIndex;
1275     } };
1276
1277     struct Insert { static void in(QQmlPropertyCache *This,
1278                                    QList<QPair<QString, QQmlPropertyData *> > &properties,
1279                                    QList<QPair<QString, QQmlPropertyData *> > &methods,
1280                                    StringCache::ConstIterator iter, QQmlPropertyData *data) {
1281         if (data->isSignalHandler())
1282             return;
1283
1284         if (data->isFunction()) {
1285             if (data->coreIndex < This->methodIndexCacheStart)
1286                 return;
1287
1288             QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
1289             // Overrides can cause the entry to already exist
1290             if (!methods.contains(entry)) methods.append(entry);
1291
1292             data = This->overrideData(data);
1293             if (data && !data->isFunction()) Insert::in(This, properties, methods, iter, data);
1294         } else {
1295             if (data->coreIndex < This->propertyIndexCacheStart)
1296                 return;
1297
1298             QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
1299             // Overrides can cause the entry to already exist
1300             if (!properties.contains(entry)) properties.append(entry);
1301
1302             data = This->overrideData(data);
1303             if (data) Insert::in(This, properties, methods, iter, data);
1304         }
1305
1306     } };
1307
1308     builder.setClassName(_dynamicClassName);
1309
1310     QList<QPair<QString, QQmlPropertyData *> > properties;
1311     QList<QPair<QString, QQmlPropertyData *> > methods;
1312
1313     for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter)
1314         Insert::in(this, properties, methods, iter, iter.value());
1315
1316     Q_ASSERT(properties.count() == propertyIndexCache.count());
1317     Q_ASSERT(methods.count() == methodIndexCache.count());
1318
1319     qSort(properties.begin(), properties.end(), Sort::lt);
1320     qSort(methods.begin(), methods.end(), Sort::lt);
1321
1322     for (int ii = 0; ii < properties.count(); ++ii) {
1323         QQmlPropertyData *data = properties.at(ii).second;
1324
1325         int notifierId = -1;
1326         if (data->notifyIndex != -1)
1327             notifierId = data->notifyIndex - signalHandlerIndexCacheStart;
1328
1329         QMetaPropertyBuilder property = builder.addProperty(properties.at(ii).first.toUtf8(),
1330                                                             QMetaType::typeName(data->propType),
1331                                                             notifierId);
1332
1333         property.setReadable(true);
1334         property.setWritable(data->isWritable());
1335         property.setResettable(data->isResettable());
1336     }
1337
1338     for (int ii = 0; ii < methods.count(); ++ii) {
1339         QQmlPropertyData *data = methods.at(ii).second;
1340
1341         QByteArray returnType;
1342         if (data->propType != 0)
1343             returnType = QMetaType::typeName(data->propType);
1344
1345         QByteArray signature = methods.at(ii).first.toUtf8() + "(";
1346
1347         QQmlPropertyCacheMethodArguments *arguments = 0;
1348         if (data->hasArguments()) {
1349             arguments = (QQmlPropertyCacheMethodArguments *)data->arguments;
1350
1351             for (int ii = 0; ii < arguments->arguments[0]; ++ii) {
1352                 if (ii != 0) signature.append(",");
1353                 signature.append(QMetaType::typeName(arguments->arguments[1 + ii]));
1354             }
1355         }
1356
1357         signature.append(")");
1358
1359         QMetaMethodBuilder method;
1360         if (data->isSignal()) {
1361             method = builder.addSignal(signature);
1362         } else {
1363             method = builder.addSlot(signature);
1364         }
1365         method.setAccess(QMetaMethod::Protected);
1366
1367         if (arguments && arguments->names)
1368             method.setParameterNames(*arguments->names);
1369
1370         if (!returnType.isEmpty())
1371             method.setReturnType(returnType);
1372     }
1373
1374     if (!_defaultPropertyName.isEmpty()) {
1375         QQmlPropertyData *dp = property(_defaultPropertyName);
1376         if (dp && dp->coreIndex >= propertyIndexCacheStart) {
1377             Q_ASSERT(!dp->isFunction());
1378             builder.addClassInfo("DefaultProperty", _defaultPropertyName.toUtf8());
1379         }
1380     }
1381 }
1382
1383 // Returns true if \a from is assignable to a property of type \a to
1384 bool QQmlMetaObject::canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to)
1385 {
1386     Q_ASSERT(!from.isNull() && !to.isNull());
1387
1388     struct I { static bool equal(const QMetaObject *lhs, const QMetaObject *rhs) {
1389         return lhs == rhs || (lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
1390     } };
1391
1392     const QMetaObject *tom = to._m.isT1()?to._m.asT1()->metaObject():to._m.asT2();
1393     if (tom == &QObject::staticMetaObject) return true;
1394
1395     if (from._m.isT1() && to._m.isT1()) { // QQmlPropertyCache -> QQmlPropertyCache
1396         QQmlPropertyCache *fromp = from._m.asT1();
1397         QQmlPropertyCache *top = to._m.asT1();
1398
1399         while (fromp) {
1400             if (fromp == top) return true;
1401             fromp = fromp->parent();
1402         }
1403     } else if (from._m.isT1() && to._m.isT2()) { // QQmlPropertyCache -> QMetaObject
1404         QQmlPropertyCache *fromp = from._m.asT1();
1405
1406         while (fromp) {
1407             const QMetaObject *fromm = fromp->metaObject();
1408             if (fromm && I::equal(fromm, tom)) return true;
1409             fromp = fromp->parent();
1410         }
1411     } else if (from._m.isT2() && to._m.isT1()) { // QMetaObject -> QQmlPropertyCache
1412         const QMetaObject *fromm = from._m.asT2();
1413
1414         if (!tom) return false;
1415
1416         while (fromm) {
1417             if (I::equal(fromm, tom)) return true;
1418             fromm = fromm->superClass();
1419         }
1420     } else { // QMetaObject -> QMetaObject
1421         const QMetaObject *fromm = from._m.asT2();
1422
1423         while (fromm) {
1424             if (I::equal(fromm, tom)) return true;
1425             fromm = fromm->superClass();
1426         }
1427     }
1428
1429     return false;
1430 }
1431
1432 QQmlPropertyCache *QQmlMetaObject::propertyCache(QQmlEnginePrivate *e) const
1433 {
1434     if (_m.isNull()) return 0;
1435     if (_m.isT1()) return _m.asT1();
1436     else return e->cache(_m.asT2());
1437 }
1438
1439 QT_END_NAMESPACE