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