Permit value types with metatype IDs >= QMetaType::User
[profile/ivi/qtdeclarative.git] / src / qml / qml / qqmlpropertycache_p.h
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #ifndef QQMLPROPERTYCACHE_P_H
43 #define QQMLPROPERTYCACHE_P_H
44
45 //
46 //  W A R N I N G
47 //  -------------
48 //
49 // This file is not part of the Qt API.  It exists purely as an
50 // implementation detail.  This header file may change from version to
51 // version without notice, or even be removed.
52 //
53 // We mean it.
54 //
55
56 #include <private/qqmlrefcount_p.h>
57 #include <private/qflagpointer_p.h>
58 #include "qqmlcleanup_p.h"
59 #include "qqmlnotifier_p.h"
60
61 #include <private/qhashedstring_p.h>
62 #include <QtCore/qvarlengtharray.h>
63 #include <QtCore/qvector.h>
64
65 QT_BEGIN_NAMESPACE
66
67 class QV8Engine;
68 class QMetaProperty;
69 class QV8QObjectWrapper;
70 class QQmlEngine;
71 class QQmlPropertyData;
72 class QQmlAccessors;
73 class QMetaObjectBuilder;
74 class QQmlPropertyCacheMethodArguments;
75
76 // We have this somewhat awful split between RawData and Data so that RawData can be
77 // used in unions.  In normal code, you should always use Data which initializes RawData
78 // to an invalid state on construction.
79 class QQmlPropertyRawData
80 {
81 public:
82     enum Flag {
83         NoFlags           = 0x00000000,
84         ValueTypeFlagMask = 0x0000FFFF, // Flags in valueTypeFlags must fit in this mask
85
86         // Can apply to all properties, except IsFunction
87         IsConstant         = 0x00000001, // Has CONST flag
88         IsWritable         = 0x00000002, // Has WRITE function
89         IsResettable       = 0x00000004, // Has RESET function
90         IsAlias            = 0x00000008, // Is a QML alias to another property
91         IsFinal            = 0x00000010, // Has FINAL flag
92         IsOverridden       = 0x00000020, // Is overridden by a extension property
93         IsDirect           = 0x00000040, // Exists on a C++ QMetaObject
94         HasAccessors       = 0x00000080, // Has property accessors
95
96         // These are mutualy exclusive
97         IsFunction         = 0x00000100, // Is an invokable
98         IsQObjectDerived   = 0x00000200, // Property type is a QObject* derived type
99         IsEnumType         = 0x00000400, // Property type is an enum
100         IsQList            = 0x00000800, // Property type is a QML list
101         IsQmlBinding       = 0x00001000, // Property type is a QQmlBinding*
102         IsQJSValue         = 0x00002000, // Property type is a QScriptValue
103         IsV8Handle         = 0x00004000, // Property type is a QQmlV8Handle
104         IsVarProperty      = 0x00008000, // Property type is a "var" property of VMEMO
105         IsValueTypeVirtual = 0x00010000, // Property is a value type "virtual" property
106         IsQVariant         = 0x00020000, // Property is a QVariant
107
108         // Apply only to IsFunctions
109         IsVMEFunction      = 0x00040000, // Function was added by QML
110         HasArguments       = 0x00080000, // Function takes arguments
111         IsSignal           = 0x00100000, // Function is a signal
112         IsVMESignal        = 0x00200000, // Signal was added by QML
113         IsV8Function       = 0x00400000, // Function takes QQmlV8Function* args
114         IsSignalHandler    = 0x00800000, // Function is a signal handler
115         IsOverload         = 0x01000000, // Function is an overload of another function
116         IsCloned           = 0x02000000, // The function was marked as cloned
117
118         // Internal QQmlPropertyCache flags
119         NotFullyResolved   = 0x04000000, // True if the type data is to be lazily resolved
120
121         // Flags that are set based on the propType field
122         PropTypeFlagMask = IsQObjectDerived | IsEnumType | IsQList | IsQmlBinding | IsQJSValue |
123                            IsV8Handle | IsQVariant,
124     };
125     Q_DECLARE_FLAGS(Flags, Flag)
126
127     Flags getFlags() const { return Flag(flags); }
128     void setFlags(Flags f) { flags = f; }
129
130     bool isValid() const { return coreIndex != -1; }
131
132     bool isConstant() const { return flags & IsConstant; }
133     bool isWritable() const { return flags & IsWritable; }
134     bool isResettable() const { return flags & IsResettable; }
135     bool isAlias() const { return flags & IsAlias; }
136     bool isFinal() const { return flags & IsFinal; }
137     bool isOverridden() const { return flags & IsOverridden; }
138     bool isDirect() const { return flags & IsDirect; }
139     bool hasAccessors() const { return flags & HasAccessors; }
140     bool isFunction() const { return flags & IsFunction; }
141     bool isQObject() const { return flags & IsQObjectDerived; }
142     bool isEnum() const { return flags & IsEnumType; }
143     bool isQList() const { return flags & IsQList; }
144     bool isQmlBinding() const { return flags & IsQmlBinding; }
145     bool isQJSValue() const { return flags & IsQJSValue; }
146     bool isV8Handle() const { return flags & IsV8Handle; }
147     bool isVarProperty() const { return flags & IsVarProperty; }
148     bool isValueTypeVirtual() const { return flags & IsValueTypeVirtual; }
149     bool isQVariant() const { return flags & IsQVariant; }
150     bool isVMEFunction() const { return flags & IsVMEFunction; }
151     bool hasArguments() const { return flags & HasArguments; }
152     bool isSignal() const { return flags & IsSignal; }
153     bool isVMESignal() const { return flags & IsVMESignal; }
154     bool isV8Function() const { return flags & IsV8Function; }
155     bool isSignalHandler() const { return flags & IsSignalHandler; }
156     bool isOverload() const { return flags & IsOverload; }
157     bool isCloned() const { return flags & IsCloned; }
158
159     bool hasOverride() const { return !(flags & IsValueTypeVirtual) &&
160                                       !(flags & HasAccessors) &&
161                                       overrideIndex >= 0; }
162     bool hasRevision() const { return !(flags & HasAccessors) && revision != 0; }
163
164     // Returns -1 if not a value type virtual property
165     inline int getValueTypeCoreIndex() const;
166
167     // Returns the "encoded" index for use with bindings.  Encoding is:
168     //     coreIndex | (valueTypeCoreIndex << 16)
169     inline int encodedIndex() const;
170
171     union {
172         int propType;             // When !NotFullyResolved
173         const char *propTypeName; // When NotFullyResolved
174     };
175     int coreIndex;
176     union {
177         // The notify index is in the range returned by QObjectPrivate::signalIndex().
178         // This is different from QMetaMethod::methodIndex().
179         int notifyIndex;  // When !IsFunction
180         void *arguments;  // When IsFunction && HasArguments
181     };
182
183     union {
184         struct { // When !HasAccessors
185             qint16 revision;
186             qint16 metaObjectOffset;
187
188             union {
189                 struct { // When IsValueTypeVirtual
190                     quint16 valueTypeFlags; // flags of the access property on the value type proxy
191                                             // object
192                     quint16 valueTypePropType; // The QVariant::Type of access property on the value
193                                                // type proxy object
194                     quint16 valueTypeCoreIndex; // The prop index of the access property on the value
195                                                 // type proxy object
196                 };
197
198                 struct { // When !IsValueTypeVirtual
199                     uint overrideIndexIsProperty : 1;
200                     signed int overrideIndex : 31;
201                 };
202             };
203         };
204         struct { // When HasAccessors
205             QQmlAccessors *accessors;
206             intptr_t accessorData;
207         };
208     };
209
210 private:
211     friend class QQmlPropertyData;
212     friend class QQmlPropertyCache;
213     quint32 flags;
214 };
215 Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyRawData::Flags);
216
217 class QQmlPropertyData : public QQmlPropertyRawData
218 {
219 public:
220     inline QQmlPropertyData();
221     inline QQmlPropertyData(const QQmlPropertyRawData &);
222
223     inline bool operator==(const QQmlPropertyRawData &);
224
225     static Flags flagsForProperty(const QMetaProperty &, QQmlEngine *engine = 0);
226     void load(const QMetaProperty &, QQmlEngine *engine = 0);
227     void load(const QMetaMethod &);
228     QString name(QObject *);
229     QString name(const QMetaObject *);
230
231 private:
232     friend class QQmlPropertyCache;
233     void lazyLoad(const QMetaProperty &, QQmlEngine *engine = 0);
234     void lazyLoad(const QMetaMethod &);
235     bool notFullyResolved() const { return flags & NotFullyResolved; }
236 };
237
238 class Q_QML_PRIVATE_EXPORT QQmlPropertyCache : public QQmlRefCount, public QQmlCleanup
239 {
240 public:
241     QQmlPropertyCache(QQmlEngine *);
242     QQmlPropertyCache(QQmlEngine *, const QMetaObject *);
243     virtual ~QQmlPropertyCache();
244
245     void update(QQmlEngine *, const QMetaObject *);
246
247     QQmlPropertyCache *copy();
248
249     QQmlPropertyCache *copyAndAppend(QQmlEngine *, const QMetaObject *,
250                 QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags,
251                 QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags,
252                 QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags);
253     QQmlPropertyCache *copyAndAppend(QQmlEngine *, const QMetaObject *, int revision,
254                 QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags,
255                 QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags,
256                 QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags);
257
258     QQmlPropertyCache *copyAndReserve(QQmlEngine *, int propertyCount,
259                                       int methodCount, int signalCount);
260     void appendProperty(const QString &,
261                         quint32 flags, int coreIndex, int propType, int notifyIndex);
262     void appendProperty(const QHashedCStringRef &,
263                         quint32 flags, int coreIndex, int propType, int notifyIndex);
264     void appendSignal(const QString &, quint32, int coreIndex, const int *types = 0,
265                       const QList<QByteArray> &names = QList<QByteArray>());
266     void appendSignal(const QHashedCStringRef &, quint32, int coreIndex, const int *types = 0,
267                       const QList<QByteArray> &names = QList<QByteArray>());
268     void appendMethod(const QString &, quint32 flags, int coreIndex,
269                       const QList<QByteArray> &names = QList<QByteArray>());
270     void appendMethod(const QHashedCStringRef &, quint32 flags, int coreIndex,
271                       const QList<QByteArray> &names = QList<QByteArray>());
272
273     const QMetaObject *metaObject() const;
274     const QMetaObject *createMetaObject();
275     const QMetaObject *firstCppMetaObject() const;
276
277     inline QQmlPropertyData *property(const QHashedV8String &) const;
278     QQmlPropertyData *property(const QHashedStringRef &) const;
279     QQmlPropertyData *property(const QHashedCStringRef &) const;
280     QQmlPropertyData *property(const QString &) const;
281     QQmlPropertyData *property(int) const;
282     QQmlPropertyData *method(int) const;
283     QQmlPropertyData *signal(int) const;
284     int methodIndexToSignalIndex(int) const;
285     QStringList propertyNames() const;
286
287     QString defaultPropertyName() const;
288     QQmlPropertyData *defaultProperty() const;
289     QQmlPropertyCache *parent() const;
290
291     inline QQmlPropertyData *overrideData(QQmlPropertyData *) const;
292     inline bool isAllowedInRevision(QQmlPropertyData *) const;
293
294     inline QQmlEngine *qmlEngine() const;
295     static QQmlPropertyData *property(QQmlEngine *, QObject *, const QString &,
296                                               QQmlPropertyData &);
297     static QQmlPropertyData *property(QQmlEngine *, QObject *, const QHashedV8String &,
298                                               QQmlPropertyData &);
299     static int *methodParameterTypes(QObject *, int index, QVarLengthArray<int, 9> &dummy,
300                                      QByteArray *unknownTypeError);
301     static int methodReturnType(QObject *, const QQmlPropertyData &data,
302                                 QByteArray *unknownTypeError);
303     static QList<QByteArray> signalParameterNames(QObject *, int index);
304
305     const char *className() const;
306
307     inline int propertyCount() const;
308     inline int propertyOffset() const;
309     inline int methodCount() const;
310     inline int methodOffset() const;
311     inline int signalCount() const;
312     inline int signalOffset() const;
313
314     static bool isDynamicMetaObject(const QMetaObject *);
315
316     void toMetaObjectBuilder(QMetaObjectBuilder &);
317
318 protected:
319     virtual void destroy();
320     virtual void clear();
321
322 private:
323     friend class QQmlEnginePrivate;
324     friend class QV8QObjectWrapper;
325     friend class QQmlCompiler;
326
327     inline QQmlPropertyCache *copy(int reserve);
328
329     void append(QQmlEngine *, const QMetaObject *, int revision,
330                 QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags,
331                 QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags,
332                 QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags);
333
334     // Implemented in v8/qv8qobjectwrapper.cpp
335     v8::Local<v8::Object> newQObject(QObject *, QV8Engine *);
336
337     typedef QVector<QQmlPropertyData> IndexCache;
338     typedef QStringHash<QQmlPropertyData *> StringCache;
339     typedef QVector<int> AllowedRevisionCache;
340
341     void resolve(QQmlPropertyData *) const;
342     void updateRecur(QQmlEngine *, const QMetaObject *);
343
344     QQmlEngine *engine;
345
346     QQmlPropertyCache *_parent;
347     int propertyIndexCacheStart;
348     int methodIndexCacheStart;
349     int signalHandlerIndexCacheStart;
350
351     IndexCache propertyIndexCache;
352     IndexCache methodIndexCache;
353     IndexCache signalHandlerIndexCache;
354     StringCache stringCache;
355     AllowedRevisionCache allowedRevisionCache;
356     v8::Persistent<v8::Function> constructor;
357
358     bool _ownMetaObject;
359     const QMetaObject *_metaObject;
360     QByteArray _dynamicClassName;
361     QByteArray _dynamicStringData;
362     QString _defaultPropertyName;
363     QQmlPropertyCacheMethodArguments *argumentsCache;
364 };
365
366 // QQmlMetaObject serves as a wrapper around either QMetaObject or QQmlPropertyCache.
367 // This is necessary as we delay creation of QMetaObject for synthesized QObjects, but
368 // we don't want to needlessly generate QQmlPropertyCaches every time we encounter a
369 // QObject type used in assignment or when we don't have a QQmlEngine etc.
370 //
371 // This class does NOT reference the propertycache.
372 class QQmlEnginePrivate;
373 class Q_QML_EXPORT QQmlMetaObject
374 {
375 public:
376     inline QQmlMetaObject();
377     inline QQmlMetaObject(QObject *);
378     inline QQmlMetaObject(const QMetaObject *);
379     inline QQmlMetaObject(QQmlPropertyCache *);
380     inline QQmlMetaObject(const QQmlMetaObject &);
381
382     inline QQmlMetaObject &operator=(const QQmlMetaObject &);
383
384     inline bool isNull() const;
385
386     inline const char *className() const;
387     inline int propertyCount() const;
388
389     inline bool hasMetaObject() const;
390     inline const QMetaObject *metaObject() const;
391
392     QQmlPropertyCache *propertyCache(QQmlEnginePrivate *) const;
393
394     static bool canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to);
395
396 private:
397     QBiPointer<QQmlPropertyCache, const QMetaObject> _m;
398 };
399   
400 QQmlPropertyData::QQmlPropertyData()
401 {
402     propType = 0;
403     coreIndex = -1;
404     notifyIndex = -1;
405     overrideIndexIsProperty = false;
406     overrideIndex = -1;
407     revision = 0;
408     metaObjectOffset = -1; 
409     flags = 0;
410 }
411
412 QQmlPropertyData::QQmlPropertyData(const QQmlPropertyRawData &d)
413 {
414     *(static_cast<QQmlPropertyRawData *>(this)) = d;
415 }
416
417 bool QQmlPropertyData::operator==(const QQmlPropertyRawData &other)
418 {
419     return flags == other.flags &&
420            propType == other.propType &&
421            coreIndex == other.coreIndex &&
422            notifyIndex == other.notifyIndex &&
423            revision == other.revision &&
424            (!isValueTypeVirtual() || 
425             (valueTypeCoreIndex == other.valueTypeCoreIndex && 
426              valueTypePropType == other.valueTypePropType));
427 }
428
429 int QQmlPropertyRawData::getValueTypeCoreIndex() const
430 {
431     return isValueTypeVirtual()?valueTypeCoreIndex:-1;
432 }
433
434 int QQmlPropertyRawData::encodedIndex() const
435 {
436     return isValueTypeVirtual()?(coreIndex | (valueTypeCoreIndex << 16)):coreIndex;
437 }
438
439 QQmlPropertyData *
440 QQmlPropertyCache::overrideData(QQmlPropertyData *data) const
441 {
442     if (!data->hasOverride())
443         return 0;
444
445     if (data->overrideIndexIsProperty)
446         return property(data->overrideIndex);
447     else
448         return method(data->overrideIndex);
449 }
450
451 bool QQmlPropertyCache::isAllowedInRevision(QQmlPropertyData *data) const
452 {
453     return (data->hasAccessors() || (data->metaObjectOffset == -1 && data->revision == 0)) ||
454            (allowedRevisionCache[data->metaObjectOffset] >= data->revision);
455 }
456
457 QQmlEngine *QQmlPropertyCache::qmlEngine() const
458 {
459     return engine;
460 }
461
462 QQmlPropertyData *QQmlPropertyCache::property(const QHashedV8String &str) const
463 {
464     QQmlPropertyData **rv = stringCache.value(str);
465     if (rv && (*rv)->notFullyResolved()) resolve(*rv);
466     return rv?*rv:0;
467 }
468
469 int QQmlPropertyCache::propertyCount() const
470 {
471     return propertyIndexCacheStart + propertyIndexCache.count();
472 }
473
474 int QQmlPropertyCache::propertyOffset() const
475 {
476     return propertyIndexCacheStart;
477 }
478
479 int QQmlPropertyCache::methodCount() const
480 {
481     return methodIndexCacheStart + methodIndexCache.count();
482 }
483
484 int QQmlPropertyCache::methodOffset() const
485 {
486     return methodIndexCacheStart;
487 }
488
489 int QQmlPropertyCache::signalCount() const
490 {
491     return signalHandlerIndexCacheStart + signalHandlerIndexCache.count();
492 }
493
494 int QQmlPropertyCache::signalOffset() const
495 {
496     return signalHandlerIndexCacheStart;
497 }
498
499 QQmlMetaObject::QQmlMetaObject()
500 {
501 }
502
503 QQmlMetaObject::QQmlMetaObject(QObject *o)
504 {
505     if (o) {
506         QQmlData *ddata = QQmlData::get(o, false);
507         if (ddata && ddata->propertyCache) _m = ddata->propertyCache;
508         else _m = o->metaObject();
509     }
510 }
511
512 QQmlMetaObject::QQmlMetaObject(const QMetaObject *m)
513 : _m(m)
514 {
515 }
516
517 QQmlMetaObject::QQmlMetaObject(QQmlPropertyCache *m)
518 : _m(m)
519 {
520 }
521
522 QQmlMetaObject::QQmlMetaObject(const QQmlMetaObject &o)
523 : _m(o._m)
524 {
525 }
526
527 QQmlMetaObject &QQmlMetaObject::operator=(const QQmlMetaObject &o)
528 {
529     _m = o._m;
530     return *this;
531 }
532
533 bool QQmlMetaObject::isNull() const
534 {
535     return _m.isNull();
536 }
537
538 const char *QQmlMetaObject::className() const
539 {
540     if (_m.isNull()) {
541         return 0;
542     } else if (_m.isT1()) {
543         return _m.asT1()->className();
544     } else {
545         return _m.asT2()->className();
546     }
547 }
548
549 int QQmlMetaObject::propertyCount() const
550 {
551     if (_m.isNull()) {
552         return 0;
553     } else if (_m.isT1()) {
554         return _m.asT1()->propertyCount();
555     } else {
556         return _m.asT2()->propertyCount();
557     }
558 }
559
560 bool QQmlMetaObject::hasMetaObject() const
561 {
562     return _m.isT2() || (!_m.isNull() && _m.asT1()->metaObject());
563 }
564
565 const QMetaObject *QQmlMetaObject::metaObject() const
566 {
567     if (_m.isNull()) return 0;
568     if (_m.isT1()) return _m.asT1()->createMetaObject();
569     else return _m.asT2();
570 }
571
572 QT_END_NAMESPACE
573
574 #endif // QQMLPROPERTYCACHE_P_H