Lazily create QMetaObjects
[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         IsDirect           = 0x00000020, // Exists on a C++ QMetaObject
93         HasAccessors       = 0x00000040, // Has property accessors
94
95         // These are mutualy exclusive
96         IsFunction         = 0x00000080, // Is an invokable
97         IsQObjectDerived   = 0x00000100, // Property type is a QObject* derived type
98         IsEnumType         = 0x00000200, // Property type is an enum
99         IsQList            = 0x00000400, // Property type is a QML list
100         IsQmlBinding       = 0x00000800, // Property type is a QQmlBinding*
101         IsQJSValue         = 0x00001000, // Property type is a QScriptValue
102         IsV8Handle         = 0x00002000, // Property type is a QQmlV8Handle
103         IsVarProperty      = 0x00004000, // Property type is a "var" property of VMEMO
104         IsValueTypeVirtual = 0x00008000, // Property is a value type "virtual" property
105         IsQVariant         = 0x00010000, // Property is a QVariant
106
107         // Apply only to IsFunctions
108         IsVMEFunction      = 0x00020000, // Function was added by QML
109         HasArguments       = 0x00040000, // Function takes arguments
110         IsSignal           = 0x00080000, // Function is a signal
111         IsVMESignal        = 0x00100000, // Signal was added by QML
112         IsV8Function       = 0x00200000, // Function takes QQmlV8Function* args
113         IsSignalHandler    = 0x00400000, // Function is a signal handler
114         IsOverload         = 0x00800000, // Function is an overload of another function
115         IsCloned           = 0x01000000, // The function was marked as cloned
116
117         // Internal QQmlPropertyCache flags
118         NotFullyResolved   = 0x02000000, // True if the type data is to be lazily resolved
119
120         // Flags that are set based on the propType field
121         PropTypeFlagMask = IsQObjectDerived | IsEnumType | IsQList | IsQmlBinding | IsQJSValue |
122                            IsV8Handle | IsQVariant,
123     };
124     Q_DECLARE_FLAGS(Flags, Flag)
125
126     Flags getFlags() const { return Flag(flags); }
127     void setFlags(Flags f) { flags = f; }
128
129     bool isValid() const { return coreIndex != -1; }
130
131     bool isConstant() const { return flags & IsConstant; }
132     bool isWritable() const { return flags & IsWritable; }
133     bool isResettable() const { return flags & IsResettable; }
134     bool isAlias() const { return flags & IsAlias; }
135     bool isFinal() const { return flags & IsFinal; }
136     bool isDirect() const { return flags & IsDirect; }
137     bool hasAccessors() const { return flags & HasAccessors; }
138     bool isFunction() const { return flags & IsFunction; }
139     bool isQObject() const { return flags & IsQObjectDerived; }
140     bool isEnum() const { return flags & IsEnumType; }
141     bool isQList() const { return flags & IsQList; }
142     bool isQmlBinding() const { return flags & IsQmlBinding; }
143     bool isQJSValue() const { return flags & IsQJSValue; }
144     bool isV8Handle() const { return flags & IsV8Handle; }
145     bool isVarProperty() const { return flags & IsVarProperty; }
146     bool isValueTypeVirtual() const { return flags & IsValueTypeVirtual; }
147     bool isQVariant() const { return flags & IsQVariant; }
148     bool isVMEFunction() const { return flags & IsVMEFunction; }
149     bool hasArguments() const { return flags & HasArguments; }
150     bool isSignal() const { return flags & IsSignal; }
151     bool isVMESignal() const { return flags & IsVMESignal; }
152     bool isV8Function() const { return flags & IsV8Function; }
153     bool isSignalHandler() const { return flags & IsSignalHandler; }
154     bool isOverload() const { return flags & IsOverload; }
155     bool isCloned() const { return flags & IsCloned; }
156
157     bool hasOverride() const { return !(flags & IsValueTypeVirtual) &&
158                                       !(flags & HasAccessors) &&
159                                       overrideIndex >= 0; }
160     bool hasRevision() const { return !(flags & HasAccessors) && revision != 0; }
161
162     // Returns -1 if not a value type virtual property
163     inline int getValueTypeCoreIndex() const;
164
165     // Returns the "encoded" index for use with bindings.  Encoding is:
166     //     coreIndex | (valueTypeCoreIndex << 24)
167     inline int encodedIndex() const;
168
169     union {
170         int propType;             // When !NotFullyResolved
171         const char *propTypeName; // When NotFullyResolved
172     };
173     int coreIndex;
174     union {
175         int notifyIndex;  // When !IsFunction
176         void *arguments;  // When IsFunction && HasArguments
177     };
178
179     union {
180         struct { // When !HasAccessors
181             qint16 revision;
182             qint16 metaObjectOffset;
183
184             union {
185                 struct { // When IsValueTypeVirtual
186                     quint16 valueTypeFlags; // flags of the access property on the value type proxy
187                                             // object
188                     quint8 valueTypePropType; // The QVariant::Type of access property on the value
189                                               // type proxy object
190                     quint8 valueTypeCoreIndex; // The prop index of the access property on the value
191                                                // type proxy object
192                 };
193
194                 struct { // When !IsValueTypeVirtual
195                     uint overrideIndexIsProperty : 1;
196                     signed int overrideIndex : 31;
197                 };
198             };
199         };
200         struct { // When HasAccessors
201             QQmlAccessors *accessors;
202             intptr_t accessorData;
203         };
204     };
205
206 private:
207     friend class QQmlPropertyData;
208     friend class QQmlPropertyCache;
209     quint32 flags;
210 };
211 Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyRawData::Flags);
212
213 class QQmlPropertyData : public QQmlPropertyRawData
214 {
215 public:
216     inline QQmlPropertyData();
217     inline QQmlPropertyData(const QQmlPropertyRawData &);
218
219     inline bool operator==(const QQmlPropertyRawData &);
220
221     static Flags flagsForProperty(const QMetaProperty &, QQmlEngine *engine = 0);
222     void load(const QMetaProperty &, QQmlEngine *engine = 0);
223     void load(const QMetaMethod &);
224     QString name(QObject *);
225     QString name(const QMetaObject *);
226
227 private:
228     friend class QQmlPropertyCache;
229     void lazyLoad(const QMetaProperty &, QQmlEngine *engine = 0);
230     void lazyLoad(const QMetaMethod &);
231     bool notFullyResolved() const { return flags & NotFullyResolved; }
232 };
233
234 class Q_QML_PRIVATE_EXPORT QQmlPropertyCache : public QQmlRefCount, public QQmlCleanup
235 {
236 public:
237     QQmlPropertyCache(QQmlEngine *);
238     QQmlPropertyCache(QQmlEngine *, const QMetaObject *);
239     virtual ~QQmlPropertyCache();
240
241     void update(QQmlEngine *, const QMetaObject *);
242
243     QQmlPropertyCache *copy();
244
245     QQmlPropertyCache *copyAndAppend(QQmlEngine *, const QMetaObject *,
246                 QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags,
247                 QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags,
248                 QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags);
249     QQmlPropertyCache *copyAndAppend(QQmlEngine *, const QMetaObject *, int revision,
250                 QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags,
251                 QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags,
252                 QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags);
253
254     QQmlPropertyCache *copyAndReserve(QQmlEngine *, int propertyCount,
255                                       int methodCount, int signalCount);
256     void appendProperty(const QString &,
257                         quint32 flags, int coreIndex, int propType, int notifyIndex);
258     void appendProperty(const QHashedCStringRef &,
259                         quint32 flags, int coreIndex, int propType, int notifyIndex);
260     void appendSignal(const QString &, quint32, int coreIndex, const int *types = 0,
261                       const QList<QByteArray> &names = QList<QByteArray>());
262     void appendSignal(const QHashedCStringRef &, quint32, int coreIndex, const int *types = 0,
263                       const QList<QByteArray> &names = QList<QByteArray>());
264     void appendMethod(const QString &, quint32 flags, int coreIndex,
265                       const QList<QByteArray> &names = QList<QByteArray>());
266     void appendMethod(const QHashedCStringRef &, quint32 flags, int coreIndex,
267                       const QList<QByteArray> &names = QList<QByteArray>());
268
269     const QMetaObject *metaObject() const;
270     const QMetaObject *createMetaObject();
271     const QMetaObject *firstCppMetaObject() const;
272
273     inline QQmlPropertyData *property(const QHashedV8String &) const;
274     QQmlPropertyData *property(const QHashedStringRef &) const;
275     QQmlPropertyData *property(const QHashedCStringRef &) const;
276     QQmlPropertyData *property(const QString &) const;
277     QQmlPropertyData *property(int) const;
278     QQmlPropertyData *method(int) const;
279     QStringList propertyNames() const;
280
281     QString defaultPropertyName() const;
282     QQmlPropertyData *defaultProperty() const;
283     QQmlPropertyCache *parent() const;
284
285     inline QQmlPropertyData *overrideData(QQmlPropertyData *) const;
286     inline bool isAllowedInRevision(QQmlPropertyData *) const;
287
288     inline QQmlEngine *qmlEngine() const;
289     static QQmlPropertyData *property(QQmlEngine *, QObject *, const QString &,
290                                               QQmlPropertyData &);
291     static QQmlPropertyData *property(QQmlEngine *, QObject *, const QHashedV8String &,
292                                               QQmlPropertyData &);
293     static int *methodParameterTypes(QObject *, int index, QVarLengthArray<int, 9> &dummy,
294                                      QByteArray *unknownTypeError);
295     static QList<QByteArray> methodParameterNames(QObject *, int index);
296
297     const char *className() const;
298
299     inline int propertyCount() const;
300     inline int propertyOffset() const;
301     inline int methodCount() const;
302     inline int methodOffset() const;
303     inline int signalCount() const;
304     inline int signalOffset() const;
305
306     static bool isDynamicMetaObject(const QMetaObject *);
307
308     void toMetaObjectBuilder(QMetaObjectBuilder &);
309
310 protected:
311     virtual void destroy();
312     virtual void clear();
313
314 private:
315     friend class QQmlEnginePrivate;
316     friend class QV8QObjectWrapper;
317     friend class QQmlCompiler;
318
319     inline QQmlPropertyCache *copy(int reserve);
320
321     void append(QQmlEngine *, const QMetaObject *, int revision,
322                 QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags,
323                 QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags,
324                 QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags);
325
326     // Implemented in v8/qv8qobjectwrapper.cpp
327     v8::Local<v8::Object> newQObject(QObject *, QV8Engine *);
328
329     typedef QVector<QQmlPropertyData> IndexCache;
330     typedef QStringHash<QQmlPropertyData *> StringCache;
331     typedef QVector<int> AllowedRevisionCache;
332
333     void resolve(QQmlPropertyData *) const;
334     void updateRecur(QQmlEngine *, const QMetaObject *);
335
336     QQmlEngine *engine;
337
338     QQmlPropertyCache *_parent;
339     int propertyIndexCacheStart;
340     int methodIndexCacheStart;
341     int signalHandlerIndexCacheStart;
342
343     IndexCache propertyIndexCache;
344     IndexCache methodIndexCache;
345     IndexCache signalHandlerIndexCache;
346     StringCache stringCache;
347     AllowedRevisionCache allowedRevisionCache;
348     v8::Persistent<v8::Function> constructor;
349
350     bool _ownMetaObject;
351     const QMetaObject *_metaObject;
352     QByteArray _dynamicClassName;
353     QByteArray _dynamicStringData;
354     QString _defaultPropertyName;
355     QQmlPropertyCacheMethodArguments *argumentsCache;
356 };
357
358 // QQmlMetaObject serves as a wrapper around either QMetaObject or QQmlPropertyCache.
359 // This is necessary as we delay creation of QMetaObject for synthesized QObjects, but
360 // we don't want to needlessly generate QQmlPropertyCaches every time we encounter a
361 // QObject type used in assignment or when we don't have a QQmlEngine etc.
362 //
363 // This class does NOT reference the propertycache.
364 class QQmlEnginePrivate;
365 class Q_QML_EXPORT QQmlMetaObject
366 {
367 public:
368     inline QQmlMetaObject();
369     inline QQmlMetaObject(QObject *);
370     inline QQmlMetaObject(const QMetaObject *);
371     inline QQmlMetaObject(QQmlPropertyCache *);
372     inline QQmlMetaObject(const QQmlMetaObject &);
373
374     inline QQmlMetaObject &operator=(const QQmlMetaObject &);
375
376     inline bool isNull() const;
377
378     inline const char *className() const;
379     inline int propertyCount() const;
380
381     inline bool hasMetaObject() const;
382     inline const QMetaObject *metaObject() const;
383
384     QQmlPropertyCache *propertyCache(QQmlEnginePrivate *) const;
385
386     static bool canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to);
387
388 private:
389     QBiPointer<QQmlPropertyCache, const QMetaObject> _m;
390 };
391   
392 QQmlPropertyData::QQmlPropertyData()
393 {
394     propType = 0;
395     coreIndex = -1;
396     notifyIndex = -1;
397     overrideIndexIsProperty = false;
398     overrideIndex = -1;
399     revision = 0;
400     metaObjectOffset = -1; 
401     flags = 0;
402 }
403
404 QQmlPropertyData::QQmlPropertyData(const QQmlPropertyRawData &d)
405 {
406     *(static_cast<QQmlPropertyRawData *>(this)) = d;
407 }
408
409 bool QQmlPropertyData::operator==(const QQmlPropertyRawData &other)
410 {
411     return flags == other.flags &&
412            propType == other.propType &&
413            coreIndex == other.coreIndex &&
414            notifyIndex == other.notifyIndex &&
415            revision == other.revision &&
416            (!isValueTypeVirtual() || 
417             (valueTypeCoreIndex == other.valueTypeCoreIndex && 
418              valueTypePropType == other.valueTypePropType));
419 }
420
421 int QQmlPropertyRawData::getValueTypeCoreIndex() const
422 {
423     return isValueTypeVirtual()?valueTypeCoreIndex:-1;
424 }
425
426 int QQmlPropertyRawData::encodedIndex() const
427 {
428     return isValueTypeVirtual()?(coreIndex | (valueTypeCoreIndex << 24)):coreIndex;
429 }
430
431 QQmlPropertyData *
432 QQmlPropertyCache::overrideData(QQmlPropertyData *data) const
433 {
434     if (!data->hasOverride())
435         return 0;
436
437     if (data->overrideIndexIsProperty)
438         return property(data->overrideIndex);
439     else
440         return method(data->overrideIndex);
441 }
442
443 bool QQmlPropertyCache::isAllowedInRevision(QQmlPropertyData *data) const
444 {
445     return (data->hasAccessors() || (data->metaObjectOffset == -1 && data->revision == 0)) ||
446            (allowedRevisionCache[data->metaObjectOffset] >= data->revision);
447 }
448
449 QQmlEngine *QQmlPropertyCache::qmlEngine() const
450 {
451     return engine;
452 }
453
454 QQmlPropertyData *QQmlPropertyCache::property(const QHashedV8String &str) const
455 {
456     QQmlPropertyData **rv = stringCache.value(str);
457     if (rv && (*rv)->notFullyResolved()) resolve(*rv);
458     return rv?*rv:0;
459 }
460
461 int QQmlPropertyCache::propertyCount() const
462 {
463     return propertyIndexCacheStart + propertyIndexCache.count();
464 }
465
466 int QQmlPropertyCache::propertyOffset() const
467 {
468     return propertyIndexCacheStart;
469 }
470
471 int QQmlPropertyCache::methodCount() const
472 {
473     return methodIndexCacheStart + methodIndexCache.count();
474 }
475
476 int QQmlPropertyCache::methodOffset() const
477 {
478     return methodIndexCacheStart;
479 }
480
481 int QQmlPropertyCache::signalCount() const
482 {
483     return signalHandlerIndexCacheStart + signalHandlerIndexCache.count();
484 }
485
486 int QQmlPropertyCache::signalOffset() const
487 {
488     return signalHandlerIndexCacheStart;
489 }
490
491 QQmlMetaObject::QQmlMetaObject()
492 {
493 }
494
495 QQmlMetaObject::QQmlMetaObject(QObject *o)
496 {
497     if (o) {
498         QQmlData *ddata = QQmlData::get(o, false);
499         if (ddata && ddata->propertyCache) _m = ddata->propertyCache;
500         else _m = o->metaObject();
501     }
502 }
503
504 QQmlMetaObject::QQmlMetaObject(const QMetaObject *m)
505 : _m(m)
506 {
507 }
508
509 QQmlMetaObject::QQmlMetaObject(QQmlPropertyCache *m)
510 : _m(m)
511 {
512 }
513
514 QQmlMetaObject::QQmlMetaObject(const QQmlMetaObject &o)
515 : _m(o._m)
516 {
517 }
518
519 QQmlMetaObject &QQmlMetaObject::operator=(const QQmlMetaObject &o)
520 {
521     _m = o._m;
522     return *this;
523 }
524
525 bool QQmlMetaObject::isNull() const
526 {
527     return _m.isNull();
528 }
529
530 const char *QQmlMetaObject::className() const
531 {
532     if (_m.isNull()) {
533         return 0;
534     } else if (_m.isT1()) {
535         return _m.asT1()->className();
536     } else {
537         return _m.asT2()->className();
538     }
539 }
540
541 int QQmlMetaObject::propertyCount() const
542 {
543     if (_m.isNull()) {
544         return 0;
545     } else if (_m.isT1()) {
546         return _m.asT1()->propertyCount();
547     } else {
548         return _m.asT2()->propertyCount();
549     }
550 }
551
552 bool QQmlMetaObject::hasMetaObject() const
553 {
554     return _m.isT2() || (!_m.isNull() && _m.asT1()->metaObject());
555 }
556
557 const QMetaObject *QQmlMetaObject::metaObject() const
558 {
559     if (_m.isNull()) return 0;
560     if (_m.isT1()) return _m.asT1()->createMetaObject();
561     else return _m.asT2();
562 }
563
564 QT_END_NAMESPACE
565
566 #endif // QQMLPROPERTYCACHE_P_H