aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Alpert <416365416c@gmail.com>2013-05-17 15:32:19 -0700
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-20 01:09:05 +0200
commitfee79b70773ef26c5d45993c4618d302392b0782 (patch)
tree89c5a0c07eb0c8504ecb1e77ef78b7899d10ed7a
parent8850e2eafaba8a6493d3ad5ab584b751eb9a8742 (diff)
Add qmlProtectModule
A C++ analog to the protected qmldir syntax, this is also a potential performance improvement because we can avoid some file system accesses. Change-Id: I41781a6cc72aa65bd2d397800345ea16ef442e90 Reviewed-by: Antti Piira <apiira@blackberry.com> Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
-rw-r--r--src/qml/doc/src/qmlfunctions.qdoc25
-rw-r--r--src/qml/qml/qqml.h3
-rw-r--r--src/qml/qml/qqmlmetatype.cpp58
-rw-r--r--src/qml/qml/qqmlmetatype_p.h4
-rw-r--r--src/qml/qml/qqmltypeloader.cpp8
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/protectedModule/plugin.cpp69
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/protectedModule/protectedModule.pro13
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/protectedModule/qmldir1
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro3
-rw-r--r--tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp21
10 files changed, 197 insertions, 8 deletions
diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc
index 386f9f49df..7d668a4a11 100644
--- a/src/qml/doc/src/qmlfunctions.qdoc
+++ b/src/qml/doc/src/qmlfunctions.qdoc
@@ -413,3 +413,28 @@
Returns non-zero if the registration was sucessful.
*/
+/*!
+ \fn int qmlProtectModule(const QString &uri, int versionMajor);
+ \relates QQmlEngine
+
+ This function protects a module from having types registered into it. This
+ can be used to prevent other plugins from injecting types into your module.
+ It can also be a performance improvement, as it allows the engine to skip
+ checking for the possibility of new types or plugins when this import is
+ reached.
+
+ The performance benefit is primarily seen when registering application
+ specific types from within the application instead of through a plugin.
+ Using qmlProtectModule allows the engine to skip checking for a plugin when
+ that uri is imported, which can be noticeable with slow file systems.
+
+ After this function is called, any attempt to register C++ types into this
+ uri, major version combination will lead to a runtime error. Call this after
+ you have registered all of your types with the engine.
+
+ #include <QtQml> to use this function.
+
+ Returns true if the module was found and locked, otherwise returns false.
+ The module must contain exported types in order to be found.
+*/
+
diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h
index ee69985edb..6082fcda08 100644
--- a/src/qml/qml/qqml.h
+++ b/src/qml/qml/qqml.h
@@ -441,6 +441,9 @@ using namespace QtQml;
#pragma clang diagnostic pop
#endif
+//The C++ version of protected namespaces in qmldir
+Q_QML_EXPORT bool qmlProtectModule(const char* uri, int majVersion);
+
template<typename T>
QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true)
{
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index f3b4d6b1e5..f9583e7a59 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -112,12 +112,15 @@ class QQmlTypeModulePrivate
{
public:
QQmlTypeModulePrivate()
- : minMinorVersion(INT_MAX), maxMinorVersion(0) {}
+ : minMinorVersion(INT_MAX), maxMinorVersion(0), locked(false) {}
+
+ static QQmlTypeModulePrivate* get(QQmlTypeModule* q) { return q->d; }
QQmlMetaTypeData::VersionedUri uri;
int minMinorVersion;
int maxMinorVersion;
+ bool locked;
void add(QQmlType *);
@@ -1126,7 +1129,7 @@ QString registrationTypeString(QQmlType::RegistrationType typeType)
}
// NOTE: caller must hold a QWriteLocker on "data"
-bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *data, const char *uri, const QString &typeName)
+bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *data, const char *uri, const QString &typeName, int majorVersion = -1)
{
if (!typeName.isEmpty()) {
int typeNameLen = typeName.length();
@@ -1158,6 +1161,18 @@ bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *da
data->typeRegistrationFailures.append(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace));
return false;
}
+ } else if (majorVersion >= 0) {
+ QQmlMetaTypeData::VersionedUri versionedUri;
+ versionedUri.uri = nameSpace;
+ versionedUri.majorVersion = majorVersion;
+ if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0)){
+ if (QQmlTypeModulePrivate::get(qqtm)->locked){
+ QString failure(QCoreApplication::translate("qmlRegisterType",
+ "Cannot install %1 '%2' into protected module '%3' version '%4'"));
+ data->typeRegistrationFailures.append(failure.arg(registrationTypeString(typeType)).arg(typeName).arg(nameSpace).arg(majorVersion));
+ return false;
+ }
+ }
}
}
@@ -1206,7 +1221,7 @@ 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))
+ if (!checkRegistration(QQmlType::CppType, data, type.uri, elementName, type.versionMajor))
return -1;
int index = data->types.count();
@@ -1226,7 +1241,7 @@ int registerSingletonType(const QQmlPrivate::RegisterSingletonType &type)
QWriteLocker lock(metaTypeDataLock());
QQmlMetaTypeData *data = metaTypeData();
QString typeName = QString::fromUtf8(type.typeName);
- if (!checkRegistration(QQmlType::SingletonType, data, type.uri, typeName))
+ if (!checkRegistration(QQmlType::SingletonType, data, type.uri, typeName, type.versionMajor))
return -1;
int index = data->types.count();
@@ -1248,7 +1263,7 @@ int registerCompositeType(const QQmlPrivate::RegisterCompositeType &type)
bool fileImport = false;
if (*(type.uri) == '\0')
fileImport = true;
- if (!checkRegistration(QQmlType::CompositeType, data, fileImport?0:type.uri, typeName))
+ if (!checkRegistration(QQmlType::CompositeType, data, fileImport?0:type.uri, typeName, type.versionMajor))
return -1;
int index = data->types.count();
@@ -1284,6 +1299,23 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data)
return -1;
}
+//From qqml.h
+bool qmlProtectModule(const char *uri, int majVersion)
+{
+ QWriteLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+
+ QQmlMetaTypeData::VersionedUri versionedUri;
+ versionedUri.uri = QString::fromUtf8(uri);
+ versionedUri.majorVersion = majVersion;
+
+ if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0)) {
+ QQmlTypeModulePrivate::get(qqtm)->locked = true;
+ return true;
+ }
+ return false;
+}
+
bool QQmlMetaType::namespaceContainsRegistrations(const QString &uri)
{
QQmlMetaTypeData *data = metaTypeData();
@@ -1342,6 +1374,22 @@ bool QQmlMetaType::isAnyModule(const QString &uri)
}
/*
+ Returns true if a module \a uri of this version is installed and locked;
+*/
+bool QQmlMetaType::isLockedModule(const QString &uri, int majVersion)
+{
+ QReadLocker lock(metaTypeDataLock());
+ QQmlMetaTypeData *data = metaTypeData();
+
+ QQmlMetaTypeData::VersionedUri versionedUri;
+ versionedUri.uri = uri;
+ versionedUri.majorVersion = majVersion;
+ if (QQmlTypeModule* qqtm = data->uriToModule.value(versionedUri, 0))
+ return QQmlTypeModulePrivate::get(qqtm)->locked;
+ return false;
+}
+
+/*
Returns true if any type or API has been registered for the given \a module with at least
versionMajor.versionMinor, or if types have been registered for \a module with at most
versionMajor.versionMinor.
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index e44eade902..f747049f11 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -113,6 +113,7 @@ public:
static StringConverter customStringConverter(int);
static bool isAnyModule(const QString &uri);
+ static bool isLockedModule(const QString &uri, int majorVersion);
static bool isModule(const QString &module, int versionMajor, int versionMinor);
static QQmlTypeModule *typeModule(const QString &uri, int majorVersion);
@@ -227,7 +228,7 @@ private:
CompositeType = 3
};
friend QString registrationTypeString(RegistrationType);
- friend bool checkRegistration(RegistrationType, QQmlMetaTypeData *, const char *, const QString &);
+ friend bool checkRegistration(RegistrationType, QQmlMetaTypeData *, const char *, const QString &, int);
friend int registerType(const QQmlPrivate::RegisterType &);
friend int registerSingletonType(const QQmlPrivate::RegisterSingletonType &);
friend int registerInterface(const QQmlPrivate::RegisterInterface &);
@@ -262,6 +263,7 @@ private:
friend void addTypeToData(QQmlType* type, QQmlMetaTypeData *data);
friend struct QQmlMetaTypeData;
friend Q_QML_EXPORT void qmlClearTypeRegistrations();
+ friend class QQmlTypeModulePrivate;
QQmlTypeModule();
~QQmlTypeModule();
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index d138a232b5..23739de3fb 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -1252,7 +1252,13 @@ bool QQmlTypeLoader::Blob::addImport(const QQmlScript::Import &import, QList<QQm
QString qmldirFilePath;
QString qmldirUrl;
- if (m_imports.locateQmldir(importDatabase, import.uri, import.majorVersion, import.minorVersion,
+ if (QQmlMetaType::isLockedModule(import.uri, import.majorVersion)) {
+ //Locked modules are checked first, to save on filesystem checks
+ if (!m_imports.addLibraryImport(importDatabase, import.uri, import.qualifier, import.majorVersion,
+ import.minorVersion, QString(), QString(), false, errors))
+ return false;
+
+ } else if (m_imports.locateQmldir(importDatabase, import.uri, import.majorVersion, import.minorVersion,
&qmldirFilePath, &qmldirUrl)) {
// This is a local library import
if (!m_imports.addLibraryImport(importDatabase, import.uri, import.qualifier, import.majorVersion,
diff --git a/tests/auto/qml/qqmlmoduleplugin/protectedModule/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/protectedModule/plugin.cpp
new file mode 100644
index 0000000000..c960a69a9e
--- /dev/null
+++ b/tests/auto/qml/qqmlmoduleplugin/protectedModule/plugin.cpp
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QtQml/qqmlextensionplugin.h>
+#include <QtQml/qqml.h>
+#include <QDebug>
+
+class MyPluginType : public QObject
+{
+ Q_OBJECT
+public:
+ MyPluginType(QObject *parent=0) : QObject(parent) {}
+};
+
+
+class MyPlugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
+
+public:
+ MyPlugin() {}
+
+ void registerTypes(const char *uri)
+ {
+ // Because the module is protected, this plugin should never be loaded
+ Q_UNUSED(uri);
+ Q_ASSERT(0);
+ }
+};
+
+#include "plugin.moc"
diff --git a/tests/auto/qml/qqmlmoduleplugin/protectedModule/protectedModule.pro b/tests/auto/qml/qqmlmoduleplugin/protectedModule/protectedModule.pro
new file mode 100644
index 0000000000..749a440ca8
--- /dev/null
+++ b/tests/auto/qml/qqmlmoduleplugin/protectedModule/protectedModule.pro
@@ -0,0 +1,13 @@
+TEMPLATE = lib
+CONFIG += plugin
+SOURCES = plugin.cpp
+QT = core qml
+DESTDIR = ../imports/org/qtproject/ProtectedModule
+
+QT += core-private gui-private qml-private
+
+IMPORT_FILES = \
+ qmldir
+
+include (../../../shared/imports.pri)
+DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
diff --git a/tests/auto/qml/qqmlmoduleplugin/protectedModule/qmldir b/tests/auto/qml/qqmlmoduleplugin/protectedModule/qmldir
new file mode 100644
index 0000000000..8d121bb17b
--- /dev/null
+++ b/tests/auto/qml/qqmlmoduleplugin/protectedModule/qmldir
@@ -0,0 +1 @@
+plugin protectedModule
diff --git a/tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro b/tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro
index 4806d34699..54acabe8eb 100644
--- a/tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro
+++ b/tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro
@@ -15,7 +15,8 @@ SUBDIRS =\
preemptiveModule\
preemptedStrictModule\
invalidNamespaceModule\
- invalidFirstCommandModule
+ invalidFirstCommandModule\
+ protectedModule
tst_qqmlmoduleplugin_pro.depends += plugin
SUBDIRS += tst_qqmlmoduleplugin.pro
diff --git a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
index ab8ff0e1a4..4379a90d47 100644
--- a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
+++ b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp
@@ -80,6 +80,7 @@ private slots:
void importLocalModule_data();
void importStrictModule();
void importStrictModule_data();
+ void importProtectedModule();
private:
QString m_importsDirectory;
@@ -542,6 +543,26 @@ void tst_qqmlmoduleplugin::importStrictModule_data()
<< ":1:1: module identifier directive must be the first directive in a qmldir file";
}
+void tst_qqmlmoduleplugin::importProtectedModule()
+{
+ //TODO: More than basic test (test errors,test inverse works...)
+ qmlRegisterType<QObject>("org.qtproject.ProtectedModule", 1, 0, "TestType");
+ qmlProtectModule("org.qtproject.ProtectedModule", 1);
+
+ QQmlEngine engine;
+ engine.addImportPath(m_importsDirectory);
+
+ QUrl url(testFileUrl("empty.qml"));
+
+ QString qml = "import org.qtproject.ProtectedModule 1.0\n TestType {}\n";
+ QQmlComponent component(&engine);
+ component.setData(qml.toUtf8(), url);
+ //If plugin is loaded due to import, should assert
+ QScopedPointer<QObject> object(component.create());
+ //qDebug() << component.errorString();
+ QVERIFY(object != 0);
+}
+
QTEST_MAIN(tst_qqmlmoduleplugin)
#include "tst_qqmlmoduleplugin.moc"