2010-01-07 12:14:35 +01:00
|
|
|
/**************************************************************************
|
|
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator
|
|
|
|
|
**
|
2012-01-26 18:33:46 +01:00
|
|
|
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
2010-01-07 12:14:35 +01:00
|
|
|
**
|
2012-07-19 12:26:56 +02:00
|
|
|
** Contact: http://www.qt-project.org/
|
2010-01-07 12:14:35 +01:00
|
|
|
**
|
|
|
|
|
**
|
|
|
|
|
** GNU Lesser General Public License Usage
|
|
|
|
|
**
|
2011-04-13 08:42:33 +02:00
|
|
|
** 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.
|
2010-01-07 12:14:35 +01:00
|
|
|
**
|
2010-12-17 16:01:08 +01:00
|
|
|
** In addition, as a special exception, Nokia gives you certain additional
|
2011-04-13 08:42:33 +02:00
|
|
|
** rights. These rights are described in the Nokia Qt LGPL Exception
|
2010-12-17 16:01:08 +01:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
|
**
|
2011-04-13 08:42:33 +02:00
|
|
|
** Other Usage
|
|
|
|
|
**
|
|
|
|
|
** Alternatively, this file may be used in accordance with the terms and
|
|
|
|
|
** conditions contained in a signed written agreement between you and Nokia.
|
|
|
|
|
**
|
2010-01-07 12:14:35 +01:00
|
|
|
**
|
|
|
|
|
**************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "pluginpath.h"
|
|
|
|
|
#include <iplugin.h>
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QLibrary>
|
2010-01-07 12:14:35 +01:00
|
|
|
#include <QWeakPointer>
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QPluginLoader>
|
|
|
|
|
#include <QFileInfo>
|
|
|
|
|
#include <QLibraryInfo>
|
|
|
|
|
#include <QCoreApplication>
|
|
|
|
|
#include <QObject>
|
|
|
|
|
#include <QSharedData>
|
2010-01-07 12:14:35 +01:00
|
|
|
#include <QDebug>
|
|
|
|
|
|
|
|
|
|
enum { debug = 1 };
|
|
|
|
|
|
|
|
|
|
namespace QmlDesigner {
|
|
|
|
|
|
|
|
|
|
// 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 IPlugin *instance(PluginData &p)
|
|
|
|
|
{
|
|
|
|
|
// 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 (!(loader.isLoaded() || loader.load())) {
|
|
|
|
|
p.failed = true;
|
|
|
|
|
p.errorMessage = loader.errorString();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
QObject *object = loader.instance();
|
|
|
|
|
if (!object) {
|
|
|
|
|
p.failed = true;
|
|
|
|
|
p.errorMessage = QCoreApplication::translate("WidgetPluginManager", "Failed to create instance.");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
IPlugin *iplugin = qobject_cast<IPlugin *>(object);
|
|
|
|
|
if (!iplugin) {
|
|
|
|
|
p.failed = true;
|
|
|
|
|
p.errorMessage = QCoreApplication::translate("WidgetPluginManager", "Not a QmlDesigner plugin.");
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}*/
|
|
|
|
|
return p.instance;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PluginData::PluginData(const QString &p) :
|
|
|
|
|
path(p),
|
|
|
|
|
failed(false),
|
|
|
|
|
instance(0)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PluginPath::PluginPath(const QDir &path) :
|
|
|
|
|
m_path(path),
|
|
|
|
|
m_loaded(false)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Determine a unique list of library files in that directory
|
|
|
|
|
QStringList PluginPath::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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
qDebug() << "Library file paths: " << result;
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PluginPath::clear()
|
|
|
|
|
{
|
|
|
|
|
m_loaded = false;
|
|
|
|
|
m_plugins.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PluginPath::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(PluginData(libFile));
|
|
|
|
|
m_loaded = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PluginPath::getInstances(PluginManager::IPluginList *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 (IPlugin *i = instance(*it))
|
|
|
|
|
list->push_back(i);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStandardItem *PluginPath::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 QmlDesigner
|
|
|
|
|
|