src/corelib/plugin/qfactoryloader.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.
00004 **
00005 ** This file is part of the QtCore module of the Qt Toolkit.
00006 **
00007 ** This file may be used under the terms of the GNU General Public
00008 ** License version 2.0 as published by the Free Software Foundation
00009 ** and appearing in the file LICENSE.GPL included in the packaging of
00010 ** this file.  Please review the following information to ensure GNU
00011 ** General Public Licensing requirements will be met:
00012 ** http://www.trolltech.com/products/qt/opensource.html
00013 **
00014 ** If you are unsure which license is appropriate for your use, please
00015 ** review the following information:
00016 ** http://www.trolltech.com/products/qt/licensing.html or contact the
00017 ** sales department at sales@trolltech.com.
00018 **
00019 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021 **
00022 ****************************************************************************/
00023 
00024 #include "qfactoryloader_p.h"
00025 
00026 #ifndef QT_NO_LIBRARY
00027 #include "qfactoryinterface.h"
00028 #include "qmap.h"
00029 #include <qdir.h>
00030 #include <qsettings.h>
00031 #include <qdebug.h>
00032 #include "qmutex.h"
00033 #include "qplugin.h"
00034 #include "qpluginloader.h"
00035 #include "private/qobject_p.h"
00036 #include "private/qcoreapplication_p.h"
00037 
00038 class QFactoryLoaderPrivate : public QObjectPrivate
00039 {
00040     Q_DECLARE_PUBLIC(QFactoryLoader)
00041 public:
00042     QFactoryLoaderPrivate(){}
00043     mutable QMutex mutex;
00044     QByteArray iid;
00045     QList<QLibraryPrivate*> libraryList;
00046     QMap<QString,QLibraryPrivate*> keyMap;
00047     QStringList keyList;
00048 };
00049 
00050 QFactoryLoader::QFactoryLoader(const char *iid,
00051                                const QStringList &paths, const QString &suffix,
00052                                Qt::CaseSensitivity cs)
00053     : QObject(*new QFactoryLoaderPrivate)
00054 {
00055     moveToThread(QCoreApplicationPrivate::mainThread());
00056     Q_D(QFactoryLoader);
00057     d->iid = iid;
00058 
00059     QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
00060 
00061     for (int i = 0; i < paths.count(); ++i) {
00062         QString path = paths.at(i) + suffix;
00063         if (!QDir(path).exists(QLatin1String(".")))
00064             continue;
00065         QStringList plugins = QDir(path).entryList(QDir::Files);
00066         QLibraryPrivate *library = 0;
00067         for (int j = 0; j < plugins.count(); ++j) {
00068             QString fileName = QDir::cleanPath(path + QLatin1Char('/') + plugins.at(j));
00069             if (qt_debug_component()) {
00070                 qDebug() << "QFactoryLoader::QFactoryLoader() looking at" << fileName;
00071             }
00072             library = QLibraryPrivate::findOrCreate(QFileInfo(fileName).canonicalFilePath());
00073             if (!library->isPlugin()) {
00074                 library->release();
00075                 if (qt_debug_component()) {
00076                     qDebug() << "         not a plugin";
00077                 }
00078                 continue;
00079             }
00080             QString regkey = QString::fromLatin1("Qt Factory Cache %1.%2/%3:/%4")
00081                              .arg((QT_VERSION & 0xff0000) >> 16)
00082                              .arg((QT_VERSION & 0xff00) >> 8)
00083                              .arg(QLatin1String(iid))
00084                              .arg(fileName);
00085             QStringList reg, keys;
00086             reg = settings.value(regkey).toStringList();
00087             if (reg.count() && library->lastModified == reg[0]) {
00088                 keys = reg;
00089                 keys.removeFirst();
00090             } else {
00091                 if (!library->loadPlugin()) {
00092                     if (qt_debug_component()) {
00093                         qDebug() << "           could not load";
00094                     }
00095                     library->release();
00096                     continue;
00097                 }
00098                 QObject *instance = library->instance();
00099                 if (!instance)
00100                     // ignore plugins that have a valid signature but cannot be loaded.
00101                     continue;
00102                 QFactoryInterface *factory = qobject_cast<QFactoryInterface*>(instance);
00103                 if (instance && factory && instance->qt_metacast(iid))
00104                     keys = factory->keys();
00105                 if (keys.isEmpty())
00106                     library->unload();
00107                 reg.clear();
00108                 reg << library->lastModified;
00109                 reg += keys;
00110                 settings.setValue(regkey, reg);
00111             }
00112             if (qt_debug_component()) {
00113                 qDebug() << "keys" << keys;
00114             }
00115 
00116             if (keys.isEmpty()) {
00117                 library->release();
00118                 continue;
00119             }
00120             d->libraryList += library;
00121             for (int k = 0; k < keys.count(); ++k) {
00122                 // first come first serve, unless the first
00123                 // library was built with a future Qt version,
00124                 // whereas the new one has a Qt version that fits
00125                 // better
00126                 QString key = keys.at(k);
00127                 if (!cs)
00128                     key = key.toLower();
00129                 QLibraryPrivate *previous = d->keyMap.value(key);
00130                 if (!previous || (previous->qt_version > QT_VERSION && library->qt_version <= QT_VERSION)) {
00131                     d->keyMap[key] = library;
00132                     d->keyList += keys.at(k);
00133                 }
00134             }
00135         }
00136     }
00137 }
00138 
00139 QFactoryLoader::~QFactoryLoader()
00140 {
00141     Q_D(QFactoryLoader);
00142     for (int i = 0; i < d->libraryList.count(); ++i)
00143         d->libraryList.at(i)->release();
00144 }
00145 
00146 QStringList QFactoryLoader::keys() const
00147 {
00148     Q_D(const QFactoryLoader);
00149     QMutexLocker locker(&d->mutex);
00150     QStringList keys = d->keyList;
00151     QObjectList instances = QPluginLoader::staticInstances();
00152     for (int i = 0; i < instances.count(); ++i)
00153         if (QFactoryInterface *factory = qobject_cast<QFactoryInterface*>(instances.at(i)))
00154             if (instances.at(i)->qt_metacast(d->iid))
00155                     keys += factory->keys();
00156     return keys;
00157 }
00158 
00159 QObject *QFactoryLoader::instance(const QString &key) const
00160 {
00161     Q_D(const QFactoryLoader);
00162     QMutexLocker locker(&d->mutex);
00163     QObjectList instances = QPluginLoader::staticInstances();
00164     for (int i = 0; i < instances.count(); ++i)
00165         if (QFactoryInterface *factory = qobject_cast<QFactoryInterface*>(instances.at(i)))
00166             if (instances.at(i)->qt_metacast(d->iid) && factory->keys().contains(key, Qt::CaseInsensitive))
00167                 return instances.at(i);
00168 
00169     if (QLibraryPrivate* library = d->keyMap.value(key)) {
00170         if (library->instance || library->loadPlugin()) {
00171             if (QObject *obj = library->instance()) {
00172                 if (obj && !obj->parent())
00173                     obj->moveToThread(QCoreApplicationPrivate::mainThread());
00174                 return obj;
00175             }
00176         }
00177     }
00178     return 0;
00179 }
00180 #endif // QT_NO_LIBRARY

Generated on Thu Mar 15 11:53:35 2007 for Qt 4.2 User's Guide by  doxygen 1.5.1