summaryrefslogtreecommitdiff
path: root/src/plugins/qmldesigner/designercore/pluginmanager
diff options
context:
space:
mode:
authorKai Koehne <kai.koehne@nokia.com>2010-05-05 08:08:43 +0200
committerKai Koehne <kai.koehne@nokia.com>2010-05-05 08:09:50 +0200
commitda621f82db110e5f169016a2200f09395b0b257d (patch)
tree1aa7d00f9dab5adf70bfe19553b9a5972219fa34 /src/plugins/qmldesigner/designercore/pluginmanager
parent75803b08d29b3e38897d1667f697d9664fd59208 (diff)
downloadqt-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')
-rw-r--r--src/plugins/qmldesigner/designercore/pluginmanager/widgetpluginmanager.cpp103
-rw-r--r--src/plugins/qmldesigner/designercore/pluginmanager/widgetpluginmanager.h76
-rw-r--r--src/plugins/qmldesigner/designercore/pluginmanager/widgetpluginpath.cpp217
-rw-r--r--src/plugins/qmldesigner/designercore/pluginmanager/widgetpluginpath.h102
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