From 9995a2910d8a5f0317fe3adeb54f838b99ab31a8 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Mon, 3 Dec 2012 08:50:11 -0800 Subject: Add a method that allows registration of files to types There is currently no way in C++ to duplicate the functionality of a qmldir file in mapping QML files to versioned types in a module. This functionality would be useful both in cases where a separate qmldir file would be overkill, and for cases where the type mapping should be generated dynamically. Change-Id: I28d7898122c5556fcd7cf3476795bcf4bb288eab Reviewed-by: Christopher Adams --- src/declarative/qml/qdeclarative.h | 14 ++++++ src/declarative/qml/qdeclarativeimport.cpp | 3 ++ src/declarative/qml/qdeclarativemetatype.cpp | 75 ++++++++++++++++++++++++++++ src/declarative/qml/qdeclarativemetatype_p.h | 4 ++ src/declarative/qml/qdeclarativeprivate.h | 11 +++- 5 files changed, 106 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/declarative/qml/qdeclarative.h b/src/declarative/qml/qdeclarative.h index 4f7dcb2b..68fae370 100644 --- a/src/declarative/qml/qdeclarative.h +++ b/src/declarative/qml/qdeclarative.h @@ -49,6 +49,7 @@ #include #include +#include #include QT_BEGIN_HEADER @@ -390,6 +391,19 @@ int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor, return QDeclarativePrivate::qmlregister(QDeclarativePrivate::TypeRegistration, &type); } +inline int Q_DECLARATIVE_EXPORT qmlRegisterType(const QUrl &url, const char *uri, int versionMajor, int versionMinor, const char *qmlName) +{ + QDeclarativePrivate::RegisterComponent type = { + url, + uri, + qmlName, + versionMajor, + versionMinor + }; + + return QDeclarativePrivate::qmlregister(QDeclarativePrivate::ComponentRegistration, &type); +} + class QDeclarativeContext; class QDeclarativeEngine; Q_DECLARATIVE_EXPORT void qmlExecuteDeferred(QObject *); diff --git a/src/declarative/qml/qdeclarativeimport.cpp b/src/declarative/qml/qdeclarativeimport.cpp index db062e47..14e69728 100644 --- a/src/declarative/qml/qdeclarativeimport.cpp +++ b/src/declarative/qml/qdeclarativeimport.cpp @@ -518,6 +518,9 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp if (QDeclarativeMetaType::isModule(uri.toUtf8(), vmaj, vmin)) versionFound = true; + //Load any type->file mappings registered for this uri + qmldircomponents << QDeclarativeMetaType::qmlComponents(uri.toUtf8(), vmaj, vmin); + if (!versionFound && qmldircomponents.isEmpty()) { if (errorString) { bool anyversion = QDeclarativeMetaType::isModule(uri.toUtf8(), -1, -1); diff --git a/src/declarative/qml/qdeclarativemetatype.cpp b/src/declarative/qml/qdeclarativemetatype.cpp index d7eacaf4..09390646 100644 --- a/src/declarative/qml/qdeclarativemetatype.cpp +++ b/src/declarative/qml/qdeclarativemetatype.cpp @@ -54,6 +54,8 @@ #include #include #include +#include +#include #include #include #include @@ -122,6 +124,15 @@ struct QDeclarativeMetaTypeData Q_GLOBAL_STATIC(QDeclarativeMetaTypeData, metaTypeData) Q_GLOBAL_STATIC(QReadWriteLock, metaTypeDataLock) +struct QDeclarativeRegisteredComponentData +{ + ~QDeclarativeRegisteredComponentData() {} ; + QMap registeredComponents; +}; + +Q_GLOBAL_STATIC(QDeclarativeRegisteredComponentData, registeredComponentData) +Q_GLOBAL_STATIC(QReadWriteLock, registeredComponentDataLock) + QDeclarativeMetaTypeData::~QDeclarativeMetaTypeData() { for (int i = 0; i < types.count(); ++i) @@ -667,6 +678,45 @@ int registerType(const QDeclarativePrivate::RegisterType &type) return index; } +int registerComponent(const QDeclarativePrivate::RegisterComponent& data) +{ + if (data.typeName) { + for (int ii = 0; data.typeName[ii]; ++ii) { + if (!isalnum(data.typeName[ii])) { + qWarning("qmlRegisterType(): Invalid QML type name \"%s\"", data.typeName); + return 0; + } + } + } else { + qWarning("qmlRegisterType(): No QML type name for \"%s\"", data.url.toString().toLatin1().constData()); + return 0; + } + + QWriteLocker lock(registeredComponentDataLock()); + QString path; + // Relative paths are relative to application working directory + if (data.url.isRelative() || data.url.scheme() == QLatin1String("file")) // Workaround QTBUG-11929 + path = QUrl::fromLocalFile(QDir::currentPath()+QLatin1String("/")).resolved(data.url).toString(); + else + path = data.url.toString(); + QDeclarativeRegisteredComponentData *d = registeredComponentData(); + QDeclarativeDirParser::Component comp( + QString::fromUtf8(data.typeName), + path, + data.majorVersion, + data.minorVersion + ); + + QDeclarativeDirComponents* comps = d->registeredComponents.value(QByteArray(data.uri), 0); + if (!comps) + d->registeredComponents.insert(QByteArray(data.uri), comps = new QDeclarativeDirComponents); + + // Types added later should take precedence, like registerType + comps->prepend(comp); + + return 1; +} + /* This method is "over generalized" to allow us to (potentially) register more types of things in the future without adding exported symbols. @@ -679,6 +729,8 @@ int QDeclarativePrivate::qmlregister(RegistrationType type, void *data) return registerInterface(*reinterpret_cast(data)); } else if (type == AutoParentRegistration) { return registerAutoParentFunction(*reinterpret_cast(data)); + } else if (type == ComponentRegistration) { + return registerComponent(*reinterpret_cast(data)); } return -1; } @@ -983,6 +1035,29 @@ QDeclarativeType *QDeclarativeMetaType::qmlType(int userType) return 0; } +/*! + Returns the component(s) that have been registered for the module specified by \a uri and the version specified + by \a version_major and \a version_minor. Returns an empty list if no such components were registered. +*/ +QDeclarativeDirComponents QDeclarativeMetaType::qmlComponents(const QByteArray &module, int version_major, int version_minor) +{ + QReadLocker lock(registeredComponentDataLock()); + QDeclarativeRegisteredComponentData *data = registeredComponentData(); + + QDeclarativeDirComponents* comps = data->registeredComponents.value(module, 0); + if (!comps) + return QDeclarativeDirComponents(); + QDeclarativeDirComponents ret = *comps; + for (int i = ret.count() - 1; i >= 0; i--) { + QDeclarativeDirParser::Component &c = ret[i]; + if (version_major >= 0 && (c.majorVersion != version_major || c.minorVersion > version_minor)) + ret.removeAt(i); + } + + return ret; +} + + /*! Returns the list of registered QML type names. */ diff --git a/src/declarative/qml/qdeclarativemetatype_p.h b/src/declarative/qml/qdeclarativemetatype_p.h index d751f049..a1699558 100644 --- a/src/declarative/qml/qdeclarativemetatype_p.h +++ b/src/declarative/qml/qdeclarativemetatype_p.h @@ -59,6 +59,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -80,6 +81,8 @@ public: static QDeclarativeType *qmlType(const QMetaObject *metaObject, const QByteArray &module, int version_major, int version_minor); static QDeclarativeType *qmlType(int); + static QDeclarativeDirComponents qmlComponents(const QByteArray& module, int version_major, int version_minor); //### Is this the right place? + static QMetaProperty defaultProperty(const QMetaObject *); static QMetaProperty defaultProperty(QObject *); static QMetaMethod defaultMethod(const QMetaObject *); @@ -161,6 +164,7 @@ private: friend struct QDeclarativeMetaTypeData; friend int registerType(const QDeclarativePrivate::RegisterType &); friend int registerInterface(const QDeclarativePrivate::RegisterInterface &); + friend int registerComponent(const QDeclarativePrivate::RegisterComponent &); QDeclarativeType(int, const QDeclarativePrivate::RegisterInterface &); QDeclarativeType(int, const QDeclarativePrivate::RegisterType &); ~QDeclarativeType(); diff --git a/src/declarative/qml/qdeclarativeprivate.h b/src/declarative/qml/qdeclarativeprivate.h index db2b0661..b88ff79f 100644 --- a/src/declarative/qml/qdeclarativeprivate.h +++ b/src/declarative/qml/qdeclarativeprivate.h @@ -233,10 +233,19 @@ namespace QDeclarativePrivate AutoParentFunction function; }; + struct RegisterComponent { + const QUrl &url; + const char *uri; + const char *typeName; + int majorVersion; + int minorVersion; + }; + enum RegistrationType { TypeRegistration = 0, InterfaceRegistration = 1, - AutoParentRegistration = 2 + AutoParentRegistration = 2, + ComponentRegistration = 3 }; int Q_DECLARATIVE_EXPORT qmlregister(RegistrationType, void *); -- cgit v1.2.3