diff options
author | Kai Koehne <kai.koehne@nokia.com> | 2010-05-05 08:08:43 +0200 |
---|---|---|
committer | Kai Koehne <kai.koehne@nokia.com> | 2010-05-05 08:09:50 +0200 |
commit | da621f82db110e5f169016a2200f09395b0b257d (patch) | |
tree | 1aa7d00f9dab5adf70bfe19553b9a5972219fa34 /src/plugins/qmldesigner/designercore/pluginmanager | |
parent | 75803b08d29b3e38897d1667f697d9664fd59208 (diff) | |
download | qt-creator-da621f82db110e5f169016a2200f09395b0b257d.tar.gz |
QuickDesigner: Rename "core" directory to "designercore"
Avoids problems when e.g. running 'make clean' - this one tries
to delete all files named core.
Diffstat (limited to 'src/plugins/qmldesigner/designercore/pluginmanager')
4 files changed, 498 insertions, 0 deletions
diff --git a/src/plugins/qmldesigner/designercore/pluginmanager/widgetpluginmanager.cpp b/src/plugins/qmldesigner/designercore/pluginmanager/widgetpluginmanager.cpp new file mode 100644 index 0000000000..fa9c404892 --- /dev/null +++ b/src/plugins/qmldesigner/designercore/pluginmanager/widgetpluginmanager.cpp @@ -0,0 +1,103 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "widgetpluginmanager.h" +#include "widgetpluginpath.h" +#include <iwidgetplugin.h> + +#include <QtCore/QCoreApplication> +#include <QtCore/QObject> +#include <QtCore/QSharedData> +#include <QtCore/QDir> +#include <QtCore/QStringList> +#include <QtCore/QDebug> +#include <QWeakPointer> +#include <QtCore/QPluginLoader> +#include <QtCore/QFileInfo> +#include <QtCore/QLibraryInfo> + +#include <QtGui/QStandardItemModel> +#include <QtGui/QStandardItem> + +enum { debug = 0 }; + +namespace QmlDesigner { + +namespace Internal { + +// ---- PluginManager[Private] +class WidgetPluginManagerPrivate { +public: + typedef QList<WidgetPluginPath> PluginPathList; + PluginPathList m_paths; +}; + +WidgetPluginManager::WidgetPluginManager() : + m_d(new WidgetPluginManagerPrivate) +{ +} + +WidgetPluginManager::~WidgetPluginManager() +{ + delete m_d; +} + +WidgetPluginManager::IWidgetPluginList WidgetPluginManager::instances() +{ + if (debug) + qDebug() << '>' << Q_FUNC_INFO << QLibraryInfo::buildKey(); + IWidgetPluginList rc; + const WidgetPluginManagerPrivate::PluginPathList::iterator end = m_d->m_paths.end(); + for (WidgetPluginManagerPrivate::PluginPathList::iterator it = m_d->m_paths.begin(); it != end; ++it) + it->getInstances(&rc); + if (debug) + qDebug() << '<' << Q_FUNC_INFO << rc.size(); + return rc; +} + +bool WidgetPluginManager::addPath(const QString &path) +{ + const QDir dir(path); + if (!dir.exists()) + return false; + m_d->m_paths.push_back(WidgetPluginPath(dir)); + return true; +} + +QAbstractItemModel *WidgetPluginManager::createModel(QObject *parent) +{ + QStandardItemModel *model = new QStandardItemModel(parent); + const WidgetPluginManagerPrivate::PluginPathList::iterator end = m_d->m_paths.end(); + for (WidgetPluginManagerPrivate::PluginPathList::iterator it = m_d->m_paths.begin(); it != end; ++it) + model->appendRow(it->createModelItem()); + return model; +} + +} // namespace Internal +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/pluginmanager/widgetpluginmanager.h b/src/plugins/qmldesigner/designercore/pluginmanager/widgetpluginmanager.h new file mode 100644 index 0000000000..0e5c301bf2 --- /dev/null +++ b/src/plugins/qmldesigner/designercore/pluginmanager/widgetpluginmanager.h @@ -0,0 +1,76 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef WIDGETPLUGINMANAGER_H +#define WIDGETPLUGINMANAGER_H + +#include <QtCore/QObject> +#include <QtCore/QList> + +QT_BEGIN_NAMESPACE +class QString; +class QAbstractItemModel; +QT_END_NAMESPACE + +namespace QmlDesigner { + +class IWidgetPlugin; + +namespace Internal { + +class WidgetPluginManagerPrivate; + +// PluginManager: Loads the plugin libraries on demand "as lazy as +// possible", that is, directories are scanned and +// instances are created only when instances() is called. + +class WidgetPluginManager +{ + Q_DISABLE_COPY(WidgetPluginManager) +public: + typedef QList<IWidgetPlugin *> IWidgetPluginList; + + WidgetPluginManager(); + ~WidgetPluginManager(); + + bool addPath(const QString &path); + + IWidgetPluginList instances(); + + // Convenience to create a model for an "About Plugins" + // dialog. Forces plugin initialization. + QAbstractItemModel *createModel(QObject *parent = 0); + +private: + WidgetPluginManagerPrivate *m_d; +}; + +} // namespace Internal +} // namespace QmlDesigner +#endif // WIDGETPLUGINMANAGER_H diff --git a/src/plugins/qmldesigner/designercore/pluginmanager/widgetpluginpath.cpp b/src/plugins/qmldesigner/designercore/pluginmanager/widgetpluginpath.cpp new file mode 100644 index 0000000000..3e7bc69d8e --- /dev/null +++ b/src/plugins/qmldesigner/designercore/pluginmanager/widgetpluginpath.cpp @@ -0,0 +1,217 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "widgetpluginpath.h" +#include <iwidgetplugin.h> +#include <QtCore/QLibrary> +#include <QWeakPointer> +#include <QtCore/QPluginLoader> +#include <QtCore/QFileInfo> +#include <QtCore/QLibraryInfo> +#include <QtCore/QCoreApplication> +#include <QtCore/QObject> +#include <QtCore/QSharedData> +#include <QDebug> + +enum { debug = 0 }; + +namespace QmlDesigner { + +namespace Internal { + +// Initialize and create instance of a plugin from scratch, +// that is, make sure the library is loaded and has an instance +// of the IPlugin type. Once something fails, mark it as failed +// ignore it from then on. +static IWidgetPlugin *instance(WidgetPluginData &p) +{ + if (debug) + qDebug() << "Loading QmlDesigner plugin" << p.path << "..."; + + // Go stale once something fails + if (p.failed) + return 0; + + // Pull up the plugin, retrieve IPlugin instance. + if (!p.instanceGuard) { + p.instance = 0; + QPluginLoader loader(p.path); + + if (debug) + qDebug() << "guard" << p.path; + + if (!(loader.isLoaded() || loader.load())) { + p.failed = true; + p.errorMessage = QCoreApplication::translate("WidgetPluginManager", + "Failed to create instance of file " + "'%1': %2").arg(p.path).arg(p.errorMessage); + qWarning() << p.errorMessage; + return 0; + } + QObject *object = loader.instance(); + if (!object) { + p.failed = true; + p.errorMessage = QCoreApplication::translate("WidgetPluginManager", + "Failed to create instance of file '%1'." + ).arg(p.path); + qWarning() << p.errorMessage; + return 0; + } + IWidgetPlugin *iplugin = qobject_cast<IWidgetPlugin *>(object); + if (!iplugin) { + p.failed = true; + p.errorMessage = QCoreApplication::translate("WidgetPluginManager", + "File '%1' is not a QmlDesigner plugin." + ).arg(p.path); + qWarning() << p.errorMessage; + delete object; + return 0; + } + p.instanceGuard = object; + p.instance = iplugin; + } + // Ensure it is initialized + /*if (!p.instance->isInitialized()) { + if (!p.instance->initialize(&p.errorMessage)) { + p.failed = true; + delete p.instance; + p.instance = 0; + return 0; + } + }*/ + + if (debug) + qDebug() << "QmlDesigner plugin" << p.path << "successfully loaded!"; + return p.instance; +} + +WidgetPluginData::WidgetPluginData(const QString &p) : + path(p), + failed(false), + instance(0) +{ +} + + +WidgetPluginPath::WidgetPluginPath(const QDir &path) : + m_path(path), + m_loaded(false) +{ +} + +// Determine a unique list of library files in that directory +QStringList WidgetPluginPath::libraryFilePaths(const QDir &dir) +{ + const QFileInfoList infoList = dir.entryInfoList(QDir::Files|QDir::Readable|QDir::NoDotAndDotDot); + if (infoList.empty()) + return QStringList(); + // Load symbolic links but make sure all file names are unique as not + // to fall for something like 'libplugin.so.1 -> libplugin.so' + QStringList result; + const QFileInfoList::const_iterator icend = infoList.constEnd(); + for (QFileInfoList::const_iterator it = infoList.constBegin(); it != icend; ++it) { + QString fileName; + if (it->isSymLink()) { + const QFileInfo linkTarget = QFileInfo(it->symLinkTarget()); + if (linkTarget.exists() && linkTarget.isFile()) + fileName = linkTarget.absoluteFilePath(); + } else { + fileName = it->absoluteFilePath(); + } + if (!fileName.isEmpty() && QLibrary::isLibrary(fileName) && !result.contains(fileName)) + result += fileName; + } + + if (debug) + qDebug() << "Library files in directory" << dir << ": " << result; + + return result; +} + +void WidgetPluginPath::clear() +{ + m_loaded = false; + m_plugins.clear(); +} + +void WidgetPluginPath::ensureLoaded() +{ + if (!m_loaded) { + const QStringList libraryFiles = libraryFilePaths(m_path); + if (debug) + qDebug() << "Checking " << libraryFiles.size() << " plugins " << m_path.absolutePath(); + foreach (const QString &libFile, libraryFiles) + m_plugins.push_back(WidgetPluginData(libFile)); + m_loaded = true; + } +} + +void WidgetPluginPath::getInstances(WidgetPluginManager::IWidgetPluginList *list) +{ + ensureLoaded(); + // Compile list of instances + if (m_plugins.empty()) + return; + const PluginDataList::iterator end = m_plugins.end(); + for (PluginDataList::iterator it = m_plugins.begin(); it != end; ++it) + if (IWidgetPlugin *i = instance(*it)) + list->push_back(i); +} + +QStandardItem *WidgetPluginPath::createModelItem() +{ + ensureLoaded(); + // Create a list of plugin lib files with classes. + // If there are failed ones, create a separate "Failed" + // category at the end + QStandardItem *pathItem = new QStandardItem(m_path.absolutePath()); + QStandardItem *failedCategory = 0; + const PluginDataList::iterator end = m_plugins.end(); + for (PluginDataList::iterator it = m_plugins.begin(); it != end; ++it) { + QStandardItem *pluginItem = new QStandardItem(QFileInfo(it->path).fileName()); + if (instance(*it)) { + pluginItem->appendRow(new QStandardItem(QString::fromLatin1(it->instanceGuard->metaObject()->className()))); + pathItem->appendRow(pluginItem); + } else { + pluginItem->setToolTip(it->errorMessage); + if (!failedCategory) { + const QString failed = QCoreApplication::translate("PluginManager", "Failed Plugins"); + failedCategory = new QStandardItem(failed); + } + failedCategory->appendRow(pluginItem); + } + } + if (failedCategory) + pathItem->appendRow(failedCategory); + return pathItem; +} + +} // namespace Internal +} // namespace QmlDesigner + diff --git a/src/plugins/qmldesigner/designercore/pluginmanager/widgetpluginpath.h b/src/plugins/qmldesigner/designercore/pluginmanager/widgetpluginpath.h new file mode 100644 index 0000000000..21e9e777e0 --- /dev/null +++ b/src/plugins/qmldesigner/designercore/pluginmanager/widgetpluginpath.h @@ -0,0 +1,102 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef WIDGETPLUGINPATH_H +#define WIDGETPLUGINPATH_H + +#include "widgetpluginmanager.h" + +#include <QtCore/QObject> +#include <QWeakPointer> +#include <QtCore/QList> +#include <QtCore/QDir> +#include <QtGui/QStandardItem> + +QT_BEGIN_NAMESPACE +class QString; +class QAbstractItemModel; +QT_END_NAMESPACE + +namespace QmlDesigner { +class IWidgetPlugin; +namespace Internal { + + + +// Dumb plugin data structure. Note that whereas QObjects can +// casted to an interface, QWeakPointer does not work with the +// interface class, so, we need a separate QWeakPointer as a guard +// to detect the deletion of a plugin instance which can happen +// in theory. +struct WidgetPluginData { + WidgetPluginData(const QString &p = QString()); + + QString path; + bool failed; + QString errorMessage; + QWeakPointer<QObject> instanceGuard; + IWidgetPlugin *instance; +}; + + +// PluginPath: Manages a plugin directory. It does nothing +// on construction following the "as lazy as possible" principle. +// In the "loaded" stage, it scans the directories and creates +// a list of PluginData for the libraries found. +// getInstances() will return the fully initialized list of +// IPlugins. + +class WidgetPluginPath { +public: + explicit WidgetPluginPath(const QDir &path); + + + void getInstances(WidgetPluginManager::IWidgetPluginList *list); + + QDir path() const { return m_path; } + + // Convenience to populate a "About Plugin" dialog with + // plugins from that path. Forces initialization. + QStandardItem *createModelItem(); + +private: + typedef QList<WidgetPluginData> PluginDataList; + + static QStringList libraryFilePaths(const QDir &dir); + void clear(); + void ensureLoaded(); + + QDir m_path; + bool m_loaded; + PluginDataList m_plugins; +}; + +} // namespace Internal +} // namespace QmlDesigner +#endif // WIDGETPLUGINPATH_H |