diff options
author | Alan Alpert <aalpert@rim.com> | 2012-12-05 19:09:54 (GMT) |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-02-19 16:45:43 (GMT) |
commit | 0632711ebfa8e2167628f5f4ef4168363eb77eba (patch) | |
tree | 75606c32d7d69bda6dabc84e13e6a86716435cc7 | |
parent | 18c47c438cde545a69e15484ef5161e5f5b48c62 (diff) | |
download | Qt-0632711ebfa8e2167628f5f4ef4168363eb77eba.zip Qt-0632711ebfa8e2167628f5f4ef4168363eb77eba.tar.gz Qt-0632711ebfa8e2167628f5f4ef4168363eb77eba.tar.bz2 |
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.
Since public API is frozen for 4.8, this is being added as private API
for those who need some measure of compatibility with qtquick1 in Qt5.
Change-Id: I28d7898122c5556fcd7cf3476795bcf4bb288ea6
Manual cherry pick of qtquick1/9995a2910d8a5f0317fe3adeb54f838b99ab31a8
Reviewed-by: Matthew Vogt <matthew.vogt@qinetic.com.au>
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
7 files changed, 145 insertions, 1 deletions
diff --git a/src/declarative/qml/qdeclarativeimport.cpp b/src/declarative/qml/qdeclarativeimport.cpp index f401ac5..5d1ff36 100644 --- a/src/declarative/qml/qdeclarativeimport.cpp +++ b/src/declarative/qml/qdeclarativeimport.cpp @@ -529,6 +529,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 a94f4be..2fe181f 100644 --- a/src/declarative/qml/qdeclarativemetatype.cpp +++ b/src/declarative/qml/qdeclarativemetatype.cpp @@ -54,6 +54,8 @@ #include <QtCore/qmetaobject.h> #include <QtCore/qbitarray.h> #include <QtCore/qreadwritelock.h> +#include <qfileinfo.h> +#include <qdir.h> #include <qmetatype.h> #include <qobjectdefs.h> #include <qdatetime.h> @@ -122,6 +124,14 @@ struct QDeclarativeMetaTypeData Q_GLOBAL_STATIC(QDeclarativeMetaTypeData, metaTypeData) Q_GLOBAL_STATIC(QReadWriteLock, metaTypeDataLock) +struct QDeclarativeRegisteredComponentData +{ + QMap<QByteArray, QDeclarativeDirComponents*> registeredComponents; +}; + +Q_GLOBAL_STATIC(QDeclarativeRegisteredComponentData, registeredComponentData) +Q_GLOBAL_STATIC(QReadWriteLock, registeredComponentDataLock) + QDeclarativeMetaTypeData::~QDeclarativeMetaTypeData() { for (int i = 0; i < types.count(); ++i) @@ -667,6 +677,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 +728,8 @@ int QDeclarativePrivate::qmlregister(RegistrationType type, void *data) return registerInterface(*reinterpret_cast<RegisterInterface *>(data)); } else if (type == AutoParentRegistration) { return registerAutoParentFunction(*reinterpret_cast<RegisterAutoParent *>(data)); + } else if (type == ComponentRegistration) { + return registerComponent(*reinterpret_cast<RegisterComponent *>(data)); } return -1; } @@ -984,6 +1035,29 @@ QDeclarativeType *QDeclarativeMetaType::qmlType(int userType) } /*! + 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. */ QList<QByteArray> QDeclarativeMetaType::qmlTypeNames() diff --git a/src/declarative/qml/qdeclarativemetatype_p.h b/src/declarative/qml/qdeclarativemetatype_p.h index 34064cd..117a669 100644 --- a/src/declarative/qml/qdeclarativemetatype_p.h +++ b/src/declarative/qml/qdeclarativemetatype_p.h @@ -59,6 +59,7 @@ #include <QtCore/qvariant.h> #include <QtCore/qbitarray.h> #include <private/qdeclarativeglobal_p.h> +#include <private/qdeclarativedirparser_p.h> 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); + 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 c90d04f..263d9b8 100644 --- a/src/declarative/qml/qdeclarativeprivate.h +++ b/src/declarative/qml/qdeclarativeprivate.h @@ -55,6 +55,7 @@ #include <QtCore/qglobal.h> #include <QtCore/qvariant.h> +#include <QtCore/qurl.h> QT_BEGIN_HEADER @@ -233,13 +234,52 @@ 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 *); + + + /*! + \internal + \fn int qmlRegisterType(const char *url, const char *uri, int versionMajor, int versionMinor, const char *qmlName); + \relates QDeclarativeEngine + + This function registers a type in the QML system with the name \a qmlName, in the library imported from \a uri having the + version number composed from \a versionMajor and \a versionMinor. The type is defined by the QML file located at \a url. + + Normally QML files can be loaded as types directly from other QML files, or using a qmldir file. This function allows + registration of files to types from a C++ module, such as when the type mapping needs to be procedurally determined at startup. + + Returns non-zero if the registration was sucessful. + + This function is added to QtQuick 1 in Qt 5, and is here as private API for developers needing compatibility. + */ + inline int qmlRegisterType(const QUrl &url, const char *uri, int versionMajor, int versionMinor, const char *qmlName) + { + RegisterComponent type = { + url, + uri, + qmlName, + versionMajor, + versionMinor + }; + + return qmlregister(QDeclarativePrivate::ComponentRegistration, &type); + } + } QT_END_NAMESPACE diff --git a/tests/auto/declarative/qdeclarativelanguage/data/MyComponentType.qml b/tests/auto/declarative/qdeclarativelanguage/data/MyComponentType.qml new file mode 100644 index 0000000..9ba0d61 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/MyComponentType.qml @@ -0,0 +1,5 @@ +import QtQuick 1.0 + +Item { + property int test: 11 +} diff --git a/tests/auto/declarative/qdeclarativelanguage/data/qmlComponentType.qml b/tests/auto/declarative/qdeclarativelanguage/data/qmlComponentType.qml new file mode 100644 index 0000000..a7c2ec4 --- /dev/null +++ b/tests/auto/declarative/qdeclarativelanguage/data/qmlComponentType.qml @@ -0,0 +1,4 @@ +import QtQuick 1.0 +import Test 1.0 + +RegisteredComponentType {} diff --git a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp index 14c7d82..dc965fd 100644 --- a/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp +++ b/tests/auto/declarative/qdeclarativelanguage/tst_qdeclarativelanguage.cpp @@ -41,6 +41,7 @@ #include <qtest.h> #include <QtDeclarative/qdeclarativeengine.h> #include <QtDeclarative/qdeclarativecomponent.h> +#include <QtDeclarative/qdeclarativeprivate.h> #include <QtCore/qfile.h> #include <QtCore/qdebug.h> #include <QtCore/qfileinfo.h> @@ -103,6 +104,7 @@ private slots: void assignLiteralToVariant(); void customParserTypes(); void rootAsQmlComponent(); + void qmlComponentType(); void inlineQmlComponents(); void idProperty(); void autoNotifyConnection(); @@ -642,6 +644,16 @@ void tst_qdeclarativelanguage::rootAsQmlComponent() QCOMPARE(object->getChildren()->count(), 2); } +// Tests that types can be specified from a QML only component +void tst_qdeclarativelanguage::qmlComponentType() +{ + QDeclarativeComponent component(&engine, TEST_FILE("qmlComponentType.qml")); + VERIFY_ERRORS(0); + QObject *object = qobject_cast<QObject *>(component.create()); + QVERIFY(object != 0); + QCOMPARE(object->property("test"), QVariant(11)); +} + // Tests that components can be specified inline void tst_qdeclarativelanguage::inlineQmlComponents() { @@ -1977,6 +1989,8 @@ void tst_qdeclarativelanguage::revisionOverloads() void tst_qdeclarativelanguage::initTestCase() { registerTypes(); + // Registered here because it uses TEST_FILE + QDeclarativePrivate::qmlRegisterType(TEST_FILE("MyComponentType.qml"), "Test", 1, 0, "RegisteredComponentType"); // Registering the TestType class in other modules should have no adverse effects qmlRegisterType<TestType>("org.qtproject.TestPre", 1, 0, "Test"); |