aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlmetatype.cpp
diff options
context:
space:
mode:
authorChris Adams <christopher.adams@nokia.com>2012-08-14 11:44:49 +1000
committerQt by Nokia <qt-info@nokia.com>2012-08-28 04:32:48 +0200
commit70a2c0491d66aa05f9e9e67f8a845f4df84da857 (patch)
tree08d7828cfb6950926e1176ee420d5e15dedd9817 /src/qml/qml/qqmlmetatype.cpp
parent3912bbaceab166eb116447311eb16453e4f26edf (diff)
Refactor singleton type registration code
Previously each singleton type was registered as an implicit separate import. This commit changes the code so that these types are treated just like any other type in the registration sense. It also ensures that singleton types are instantiated per-engine. Change-Id: I5c81c4ca5bf65210f7125d74a62a282a21838068 Reviewed-by: Matthew Vogt <matthew.vogt@nokia.com>
Diffstat (limited to 'src/qml/qml/qqmlmetatype.cpp')
-rw-r--r--src/qml/qml/qqmlmetatype.cpp345
1 files changed, 192 insertions, 153 deletions
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 1b94365d03..284269bf63 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -94,36 +94,6 @@ struct QQmlMetaTypeData
typedef QHash<VersionedUri, QQmlTypeModule *> TypeModules;
TypeModules uriToModule;
- struct SingletonTypeList {
- SingletonTypeList() : sorted(true) {}
- QList<QQmlMetaType::SingletonType> singletonTypes;
- bool sorted;
- };
- typedef QStringHash<SingletonTypeList> SingletonTypes;
- SingletonTypes singletonTypes;
- int singletonTypeCount;
-
- bool singletonTypeExists(const QString &uri, const QString &typeName, int major, int minor)
- {
- QQmlMetaTypeData::SingletonTypeList *apiList = singletonTypes.value(uri);
- if (apiList) {
- for (int i=0 ; i < apiList->singletonTypes.size() ; ++i) {
- const QQmlMetaType::SingletonType &import = apiList->singletonTypes.at(i);
- if (import.major == major && import.minor == minor && typeName == import.typeName)
- return true;
- }
- }
-
- return false;
- }
-
- bool typeExists(const QString &uri, const QString &typeName, int major, int minor)
- {
- QQmlMetaTypeData::VersionedUri versionedUri(uri, major);
- QQmlTypeModule *module = uriToModule.value(versionedUri);
- return module && module->typeNoLock(typeName, minor) != 0;
- }
-
QBitArray objects;
QBitArray interfaces;
QBitArray lists;
@@ -162,7 +132,6 @@ static uint qHash(const QQmlMetaTypeData::VersionedUri &v)
}
QQmlMetaTypeData::QQmlMetaTypeData()
-: singletonTypeCount(0)
{
}
@@ -176,6 +145,7 @@ class QQmlTypePrivate
{
public:
QQmlTypePrivate();
+ ~QQmlTypePrivate();
void init() const;
void initEnums() const;
@@ -213,6 +183,7 @@ public:
mutable bool m_haveSuperType:1;
mutable QList<QQmlProxyMetaObject::ProxyData> m_metaObjects;
mutable QStringHash<int> m_enums;
+ QQmlType::SingletonInstanceInfo *m_singletonInstanceInfo;
static QHash<const QMetaObject *, int> m_attachedPropertyIds;
};
@@ -238,6 +209,43 @@ static QHashedString moduleFromUtf8(const char *module)
return lastModuleStr;
}
+void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e)
+{
+ if (scriptCallback && scriptApi(e).isUndefined()) {
+ setScriptApi(e, scriptCallback(e, e));
+ } else if (qobjectCallback && !qobjectApi(e)) {
+ setQObjectApi(e, qobjectCallback(e, e));
+ }
+}
+
+void QQmlType::SingletonInstanceInfo::destroy(QQmlEngine *e)
+{
+ // cleans up the engine-specific singleton instances if they exist.
+ scriptApis.remove(e);
+ QObject *o = qobjectApis.take(e);
+ delete o;
+}
+
+void QQmlType::SingletonInstanceInfo::setQObjectApi(QQmlEngine *e, QObject *o)
+{
+ qobjectApis.insert(e, o);
+}
+
+QObject *QQmlType::SingletonInstanceInfo::qobjectApi(QQmlEngine *e) const
+{
+ return qobjectApis.value(e);
+}
+
+void QQmlType::SingletonInstanceInfo::setScriptApi(QQmlEngine *e, QJSValue v)
+{
+ scriptApis.insert(e, v);
+}
+
+QJSValue QQmlType::SingletonInstanceInfo::scriptApi(QQmlEngine *e) const
+{
+ return scriptApis.value(e);
+}
+
QHash<const QMetaObject *, int> QQmlTypePrivate::m_attachedPropertyIds;
QQmlTypePrivate::QQmlTypePrivate()
@@ -245,10 +253,14 @@ QQmlTypePrivate::QQmlTypePrivate()
m_superType(0), m_allocationSize(0), m_newFunc(0), m_baseMetaObject(0), m_attachedPropertiesFunc(0),
m_attachedPropertiesType(0), m_parserStatusCast(-1), m_propertyValueSourceCast(-1),
m_propertyValueInterceptorCast(-1), m_extFunc(0), m_extMetaObject(0), m_index(-1), m_customParser(0),
- m_isSetup(false), m_isEnumSetup(false), m_haveSuperType(false)
+ m_isSetup(false), m_isEnumSetup(false), m_haveSuperType(false), m_singletonInstanceInfo(0)
{
}
+QQmlTypePrivate::~QQmlTypePrivate()
+{
+ delete m_singletonInstanceInfo;
+}
QQmlType::QQmlType(int index, const QQmlPrivate::RegisterInterface &interface)
: d(new QQmlTypePrivate)
@@ -264,6 +276,34 @@ QQmlType::QQmlType(int index, const QQmlPrivate::RegisterInterface &interface)
d->m_version_min = 0;
}
+QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterSingletonType &type)
+: d(new QQmlTypePrivate)
+{
+ d->m_elementName = elementName;
+ d->m_module = moduleFromUtf8(type.uri);
+
+ d->m_version_maj = type.versionMajor;
+ d->m_version_min = type.versionMinor;
+
+ if (type.qobjectApi) {
+ if (type.version >= 1) // static metaobject added in version 1
+ d->m_baseMetaObject = type.instanceMetaObject;
+ if (type.version >= 2) // typeId added in version 2
+ d->m_typeId = type.typeId;
+ if (type.version >= 2) // revisions added in version 2
+ d->m_revision = type.revision;
+ }
+
+ d->m_newFunc = 0;
+ d->m_index = index;
+
+ d->m_singletonInstanceInfo = new SingletonInstanceInfo;
+ d->m_singletonInstanceInfo->scriptCallback = type.scriptApi;
+ d->m_singletonInstanceInfo->qobjectCallback = type.qobjectApi;
+ d->m_singletonInstanceInfo->typeName = QString::fromUtf8(type.typeName);
+ d->m_singletonInstanceInfo->instanceMetaObject = (type.qobjectApi && type.version >= 1) ? type.instanceMetaObject : 0;
+}
+
QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::RegisterType &type)
: d(new QQmlTypePrivate)
{
@@ -337,7 +377,7 @@ bool QQmlType::availableInVersion(const QHashedStringRef &module, int vmajor, in
// returns the nearest _registered_ super class
QQmlType *QQmlType::superType() const
{
- if (!d->m_haveSuperType) {
+ if (!d->m_haveSuperType && d->m_baseMetaObject) {
const QMetaObject *mo = d->m_baseMetaObject->superClass();
while (mo && !d->m_superType) {
d->m_superType = QQmlMetaType::qmlType(mo, d->m_module, d->m_version_maj, d->m_version_min);
@@ -443,9 +483,14 @@ void QQmlTypePrivate::init() const
if (m_isSetup)
return;
+ const QMetaObject *mo = m_baseMetaObject;
+ if (!mo) {
+ // singleton type without metaobject information
+ return;
+ }
+
// Setup extended meta object
// XXX - very inefficient
- const QMetaObject *mo = m_baseMetaObject;
if (m_extFunc) {
QMetaObjectBuilder builder;
clone(builder, m_extMetaObject, m_extMetaObject, m_extMetaObject);
@@ -514,7 +559,8 @@ void QQmlTypePrivate::initEnums() const
QWriteLocker lock(metaTypeDataLock());
if (m_isEnumSetup) return;
- insertEnums(m_baseMetaObject);
+ if (m_baseMetaObject) // could be singleton type without metaobject
+ insertEnums(m_baseMetaObject);
m_isEnumSetup = true;
}
@@ -540,6 +586,8 @@ void QQmlTypePrivate::insertEnums(const QMetaObject *metaObject) const
QByteArray QQmlType::typeName() const
{
+ if (d->m_singletonInstanceInfo)
+ return d->m_singletonInstanceInfo->typeName.toUtf8();
if (d->m_baseMetaObject)
return d->m_baseMetaObject->className();
else
@@ -590,6 +638,11 @@ void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) con
*memory = ((char *)rv) + d->m_allocationSize;
}
+QQmlType::SingletonInstanceInfo *QQmlType::singletonInstanceInfo() const
+{
+ return d->m_singletonInstanceInfo;
+}
+
QQmlCustomParser *QQmlType::customParser() const
{
return d->m_customParser;
@@ -622,6 +675,11 @@ bool QQmlType::isExtendedType() const
return !d->m_metaObjects.isEmpty();
}
+bool QQmlType::isSingleton() const
+{
+ return d->m_singletonInstanceInfo != 0;
+}
+
bool QQmlType::isInterface() const
{
return d->m_isInterface;
@@ -800,9 +858,9 @@ void QQmlTypeModulePrivate::add(QQmlType *type)
list.append(type);
}
-QQmlType *QQmlTypeModule::typeNoLock(const QString &name, int minor)
+QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor)
{
- // Expected that the caller has already handled locking metaTypeDataLock
+ QReadLocker lock(metaTypeDataLock());
QList<QQmlType *> *types = d->typeHash.value(name);
if (!types) return 0;
@@ -814,7 +872,7 @@ QQmlType *QQmlTypeModule::typeNoLock(const QString &name, int minor)
return 0;
}
-QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor)
+QQmlType *QQmlTypeModule::type(const QHashedV8String &name, int minor)
{
QReadLocker lock(metaTypeDataLock());
@@ -828,18 +886,18 @@ QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor)
return 0;
}
-QQmlType *QQmlTypeModule::type(const QHashedV8String &name, int minor)
+QList<QQmlType*> QQmlTypeModule::singletonTypes(int minor) const
{
QReadLocker lock(metaTypeDataLock());
- QList<QQmlType *> *types = d->typeHash.value(name);
- if (!types) return 0;
-
- for (int ii = 0; ii < types->count(); ++ii)
- if (types->at(ii)->minorVersion() <= minor)
- return types->at(ii);
+ QList<QQmlType *> retn;
+ for (int ii = 0; ii < d->types.count(); ++ii) {
+ QQmlType *curr = d->types.at(ii);
+ if (curr->isSingleton() && curr->minorVersion() <= minor)
+ retn.append(curr);
+ }
- return 0;
+ return retn;
}
@@ -929,49 +987,63 @@ int registerInterface(const QQmlPrivate::RegisterInterface &interface)
return index;
}
-int registerType(const QQmlPrivate::RegisterType &type)
+QString registrationTypeString(QQmlType::RegistrationType typeType)
{
- if (type.elementName) {
- for (int ii = 0; type.elementName[ii]; ++ii) {
- if (!isalnum(type.elementName[ii])) {
- qWarning("qmlRegisterType(): Invalid QML element name \"%s\"", type.elementName);
- return -1;
+ QString typeStr;
+ if (typeType == QQmlType::CppType)
+ typeStr = QStringLiteral("element");
+ else if (typeType == QQmlType::SingletonType)
+ typeStr = QStringLiteral("singleton type");
+ return typeStr;
+}
+
+// NOTE: caller must hold a QWriteLocker on "data"
+bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *data, const char *uri, const QString &typeName)
+{
+ if (!typeName.isEmpty()) {
+ int typeNameLen = typeName.length();
+ for (int ii = 0; ii < typeNameLen; ++ii) {
+ if (!typeName.at(ii).isLetterOrNumber()) {
+ QString failure(QCoreApplication::translate("qmlRegisterType", "Invalid QML %1 name \"%2\""));
+ data->typeRegistrationFailures.append(failure.arg(registrationTypeString(typeType)).arg(typeName));
+ return false;
}
}
}
- QWriteLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
-
- QString elementName = QString::fromUtf8(type.elementName);
-
- if (type.uri && type.elementName) {
- QString nameSpace = moduleFromUtf8(type.uri);
-
- if (data->singletonTypeExists(nameSpace, elementName, type.versionMajor, type.versionMinor)) {
- qWarning("Cannot register type %s in uri %s %d.%d (a conflicting singleton type already exists)", qPrintable(elementName), qPrintable(nameSpace), type.versionMajor, type.versionMinor);
- return -1;
- }
+ if (uri && !typeName.isEmpty()) {
+ QString nameSpace = moduleFromUtf8(uri);
if (!data->typeRegistrationNamespace.isEmpty()) {
// We can only install types into the registered namespace
if (nameSpace != data->typeRegistrationNamespace) {
QString failure(QCoreApplication::translate("qmlRegisterType",
- "Cannot install element '%1' into unregistered namespace '%2'"));
- data->typeRegistrationFailures.append(failure.arg(elementName).arg(nameSpace));
- return -1;
+ "Cannot install %1 '%2' into unregistered namespace '%3'"));
+ data->typeRegistrationFailures.append(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace));
+ return false;
}
} else if (data->typeRegistrationNamespace != nameSpace) {
// Is the target namespace protected against further registrations?
if (data->protectedNamespaces.contains(nameSpace)) {
QString failure(QCoreApplication::translate("qmlRegisterType",
- "Cannot install element '%1' into protected namespace '%2'"));
- data->typeRegistrationFailures.append(failure.arg(elementName).arg(nameSpace));
- return -1;
+ "Cannot install %1 '%2' into protected namespace '%3'"));
+ data->typeRegistrationFailures.append(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace));
+ return false;
}
}
}
+ return true;
+}
+
+int registerType(const QQmlPrivate::RegisterType &type)
+{
+ QWriteLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+ QString elementName = QString::fromUtf8(type.elementName);
+ if (!checkRegistration(QQmlType::CppType, data, type.uri, elementName))
+ return -1;
+
int index = data->types.count();
QQmlType *dtype = new QQmlType(index, elementName, type);
@@ -1008,39 +1080,44 @@ int registerType(const QQmlPrivate::RegisterType &type)
return index;
}
-int registerSingletonType(const QQmlPrivate::RegisterSingletonType &api)
+int registerSingletonType(const QQmlPrivate::RegisterSingletonType &type)
{
QWriteLocker lock(metaTypeDataLock());
-
QQmlMetaTypeData *data = metaTypeData();
- QString uri = QString::fromUtf8(api.uri);
- QQmlMetaType::SingletonType import;
- import.major = api.versionMajor;
- import.minor = api.versionMinor;
- import.script = api.scriptApi;
- import.qobject = api.qobjectApi;
- Q_ASSERT(api.typeName);
- import.typeName = QString::fromUtf8(api.typeName);
- import.instanceMetaObject = (api.qobjectApi && api.version >= 1) ? api.instanceMetaObject : 0; // BC with version 0.
-
- if (data->singletonTypeExists(uri, import.typeName, import.major, import.minor)) {
- qWarning("Cannot register singleton type %s in uri %s %d.%d (a conflicting singleton type already exists)", qPrintable(import.typeName), qPrintable(uri), import.major, import.minor);
- return -1;
- } else if (data->typeExists(uri, import.typeName, import.major, import.minor)) {
- qWarning("Cannot register singleton type %s in uri %s %d.%d (a conflicting type already exists)", qPrintable(import.typeName), qPrintable(uri), import.major, import.minor);
+ QString typeName = QString::fromUtf8(type.typeName);
+ if (!checkRegistration(QQmlType::SingletonType, data, type.uri, typeName))
return -1;
+
+ int index = data->types.count();
+
+ QQmlType *dtype = new QQmlType(index, typeName, type);
+
+ data->types.append(dtype);
+ data->idToType.insert(dtype->typeId(), dtype);
+
+ if (!dtype->elementName().isEmpty())
+ data->nameToType.insertMulti(dtype->elementName(), dtype);
+
+ if (dtype->baseMetaObject())
+ data->metaObjectToType.insertMulti(dtype->baseMetaObject(), dtype);
+
+ if (type.typeId) {
+ if (data->objects.size() <= type.typeId)
+ data->objects.resize(type.typeId + 16);
+ data->objects.setBit(type.typeId, true);
}
- int index = data->singletonTypeCount++;
+ if (!dtype->module().isEmpty()) {
+ const QHashedString &mod = dtype->module();
- QQmlMetaTypeData::SingletonTypeList *apiList = data->singletonTypes.value(uri);
- if (!apiList) {
- QQmlMetaTypeData::SingletonTypeList apis;
- apis.singletonTypes << import;
- data->singletonTypes.insert(uri, apis);
- } else {
- apiList->singletonTypes << import;
- apiList->sorted = false;
+ QQmlMetaTypeData::VersionedUri versionedUri(mod, type.versionMajor);
+ QQmlTypeModule *module = data->uriToModule.value(versionedUri);
+ if (!module) {
+ module = new QQmlTypeModule;
+ module->d->uri = versionedUri;
+ data->uriToModule.insert(versionedUri, module);
+ }
+ module->d->add(dtype);
}
return index;
@@ -1113,18 +1190,12 @@ bool QQmlMetaType::isAnyModule(const QString &uri)
QReadLocker lock(metaTypeDataLock());
QQmlMetaTypeData *data = metaTypeData();
- // first, check Types
for (QQmlMetaTypeData::TypeModules::ConstIterator iter = data->uriToModule.begin();
iter != data->uriToModule.end(); ++iter) {
if ((*iter)->module() == uri)
return true;
}
- // then, check SingletonTypes
- QQmlMetaTypeData::SingletonTypeList *apiList = data->singletonTypes.value(uri);
- if (apiList)
- return true;
-
return false;
}
@@ -1148,15 +1219,6 @@ bool QQmlMetaType::isModule(const QString &module, int versionMajor, int version
if (tm && tm->minimumMinorVersion() <= versionMinor && tm->maximumMinorVersion() >= versionMinor)
return true;
- // then, check SingletonTypes
- QQmlMetaTypeData::SingletonTypeList *apiList = data->singletonTypes.value(module);
- if (apiList) {
- foreach (const QQmlMetaType::SingletonType &mApi, apiList->singletonTypes) {
- if (mApi.major == versionMajor && mApi.minor == versionMinor) // XXX is this correct?
- return true;
- }
- }
-
return false;
}
@@ -1174,48 +1236,6 @@ QList<QQmlPrivate::AutoParentFunction> QQmlMetaType::parentFunctions()
return data->parentFunctions;
}
-static bool operator<(const QQmlMetaType::SingletonType &lhs, const QQmlMetaType::SingletonType &rhs)
-{
- return lhs.major < rhs.major || (lhs.major == rhs.major && lhs.minor < rhs.minor);
-}
-
-QQmlMetaType::SingletonType
-QQmlMetaType::singletonType(const QString &uri, int versionMajor, int versionMinor)
-{
- QReadLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
-
- QQmlMetaTypeData::SingletonTypeList *apiList = data->singletonTypes.value(uri);
- if (!apiList)
- return SingletonType();
-
- if (apiList->sorted == false) {
- qSort(apiList->singletonTypes.begin(), apiList->singletonTypes.end());
- apiList->sorted = true;
- }
-
- for (int ii = apiList->singletonTypes.count() - 1; ii >= 0; --ii) {
- const SingletonType &import = apiList->singletonTypes.at(ii);
- if (import.major == versionMajor && import.minor <= versionMinor)
- return import;
- }
-
- return SingletonType();
-}
-
-QHash<QString, QList<QQmlMetaType::SingletonType> > QQmlMetaType::singletonTypes()
-{
- QReadLocker lock(metaTypeDataLock());
- QQmlMetaTypeData *data = metaTypeData();
-
- QHash<QString, QList<SingletonType> > singletonTypes;
- QStringHash<QQmlMetaTypeData::SingletonTypeList>::ConstIterator it = data->singletonTypes.begin();
- for (; it != data->singletonTypes.end(); ++it)
- singletonTypes[it.key()] = it.value().singletonTypes;
-
- return singletonTypes;
-}
-
QObject *QQmlMetaType::toQObject(const QVariant &v, bool *ok)
{
if (!isQObject(v.userType())) {
@@ -1521,6 +1541,25 @@ QList<QQmlType*> QQmlMetaType::qmlTypes()
return data->nameToType.values();
}
+/*!
+ Returns the list of registered QML singleton types.
+*/
+QList<QQmlType*> QQmlMetaType::qmlSingletonTypes()
+{
+ QReadLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+
+ QList<QQmlType*> alltypes = data->nameToType.values();
+ QList<QQmlType*> retn;
+ foreach (QQmlType* t, alltypes) {
+ if (t->isSingleton()) {
+ retn.append(t);
+ }
+ }
+
+ return retn;
+}
+
int QQmlMetaType::QQuickAnchorLineMetaTypeId()
{
static int id = 0;