Remove QQmlData::objectNameChanged callback.
[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
51 #include <QtCore/qdebug.h>
52
53 #include <ctype.h> // for toupper
54
55 #ifdef Q_CC_MSVC
56 // nonstandard extension used : zero-sized array in struct/union.
57 #  pragma warning( disable : 4200 )
58 #endif
59
60 Q_DECLARE_METATYPE(QJSValue)
61 Q_DECLARE_METATYPE(QQmlV8Handle);
62
63 QT_BEGIN_NAMESPACE
64
65 #define Q_INT16_MAX 32767
66
67 class QQmlPropertyCacheMethodArguments 
68 {
69 public:
70     QQmlPropertyCacheMethodArguments *next;
71     int arguments[0];
72 };
73
74 // Flags that do *NOT* depend on the property's QMetaProperty::userType() and thus are quick
75 // to load
76 static QQmlPropertyData::Flags fastFlagsForProperty(const QMetaProperty &p)
77 {
78     QQmlPropertyData::Flags flags;
79
80     if (p.isConstant())
81         flags |= QQmlPropertyData::IsConstant;
82     if (p.isWritable())
83         flags |= QQmlPropertyData::IsWritable;
84     if (p.isResettable())
85         flags |= QQmlPropertyData::IsResettable;
86     if (p.isFinal())
87         flags |= QQmlPropertyData::IsFinal;
88     if (p.isEnumType())
89         flags |= QQmlPropertyData::IsEnumType;
90
91     return flags;
92 }
93
94 // Flags that do depend on the property's QMetaProperty::userType() and thus are slow to 
95 // load
96 static QQmlPropertyData::Flags flagsForPropertyType(int propType, QQmlEngine *engine)
97 {
98     Q_ASSERT(propType != -1);
99
100     QQmlPropertyData::Flags flags;
101
102     if (propType == QMetaType::QObjectStar || propType == QMetaType::QWidgetStar) {
103         flags |= QQmlPropertyData::IsQObjectDerived;
104     } else if (propType == QMetaType::QVariant) {
105         flags |= QQmlPropertyData::IsQVariant;
106     } else if (propType < (int)QVariant::UserType) {
107     } else if (propType == qMetaTypeId<QQmlBinding *>()) {
108         flags |= QQmlPropertyData::IsQmlBinding;
109     } else if (propType == qMetaTypeId<QJSValue>()) {
110         flags |= QQmlPropertyData::IsQJSValue;
111     } else if (propType == qMetaTypeId<QQmlV8Handle>()) {
112         flags |= QQmlPropertyData::IsV8Handle;
113     } else {
114         QQmlMetaType::TypeCategory cat = 
115             engine ? QQmlEnginePrivate::get(engine)->typeCategory(propType)
116                    : QQmlMetaType::typeCategory(propType);
117
118         if (cat == QQmlMetaType::Object)
119             flags |= QQmlPropertyData::IsQObjectDerived;
120         else if (cat == QQmlMetaType::List)
121             flags |= QQmlPropertyData::IsQList;
122     }
123
124     return flags;
125 }
126
127 static int metaObjectSignalCount(const QMetaObject *metaObject)
128 {
129     int signalCount = 0;
130     for (const QMetaObject *obj = metaObject; obj; obj = obj->superClass())
131         signalCount += QMetaObjectPrivate::get(obj)->signalCount;
132     return signalCount;
133 }
134
135 QQmlPropertyData::Flags
136 QQmlPropertyData::flagsForProperty(const QMetaProperty &p, QQmlEngine *engine)
137 {
138     return fastFlagsForProperty(p) | flagsForPropertyType(p.userType(), engine);
139 }
140
141 void QQmlPropertyData::lazyLoad(const QMetaProperty &p, QQmlEngine *engine)
142 {
143     Q_UNUSED(engine);
144
145     coreIndex = p.propertyIndex();
146     notifyIndex = p.notifySignalIndex();
147     Q_ASSERT(p.revision() <= Q_INT16_MAX);
148     revision = p.revision();
149
150     flags = fastFlagsForProperty(p);
151
152     int type = p.type();
153     if (type == QMetaType::QObjectStar || type == QMetaType::QWidgetStar) {
154         propType = type;
155         flags |= QQmlPropertyData::IsQObjectDerived;
156     } else if (type == QMetaType::QVariant) {
157         propType = type;
158         flags |= QQmlPropertyData::IsQVariant;
159     } else if (type == QVariant::UserType || type == -1) {
160         propTypeName = p.typeName();
161         flags |= QQmlPropertyData::NotFullyResolved;
162     } else {
163         propType = type;
164     }
165 }
166
167 void QQmlPropertyData::load(const QMetaProperty &p, QQmlEngine *engine)
168 {
169     propType = p.userType();
170     coreIndex = p.propertyIndex();
171     notifyIndex = p.notifySignalIndex();
172     flags = fastFlagsForProperty(p) | flagsForPropertyType(propType, engine);
173     Q_ASSERT(p.revision() <= Q_INT16_MAX);
174     revision = p.revision();
175 }
176
177 void QQmlPropertyData::load(const QMetaMethod &m)
178 {
179     coreIndex = m.methodIndex();
180     arguments = 0;
181     flags |= IsFunction;
182     if (m.methodType() == QMetaMethod::Signal)
183         flags |= IsSignal;
184     propType = m.returnType();
185
186     if (m.parameterCount()) {
187         flags |= HasArguments;
188         if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV8Function*")) {
189             flags |= IsV8Function;
190         }
191     }
192
193     Q_ASSERT(m.revision() <= Q_INT16_MAX);
194     revision = m.revision();
195 }
196
197 void QQmlPropertyData::lazyLoad(const QMetaMethod &m)
198 {
199     coreIndex = m.methodIndex();
200     arguments = 0;
201     flags |= IsFunction;
202     if (m.methodType() == QMetaMethod::Signal)
203         flags |= IsSignal;
204     propType = QMetaType::Void;
205
206     const char *returnType = m.typeName();
207     Q_ASSERT(returnType != 0);
208     if ((*returnType != 'v') || (qstrcmp(returnType+1, "oid") != 0)) {
209         propTypeName = returnType;
210         flags |= NotFullyResolved;
211     }
212
213     if (m.parameterCount()) {
214         flags |= HasArguments;
215         if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV8Function*")) {
216             flags |= IsV8Function;
217         }
218     }
219
220     Q_ASSERT(m.revision() <= Q_INT16_MAX);
221     revision = m.revision();
222 }
223
224 /*!
225 Creates a new empty QQmlPropertyCache.
226 */
227 QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e)
228 : engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
229   signalHanderIndexCacheStart(0), metaObject(0), argumentsCache(0)
230 {
231     Q_ASSERT(engine);
232 }
233
234 /*!
235 Creates a new QQmlPropertyCache of \a metaObject.
236 */
237 QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e, const QMetaObject *metaObject)
238 : engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
239   signalHanderIndexCacheStart(0), metaObject(0), argumentsCache(0)
240 {
241     Q_ASSERT(engine);
242     Q_ASSERT(metaObject);
243
244     update(engine, metaObject);
245 }
246
247 QQmlPropertyCache::~QQmlPropertyCache()
248 {
249     clear();
250
251     QQmlPropertyCacheMethodArguments *args = argumentsCache;
252     while (args) {
253         QQmlPropertyCacheMethodArguments *next = args->next;
254         free(args);
255         args = next;
256     }
257
258     // We must clear this prior to releasing the parent incase it is a
259     // linked hash
260     stringCache.clear();
261     if (parent) parent->release();
262     parent = 0;
263     engine = 0;
264 }
265
266 void QQmlPropertyCache::destroy()
267 {
268     Q_ASSERT(engine || constructor.IsEmpty());
269     if (constructor.IsEmpty())
270         delete this;
271     else
272         QQmlEnginePrivate::deleteInEngineThread(engine, this);
273 }
274
275 // This is inherited from QQmlCleanup, so it should only clear the things
276 // that are tied to the specific QQmlEngine.
277 void QQmlPropertyCache::clear()
278 {
279     qPersistentDispose(constructor);
280     engine = 0;
281 }
282
283 QQmlPropertyCache *QQmlPropertyCache::copy(int reserve)
284 {
285     QQmlPropertyCache *cache = new QQmlPropertyCache(engine);
286     cache->parent = this;
287     cache->parent->addref();
288     cache->propertyIndexCacheStart = propertyIndexCache.count() + propertyIndexCacheStart;
289     cache->methodIndexCacheStart = methodIndexCache.count() + methodIndexCacheStart;
290     cache->signalHanderIndexCacheStart = signalHandlerIndexCache.count() + signalHanderIndexCacheStart;
291     cache->stringCache.linkAndReserve(stringCache, reserve);
292     cache->allowedRevisionCache = allowedRevisionCache;
293     cache->metaObject = metaObject;
294
295     // We specifically do *NOT* copy the constructor
296
297     return cache;
298 }
299
300 QQmlPropertyCache *QQmlPropertyCache::copy()
301 {
302     return copy(0);
303 }
304
305 QQmlPropertyCache *
306 QQmlPropertyCache::copyAndAppend(QQmlEngine *engine, const QMetaObject *metaObject,
307                                          QQmlPropertyData::Flag propertyFlags,
308                                          QQmlPropertyData::Flag methodFlags,
309                                          QQmlPropertyData::Flag signalFlags)
310 {
311     return copyAndAppend(engine, metaObject, -1, propertyFlags, methodFlags, signalFlags);
312 }
313
314 QQmlPropertyCache *
315 QQmlPropertyCache::copyAndAppend(QQmlEngine *engine, const QMetaObject *metaObject,
316                                          int revision,
317                                          QQmlPropertyData::Flag propertyFlags,
318                                          QQmlPropertyData::Flag methodFlags,
319                                          QQmlPropertyData::Flag signalFlags)
320 {
321     Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
322
323     // Reserve enough space in the name hash for all the methods (including signals), all the
324     // signal handlers and all the properties.  This assumes no name clashes, but this is the
325     // common case.
326     QQmlPropertyCache *rv = copy(QMetaObjectPrivate::get(metaObject)->methodCount +
327                                          QMetaObjectPrivate::get(metaObject)->signalCount +
328                                          QMetaObjectPrivate::get(metaObject)->propertyCount);
329
330     rv->append(engine, metaObject, revision, propertyFlags, methodFlags, signalFlags);
331
332     return rv;
333 }
334
335 void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject, 
336                                        QQmlPropertyData::Flag propertyFlags,
337                                        QQmlPropertyData::Flag methodFlags,
338                                        QQmlPropertyData::Flag signalFlags)
339 {
340     append(engine, metaObject, -1, propertyFlags, methodFlags, signalFlags);
341 }
342
343 void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject, 
344                                        int revision, 
345                                        QQmlPropertyData::Flag propertyFlags,
346                                        QQmlPropertyData::Flag methodFlags,
347                                        QQmlPropertyData::Flag signalFlags)
348 {
349     Q_UNUSED(revision);
350     Q_ASSERT(constructor.IsEmpty()); // We should not be appending to an in-use property cache
351
352     this->metaObject = metaObject;
353
354     bool dynamicMetaObject = isDynamicMetaObject(metaObject);
355
356     allowedRevisionCache.append(0);
357
358     int methodCount = metaObject->methodCount();
359     Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 4);
360     int signalCount = metaObjectSignalCount(metaObject);
361     int classInfoCount = QMetaObjectPrivate::get(metaObject)->classInfoCount;
362
363     QQmlAccessorProperties::Properties accessorProperties;
364
365     if (classInfoCount) {
366         int classInfoOffset = metaObject->classInfoOffset();
367         bool hasFastProperty = false;
368         for (int ii = 0; ii < classInfoCount; ++ii) {
369             int idx = ii + classInfoOffset;
370
371             if (0 == qstrcmp(metaObject->classInfo(idx).name(), "qt_HasQmlAccessors")) {
372                 hasFastProperty = true;
373                 break;
374             }
375         }
376
377         if (hasFastProperty) {
378             accessorProperties = QQmlAccessorProperties::properties(metaObject);
379             if (accessorProperties.count == 0)
380                 qFatal("QQmlPropertyCache: %s has FastProperty class info, but has not "
381                        "installed property accessors", metaObject->className());
382         } else {
383 #ifndef QT_NO_DEBUG
384             accessorProperties = QQmlAccessorProperties::properties(metaObject);
385             if (accessorProperties.count != 0)
386                 qFatal("QQmlPropertyCache: %s has fast property accessors, but is missing "
387                        "FastProperty class info", metaObject->className());
388 #endif
389         }
390     }
391
392     //Used to block access to QObject::destroyed() and QObject::deleteLater() from QML
393     static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
394     static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()");
395     static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()");
396
397     int methodOffset = metaObject->methodOffset();
398     int signalOffset = signalCount - QMetaObjectPrivate::get(metaObject)->signalCount;
399
400     // update() should have reserved enough space in the vector that this doesn't cause a realloc
401     // and invalidate the stringCache.
402     methodIndexCache.resize(methodCount - methodIndexCacheStart);
403     signalHandlerIndexCache.resize(signalCount - signalHanderIndexCacheStart);
404     int signalHandlerIndex = signalOffset;
405     for (int ii = methodOffset; ii < methodCount; ++ii) {
406         if (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx)
407             continue;
408         QMetaMethod m = metaObject->method(ii);
409         if (m.access() == QMetaMethod::Private) 
410             continue;
411
412         // Extract method name
413         const char *signature;
414         if (QMetaObjectPrivate::get(metaObject)->revision >= 7) {
415             // Safe to use the raw name pointer
416             signature = m.name().constData();
417         } else {
418             // Safe to use the raw signature pointer
419             signature = m.methodSignature().constData();
420         }
421         const char *cptr = signature;
422         char utf8 = 0;
423         while (*cptr && *cptr != '(') {
424             Q_ASSERT(*cptr != 0);
425             utf8 |= *cptr & 0x80;
426             ++cptr;
427         }
428
429         QQmlPropertyData *data = &methodIndexCache[ii - methodIndexCacheStart];
430         QQmlPropertyData *sigdata = 0;
431
432         data->lazyLoad(m);
433
434         if (data->isSignal())
435             data->flags |= signalFlags;
436         else
437             data->flags |= methodFlags;
438
439         if (!dynamicMetaObject)
440             data->flags |= QQmlPropertyData::IsDirect;
441
442         Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
443         data->metaObjectOffset = allowedRevisionCache.count() - 1;
444
445         if (data->isSignal()) {
446             sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHanderIndexCacheStart];
447             *sigdata = *data;
448             sigdata->flags |= QQmlPropertyData::IsSignalHandler;
449         }
450
451         QQmlPropertyData *old = 0;
452
453         if (utf8) {
454             QHashedString methodName(QString::fromUtf8(signature, cptr - signature));
455             if (QQmlPropertyData **it = stringCache.value(methodName))
456                 old = *it;
457             stringCache.insert(methodName, data);
458
459             if (data->isSignal()) {
460                 QHashedString on(QStringLiteral("on") % methodName.at(0).toUpper() % methodName.midRef(1));
461                 stringCache.insert(on, sigdata);
462                 ++signalHandlerIndex;
463             }
464         } else {
465             QHashedCStringRef methodName(signature, cptr - signature);
466             if (QQmlPropertyData **it = stringCache.value(methodName))
467                 old = *it;
468             stringCache.insert(methodName, data);
469
470             if (data->isSignal()) {
471                 int length = methodName.length();
472
473                 QVarLengthArray<char, 128> str(length+3);
474                 str[0] = 'o';
475                 str[1] = 'n';
476                 str[2] = toupper(signature[0]);
477                 if (length > 1)
478                     memcpy(&str[3], &signature[1], length - 1);
479                 str[length + 2] = '\0';
480
481                 QHashedString on(QString::fromLatin1(str.data()));
482                 stringCache.insert(on, sigdata);
483                 ++signalHandlerIndex;
484             }
485         }
486
487         if (old) {
488             // We only overload methods in the same class, exactly like C++
489             if (old->isFunction() && old->coreIndex >= methodOffset)
490                 data->flags |= QQmlPropertyData::IsOverload;
491             data->overrideIndexIsProperty = !old->isFunction();
492             data->overrideIndex = old->coreIndex;
493         }
494     }
495
496     int propCount = metaObject->propertyCount();
497     int propOffset = metaObject->propertyOffset();
498
499     // update() should have reserved enough space in the vector that this doesn't cause a realloc
500     // and invalidate the stringCache.
501     propertyIndexCache.resize(propCount - propertyIndexCacheStart);
502     for (int ii = propOffset; ii < propCount; ++ii) {
503         QMetaProperty p = metaObject->property(ii);
504         if (!p.isScriptable())
505             continue;
506
507         const char *str = p.name();
508         char utf8 = 0;
509         const char *cptr = str;
510         while (*cptr != 0) {
511             utf8 |= *cptr & 0x80;
512             ++cptr;
513         }
514
515         QQmlPropertyData *data = &propertyIndexCache[ii - propertyIndexCacheStart];
516
517         data->lazyLoad(p, engine);
518         data->flags |= propertyFlags;
519
520         if (!dynamicMetaObject) 
521             data->flags |= QQmlPropertyData::IsDirect;
522
523         Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
524         data->metaObjectOffset = allowedRevisionCache.count() - 1;
525
526         QQmlPropertyData *old = 0;
527
528         if (utf8) {
529             QHashedString propName(QString::fromUtf8(str, cptr - str));
530             if (QQmlPropertyData **it = stringCache.value(propName))
531                 old = *it;
532             stringCache.insert(propName, data);
533         } else {
534             QHashedCStringRef propName(str, cptr - str);
535             if (QQmlPropertyData **it = stringCache.value(propName))
536                 old = *it;
537             stringCache.insert(propName, data);
538         }
539
540         QQmlAccessorProperties::Property *accessorProperty = accessorProperties.property(str);
541
542         // Fast properties may not be overrides or revisioned
543         Q_ASSERT(accessorProperty == 0 || (old == 0 && data->revision == 0));
544
545         if (accessorProperty) {
546             data->flags |= QQmlPropertyData::HasAccessors;
547             data->accessors = accessorProperty->accessors;
548             data->accessorData = accessorProperty->data;
549         } else if (old) {
550             data->overrideIndexIsProperty = !old->isFunction();
551             data->overrideIndex = old->coreIndex;
552         }
553     }
554 }
555
556 void QQmlPropertyCache::resolve(QQmlPropertyData *data) const
557 {
558     Q_ASSERT(data->notFullyResolved());
559
560     data->propType = QMetaType::type(data->propTypeName);
561
562     if (!data->isFunction())
563         data->flags |= flagsForPropertyType(data->propType, engine);
564
565     data->flags &= ~QQmlPropertyData::NotFullyResolved;
566 }
567
568 void QQmlPropertyCache::updateRecur(QQmlEngine *engine, const QMetaObject *metaObject)
569 {
570     if (!metaObject)
571         return;
572
573     updateRecur(engine, metaObject->superClass());
574
575     append(engine, metaObject);
576 }
577
578 void QQmlPropertyCache::update(QQmlEngine *engine, const QMetaObject *metaObject)
579 {
580     Q_ASSERT(engine);
581     Q_ASSERT(metaObject);
582     Q_ASSERT(stringCache.isEmpty());
583
584     // Preallocate enough space in the index caches for all the properties/methods/signals that
585     // are not cached in a parent cache so that the caches never need to be reallocated as this
586     // would invalidate pointers stored in the stringCache.
587     int pc = metaObject->propertyCount();
588     int mc = metaObject->methodCount();
589     int sc = metaObjectSignalCount(metaObject);
590     propertyIndexCache.reserve(pc - propertyIndexCacheStart);
591     methodIndexCache.reserve(mc - methodIndexCacheStart);
592     signalHandlerIndexCache.reserve(sc - signalHanderIndexCacheStart);
593
594     // Reserve enough space in the stringCache for all properties/methods/signals including those
595     // cached in a parent cache.
596     stringCache.reserve(pc + mc + sc);
597
598     updateRecur(engine,metaObject);
599 }
600
601 QQmlPropertyData *
602 QQmlPropertyCache::property(int index) const
603 {
604     if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count()))
605         return 0;
606     
607     if (index < propertyIndexCacheStart)
608         return parent->property(index);
609
610     QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
611     if (rv->notFullyResolved()) resolve(rv);
612     return rv;
613 }
614
615 QQmlPropertyData *
616 QQmlPropertyCache::method(int index) const
617 {
618     if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
619         return 0;
620
621     if (index < methodIndexCacheStart)
622         return parent->method(index);
623
624     QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
625     if (rv->notFullyResolved()) resolve(rv);
626     return rv;
627 }
628
629 QQmlPropertyData *
630 QQmlPropertyCache::property(const QHashedStringRef &str) const
631 {
632     QQmlPropertyData **rv = stringCache.value(str);
633     if (rv && (*rv)->notFullyResolved()) resolve(*rv);
634     return rv?*rv:0;
635 }
636
637 QQmlPropertyData *
638 QQmlPropertyCache::property(const QHashedCStringRef &str) const
639 {
640     QQmlPropertyData **rv = stringCache.value(str);
641     if (rv && (*rv)->notFullyResolved()) resolve(*rv);
642     return rv?*rv:0;
643 }
644
645 QQmlPropertyData *
646 QQmlPropertyCache::property(const QString &str) const
647 {
648     QQmlPropertyData **rv = stringCache.value(str);
649     if (rv && (*rv)->notFullyResolved()) resolve(*rv);
650     return rv?*rv:0;
651 }
652
653 QString QQmlPropertyData::name(QObject *object)
654 {
655     if (!object)
656         return QString();
657
658     return name(object->metaObject());
659 }
660
661 QString QQmlPropertyData::name(const QMetaObject *metaObject)
662 {
663     if (!metaObject || coreIndex == -1)
664         return QString();
665
666     if (flags & IsFunction) {
667         QMetaMethod m = metaObject->method(coreIndex);
668
669         return QString::fromUtf8(m.name().constData());
670     } else {
671         QMetaProperty p = metaObject->property(coreIndex);
672         return QString::fromUtf8(p.name());
673     }
674 }
675
676 QStringList QQmlPropertyCache::propertyNames() const
677 {
678     QStringList keys;
679     for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) 
680         keys.append(iter.key());
681     return keys;
682 }
683
684 struct StaticQtMetaObject : public QObject
685 {
686     static const QMetaObject *get()
687         { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
688 };
689
690 static int EnumType(const QMetaObject *metaobj, const QByteArray &str, int type)
691 {
692     QByteArray scope;
693     QByteArray name;
694     int scopeIdx = str.lastIndexOf("::");
695     if (scopeIdx != -1) {
696         scope = str.left(scopeIdx);
697         name = str.mid(scopeIdx + 2);
698     } else { 
699         name = str;
700     }
701     const QMetaObject *meta;
702     if (scope == "Qt")
703         meta = StaticQtMetaObject::get();
704     else
705         meta = metaobj;
706     for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
707         QMetaEnum m = meta->enumerator(i);
708         if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
709             return QVariant::Int;
710     }
711     return type;
712 }
713
714 // Returns an array of the arguments for method \a index.  The first entry in the array
715 // is the number of arguments.
716 int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index, 
717                                                      QVarLengthArray<int, 9> &dummy,
718                                                      QByteArray *unknownTypeError)
719 {
720     Q_ASSERT(object && index >= 0);
721
722     QQmlData *ddata = QQmlData::get(object, false);
723
724     if (ddata && ddata->propertyCache) {
725         typedef QQmlPropertyCacheMethodArguments A;
726
727         QQmlPropertyCache *c = ddata->propertyCache;
728         Q_ASSERT(index < c->methodIndexCacheStart + c->methodIndexCache.count());
729
730         while (index < c->methodIndexCacheStart)
731             c = c->parent;
732
733         QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&c->methodIndexCache.at(index - c->methodIndexCacheStart));
734
735         if (rv->arguments)  
736             return static_cast<A *>(rv->arguments)->arguments;
737
738         const QMetaObject *metaObject = object->metaObject();
739         QMetaMethod m = metaObject->method(index);
740
741         int argc = m.parameterCount();
742         A *args = static_cast<A *>(malloc(sizeof(A) + (argc + 1) * sizeof(int)));
743         args->arguments[0] = argc;
744         QList<QByteArray> argTypeNames; // Only loaded if needed
745
746         for (int ii = 0; ii < argc; ++ii) {
747             int type = m.parameterType(ii);
748             QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
749             if (flags & QMetaType::IsEnumeration)
750                 type = QVariant::Int;
751             else if (type == QMetaType::UnknownType ||
752                      (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
753                       type != qMetaTypeId<QJSValue>())) {
754                 //the UserType clause is to catch registered QFlags
755                 if (argTypeNames.isEmpty())
756                     argTypeNames = m.parameterTypes();
757                 type = EnumType(object->metaObject(), argTypeNames.at(ii), type);
758             }
759             if (type == QMetaType::UnknownType) {
760                 if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
761                 free(args);
762                 return 0;
763             }
764             args->arguments[ii + 1] = type;
765         }
766
767         rv->arguments = args;
768         args->next = c->argumentsCache;
769         c->argumentsCache = args;
770         return static_cast<A *>(rv->arguments)->arguments;
771
772     } else {
773         QMetaMethod m = object->metaObject()->method(index);
774         int argc = m.parameterCount();
775         dummy.resize(argc + 1);
776         dummy[0] = argc;
777         QList<QByteArray> argTypeNames; // Only loaded if needed
778
779         for (int ii = 0; ii < argc; ++ii) {
780             int type = m.parameterType(ii);
781             QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
782             if (flags & QMetaType::IsEnumeration)
783                 type = QVariant::Int;
784             else if (type == QMetaType::UnknownType ||
785                      (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
786                       type != qMetaTypeId<QJSValue>())) {
787                 //the UserType clause is to catch registered QFlags)
788                 if (argTypeNames.isEmpty())
789                     argTypeNames = m.parameterTypes();
790                 type = EnumType(object->metaObject(), argTypeNames.at(ii), type);
791             }
792             if (type == QMetaType::UnknownType) {
793                 if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
794                 return 0;
795             }
796             dummy[ii + 1] = type;
797         }
798
799         return dummy.data();
800     }
801 }
802
803 QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject,
804                                                          const QString &property)
805 {
806     Q_ASSERT(metaObject);
807
808     QQmlPropertyData rv;
809     {
810         const QMetaObject *cmo = metaObject;
811         const QByteArray propertyName = property.toUtf8();
812         while (cmo) {
813             int idx = cmo->indexOfProperty(propertyName);
814             if (idx != -1) {
815                 QMetaProperty p = cmo->property(idx);
816                 if (p.isScriptable()) {
817                     rv.load(p);
818                     return rv;
819                 } else {
820                     while (cmo && cmo->propertyOffset() >= idx)
821                         cmo = cmo->superClass();
822                 }
823             } else {
824                 cmo = 0;
825             }
826         }
827     }
828
829     //Used to block access to QObject::destroyed() and QObject::deleteLater() from QML
830     static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
831     static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()");
832     static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()");
833
834     int methodCount = metaObject->methodCount();
835     for (int ii = methodCount - 1; ii >= 0; --ii) {
836         if (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx)
837             continue;
838         QMetaMethod m = metaObject->method(ii);
839         if (m.access() == QMetaMethod::Private)
840             continue;
841         QString methodName = QString::fromUtf8(m.name().constData());
842
843         if (methodName == property) {
844             rv.load(m);
845             return rv;
846         }
847     }
848
849     return rv;
850 }
851
852 inline const QString &qQmlPropertyCacheToString(const QString &string)
853 {
854     return string;
855 }
856
857 inline QString qQmlPropertyCacheToString(const QHashedV8String &string)
858 {
859     return QV8Engine::toStringStatic(string.string());
860 }
861
862 template<typename T>
863 QQmlPropertyData *
864 qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj,
865                                   const T &name, QQmlPropertyData &local)
866 {
867     QQmlPropertyCache *cache = 0;
868
869     if (engine) {
870         QQmlData *ddata = QQmlData::get(obj);
871
872         if (ddata && ddata->propertyCache) {
873             cache = ddata->propertyCache;
874         } else if (engine) {
875             QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
876             cache = ep->cache(obj);
877             if (cache) {
878                 ddata = QQmlData::get(obj, true);
879                 cache->addref();
880                 ddata->propertyCache = cache;
881             }
882         }
883     }
884
885     QQmlPropertyData *rv = 0;
886
887     if (cache) {
888         rv = cache->property(name);
889     } else {
890         local = qQmlPropertyCacheCreate(obj->metaObject(),
891                                                 qQmlPropertyCacheToString(name));
892         if (local.isValid())
893             rv = &local;
894     }
895
896     return rv;
897 }
898
899 QQmlPropertyData *
900 QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj, 
901                                     const QHashedV8String &name, QQmlPropertyData &local)
902 {
903     return qQmlPropertyCacheProperty<QHashedV8String>(engine, obj, name, local);
904 }
905
906 QQmlPropertyData *
907 QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj,
908                                     const QString &name, QQmlPropertyData &local)
909 {
910     return qQmlPropertyCacheProperty<QString>(engine, obj, name, local);
911 }
912
913 static inline const QMetaObjectPrivate *priv(const uint* data)
914 { return reinterpret_cast<const QMetaObjectPrivate*>(data); }
915
916 bool QQmlPropertyCache::isDynamicMetaObject(const QMetaObject *mo)
917 {
918     return priv(mo->d.data)->revision >= 3 && priv(mo->d.data)->flags & DynamicMetaObject;
919 }
920
921 QT_END_NAMESPACE