summaryrefslogtreecommitdiffstats
path: root/src/corelib/plugin/qfactoryloader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/plugin/qfactoryloader.cpp')
-rw-r--r--src/corelib/plugin/qfactoryloader.cpp269
1 files changed, 269 insertions, 0 deletions
diff --git a/src/corelib/plugin/qfactoryloader.cpp b/src/corelib/plugin/qfactoryloader.cpp
new file mode 100644
index 0000000000..c0b947ad19
--- /dev/null
+++ b/src/corelib/plugin/qfactoryloader.cpp
@@ -0,0 +1,269 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfactoryloader_p.h"
+
+#ifndef QT_NO_LIBRARY
+#include "qfactoryinterface.h"
+#include "qmap.h"
+#include <qdir.h>
+#include <qsettings.h>
+#include <qdebug.h>
+#include "qmutex.h"
+#include "qplugin.h"
+#include "qpluginloader.h"
+#include "private/qobject_p.h"
+#include "private/qcoreapplication_p.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(QList<QFactoryLoader *>, qt_factory_loaders)
+
+Q_GLOBAL_STATIC_WITH_ARGS(QMutex, qt_factoryloader_mutex, (QMutex::Recursive))
+
+class QFactoryLoaderPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QFactoryLoader)
+public:
+ QFactoryLoaderPrivate(){}
+ ~QFactoryLoaderPrivate();
+ mutable QMutex mutex;
+ QByteArray iid;
+ QList<QLibraryPrivate*> libraryList;
+ QMap<QString,QLibraryPrivate*> keyMap;
+ QStringList keyList;
+ QString suffix;
+ Qt::CaseSensitivity cs;
+ QStringList loadedPaths;
+
+ void unloadPath(const QString &path);
+};
+
+QFactoryLoaderPrivate::~QFactoryLoaderPrivate()
+{
+ for (int i = 0; i < libraryList.count(); ++i)
+ libraryList.at(i)->release();
+}
+
+QFactoryLoader::QFactoryLoader(const char *iid,
+ const QString &suffix,
+ Qt::CaseSensitivity cs)
+ : QObject(*new QFactoryLoaderPrivate)
+{
+ moveToThread(QCoreApplicationPrivate::mainThread());
+ Q_D(QFactoryLoader);
+ d->iid = iid;
+ d->cs = cs;
+ d->suffix = suffix;
+
+
+ QMutexLocker locker(qt_factoryloader_mutex());
+ update();
+ qt_factory_loaders()->append(this);
+}
+
+
+
+void QFactoryLoader::update()
+{
+#ifdef QT_SHARED
+ Q_D(QFactoryLoader);
+ QStringList paths = QCoreApplication::libraryPaths();
+ QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
+ for (int i = 0; i < paths.count(); ++i) {
+ const QString &pluginDir = paths.at(i);
+ // Already loaded, skip it...
+ if (d->loadedPaths.contains(pluginDir))
+ continue;
+ d->loadedPaths << pluginDir;
+
+ QString path = pluginDir + d->suffix;
+ if (!QDir(path).exists(QLatin1String(".")))
+ continue;
+
+ QStringList plugins = QDir(path).entryList(QDir::Files);
+ QLibraryPrivate *library = 0;
+ for (int j = 0; j < plugins.count(); ++j) {
+ QString fileName = QDir::cleanPath(path + QLatin1Char('/') + plugins.at(j));
+ if (qt_debug_component()) {
+ qDebug() << "QFactoryLoader::QFactoryLoader() looking at" << fileName;
+ }
+ library = QLibraryPrivate::findOrCreate(QFileInfo(fileName).canonicalFilePath());
+ if (!library->isPlugin(&settings)) {
+ if (qt_debug_component()) {
+ qDebug() << library->errorString;
+ qDebug() << " not a plugin";
+ }
+ library->release();
+ continue;
+ }
+ QString regkey = QString::fromLatin1("Qt Factory Cache %1.%2/%3:/%4")
+ .arg((QT_VERSION & 0xff0000) >> 16)
+ .arg((QT_VERSION & 0xff00) >> 8)
+ .arg(QLatin1String(d->iid))
+ .arg(fileName);
+ QStringList reg, keys;
+ reg = settings.value(regkey).toStringList();
+ if (reg.count() && library->lastModified == reg[0]) {
+ keys = reg;
+ keys.removeFirst();
+ } else {
+ if (!library->loadPlugin()) {
+ if (qt_debug_component()) {
+ qDebug() << library->errorString;
+ qDebug() << " could not load";
+ }
+ library->release();
+ continue;
+ }
+ QObject *instance = library->instance();
+ if (!instance) {
+ library->release();
+ // ignore plugins that have a valid signature but cannot be loaded.
+ continue;
+ }
+ QFactoryInterface *factory = qobject_cast<QFactoryInterface*>(instance);
+ if (instance && factory && instance->qt_metacast(d->iid))
+ keys = factory->keys();
+ if (keys.isEmpty())
+ library->unload();
+ reg.clear();
+ reg << library->lastModified;
+ reg += keys;
+ settings.setValue(regkey, reg);
+ }
+ if (qt_debug_component()) {
+ qDebug() << "keys" << keys;
+ }
+
+ if (keys.isEmpty()) {
+ library->release();
+ continue;
+ }
+ d->libraryList += library;
+ for (int k = 0; k < keys.count(); ++k) {
+ // first come first serve, unless the first
+ // library was built with a future Qt version,
+ // whereas the new one has a Qt version that fits
+ // better
+ QString key = keys.at(k);
+ if (!d->cs)
+ key = key.toLower();
+ QLibraryPrivate *previous = d->keyMap.value(key);
+ if (!previous || (previous->qt_version > QT_VERSION && library->qt_version <= QT_VERSION)) {
+ d->keyMap[key] = library;
+ d->keyList += keys.at(k);
+ }
+ }
+ }
+ }
+#else
+ Q_D(QFactoryLoader);
+ if (qt_debug_component()) {
+ qDebug() << "QFactoryLoader::QFactoryLoader() ignoring" << d->iid
+ << "since plugins are disabled in static builds";
+ }
+#endif
+}
+
+QFactoryLoader::~QFactoryLoader()
+{
+ QMutexLocker locker(qt_factoryloader_mutex());
+ qt_factory_loaders()->removeAll(this);
+}
+
+QStringList QFactoryLoader::keys() const
+{
+ Q_D(const QFactoryLoader);
+ QMutexLocker locker(&d->mutex);
+ QStringList keys = d->keyList;
+ QObjectList instances = QPluginLoader::staticInstances();
+ for (int i = 0; i < instances.count(); ++i)
+ if (QFactoryInterface *factory = qobject_cast<QFactoryInterface*>(instances.at(i)))
+ if (instances.at(i)->qt_metacast(d->iid))
+ keys += factory->keys();
+ return keys;
+}
+
+QObject *QFactoryLoader::instance(const QString &key) const
+{
+ Q_D(const QFactoryLoader);
+ QMutexLocker locker(&d->mutex);
+ QObjectList instances = QPluginLoader::staticInstances();
+ for (int i = 0; i < instances.count(); ++i)
+ if (QFactoryInterface *factory = qobject_cast<QFactoryInterface*>(instances.at(i)))
+ if (instances.at(i)->qt_metacast(d->iid) && factory->keys().contains(key, Qt::CaseInsensitive))
+ return instances.at(i);
+
+ QString lowered = d->cs ? key : key.toLower();
+ if (QLibraryPrivate* library = d->keyMap.value(lowered)) {
+ if (library->instance || library->loadPlugin()) {
+ if (QObject *obj = library->instance()) {
+ if (obj && !obj->parent())
+ obj->moveToThread(QCoreApplicationPrivate::mainThread());
+ return obj;
+ }
+ }
+ }
+ return 0;
+}
+
+#ifdef Q_WS_X11
+QLibraryPrivate *QFactoryLoader::library(const QString &key) const
+{
+ Q_D(const QFactoryLoader);
+ return d->keyMap.value(d->cs ? key : key.toLower());
+}
+#endif
+
+void QFactoryLoader::refreshAll()
+{
+ QMutexLocker locker(qt_factoryloader_mutex());
+ QList<QFactoryLoader *> *loaders = qt_factory_loaders();
+ for (QList<QFactoryLoader *>::const_iterator it = loaders->constBegin();
+ it != loaders->constEnd(); ++it) {
+ (*it)->update();
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_LIBRARY