#include "qqmlpropertycache_p.h"
-#include "qqmlengine_p.h"
-#include "qqmlbinding_p.h"
+#include <private/qqmlengine_p.h>
+#include <private/qqmlbinding_p.h>
+#include <private/qqmlvmemetaobject_p.h>
#include <private/qv8engine_p.h>
#include <private/qmetaobject_p.h>
#include <private/qqmlaccessors_p.h>
+#include <private/qmetaobjectbuilder_p.h>
+#include <private/qqmlrewrite_p.h>
#include <QtCore/qdebug.h>
#include <ctype.h> // for toupper
+#include <limits.h>
+
+#ifdef Q_CC_MSVC
+// nonstandard extension used : zero-sized array in struct/union.
+# pragma warning( disable : 4200 )
+#endif
Q_DECLARE_METATYPE(QJSValue)
Q_DECLARE_METATYPE(QQmlV8Handle);
#define Q_INT16_MAX 32767
-class QQmlPropertyCacheMethodArguments
+class QQmlPropertyCacheMethodArguments
{
public:
QQmlPropertyCacheMethodArguments *next;
+
+ //for signal handler rewrites
+ QString *signalParameterStringForJS;
+ int signalParameterCountForJS:30;
+ int parameterError:1;
+ int argumentsValid:1;
+
+ QList<QByteArray> *names;
int arguments[0];
};
return flags;
}
-// Flags that do depend on the property's QMetaProperty::userType() and thus are slow to
+// Flags that do depend on the property's QMetaProperty::userType() and thus are slow to
// load
static QQmlPropertyData::Flags flagsForPropertyType(int propType, QQmlEngine *engine)
{
QQmlPropertyData::Flags flags;
- if (propType == QMetaType::QObjectStar || propType == QMetaType::QWidgetStar) {
+ if (propType == QMetaType::QObjectStar) {
flags |= QQmlPropertyData::IsQObjectDerived;
} else if (propType == QMetaType::QVariant) {
flags |= QQmlPropertyData::IsQVariant;
} else if (propType == qMetaTypeId<QQmlV8Handle>()) {
flags |= QQmlPropertyData::IsV8Handle;
} else {
- QQmlMetaType::TypeCategory cat =
+ QQmlMetaType::TypeCategory cat =
engine ? QQmlEnginePrivate::get(engine)->typeCategory(propType)
: QQmlMetaType::typeCategory(propType);
Q_UNUSED(engine);
coreIndex = p.propertyIndex();
- notifyIndex = p.notifySignalIndex();
+ notifyIndex = QMetaObjectPrivate::signalIndex(p.notifySignal());
Q_ASSERT(p.revision() <= Q_INT16_MAX);
revision = p.revision();
flags = fastFlagsForProperty(p);
int type = p.type();
- if (type == QMetaType::QObjectStar || type == QMetaType::QWidgetStar) {
+ if (type == QMetaType::QObjectStar) {
propType = type;
flags |= QQmlPropertyData::IsQObjectDerived;
} else if (type == QMetaType::QVariant) {
{
propType = p.userType();
coreIndex = p.propertyIndex();
- notifyIndex = p.notifySignalIndex();
+ notifyIndex = QMetaObjectPrivate::signalIndex(p.notifySignal());
flags = fastFlagsForProperty(p) | flagsForPropertyType(propType, engine);
Q_ASSERT(p.revision() <= Q_INT16_MAX);
revision = p.revision();
}
}
+ if (m.attributes() & QMetaMethod::Cloned)
+ flags |= IsCloned;
+
Q_ASSERT(m.revision() <= Q_INT16_MAX);
revision = m.revision();
}
flags |= IsFunction;
if (m.methodType() == QMetaMethod::Signal)
flags |= IsSignal;
- propType = QVariant::Invalid;
+ propType = QMetaType::Void;
const char *returnType = m.typeName();
- if (returnType && *returnType) {
+ if (!returnType)
+ returnType = "\0";
+ if ((*returnType != 'v') || (qstrcmp(returnType+1, "oid") != 0)) {
propTypeName = returnType;
flags |= NotFullyResolved;
}
}
}
+ if (m.attributes() & QMetaMethod::Cloned)
+ flags |= IsCloned;
+
Q_ASSERT(m.revision() <= Q_INT16_MAX);
revision = m.revision();
}
Creates a new empty QQmlPropertyCache.
*/
QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e)
-: engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
- signalHanderIndexCacheStart(0), metaObject(0), argumentsCache(0)
+: engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
+ signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false),
+ _metaObject(0), argumentsCache(0)
{
Q_ASSERT(engine);
}
Creates a new QQmlPropertyCache of \a metaObject.
*/
QQmlPropertyCache::QQmlPropertyCache(QQmlEngine *e, const QMetaObject *metaObject)
-: engine(e), parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
- signalHanderIndexCacheStart(0), metaObject(0), argumentsCache(0)
+: engine(e), _parent(0), propertyIndexCacheStart(0), methodIndexCacheStart(0),
+ signalHandlerIndexCacheStart(0), _hasPropertyOverrides(false), _ownMetaObject(false),
+ _metaObject(0), argumentsCache(0)
{
Q_ASSERT(engine);
Q_ASSERT(metaObject);
QQmlPropertyCacheMethodArguments *args = argumentsCache;
while (args) {
QQmlPropertyCacheMethodArguments *next = args->next;
+ if (args->signalParameterStringForJS) delete args->signalParameterStringForJS;
+ if (args->names) delete args->names;
free(args);
args = next;
}
// We must clear this prior to releasing the parent incase it is a
// linked hash
stringCache.clear();
- if (parent) parent->release();
- parent = 0;
+ if (_parent) _parent->release();
+
+ if (_ownMetaObject) free((void *)_metaObject);
+ _metaObject = 0;
+ _parent = 0;
engine = 0;
}
QQmlPropertyCache *QQmlPropertyCache::copy(int reserve)
{
QQmlPropertyCache *cache = new QQmlPropertyCache(engine);
- cache->parent = this;
- cache->parent->addref();
+ cache->_parent = this;
+ cache->_parent->addref();
cache->propertyIndexCacheStart = propertyIndexCache.count() + propertyIndexCacheStart;
cache->methodIndexCacheStart = methodIndexCache.count() + methodIndexCacheStart;
- cache->signalHanderIndexCacheStart = signalHandlerIndexCache.count() + signalHanderIndexCacheStart;
+ cache->signalHandlerIndexCacheStart = signalHandlerIndexCache.count() + signalHandlerIndexCacheStart;
cache->stringCache.linkAndReserve(stringCache, reserve);
cache->allowedRevisionCache = allowedRevisionCache;
- cache->metaObject = metaObject;
+ cache->_metaObject = _metaObject;
+ cache->_defaultPropertyName = _defaultPropertyName;
// We specifically do *NOT* copy the constructor
return copy(0);
}
+QQmlPropertyCache *QQmlPropertyCache::copyAndReserve(QQmlEngine *, int propertyCount, int methodCount,
+ int signalCount)
+{
+ QQmlPropertyCache *rv = copy(propertyCount + methodCount + signalCount);
+ rv->propertyIndexCache.reserve(propertyCount);
+ rv->methodIndexCache.reserve(methodCount);
+ rv->signalHandlerIndexCache.reserve(signalCount);
+ rv->_metaObject = 0;
+
+ return rv;
+}
+
+/*! \internal
+
+ \a notifyIndex MUST be in the signal index range (see QObjectPrivate::signalIndex()).
+ This is different from QMetaMethod::methodIndex().
+*/
+void QQmlPropertyCache::appendProperty(const QString &name,
+ quint32 flags, int coreIndex, int propType, int notifyIndex)
+{
+ QQmlPropertyData data;
+ data.propType = propType;
+ data.coreIndex = coreIndex;
+ data.notifyIndex = notifyIndex;
+ data.flags = flags;
+
+ QQmlPropertyData *old = findNamedProperty(name);
+ if (old)
+ data.markAsOverrideOf(old);
+
+ int index = propertyIndexCache.count();
+ propertyIndexCache.append(data);
+
+ setNamedProperty(name, index + propertyOffset(), propertyIndexCache.data() + index, (old != 0));
+}
+
+void QQmlPropertyCache::appendProperty(const QHashedCStringRef &name,
+ quint32 flags, int coreIndex, int propType, int notifyIndex)
+{
+ QQmlPropertyData data;
+ data.propType = propType;
+ data.coreIndex = coreIndex;
+ data.notifyIndex = notifyIndex;
+ data.flags = flags;
+
+ QQmlPropertyData *old = findNamedProperty(name);
+ if (old)
+ data.markAsOverrideOf(old);
+
+ int index = propertyIndexCache.count();
+ propertyIndexCache.append(data);
+
+ setNamedProperty(name, index + propertyOffset(), propertyIndexCache.data() + index, (old != 0));
+}
+
+void QQmlPropertyCache::appendSignal(const QString &name, quint32 flags, int coreIndex,
+ const int *types, const QList<QByteArray> &names)
+{
+ QQmlPropertyData data;
+ data.propType = QVariant::Invalid;
+ data.coreIndex = coreIndex;
+ data.flags = flags;
+ data.arguments = 0;
+
+ QQmlPropertyData handler = data;
+ handler.flags |= QQmlPropertyData::IsSignalHandler;
+
+ if (types) {
+ int argumentCount = *types;
+ typedef QQmlPropertyCacheMethodArguments A;
+ A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
+ ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int));
+ args->argumentsValid = true;
+ args->signalParameterStringForJS = 0;
+ args->signalParameterCountForJS = 0;
+ args->parameterError = false;
+ args->names = new QList<QByteArray>(names);
+ args->next = argumentsCache;
+ argumentsCache = args;
+ data.arguments = args;
+ }
+
+ QQmlPropertyData *old = findNamedProperty(name);
+ if (old)
+ data.markAsOverrideOf(old);
+
+ int methodIndex = methodIndexCache.count();
+ methodIndexCache.append(data);
+
+ int signalHandlerIndex = signalHandlerIndexCache.count();
+ signalHandlerIndexCache.append(handler);
+
+ QString handlerName = QLatin1String("on") + name;
+ handlerName[2] = handlerName[2].toUpper();
+
+ setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0));
+ setNamedProperty(handlerName, signalHandlerIndex + signalOffset(), signalHandlerIndexCache.data() + signalHandlerIndex, (old != 0));
+}
+
+void QQmlPropertyCache::appendSignal(const QHashedCStringRef &name, quint32 flags, int coreIndex,
+ const int *types, const QList<QByteArray> &names)
+{
+ QQmlPropertyData data;
+ data.propType = QVariant::Invalid;
+ data.coreIndex = coreIndex;
+ data.flags = flags;
+ data.arguments = 0;
+
+ QQmlPropertyData handler = data;
+ handler.flags |= QQmlPropertyData::IsSignalHandler;
+
+ if (types) {
+ int argumentCount = *types;
+ typedef QQmlPropertyCacheMethodArguments A;
+ A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
+ ::memcpy(args->arguments, types, (argumentCount + 1) * sizeof(int));
+ args->argumentsValid = true;
+ args->signalParameterStringForJS = 0;
+ args->signalParameterCountForJS = 0;
+ args->parameterError = false;
+ args->names = new QList<QByteArray>(names);
+ args->next = argumentsCache;
+ argumentsCache = args;
+ data.arguments = args;
+ }
+
+ QQmlPropertyData *old = findNamedProperty(name);
+ if (old)
+ data.markAsOverrideOf(old);
+
+ int methodIndex = methodIndexCache.count();
+ methodIndexCache.append(data);
+
+ int signalHandlerIndex = signalHandlerIndexCache.count();
+ signalHandlerIndexCache.append(handler);
+
+ QString handlerName = QLatin1String("on") + name.toUtf16();
+ handlerName[2] = handlerName[2].toUpper();
+
+ setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0));
+ setNamedProperty(handlerName, signalHandlerIndex + signalOffset(), signalHandlerIndexCache.data() + signalHandlerIndex, (old != 0));
+}
+
+void QQmlPropertyCache::appendMethod(const QString &name, quint32 flags, int coreIndex,
+ const QList<QByteArray> &names)
+{
+ int argumentCount = names.count();
+
+ QQmlPropertyData data;
+ data.propType = QMetaType::QVariant;
+ data.coreIndex = coreIndex;
+
+ typedef QQmlPropertyCacheMethodArguments A;
+ A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
+ args->arguments[0] = argumentCount;
+ for (int ii = 0; ii < argumentCount; ++ii)
+ args->arguments[ii + 1] = QMetaType::QVariant;
+ args->argumentsValid = true;
+ args->signalParameterStringForJS = 0;
+ args->signalParameterCountForJS = 0;
+ args->parameterError = false;
+ args->names = 0;
+ if (argumentCount)
+ args->names = new QList<QByteArray>(names);
+ args->next = argumentsCache;
+ argumentsCache = args;
+ data.arguments = args;
+
+ data.flags = flags;
+
+ QQmlPropertyData *old = findNamedProperty(name);
+ if (old)
+ data.markAsOverrideOf(old);
+
+ int methodIndex = methodIndexCache.count();
+ methodIndexCache.append(data);
+
+ setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0));
+}
+
+void QQmlPropertyCache::appendMethod(const QHashedCStringRef &name, quint32 flags, int coreIndex,
+ const QList<QByteArray> &names)
+{
+ int argumentCount = names.count();
+
+ QQmlPropertyData data;
+ data.propType = QMetaType::QVariant;
+ data.coreIndex = coreIndex;
+
+ typedef QQmlPropertyCacheMethodArguments A;
+ A *args = static_cast<A *>(malloc(sizeof(A) + (argumentCount + 1) * sizeof(int)));
+ args->arguments[0] = argumentCount;
+ for (int ii = 0; ii < argumentCount; ++ii)
+ args->arguments[ii + 1] = QMetaType::QVariant;
+ args->argumentsValid = true;
+ args->signalParameterStringForJS = 0;
+ args->signalParameterCountForJS = 0;
+ args->parameterError = false;
+ args->names = 0;
+ if (argumentCount)
+ args->names = new QList<QByteArray>(names);
+ args->next = argumentsCache;
+ argumentsCache = args;
+ data.arguments = args;
+
+ data.flags = flags;
+
+ QQmlPropertyData *old = findNamedProperty(name);
+ if (old)
+ data.markAsOverrideOf(old);
+
+ int methodIndex = methodIndexCache.count();
+ methodIndexCache.append(data);
+
+ setNamedProperty(name, methodIndex + methodOffset(), methodIndexCache.data() + methodIndex, (old != 0));
+}
+
+// Returns this property cache's metaObject. May be null if it hasn't been created yet.
+const QMetaObject *QQmlPropertyCache::metaObject() const
+{
+ return _metaObject;
+}
+
+// Returns this property cache's metaObject, creating it if necessary.
+const QMetaObject *QQmlPropertyCache::createMetaObject()
+{
+ if (!_metaObject) {
+ _ownMetaObject = true;
+
+ QMetaObjectBuilder builder;
+ toMetaObjectBuilder(builder);
+ builder.setSuperClass(_parent->createMetaObject());
+ _metaObject = builder.toMetaObject();
+ }
+
+ return _metaObject;
+}
+
+// Returns the name of the default property for this cache
+QString QQmlPropertyCache::defaultPropertyName() const
+{
+ return _defaultPropertyName;
+}
+
+QQmlPropertyData *QQmlPropertyCache::defaultProperty() const
+{
+ return property(defaultPropertyName(), 0, 0);
+}
+
+QQmlPropertyCache *QQmlPropertyCache::parent() const
+{
+ return _parent;
+}
+
+// Returns the first C++ type's QMetaObject - that is, the first QMetaObject not created by
+// QML
+const QMetaObject *QQmlPropertyCache::firstCppMetaObject() const
+{
+ while (_parent && (_metaObject == 0 || _ownMetaObject))
+ return _parent->firstCppMetaObject();
+ return _metaObject;
+}
+
QQmlPropertyCache *
QQmlPropertyCache::copyAndAppend(QQmlEngine *engine, const QMetaObject *metaObject,
QQmlPropertyData::Flag propertyFlags,
return rv;
}
-void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject,
- QQmlPropertyData::Flag propertyFlags,
- QQmlPropertyData::Flag methodFlags,
- QQmlPropertyData::Flag signalFlags)
-{
- append(engine, metaObject, -1, propertyFlags, methodFlags, signalFlags);
-}
-
-void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject,
- int revision,
+void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject,
+ int revision,
QQmlPropertyData::Flag propertyFlags,
QQmlPropertyData::Flag methodFlags,
QQmlPropertyData::Flag signalFlags)
Q_UNUSED(revision);
Q_ASSERT(constructor.IsEmpty()); // We should not be appending to an in-use property cache
- this->metaObject = metaObject;
+ _metaObject = metaObject;
bool dynamicMetaObject = isDynamicMetaObject(metaObject);
QQmlAccessorProperties::Properties accessorProperties;
- // Special case QObject as we don't want to add a qt_HasQmlAccessors classinfo to it
- if (metaObject == &QObject::staticMetaObject) {
- accessorProperties = QQmlAccessorProperties::properties(metaObject);
- } else if (classInfoCount) {
+ if (classInfoCount) {
int classInfoOffset = metaObject->classInfoOffset();
bool hasFastProperty = false;
for (int ii = 0; ii < classInfoCount; ++ii) {
if (0 == qstrcmp(metaObject->classInfo(idx).name(), "qt_HasQmlAccessors")) {
hasFastProperty = true;
- break;
+ } else if (0 == qstrcmp(metaObject->classInfo(idx).name(), "DefaultProperty")) {
+ _defaultPropertyName = QString::fromUtf8(metaObject->classInfo(idx).value());
}
}
}
}
- // qMax(defaultMethods, methodOffset) to block the signals and slots of QObject::staticMetaObject
- // incl. destroyed signals, objectNameChanged signal, deleteLater slot, _q_reregisterTimers slot.
- int methodOffset = qMax(QObject::staticMetaObject.methodCount(), metaObject->methodOffset());
+ //Used to block access to QObject::destroyed() and QObject::deleteLater() from QML
+ static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
+ static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()");
+ static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()");
+
+ int methodOffset = metaObject->methodOffset();
int signalOffset = signalCount - QMetaObjectPrivate::get(metaObject)->signalCount;
// update() should have reserved enough space in the vector that this doesn't cause a realloc
// and invalidate the stringCache.
methodIndexCache.resize(methodCount - methodIndexCacheStart);
- signalHandlerIndexCache.resize(signalCount - signalHanderIndexCacheStart);
+ signalHandlerIndexCache.resize(signalCount - signalHandlerIndexCacheStart);
int signalHandlerIndex = signalOffset;
for (int ii = methodOffset; ii < methodCount; ++ii) {
+ if (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx)
+ continue;
QMetaMethod m = metaObject->method(ii);
- if (m.access() == QMetaMethod::Private)
+ if (m.access() == QMetaMethod::Private)
continue;
// Extract method name
- const char *signature;
- if (QMetaObjectPrivate::get(metaObject)->revision >= 7) {
- // Safe to use the raw name pointer
- signature = m.name().constData();
- } else {
- // Safe to use the raw signature pointer
- signature = m.methodSignature().constData();
- }
- const char *cptr = signature;
+ // It's safe to keep the raw name pointer
+ Q_ASSERT(QMetaObjectPrivate::get(metaObject)->revision >= 7);
+ const char *rawName = m.name().constData();
+ const char *cptr = rawName;
char utf8 = 0;
- while (*cptr && *cptr != '(') {
- Q_ASSERT(*cptr != 0);
+ while (*cptr) {
utf8 |= *cptr & 0x80;
++cptr;
}
data->metaObjectOffset = allowedRevisionCache.count() - 1;
if (data->isSignal()) {
- sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHanderIndexCacheStart];
+ sigdata = &signalHandlerIndexCache[signalHandlerIndex - signalHandlerIndexCacheStart];
*sigdata = *data;
sigdata->flags |= QQmlPropertyData::IsSignalHandler;
}
QQmlPropertyData *old = 0;
if (utf8) {
- QHashedString methodName(QString::fromUtf8(signature, cptr - signature));
- if (QQmlPropertyData **it = stringCache.value(methodName))
- old = *it;
- stringCache.insert(methodName, data);
+ QHashedString methodName(QString::fromUtf8(rawName, cptr - rawName));
+ if (StringCache::mapped_type *it = stringCache.value(methodName))
+ old = it->second;
+ setNamedProperty(methodName, ii, data, (old != 0));
if (data->isSignal()) {
QHashedString on(QStringLiteral("on") % methodName.at(0).toUpper() % methodName.midRef(1));
- stringCache.insert(on, sigdata);
+ setNamedProperty(on, ii, sigdata, (old != 0));
++signalHandlerIndex;
}
} else {
- QHashedCStringRef methodName(signature, cptr - signature);
- if (QQmlPropertyData **it = stringCache.value(methodName))
- old = *it;
- stringCache.insert(methodName, data);
+ QHashedCStringRef methodName(rawName, cptr - rawName);
+ if (StringCache::mapped_type *it = stringCache.value(methodName))
+ old = it->second;
+ setNamedProperty(methodName, ii, data, (old != 0));
if (data->isSignal()) {
int length = methodName.length();
QVarLengthArray<char, 128> str(length+3);
str[0] = 'o';
str[1] = 'n';
- str[2] = toupper(signature[0]);
+ str[2] = toupper(rawName[0]);
if (length > 1)
- memcpy(&str[3], &signature[1], length - 1);
+ memcpy(&str[3], &rawName[1], length - 1);
str[length + 2] = '\0';
QHashedString on(QString::fromLatin1(str.data()));
- stringCache.insert(on, sigdata);
+ setNamedProperty(on, ii, data, (old != 0));
++signalHandlerIndex;
}
}
// We only overload methods in the same class, exactly like C++
if (old->isFunction() && old->coreIndex >= methodOffset)
data->flags |= QQmlPropertyData::IsOverload;
- data->overrideIndexIsProperty = !old->isFunction();
- data->overrideIndex = old->coreIndex;
+
+ data->markAsOverrideOf(old);
}
}
data->lazyLoad(p, engine);
data->flags |= propertyFlags;
- if (!dynamicMetaObject)
+ if (!dynamicMetaObject)
data->flags |= QQmlPropertyData::IsDirect;
Q_ASSERT((allowedRevisionCache.count() - 1) < Q_INT16_MAX);
if (utf8) {
QHashedString propName(QString::fromUtf8(str, cptr - str));
- if (QQmlPropertyData **it = stringCache.value(propName))
- old = *it;
- stringCache.insert(propName, data);
+ if (StringCache::mapped_type *it = stringCache.value(propName))
+ old = it->second;
+ setNamedProperty(propName, ii, data, (old != 0));
} else {
QHashedCStringRef propName(str, cptr - str);
- if (QQmlPropertyData **it = stringCache.value(propName))
- old = *it;
- stringCache.insert(propName, data);
+ if (StringCache::mapped_type *it = stringCache.value(propName))
+ old = it->second;
+ setNamedProperty(propName, ii, data, (old != 0));
}
QQmlAccessorProperties::Property *accessorProperty = accessorProperties.property(str);
data->accessors = accessorProperty->accessors;
data->accessorData = accessorProperty->data;
} else if (old) {
- data->overrideIndexIsProperty = !old->isFunction();
- data->overrideIndex = old->coreIndex;
+ data->markAsOverrideOf(old);
}
}
}
+QQmlPropertyData *QQmlPropertyCache::ensureResolved(QQmlPropertyData *p) const
+{
+ if (p && p->notFullyResolved())
+ resolve(p);
+
+ return p;
+}
+
void QQmlPropertyCache::resolve(QQmlPropertyData *data) const
{
Q_ASSERT(data->notFullyResolved());
updateRecur(engine, metaObject->superClass());
- append(engine, metaObject);
+ append(engine, metaObject, -1);
}
void QQmlPropertyCache::update(QQmlEngine *engine, const QMetaObject *metaObject)
int sc = metaObjectSignalCount(metaObject);
propertyIndexCache.reserve(pc - propertyIndexCacheStart);
methodIndexCache.reserve(mc - methodIndexCacheStart);
- signalHandlerIndexCache.reserve(sc - signalHanderIndexCacheStart);
+ signalHandlerIndexCache.reserve(sc - signalHandlerIndexCacheStart);
// Reserve enough space in the stringCache for all properties/methods/signals including those
// cached in a parent cache.
updateRecur(engine,metaObject);
}
+/*! \internal
+ \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
+ This is different from QMetaMethod::methodIndex().
+*/
+QQmlPropertyData *
+QQmlPropertyCache::signal(int index, QQmlPropertyCache **c) const
+{
+ if (index < 0 || index >= (signalHandlerIndexCacheStart + signalHandlerIndexCache.count()))
+ return 0;
+
+ if (index < signalHandlerIndexCacheStart)
+ return _parent->signal(index, c);
+
+ QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - signalHandlerIndexCacheStart));
+ if (rv->notFullyResolved()) resolve(rv);
+ Q_ASSERT(rv->isSignal() || rv->coreIndex == -1);
+ if (c) *c = const_cast<QQmlPropertyCache *>(this);
+ return rv;
+}
+
+int QQmlPropertyCache::methodIndexToSignalIndex(int index) const
+{
+ if (index < 0 || index >= (methodIndexCacheStart + methodIndexCache.count()))
+ return index;
+
+ if (index < methodIndexCacheStart)
+ return _parent->methodIndexToSignalIndex(index);
+
+ return index - methodIndexCacheStart + signalHandlerIndexCacheStart;
+}
+
QQmlPropertyData *
QQmlPropertyCache::property(int index) const
{
if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count()))
return 0;
-
+
if (index < propertyIndexCacheStart)
- return parent->property(index);
+ return _parent->property(index);
QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&propertyIndexCache.at(index - propertyIndexCacheStart));
- if (rv->notFullyResolved()) resolve(rv);
- return rv;
+ return ensureResolved(rv);
}
QQmlPropertyData *
return 0;
if (index < methodIndexCacheStart)
- return parent->method(index);
+ return _parent->method(index);
QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&methodIndexCache.at(index - methodIndexCacheStart));
- if (rv->notFullyResolved()) resolve(rv);
- return rv;
+ return ensureResolved(rv);
}
-QQmlPropertyData *
-QQmlPropertyCache::property(const QHashedStringRef &str) const
+QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, QObject *object, QQmlContextData *context) const
{
- QQmlPropertyData **rv = stringCache.value(str);
- if (rv && (*rv)->notFullyResolved()) resolve(*rv);
- return rv?*rv:0;
+ QQmlData *data = (object ? QQmlData::get(object) : 0);
+ const QQmlVMEMetaObject *vmemo = (data && data->hasVMEMetaObject ? static_cast<const QQmlVMEMetaObject *>(object->metaObject()) : 0);
+ return findProperty(it, vmemo, context);
}
-QQmlPropertyData *
-QQmlPropertyCache::property(const QHashedCStringRef &str) const
+namespace {
+
+inline bool contextHasNoExtensions(QQmlContextData *context)
{
- QQmlPropertyData **rv = stringCache.value(str);
- if (rv && (*rv)->notFullyResolved()) resolve(*rv);
- return rv?*rv:0;
+ // This context has no extension if its parent is the engine's rootContext,
+ // which has children but no imports
+ return (!context->parent || !context->parent->imports);
}
-QQmlPropertyData *
-QQmlPropertyCache::property(const QString &str) const
+inline int maximumIndexForProperty(QQmlPropertyData *prop, const QQmlVMEMetaObject *vmemo)
+{
+ return (prop->isFunction() ? vmemo->methodCount()
+ : prop->isSignalHandler() ? vmemo->signalCount()
+ : vmemo->propertyCount());
+}
+
+}
+
+QQmlPropertyData *QQmlPropertyCache::findProperty(StringCache::ConstIterator it, const QQmlVMEMetaObject *vmemo, QQmlContextData *context) const
{
- QQmlPropertyData **rv = stringCache.value(str);
- if (rv && (*rv)->notFullyResolved()) resolve(*rv);
- return rv?*rv:0;
+ StringCache::ConstIterator end = stringCache.end();
+
+ if (it != end) {
+ if (vmemo && context && !contextHasNoExtensions(context)) {
+ // Find the highest property offset known to the supplied context
+ do {
+ if (vmemo->ctxt == context)
+ break;
+
+ vmemo = vmemo->parentVMEMetaObject();
+ } while (vmemo);
+ }
+
+ do {
+ // Is this property available to this context?
+ const StringCache::mapped_type &property(it.value());
+ if (!vmemo || (property.first < maximumIndexForProperty(property.second, vmemo)))
+ return ensureResolved(property.second);
+
+ it = stringCache.findNext(it);
+ } while (it != end);
+ }
+
+ return 0;
}
QString QQmlPropertyData::name(QObject *object)
}
}
+void QQmlPropertyData::markAsOverrideOf(QQmlPropertyData *predecessor)
+{
+ overrideIndexIsProperty = !predecessor->isFunction();
+ overrideIndex = predecessor->coreIndex;
+
+ predecessor->flags |= QQmlPropertyData::IsOverridden;
+}
+
QStringList QQmlPropertyCache::propertyNames() const
{
QStringList keys;
- for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter)
+ for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter)
keys.append(iter.key());
return keys;
}
-static int EnumType(const QMetaObject *meta, const QByteArray &str)
+struct StaticQtMetaObject : public QObject
+{
+ static const QMetaObject *get()
+ { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
+};
+
+static int EnumType(const QMetaObject *metaobj, const QByteArray &str, int type)
{
QByteArray scope;
QByteArray name;
if (scopeIdx != -1) {
scope = str.left(scopeIdx);
name = str.mid(scopeIdx + 2);
- } else {
+ } else {
name = str;
}
+ const QMetaObject *meta;
+ if (scope == "Qt")
+ meta = StaticQtMetaObject::get();
+ else
+ meta = metaobj;
for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
QMetaEnum m = meta->enumerator(i);
if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
return QVariant::Int;
}
- return QVariant::Invalid;
+ return type;
+}
+
+/*! \internal
+ \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
+ This is different from QMetaMethod::methodIndex().
+*/
+QString QQmlPropertyCache::signalParameterStringForJS(int index, int *count, QString *errorString)
+{
+ QQmlPropertyCache *c = 0;
+ QQmlPropertyData *signalData = signal(index, &c);
+ if (!signalData)
+ return QString();
+
+ typedef QQmlPropertyCacheMethodArguments A;
+
+ if (signalData->arguments) {
+ A *arguments = static_cast<A *>(signalData->arguments);
+ if (arguments->signalParameterStringForJS) {
+ if (count)
+ *count = arguments->signalParameterCountForJS;
+ if (arguments->parameterError) {
+ if (errorString)
+ *errorString = *arguments->signalParameterStringForJS;
+ return QString();
+ }
+ return *arguments->signalParameterStringForJS;
+ }
+ }
+
+ QList<QByteArray> parameterNameList = signalParameterNames(index);
+
+ if (!signalData->arguments) {
+ int argc = parameterNameList.count();
+ A *args = static_cast<A *>(malloc(sizeof(A) + (argc + 1) * sizeof(int)));
+ args->arguments[0] = argc;
+ args->argumentsValid = false;
+ args->signalParameterStringForJS = 0;
+ args->signalParameterCountForJS = 0;
+ args->parameterError = false;
+ args->names = new QList<QByteArray>(parameterNameList);
+ signalData->arguments = args;
+ args->next = c->argumentsCache;
+ c->argumentsCache = args;
+ }
+
+ QQmlRewrite::RewriteSignalHandler rewriter;
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+ const QString ¶meters = rewriter.createParameterString(parameterNameList,
+ ep->v8engine()->illegalNames());
+
+ bool error = rewriter.hasParameterError();
+ A *arguments = static_cast<A *>(signalData->arguments);
+ arguments->signalParameterStringForJS = new QString(error ? rewriter.parameterError() : parameters);
+ arguments->signalParameterCountForJS = rewriter.parameterCountForJS();
+ if (count)
+ *count = arguments->signalParameterCountForJS;
+ if (error) {
+ arguments->parameterError = true;
+ if (errorString)
+ *errorString = *arguments->signalParameterStringForJS;
+ return QString();
+ }
+ return *arguments->signalParameterStringForJS;
}
// Returns an array of the arguments for method \a index. The first entry in the array
// is the number of arguments.
-int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index,
+int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index,
QVarLengthArray<int, 9> &dummy,
QByteArray *unknownTypeError)
{
Q_ASSERT(index < c->methodIndexCacheStart + c->methodIndexCache.count());
while (index < c->methodIndexCacheStart)
- c = c->parent;
+ c = c->_parent;
QQmlPropertyData *rv = const_cast<QQmlPropertyData *>(&c->methodIndexCache.at(index - c->methodIndexCacheStart));
- if (rv->arguments)
+ if (rv->arguments && static_cast<A *>(rv->arguments)->argumentsValid)
return static_cast<A *>(rv->arguments)->arguments;
- const QMetaObject *metaObject = object->metaObject();
+ const QMetaObject *metaObject = c->createMetaObject();
+ Q_ASSERT(metaObject);
QMetaMethod m = metaObject->method(index);
int argc = m.parameterCount();
- A *args = static_cast<A *>(malloc(sizeof(A) + (argc + 1) * sizeof(int)));
- args->arguments[0] = argc;
+ if (!rv->arguments) {
+ A *args = static_cast<A *>(malloc(sizeof(A) + (argc + 1) * sizeof(int)));
+ args->arguments[0] = argc;
+ args->argumentsValid = false;
+ args->signalParameterStringForJS = 0;
+ args->signalParameterCountForJS = 0;
+ args->parameterError = false;
+ args->names = 0;
+ rv->arguments = args;
+ args->next = c->argumentsCache;
+ c->argumentsCache = args;
+ }
+ A *args = static_cast<A *>(rv->arguments);
+
QList<QByteArray> argTypeNames; // Only loaded if needed
for (int ii = 0; ii < argc; ++ii) {
int type = m.parameterType(ii);
- if (type == QVariant::Invalid) {
+ QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
+ if (flags & QMetaType::IsEnumeration)
+ type = QVariant::Int;
+ else if (type == QMetaType::UnknownType ||
+ (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
+ type != qMetaTypeId<QJSValue>())) {
+ //the UserType clause is to catch registered QFlags
if (argTypeNames.isEmpty())
argTypeNames = m.parameterTypes();
- type = EnumType(object->metaObject(), argTypeNames.at(ii));
+ type = EnumType(object->metaObject(), argTypeNames.at(ii), type);
}
- if (type == QVariant::Invalid) {
+ if (type == QMetaType::UnknownType) {
if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
- free(args);
return 0;
}
args->arguments[ii + 1] = type;
}
-
- rv->arguments = args;
- args->next = c->argumentsCache;
- c->argumentsCache = args;
+ args->argumentsValid = true;
return static_cast<A *>(rv->arguments)->arguments;
} else {
for (int ii = 0; ii < argc; ++ii) {
int type = m.parameterType(ii);
- if (type == QVariant::Invalid) {
+ QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
+ if (flags & QMetaType::IsEnumeration)
+ type = QVariant::Int;
+ else if (type == QMetaType::UnknownType ||
+ (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
+ type != qMetaTypeId<QJSValue>())) {
+ //the UserType clause is to catch registered QFlags)
if (argTypeNames.isEmpty())
argTypeNames = m.parameterTypes();
- type = EnumType(object->metaObject(), argTypeNames.at(ii));
+ type = EnumType(object->metaObject(), argTypeNames.at(ii), type);
}
- if (type == QVariant::Invalid) {
+ if (type == QMetaType::UnknownType) {
if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii);
return 0;
}
}
}
-QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject,
- const QString &property)
+// Returns the return type of the method.
+int QQmlPropertyCache::methodReturnType(QObject *object, const QQmlPropertyData &data,
+ QByteArray *unknownTypeError)
+{
+ Q_ASSERT(object && data.coreIndex >= 0);
+
+ int type = data.propType;
+
+ const char *propTypeName = 0;
+
+ if (type == QMetaType::UnknownType) {
+ // Find the return type name from the method info
+ QMetaMethod m;
+
+ QQmlData *ddata = QQmlData::get(object, false);
+ if (ddata && ddata->propertyCache) {
+ QQmlPropertyCache *c = ddata->propertyCache;
+ Q_ASSERT(data.coreIndex < c->methodIndexCacheStart + c->methodIndexCache.count());
+
+ while (data.coreIndex < c->methodIndexCacheStart)
+ c = c->_parent;
+
+ const QMetaObject *metaObject = c->createMetaObject();
+ Q_ASSERT(metaObject);
+ m = metaObject->method(data.coreIndex);
+ } else {
+ m = object->metaObject()->method(data.coreIndex);
+ }
+
+ type = m.returnType();
+ propTypeName = m.typeName();
+ }
+
+ QMetaType::TypeFlags flags = QMetaType::typeFlags(type);
+ if (flags & QMetaType::IsEnumeration) {
+ type = QVariant::Int;
+ } else if (type == QMetaType::UnknownType ||
+ (type >= (int)QVariant::UserType && !(flags & QMetaType::PointerToQObject) &&
+ type != qMetaTypeId<QJSValue>())) {
+ //the UserType clause is to catch registered QFlags
+ type = EnumType(object->metaObject(), propTypeName, type);
+ }
+
+ if (type == QMetaType::UnknownType) {
+ if (unknownTypeError) *unknownTypeError = propTypeName;
+ }
+
+ return type;
+}
+
+int QQmlPropertyCache::originalClone(int index)
+{
+ while (signal(index)->isCloned())
+ --index;
+ return index;
+}
+
+int QQmlPropertyCache::originalClone(QObject *object, int index)
+{
+ QQmlData *data = QQmlData::get(object, false);
+ if (data && data->propertyCache) {
+ QQmlPropertyCache *cache = data->propertyCache;
+ while (cache->signal(index)->isCloned())
+ --index;
+ } else {
+ while (QMetaObjectPrivate::signal(object->metaObject(), index).attributes() & QMetaMethod::Cloned)
+ --index;
+ }
+ return index;
+}
+
+QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject, const QString &property)
{
Q_ASSERT(metaObject);
}
}
+ //Used to block access to QObject::destroyed() and QObject::deleteLater() from QML
+ static const int destroyedIdx1 = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
+ static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()");
+ static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()");
+
int methodCount = metaObject->methodCount();
- int defaultMethods = QObject::staticMetaObject.methodCount();
- for (int ii = methodCount - 1; ii >= defaultMethods; --ii) {
- // >=defaultMethods to block the signals and slots of QObject::staticMetaObject
- // incl. destroyed signals, objectNameChanged signal, deleteLater slot, _q_reregisterTimers slot.
+ for (int ii = methodCount - 1; ii >= 0; --ii) {
+ if (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx)
+ continue;
QMetaMethod m = metaObject->method(ii);
if (m.access() == QMetaMethod::Private)
continue;
template<typename T>
QQmlPropertyData *
-qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj,
- const T &name, QQmlPropertyData &local)
+qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, const T &name,
+ QQmlContextData *context, QQmlPropertyData &local)
{
QQmlPropertyCache *cache = 0;
- if (engine) {
- QQmlData *ddata = QQmlData::get(obj);
+ QQmlData *ddata = QQmlData::get(obj, false);
- if (ddata && ddata->propertyCache) {
- cache = ddata->propertyCache;
- } else if (engine) {
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
- cache = ep->cache(obj);
- if (cache) {
- ddata = QQmlData::get(obj, true);
- cache->addref();
- ddata->propertyCache = cache;
- }
+ if (ddata && ddata->propertyCache) {
+ cache = ddata->propertyCache;
+ } else if (engine) {
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+ cache = ep->cache(obj);
+ if (cache) {
+ ddata = QQmlData::get(obj, true);
+ cache->addref();
+ ddata->propertyCache = cache;
}
}
QQmlPropertyData *rv = 0;
if (cache) {
- rv = cache->property(name);
+ rv = cache->property(name, obj, context);
} else {
- local = qQmlPropertyCacheCreate(obj->metaObject(),
- qQmlPropertyCacheToString(name));
+ local = qQmlPropertyCacheCreate(obj->metaObject(), qQmlPropertyCacheToString(name));
if (local.isValid())
rv = &local;
}
}
QQmlPropertyData *
-QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj,
- const QHashedV8String &name, QQmlPropertyData &local)
+QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj, const QHashedV8String &name,
+ QQmlContextData *context, QQmlPropertyData &local)
{
- return qQmlPropertyCacheProperty<QHashedV8String>(engine, obj, name, local);
+ return qQmlPropertyCacheProperty<QHashedV8String>(engine, obj, name, context, local);
}
QQmlPropertyData *
QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj,
- const QString &name, QQmlPropertyData &local)
+ const QString &name, QQmlContextData *context, QQmlPropertyData &local)
{
- return qQmlPropertyCacheProperty<QString>(engine, obj, name, local);
+ return qQmlPropertyCacheProperty<QString>(engine, obj, name, context, local);
}
static inline const QMetaObjectPrivate *priv(const uint* data)
return priv(mo->d.data)->revision >= 3 && priv(mo->d.data)->flags & DynamicMetaObject;
}
+const char *QQmlPropertyCache::className() const
+{
+ if (!_ownMetaObject && _metaObject)
+ return _metaObject->className();
+ else
+ return _dynamicClassName.constData();
+}
+
+void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
+{
+ struct Sort { static bool lt(const QPair<QString, QQmlPropertyData *> &lhs,
+ const QPair<QString, QQmlPropertyData *> &rhs) {
+ return lhs.second->coreIndex < rhs.second->coreIndex;
+ } };
+
+ struct Insert { static void in(QQmlPropertyCache *This,
+ QList<QPair<QString, QQmlPropertyData *> > &properties,
+ QList<QPair<QString, QQmlPropertyData *> > &methods,
+ StringCache::ConstIterator iter, QQmlPropertyData *data) {
+ if (data->isSignalHandler())
+ return;
+
+ if (data->isFunction()) {
+ if (data->coreIndex < This->methodIndexCacheStart)
+ return;
+
+ QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
+ // Overrides can cause the entry to already exist
+ if (!methods.contains(entry)) methods.append(entry);
+
+ data = This->overrideData(data);
+ if (data && !data->isFunction()) Insert::in(This, properties, methods, iter, data);
+ } else {
+ if (data->coreIndex < This->propertyIndexCacheStart)
+ return;
+
+ QPair<QString, QQmlPropertyData *> entry = qMakePair((QString)iter.key(), data);
+ // Overrides can cause the entry to already exist
+ if (!properties.contains(entry)) properties.append(entry);
+
+ data = This->overrideData(data);
+ if (data) Insert::in(This, properties, methods, iter, data);
+ }
+
+ } };
+
+ builder.setClassName(_dynamicClassName);
+
+ QList<QPair<QString, QQmlPropertyData *> > properties;
+ QList<QPair<QString, QQmlPropertyData *> > methods;
+
+ for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter)
+ Insert::in(this, properties, methods, iter, iter.value().second);
+
+ Q_ASSERT(properties.count() == propertyIndexCache.count());
+ Q_ASSERT(methods.count() == methodIndexCache.count());
+
+ qSort(properties.begin(), properties.end(), Sort::lt);
+ qSort(methods.begin(), methods.end(), Sort::lt);
+
+ for (int ii = 0; ii < properties.count(); ++ii) {
+ QQmlPropertyData *data = properties.at(ii).second;
+
+ int notifierId = -1;
+ if (data->notifyIndex != -1)
+ notifierId = data->notifyIndex - signalHandlerIndexCacheStart;
+
+ QMetaPropertyBuilder property = builder.addProperty(properties.at(ii).first.toUtf8(),
+ QMetaType::typeName(data->propType),
+ notifierId);
+
+ property.setReadable(true);
+ property.setWritable(data->isWritable());
+ property.setResettable(data->isResettable());
+ }
+
+ for (int ii = 0; ii < methods.count(); ++ii) {
+ QQmlPropertyData *data = methods.at(ii).second;
+
+ QByteArray returnType;
+ if (data->propType != 0)
+ returnType = QMetaType::typeName(data->propType);
+
+ QByteArray signature = methods.at(ii).first.toUtf8() + "(";
+
+ QQmlPropertyCacheMethodArguments *arguments = 0;
+ if (data->hasArguments()) {
+ arguments = (QQmlPropertyCacheMethodArguments *)data->arguments;
+ Q_ASSERT(arguments->argumentsValid);
+ for (int ii = 0; ii < arguments->arguments[0]; ++ii) {
+ if (ii != 0) signature.append(",");
+ signature.append(QMetaType::typeName(arguments->arguments[1 + ii]));
+ }
+ }
+
+ signature.append(")");
+
+ QMetaMethodBuilder method;
+ if (data->isSignal()) {
+ method = builder.addSignal(signature);
+ } else {
+ method = builder.addSlot(signature);
+ }
+ method.setAccess(QMetaMethod::Protected);
+
+ if (arguments && arguments->names)
+ method.setParameterNames(*arguments->names);
+
+ if (!returnType.isEmpty())
+ method.setReturnType(returnType);
+ }
+
+ if (!_defaultPropertyName.isEmpty()) {
+ QQmlPropertyData *dp = property(_defaultPropertyName, 0, 0);
+ if (dp && dp->coreIndex >= propertyIndexCacheStart) {
+ Q_ASSERT(!dp->isFunction());
+ builder.addClassInfo("DefaultProperty", _defaultPropertyName.toUtf8());
+ }
+ }
+}
+
+/*! \internal
+ \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
+ This is different from QMetaMethod::methodIndex().
+*/
+QList<QByteArray> QQmlPropertyCache::signalParameterNames(int index) const
+{
+ QQmlPropertyData *signalData = signal(index);
+ if (signalData && signalData->hasArguments()) {
+ QQmlPropertyCacheMethodArguments *args = (QQmlPropertyCacheMethodArguments *)signalData->arguments;
+ if (args && args->names)
+ return *args->names;
+ const QMetaMethod &method = QMetaObjectPrivate::signal(firstCppMetaObject(), index);
+ return method.parameterNames();
+ }
+ return QList<QByteArray>();
+}
+
+// Returns true if \a from is assignable to a property of type \a to
+bool QQmlMetaObject::canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to)
+{
+ Q_ASSERT(!from.isNull() && !to.isNull());
+
+ struct I { static bool equal(const QMetaObject *lhs, const QMetaObject *rhs) {
+ return lhs == rhs || (lhs && rhs && lhs->d.stringdata == rhs->d.stringdata);
+ } };
+
+ const QMetaObject *tom = to._m.isT1()?to._m.asT1()->metaObject():to._m.asT2();
+ if (tom == &QObject::staticMetaObject) return true;
+
+ if (from._m.isT1() && to._m.isT1()) { // QQmlPropertyCache -> QQmlPropertyCache
+ QQmlPropertyCache *fromp = from._m.asT1();
+ QQmlPropertyCache *top = to._m.asT1();
+
+ while (fromp) {
+ if (fromp == top) return true;
+ fromp = fromp->parent();
+ }
+ } else if (from._m.isT1() && to._m.isT2()) { // QQmlPropertyCache -> QMetaObject
+ QQmlPropertyCache *fromp = from._m.asT1();
+
+ while (fromp) {
+ const QMetaObject *fromm = fromp->metaObject();
+ if (fromm && I::equal(fromm, tom)) return true;
+ fromp = fromp->parent();
+ }
+ } else if (from._m.isT2() && to._m.isT1()) { // QMetaObject -> QQmlPropertyCache
+ const QMetaObject *fromm = from._m.asT2();
+
+ if (!tom) return false;
+
+ while (fromm) {
+ if (I::equal(fromm, tom)) return true;
+ fromm = fromm->superClass();
+ }
+ } else { // QMetaObject -> QMetaObject
+ const QMetaObject *fromm = from._m.asT2();
+
+ while (fromm) {
+ if (I::equal(fromm, tom)) return true;
+ fromm = fromm->superClass();
+ }
+ }
+
+ return false;
+}
+
+QQmlPropertyCache *QQmlMetaObject::propertyCache(QQmlEnginePrivate *e) const
+{
+ if (_m.isNull()) return 0;
+ if (_m.isT1()) return _m.asT1();
+ else return e->cache(_m.asT2());
+}
+
QT_END_NAMESPACE