2012-10-02 09:12:39 +02:00
|
|
|
/****************************************************************************
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
|
|
|
|
|
** Contact: http://www.qt-project.org/legal
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
|
** a written agreement between you and Digia. For licensing terms and
|
|
|
|
|
** conditions see http://qt.digia.com/licensing. For further information
|
|
|
|
|
** use the contact form at http://qt.digia.com/contact-us.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2009-02-25 09:15:00 +01:00
|
|
|
** GNU Lesser General Public License Usage
|
2012-10-02 09:12:39 +02:00
|
|
|
** 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, Digia gives you certain additional
|
|
|
|
|
** rights. These rights are described in the Digia Qt LGPL Exception
|
2010-12-17 16:01:08 +01:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2008-12-02 14:09:21 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
#include "pluginspec.h"
|
2010-01-11 09:45:20 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
#include "pluginspec_p.h"
|
|
|
|
|
#include "iplugin.h"
|
|
|
|
|
#include "iplugin_p.h"
|
|
|
|
|
#include "pluginmanager.h"
|
|
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QDir>
|
|
|
|
|
#include <QFile>
|
|
|
|
|
#include <QFileInfo>
|
|
|
|
|
#include <QXmlStreamReader>
|
|
|
|
|
#include <QRegExp>
|
|
|
|
|
#include <QCoreApplication>
|
2012-08-06 13:42:46 +02:00
|
|
|
#include <QDebug>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2009-02-19 16:30:08 +01:00
|
|
|
#ifdef Q_OS_LINUX
|
2009-04-07 14:08:44 +02:00
|
|
|
// Using the patched version breaks on Fedora 10, KDE4.2.2/Qt4.5.
|
|
|
|
|
# define USE_UNPATCHED_QPLUGINLOADER 1
|
2009-02-19 16:30:08 +01:00
|
|
|
#else
|
|
|
|
|
# define USE_UNPATCHED_QPLUGINLOADER 1
|
|
|
|
|
#endif
|
2009-02-19 15:32:50 +01:00
|
|
|
|
|
|
|
|
#if USE_UNPATCHED_QPLUGINLOADER
|
|
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
# include <QPluginLoader>
|
2009-02-19 16:30:08 +01:00
|
|
|
typedef QT_PREPEND_NAMESPACE(QPluginLoader) PluginLoader;
|
2009-02-19 15:32:50 +01:00
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
2009-02-19 16:30:08 +01:00
|
|
|
# include "patchedpluginloader.cpp"
|
|
|
|
|
typedef PatchedPluginLoader PluginLoader;
|
2009-02-19 15:32:50 +01:00
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
|
|
|
|
\class ExtensionSystem::PluginDependency
|
|
|
|
|
\brief Struct that contains the name and required compatible version number of a plugin's dependency.
|
|
|
|
|
|
|
|
|
|
This reflects the data of a dependency tag in the plugin's xml description file.
|
|
|
|
|
The name and version are used to resolve the dependency, i.e. a plugin with the given name and
|
|
|
|
|
plugin \c {compatibility version <= dependency version <= plugin version} is searched for.
|
|
|
|
|
|
|
|
|
|
See also ExtensionSystem::IPlugin for more information about plugin dependencies and
|
|
|
|
|
version matching.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\variable ExtensionSystem::PluginDependency::name
|
|
|
|
|
String identifier of the plugin.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\variable ExtensionSystem::PluginDependency::version
|
|
|
|
|
Version string that a plugin must match to fill this dependency.
|
|
|
|
|
*/
|
|
|
|
|
|
2011-01-11 14:01:08 +01:00
|
|
|
/*!
|
|
|
|
|
\variable ExtensionSystem::PluginDependency::type
|
|
|
|
|
Defines whether the dependency is required or optional.
|
|
|
|
|
\sa ExtensionSystem::PluginDependency::Type
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\enum ExtensionSystem::PluginDependency::Type
|
|
|
|
|
Whether the dependency is required or optional.
|
|
|
|
|
\value Required
|
|
|
|
|
Dependency needs to be there.
|
|
|
|
|
\value Optional
|
|
|
|
|
Dependency is not necessarily needed. You need to make sure that
|
|
|
|
|
the plugin is able to load without this dependency installed, so
|
|
|
|
|
for example you may not link to the dependency's library.
|
|
|
|
|
*/
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
|
|
|
|
\class ExtensionSystem::PluginSpec
|
|
|
|
|
\brief Contains the information of the plugins xml description file and
|
|
|
|
|
information about the plugin's current state.
|
|
|
|
|
|
|
|
|
|
The plugin spec is also filled with more information as the plugin
|
2009-06-12 13:07:15 +02:00
|
|
|
goes through its loading process (see PluginSpec::State).
|
2008-12-02 12:01:29 +01:00
|
|
|
If an error occurs, the plugin spec is the place to look for the
|
|
|
|
|
error details.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\enum ExtensionSystem::PluginSpec::State
|
|
|
|
|
|
|
|
|
|
The plugin goes through several steps while being loaded.
|
|
|
|
|
The state gives a hint on what went wrong in case of an error.
|
|
|
|
|
|
|
|
|
|
\value Invalid
|
|
|
|
|
Starting point: Even the xml description file was not read.
|
|
|
|
|
\value Read
|
2009-06-12 13:07:15 +02:00
|
|
|
The xml description file has been successfully read, and its
|
2008-12-02 12:01:29 +01:00
|
|
|
information is available via the PluginSpec.
|
|
|
|
|
\value Resolved
|
|
|
|
|
The dependencies given in the description file have been
|
|
|
|
|
successfully found, and are available via the dependencySpecs() method.
|
|
|
|
|
\value Loaded
|
|
|
|
|
The plugin's library is loaded and the plugin instance created
|
|
|
|
|
(available through plugin()).
|
|
|
|
|
\value Initialized
|
|
|
|
|
The plugin instance's IPlugin::initialize() method has been called
|
|
|
|
|
and returned a success value.
|
|
|
|
|
\value Running
|
|
|
|
|
The plugin's dependencies are successfully initialized and
|
|
|
|
|
extensionsInitialized has been called. The loading process is
|
|
|
|
|
complete.
|
|
|
|
|
\value Stopped
|
2010-04-28 16:59:03 +02:00
|
|
|
The plugin has been shut down, i.e. the plugin's IPlugin::aboutToShutdown() method has been called.
|
2008-12-02 12:01:29 +01:00
|
|
|
\value Deleted
|
|
|
|
|
The plugin instance has been deleted.
|
|
|
|
|
*/
|
2011-01-11 14:01:08 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
using namespace ExtensionSystem;
|
|
|
|
|
using namespace ExtensionSystem::Internal;
|
|
|
|
|
|
2011-01-11 14:01:08 +01:00
|
|
|
/*!
|
|
|
|
|
\fn uint qHash(const ExtensionSystem::PluginDependency &value)
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
uint ExtensionSystem::qHash(const ExtensionSystem::PluginDependency &value)
|
|
|
|
|
{
|
|
|
|
|
return qHash(value.name);
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
2011-03-28 14:58:12 +02:00
|
|
|
\fn bool PluginDependency::operator==(const PluginDependency &other) const
|
2008-12-02 12:01:29 +01:00
|
|
|
\internal
|
|
|
|
|
*/
|
2011-01-11 14:01:08 +01:00
|
|
|
bool PluginDependency::operator==(const PluginDependency &other) const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2011-01-11 14:01:08 +01:00
|
|
|
return name == other.name && version == other.version && type == other.type;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn PluginSpec::PluginSpec()
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
PluginSpec::PluginSpec()
|
|
|
|
|
: d(new PluginSpecPrivate(this))
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn PluginSpec::~PluginSpec()
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
PluginSpec::~PluginSpec()
|
|
|
|
|
{
|
|
|
|
|
delete d;
|
|
|
|
|
d = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn QString PluginSpec::name() const
|
|
|
|
|
The plugin name. This is valid after the PluginSpec::Read state is reached.
|
|
|
|
|
*/
|
|
|
|
|
QString PluginSpec::name() const
|
|
|
|
|
{
|
|
|
|
|
return d->name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn QString PluginSpec::version() const
|
|
|
|
|
The plugin version. This is valid after the PluginSpec::Read state is reached.
|
|
|
|
|
*/
|
|
|
|
|
QString PluginSpec::version() const
|
|
|
|
|
{
|
|
|
|
|
return d->version;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn QString PluginSpec::compatVersion() const
|
|
|
|
|
The plugin compatibility version. This is valid after the PluginSpec::Read state is reached.
|
|
|
|
|
*/
|
|
|
|
|
QString PluginSpec::compatVersion() const
|
|
|
|
|
{
|
|
|
|
|
return d->compatVersion;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn QString PluginSpec::vendor() const
|
|
|
|
|
The plugin vendor. This is valid after the PluginSpec::Read state is reached.
|
|
|
|
|
*/
|
|
|
|
|
QString PluginSpec::vendor() const
|
|
|
|
|
{
|
|
|
|
|
return d->vendor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn QString PluginSpec::copyright() const
|
|
|
|
|
The plugin copyright. This is valid after the PluginSpec::Read state is reached.
|
|
|
|
|
*/
|
|
|
|
|
QString PluginSpec::copyright() const
|
|
|
|
|
{
|
|
|
|
|
return d->copyright;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn QString PluginSpec::license() const
|
|
|
|
|
The plugin license. This is valid after the PluginSpec::Read state is reached.
|
|
|
|
|
*/
|
|
|
|
|
QString PluginSpec::license() const
|
|
|
|
|
{
|
|
|
|
|
return d->license;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn QString PluginSpec::description() const
|
|
|
|
|
The plugin description. This is valid after the PluginSpec::Read state is reached.
|
|
|
|
|
*/
|
|
|
|
|
QString PluginSpec::description() const
|
|
|
|
|
{
|
|
|
|
|
return d->description;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn QString PluginSpec::url() const
|
|
|
|
|
The plugin url where you can find more information about the plugin. This is valid after the PluginSpec::Read state is reached.
|
|
|
|
|
*/
|
|
|
|
|
QString PluginSpec::url() const
|
|
|
|
|
{
|
|
|
|
|
return d->url;
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-12 16:02:23 +01:00
|
|
|
/*!
|
|
|
|
|
\fn QString PluginSpec::category() const
|
|
|
|
|
The category that the plugin belongs to. Categories are groups of plugins which allow for keeping them together in the UI.
|
|
|
|
|
Returns an empty string if the plugin does not belong to a category.
|
|
|
|
|
*/
|
|
|
|
|
QString PluginSpec::category() const
|
|
|
|
|
{
|
|
|
|
|
return d->category;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
2010-03-30 16:54:29 +02:00
|
|
|
\fn bool PluginSpec::isExperimental() const
|
|
|
|
|
Returns if the plugin has its experimental flag set.
|
|
|
|
|
*/
|
|
|
|
|
bool PluginSpec::isExperimental() const
|
|
|
|
|
{
|
|
|
|
|
return d->experimental;
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-26 14:46:29 +02:00
|
|
|
/*!
|
|
|
|
|
Returns if the plugin is disabled by default.
|
|
|
|
|
This might be because the plugin is experimental, or because
|
|
|
|
|
the plugin manager's settings define it as disabled by default.
|
|
|
|
|
*/
|
|
|
|
|
bool PluginSpec::isDisabledByDefault() const
|
|
|
|
|
{
|
|
|
|
|
return d->disabledByDefault;
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-30 16:54:29 +02:00
|
|
|
/*!
|
|
|
|
|
\fn bool PluginSpec::isEnabled() const
|
|
|
|
|
Returns if the plugin is loaded at startup. True by default - the user can change it from the Plugin settings.
|
2010-03-12 16:02:23 +01:00
|
|
|
*/
|
2010-03-30 14:18:15 +02:00
|
|
|
bool PluginSpec::isEnabled() const
|
2010-03-12 16:02:23 +01:00
|
|
|
{
|
2010-03-30 14:18:15 +02:00
|
|
|
return d->enabled;
|
2010-03-12 16:02:23 +01:00
|
|
|
}
|
|
|
|
|
|
2010-05-12 14:34:36 +02:00
|
|
|
/*!
|
|
|
|
|
\fn bool PluginSpec::isDisabledIndirectly() const
|
|
|
|
|
Returns true if loading was not done due to user unselecting this plugin or its dependencies,
|
|
|
|
|
or if command-line parameter -noload was used.
|
|
|
|
|
*/
|
|
|
|
|
bool PluginSpec::isDisabledIndirectly() const
|
2010-03-12 16:02:23 +01:00
|
|
|
{
|
2010-05-12 14:34:36 +02:00
|
|
|
return d->disabledIndirectly;
|
2010-03-12 16:02:23 +01:00
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
|
|
|
|
\fn QList<PluginDependency> PluginSpec::dependencies() const
|
|
|
|
|
The plugin dependencies. This is valid after the PluginSpec::Read state is reached.
|
|
|
|
|
*/
|
|
|
|
|
QList<PluginDependency> PluginSpec::dependencies() const
|
|
|
|
|
{
|
|
|
|
|
return d->dependencies;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
2009-01-05 18:04:24 +01:00
|
|
|
\fn PluginSpec::PluginArgumentDescriptions PluginSpec::argumentDescriptions() const
|
2008-12-02 12:01:29 +01:00
|
|
|
Returns a list of descriptions of command line arguments the plugin processes.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
PluginSpec::PluginArgumentDescriptions PluginSpec::argumentDescriptions() const
|
|
|
|
|
{
|
|
|
|
|
return d->argumentDescriptions;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn QString PluginSpec::location() const
|
|
|
|
|
The absolute path to the directory containing the plugin xml description file
|
|
|
|
|
this PluginSpec corresponds to.
|
|
|
|
|
*/
|
|
|
|
|
QString PluginSpec::location() const
|
|
|
|
|
{
|
|
|
|
|
return d->location;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn QString PluginSpec::filePath() const
|
|
|
|
|
The absolute path to the plugin xml description file (including the file name)
|
|
|
|
|
this PluginSpec corresponds to.
|
|
|
|
|
*/
|
|
|
|
|
QString PluginSpec::filePath() const
|
|
|
|
|
{
|
|
|
|
|
return d->filePath;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn QStringList PluginSpec::arguments() const
|
|
|
|
|
Command line arguments specific to that plugin. Set at startup
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
QStringList PluginSpec::arguments() const
|
|
|
|
|
{
|
|
|
|
|
return d->arguments;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn void PluginSpec::setArguments(const QStringList &arguments)
|
|
|
|
|
Set the command line arguments specific to that plugin to \a arguments.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void PluginSpec::setArguments(const QStringList &arguments)
|
|
|
|
|
{
|
|
|
|
|
d->arguments = arguments;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn PluginSpec::addArgument(const QString &argument)
|
|
|
|
|
Adds \a argument to the command line arguments specific to that plugin.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void PluginSpec::addArgument(const QString &argument)
|
|
|
|
|
{
|
|
|
|
|
d->arguments.push_back(argument);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn PluginSpec::State PluginSpec::state() const
|
|
|
|
|
The state in which the plugin currently is.
|
|
|
|
|
See the description of the PluginSpec::State enum for details.
|
|
|
|
|
*/
|
|
|
|
|
PluginSpec::State PluginSpec::state() const
|
|
|
|
|
{
|
|
|
|
|
return d->state;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn bool PluginSpec::hasError() const
|
|
|
|
|
Returns whether an error occurred while reading/starting the plugin.
|
|
|
|
|
*/
|
|
|
|
|
bool PluginSpec::hasError() const
|
|
|
|
|
{
|
|
|
|
|
return d->hasError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn QString PluginSpec::errorString() const
|
|
|
|
|
Detailed, possibly multi-line, error description in case of an error.
|
|
|
|
|
*/
|
|
|
|
|
QString PluginSpec::errorString() const
|
|
|
|
|
{
|
|
|
|
|
return d->errorString;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn bool PluginSpec::provides(const QString &pluginName, const QString &version) const
|
|
|
|
|
Returns if this plugin can be used to fill in a dependency of the given
|
|
|
|
|
\a pluginName and \a version.
|
|
|
|
|
|
|
|
|
|
\sa PluginSpec::dependencies()
|
|
|
|
|
*/
|
|
|
|
|
bool PluginSpec::provides(const QString &pluginName, const QString &version) const
|
|
|
|
|
{
|
|
|
|
|
return d->provides(pluginName, version);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn IPlugin *PluginSpec::plugin() const
|
|
|
|
|
The corresponding IPlugin instance, if the plugin library has already been successfully loaded,
|
|
|
|
|
i.e. the PluginSpec::Loaded state is reached.
|
|
|
|
|
*/
|
|
|
|
|
IPlugin *PluginSpec::plugin() const
|
|
|
|
|
{
|
|
|
|
|
return d->plugin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn QList<PluginSpec *> PluginSpec::dependencySpecs() const
|
|
|
|
|
Returns the list of dependencies, already resolved to existing plugin specs.
|
|
|
|
|
Valid if PluginSpec::Resolved state is reached.
|
|
|
|
|
|
|
|
|
|
\sa PluginSpec::dependencies()
|
|
|
|
|
*/
|
2011-01-11 14:01:08 +01:00
|
|
|
QHash<PluginDependency, PluginSpec *> PluginSpec::dependencySpecs() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
return d->dependencySpecs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//==========PluginSpecPrivate==================
|
|
|
|
|
|
|
|
|
|
namespace {
|
2011-11-02 16:45:13 +01:00
|
|
|
const char PLUGIN[] = "plugin";
|
|
|
|
|
const char PLUGIN_NAME[] = "name";
|
|
|
|
|
const char PLUGIN_VERSION[] = "version";
|
|
|
|
|
const char PLUGIN_COMPATVERSION[] = "compatVersion";
|
|
|
|
|
const char PLUGIN_EXPERIMENTAL[] = "experimental";
|
|
|
|
|
const char VENDOR[] = "vendor";
|
|
|
|
|
const char COPYRIGHT[] = "copyright";
|
|
|
|
|
const char LICENSE[] = "license";
|
|
|
|
|
const char DESCRIPTION[] = "description";
|
|
|
|
|
const char URL[] = "url";
|
|
|
|
|
const char CATEGORY[] = "category";
|
|
|
|
|
const char DEPENDENCYLIST[] = "dependencyList";
|
|
|
|
|
const char DEPENDENCY[] = "dependency";
|
|
|
|
|
const char DEPENDENCY_NAME[] = "name";
|
|
|
|
|
const char DEPENDENCY_VERSION[] = "version";
|
|
|
|
|
const char DEPENDENCY_TYPE[] = "type";
|
|
|
|
|
const char DEPENDENCY_TYPE_SOFT[] = "optional";
|
|
|
|
|
const char DEPENDENCY_TYPE_HARD[] = "required";
|
|
|
|
|
const char ARGUMENTLIST[] = "argumentList";
|
|
|
|
|
const char ARGUMENT[] = "argument";
|
|
|
|
|
const char ARGUMENT_NAME[] = "name";
|
|
|
|
|
const char ARGUMENT_PARAMETER[] = "parameter";
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
/*!
|
|
|
|
|
\fn PluginSpecPrivate::PluginSpecPrivate(PluginSpec *spec)
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
PluginSpecPrivate::PluginSpecPrivate(PluginSpec *spec)
|
2010-03-12 16:02:23 +01:00
|
|
|
:
|
2011-10-26 14:46:29 +02:00
|
|
|
experimental(false),
|
|
|
|
|
disabledByDefault(false),
|
2010-03-30 14:18:15 +02:00
|
|
|
enabled(true),
|
2010-05-12 14:34:36 +02:00
|
|
|
disabledIndirectly(false),
|
2010-03-12 16:02:23 +01:00
|
|
|
plugin(0),
|
2008-12-02 12:01:29 +01:00
|
|
|
state(PluginSpec::Invalid),
|
|
|
|
|
hasError(false),
|
|
|
|
|
q(spec)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn bool PluginSpecPrivate::read(const QString &fileName)
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
bool PluginSpecPrivate::read(const QString &fileName)
|
|
|
|
|
{
|
|
|
|
|
name
|
|
|
|
|
= version
|
|
|
|
|
= compatVersion
|
|
|
|
|
= vendor
|
|
|
|
|
= copyright
|
|
|
|
|
= license
|
|
|
|
|
= description
|
|
|
|
|
= url
|
2010-03-12 16:02:23 +01:00
|
|
|
= category
|
2008-12-02 12:01:29 +01:00
|
|
|
= location
|
|
|
|
|
= "";
|
|
|
|
|
state = PluginSpec::Invalid;
|
|
|
|
|
hasError = false;
|
|
|
|
|
errorString = "";
|
|
|
|
|
dependencies.clear();
|
|
|
|
|
QFile file(fileName);
|
|
|
|
|
if (!file.open(QIODevice::ReadOnly))
|
2011-06-21 17:07:45 +02:00
|
|
|
return reportError(tr("Cannot open file %1 for reading: %2")
|
2011-03-30 15:15:15 +02:00
|
|
|
.arg(QDir::toNativeSeparators(file.fileName()), file.errorString()));
|
2008-12-02 12:01:29 +01:00
|
|
|
QFileInfo fileInfo(file);
|
|
|
|
|
location = fileInfo.absolutePath();
|
|
|
|
|
filePath = fileInfo.absoluteFilePath();
|
|
|
|
|
QXmlStreamReader reader(&file);
|
|
|
|
|
while (!reader.atEnd()) {
|
|
|
|
|
reader.readNext();
|
|
|
|
|
switch (reader.tokenType()) {
|
|
|
|
|
case QXmlStreamReader::StartElement:
|
|
|
|
|
readPluginSpec(reader);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (reader.hasError())
|
|
|
|
|
return reportError(tr("Error parsing file %1: %2, at line %3, column %4")
|
2011-12-29 20:15:58 +01:00
|
|
|
.arg(QDir::toNativeSeparators(file.fileName()))
|
2008-12-02 12:01:29 +01:00
|
|
|
.arg(reader.errorString())
|
|
|
|
|
.arg(reader.lineNumber())
|
|
|
|
|
.arg(reader.columnNumber()));
|
|
|
|
|
state = PluginSpec::Read;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-30 14:18:15 +02:00
|
|
|
void PluginSpec::setEnabled(bool value)
|
2010-03-12 16:02:23 +01:00
|
|
|
{
|
2010-03-30 14:18:15 +02:00
|
|
|
d->enabled = value;
|
2010-03-12 16:02:23 +01:00
|
|
|
}
|
|
|
|
|
|
2011-10-26 14:46:29 +02:00
|
|
|
void PluginSpec::setDisabledByDefault(bool value)
|
|
|
|
|
{
|
|
|
|
|
d->disabledByDefault = value;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-19 16:29:47 +02:00
|
|
|
void PluginSpec::setDisabledIndirectly(bool value)
|
|
|
|
|
{
|
|
|
|
|
d->disabledIndirectly = value;
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
|
|
|
|
\fn bool PluginSpecPrivate::reportError(const QString &err)
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
bool PluginSpecPrivate::reportError(const QString &err)
|
|
|
|
|
{
|
|
|
|
|
errorString = err;
|
|
|
|
|
hasError = true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline QString msgAttributeMissing(const char *elt, const char *attribute)
|
|
|
|
|
{
|
|
|
|
|
return QCoreApplication::translate("PluginSpec", "'%1' misses attribute '%2'").arg(QLatin1String(elt), QLatin1String(attribute));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline QString msgInvalidFormat(const char *content)
|
|
|
|
|
{
|
|
|
|
|
return QCoreApplication::translate("PluginSpec", "'%1' has invalid format").arg(content);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline QString msgInvalidElement(const QString &name)
|
|
|
|
|
{
|
|
|
|
|
return QCoreApplication::translate("PluginSpec", "Invalid element '%1'").arg(name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline QString msgUnexpectedClosing(const QString &name)
|
|
|
|
|
{
|
|
|
|
|
return QCoreApplication::translate("PluginSpec", "Unexpected closing element '%1'").arg(name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline QString msgUnexpectedToken()
|
|
|
|
|
{
|
|
|
|
|
return QCoreApplication::translate("PluginSpec", "Unexpected token");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn void PluginSpecPrivate::readPluginSpec(QXmlStreamReader &reader)
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
void PluginSpecPrivate::readPluginSpec(QXmlStreamReader &reader)
|
|
|
|
|
{
|
|
|
|
|
QString element = reader.name().toString();
|
|
|
|
|
if (element != QString(PLUGIN)) {
|
|
|
|
|
reader.raiseError(QCoreApplication::translate("PluginSpec", "Expected element '%1' as top level element").arg(PLUGIN));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
name = reader.attributes().value(PLUGIN_NAME).toString();
|
|
|
|
|
if (name.isEmpty()) {
|
|
|
|
|
reader.raiseError(msgAttributeMissing(PLUGIN, PLUGIN_NAME));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
version = reader.attributes().value(PLUGIN_VERSION).toString();
|
|
|
|
|
if (version.isEmpty()) {
|
|
|
|
|
reader.raiseError(msgAttributeMissing(PLUGIN, PLUGIN_VERSION));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!isValidVersion(version)) {
|
|
|
|
|
reader.raiseError(msgInvalidFormat(PLUGIN_VERSION));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
compatVersion = reader.attributes().value(PLUGIN_COMPATVERSION).toString();
|
|
|
|
|
if (!compatVersion.isEmpty() && !isValidVersion(compatVersion)) {
|
|
|
|
|
reader.raiseError(msgInvalidFormat(PLUGIN_COMPATVERSION));
|
|
|
|
|
return;
|
|
|
|
|
} else if (compatVersion.isEmpty()) {
|
|
|
|
|
compatVersion = version;
|
|
|
|
|
}
|
2010-03-30 16:54:29 +02:00
|
|
|
QString experimentalString = reader.attributes().value(PLUGIN_EXPERIMENTAL).toString();
|
|
|
|
|
experimental = (experimentalString.compare(QLatin1String("true"), Qt::CaseInsensitive) == 0);
|
|
|
|
|
if (!experimentalString.isEmpty() && !experimental
|
|
|
|
|
&& experimentalString.compare(QLatin1String("false"), Qt::CaseInsensitive) != 0) {
|
|
|
|
|
reader.raiseError(msgInvalidFormat(PLUGIN_EXPERIMENTAL));
|
|
|
|
|
return;
|
|
|
|
|
}
|
2011-10-26 14:46:29 +02:00
|
|
|
disabledByDefault = experimental;
|
2010-03-30 16:54:29 +02:00
|
|
|
enabled = !experimental;
|
2008-12-02 12:01:29 +01:00
|
|
|
while (!reader.atEnd()) {
|
|
|
|
|
reader.readNext();
|
|
|
|
|
switch (reader.tokenType()) {
|
|
|
|
|
case QXmlStreamReader::StartElement:
|
|
|
|
|
element = reader.name().toString();
|
|
|
|
|
if (element == VENDOR)
|
|
|
|
|
vendor = reader.readElementText().trimmed();
|
|
|
|
|
else if (element == COPYRIGHT)
|
|
|
|
|
copyright = reader.readElementText().trimmed();
|
|
|
|
|
else if (element == LICENSE)
|
|
|
|
|
license = reader.readElementText().trimmed();
|
|
|
|
|
else if (element == DESCRIPTION)
|
|
|
|
|
description = reader.readElementText().trimmed();
|
|
|
|
|
else if (element == URL)
|
|
|
|
|
url = reader.readElementText().trimmed();
|
2010-03-12 16:02:23 +01:00
|
|
|
else if (element == CATEGORY)
|
|
|
|
|
category = reader.readElementText().trimmed();
|
2008-12-02 12:01:29 +01:00
|
|
|
else if (element == DEPENDENCYLIST)
|
|
|
|
|
readDependencies(reader);
|
|
|
|
|
else if (element == ARGUMENTLIST)
|
|
|
|
|
readArgumentDescriptions(reader);
|
|
|
|
|
else
|
|
|
|
|
reader.raiseError(msgInvalidElement(name));
|
|
|
|
|
break;
|
|
|
|
|
case QXmlStreamReader::EndDocument:
|
|
|
|
|
case QXmlStreamReader::Comment:
|
|
|
|
|
case QXmlStreamReader::EndElement:
|
|
|
|
|
case QXmlStreamReader::Characters:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
reader.raiseError(msgUnexpectedToken());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn void PluginSpecPrivate::readArgumentDescriptions(QXmlStreamReader &reader)
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
void PluginSpecPrivate::readArgumentDescriptions(QXmlStreamReader &reader)
|
|
|
|
|
{
|
|
|
|
|
QString element;
|
|
|
|
|
while (!reader.atEnd()) {
|
|
|
|
|
reader.readNext();
|
|
|
|
|
switch (reader.tokenType()) {
|
|
|
|
|
case QXmlStreamReader::StartElement:
|
|
|
|
|
element = reader.name().toString();
|
|
|
|
|
if (element == ARGUMENT) {
|
|
|
|
|
readArgumentDescription(reader);
|
|
|
|
|
} else {
|
|
|
|
|
reader.raiseError(msgInvalidElement(name));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case QXmlStreamReader::Comment:
|
|
|
|
|
case QXmlStreamReader::Characters:
|
|
|
|
|
break;
|
|
|
|
|
case QXmlStreamReader::EndElement:
|
|
|
|
|
element = reader.name().toString();
|
|
|
|
|
if (element == ARGUMENTLIST)
|
|
|
|
|
return;
|
|
|
|
|
reader.raiseError(msgUnexpectedClosing(element));
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
reader.raiseError(msgUnexpectedToken());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn void PluginSpecPrivate::readArgumentDescription(QXmlStreamReader &reader)
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
void PluginSpecPrivate::readArgumentDescription(QXmlStreamReader &reader)
|
|
|
|
|
{
|
|
|
|
|
PluginArgumentDescription arg;
|
|
|
|
|
arg.name = reader.attributes().value(ARGUMENT_NAME).toString();
|
|
|
|
|
if (arg.name.isEmpty()) {
|
|
|
|
|
reader.raiseError(msgAttributeMissing(ARGUMENT, ARGUMENT_NAME));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
arg.parameter = reader.attributes().value(ARGUMENT_PARAMETER).toString();
|
|
|
|
|
arg.description = reader.readElementText();
|
|
|
|
|
if (reader.tokenType() != QXmlStreamReader::EndElement)
|
|
|
|
|
reader.raiseError(msgUnexpectedToken());
|
|
|
|
|
argumentDescriptions.push_back(arg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn void PluginSpecPrivate::readDependencies(QXmlStreamReader &reader)
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
void PluginSpecPrivate::readDependencies(QXmlStreamReader &reader)
|
|
|
|
|
{
|
|
|
|
|
QString element;
|
|
|
|
|
while (!reader.atEnd()) {
|
|
|
|
|
reader.readNext();
|
|
|
|
|
switch (reader.tokenType()) {
|
|
|
|
|
case QXmlStreamReader::StartElement:
|
|
|
|
|
element = reader.name().toString();
|
|
|
|
|
if (element == DEPENDENCY) {
|
|
|
|
|
readDependencyEntry(reader);
|
|
|
|
|
} else {
|
|
|
|
|
reader.raiseError(msgInvalidElement(name));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case QXmlStreamReader::Comment:
|
|
|
|
|
case QXmlStreamReader::Characters:
|
|
|
|
|
break;
|
|
|
|
|
case QXmlStreamReader::EndElement:
|
|
|
|
|
element = reader.name().toString();
|
|
|
|
|
if (element == DEPENDENCYLIST)
|
|
|
|
|
return;
|
|
|
|
|
reader.raiseError(msgUnexpectedClosing(element));
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
reader.raiseError(msgUnexpectedToken());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn void PluginSpecPrivate::readDependencyEntry(QXmlStreamReader &reader)
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
void PluginSpecPrivate::readDependencyEntry(QXmlStreamReader &reader)
|
|
|
|
|
{
|
|
|
|
|
PluginDependency dep;
|
|
|
|
|
dep.name = reader.attributes().value(DEPENDENCY_NAME).toString();
|
|
|
|
|
if (dep.name.isEmpty()) {
|
|
|
|
|
reader.raiseError(msgAttributeMissing(DEPENDENCY, DEPENDENCY_NAME));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
dep.version = reader.attributes().value(DEPENDENCY_VERSION).toString();
|
|
|
|
|
if (!dep.version.isEmpty() && !isValidVersion(dep.version)) {
|
|
|
|
|
reader.raiseError(msgInvalidFormat(DEPENDENCY_VERSION));
|
|
|
|
|
return;
|
|
|
|
|
}
|
2011-01-11 14:01:08 +01:00
|
|
|
dep.type = PluginDependency::Required;
|
|
|
|
|
if (reader.attributes().hasAttribute(DEPENDENCY_TYPE)) {
|
|
|
|
|
QString typeValue = reader.attributes().value(DEPENDENCY_TYPE).toString();
|
|
|
|
|
if (typeValue == QLatin1String(DEPENDENCY_TYPE_HARD)) {
|
|
|
|
|
dep.type = PluginDependency::Required;
|
|
|
|
|
} else if (typeValue == QLatin1String(DEPENDENCY_TYPE_SOFT)) {
|
|
|
|
|
dep.type = PluginDependency::Optional;
|
|
|
|
|
} else {
|
|
|
|
|
reader.raiseError(msgInvalidFormat(DEPENDENCY_TYPE));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
dependencies.append(dep);
|
|
|
|
|
reader.readNext();
|
|
|
|
|
if (reader.tokenType() != QXmlStreamReader::EndElement)
|
|
|
|
|
reader.raiseError(msgUnexpectedToken());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn bool PluginSpecPrivate::provides(const QString &pluginName, const QString &pluginVersion) const
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
bool PluginSpecPrivate::provides(const QString &pluginName, const QString &pluginVersion) const
|
|
|
|
|
{
|
|
|
|
|
if (QString::compare(pluginName, name, Qt::CaseInsensitive) != 0)
|
|
|
|
|
return false;
|
|
|
|
|
return (versionCompare(version, pluginVersion) >= 0) && (versionCompare(compatVersion, pluginVersion) <= 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn QRegExp &PluginSpecPrivate::versionRegExp()
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
QRegExp &PluginSpecPrivate::versionRegExp()
|
|
|
|
|
{
|
|
|
|
|
static QRegExp reg("([0-9]+)(?:[.]([0-9]+))?(?:[.]([0-9]+))?(?:_([0-9]+))?");
|
|
|
|
|
return reg;
|
|
|
|
|
}
|
|
|
|
|
/*!
|
|
|
|
|
\fn bool PluginSpecPrivate::isValidVersion(const QString &version)
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
bool PluginSpecPrivate::isValidVersion(const QString &version)
|
|
|
|
|
{
|
|
|
|
|
return versionRegExp().exactMatch(version);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn int PluginSpecPrivate::versionCompare(const QString &version1, const QString &version2)
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
int PluginSpecPrivate::versionCompare(const QString &version1, const QString &version2)
|
|
|
|
|
{
|
|
|
|
|
QRegExp reg1 = versionRegExp();
|
|
|
|
|
QRegExp reg2 = versionRegExp();
|
|
|
|
|
if (!reg1.exactMatch(version1))
|
|
|
|
|
return 0;
|
|
|
|
|
if (!reg2.exactMatch(version2))
|
|
|
|
|
return 0;
|
|
|
|
|
int number1;
|
|
|
|
|
int number2;
|
|
|
|
|
for (int i = 0; i < 4; ++i) {
|
|
|
|
|
number1 = reg1.cap(i+1).toInt();
|
|
|
|
|
number2 = reg2.cap(i+1).toInt();
|
|
|
|
|
if (number1 < number2)
|
|
|
|
|
return -1;
|
|
|
|
|
if (number1 > number2)
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
2008-12-11 11:26:42 +01:00
|
|
|
\fn bool PluginSpecPrivate::resolveDependencies(const QList<PluginSpec *> &specs)
|
2008-12-02 12:01:29 +01:00
|
|
|
\internal
|
|
|
|
|
*/
|
2008-12-11 11:26:42 +01:00
|
|
|
bool PluginSpecPrivate::resolveDependencies(const QList<PluginSpec *> &specs)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
if (hasError)
|
|
|
|
|
return false;
|
|
|
|
|
if (state == PluginSpec::Resolved)
|
|
|
|
|
state = PluginSpec::Read; // Go back, so we just re-resolve the dependencies.
|
|
|
|
|
if (state != PluginSpec::Read) {
|
|
|
|
|
errorString = QCoreApplication::translate("PluginSpec", "Resolving dependencies failed because state != Read");
|
|
|
|
|
hasError = true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2011-01-11 14:01:08 +01:00
|
|
|
QHash<PluginDependency, PluginSpec *> resolvedDependencies;
|
2008-12-02 12:01:29 +01:00
|
|
|
foreach (const PluginDependency &dependency, dependencies) {
|
|
|
|
|
PluginSpec *found = 0;
|
2010-03-12 16:02:23 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
foreach (PluginSpec *spec, specs) {
|
|
|
|
|
if (spec->provides(dependency.name, dependency.version)) {
|
|
|
|
|
found = spec;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!found) {
|
2011-01-11 14:01:08 +01:00
|
|
|
if (dependency.type == PluginDependency::Required) {
|
|
|
|
|
hasError = true;
|
|
|
|
|
if (!errorString.isEmpty())
|
|
|
|
|
errorString.append(QLatin1Char('\n'));
|
|
|
|
|
errorString.append(QCoreApplication::translate("PluginSpec", "Could not resolve dependency '%1(%2)'")
|
|
|
|
|
.arg(dependency.name).arg(dependency.version));
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
2011-01-11 14:01:08 +01:00
|
|
|
resolvedDependencies.insert(dependency, found);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
if (hasError)
|
|
|
|
|
return false;
|
2010-03-12 16:02:23 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
dependencySpecs = resolvedDependencies;
|
2010-03-12 16:02:23 +01:00
|
|
|
|
2010-05-19 16:29:47 +02:00
|
|
|
state = PluginSpec::Resolved;
|
2010-03-12 16:02:23 +01:00
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-19 16:29:47 +02:00
|
|
|
void PluginSpecPrivate::disableIndirectlyIfDependencyDisabled()
|
|
|
|
|
{
|
|
|
|
|
if (!enabled)
|
|
|
|
|
return;
|
|
|
|
|
|
2010-09-08 11:13:37 +02:00
|
|
|
if (disabledIndirectly)
|
|
|
|
|
return;
|
|
|
|
|
|
2011-01-11 14:01:08 +01:00
|
|
|
QHashIterator<PluginDependency, PluginSpec *> it(dependencySpecs);
|
|
|
|
|
while (it.hasNext()) {
|
|
|
|
|
it.next();
|
|
|
|
|
if (it.key().type == PluginDependency::Optional)
|
|
|
|
|
continue;
|
|
|
|
|
PluginSpec *dependencySpec = it.value();
|
2010-05-19 16:29:47 +02:00
|
|
|
if (dependencySpec->isDisabledIndirectly() || !dependencySpec->isEnabled()) {
|
|
|
|
|
disabledIndirectly = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
|
|
|
|
\fn bool PluginSpecPrivate::loadLibrary()
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
bool PluginSpecPrivate::loadLibrary()
|
|
|
|
|
{
|
|
|
|
|
if (hasError)
|
|
|
|
|
return false;
|
|
|
|
|
if (state != PluginSpec::Resolved) {
|
|
|
|
|
if (state == PluginSpec::Loaded)
|
|
|
|
|
return true;
|
|
|
|
|
errorString = QCoreApplication::translate("PluginSpec", "Loading the library failed because state != Resolved");
|
|
|
|
|
hasError = true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
#ifdef QT_NO_DEBUG
|
|
|
|
|
|
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
|
QString libName = QString("%1/%2.dll").arg(location).arg(name);
|
|
|
|
|
#elif defined(Q_OS_MAC)
|
|
|
|
|
QString libName = QString("%1/lib%2.dylib").arg(location).arg(name);
|
|
|
|
|
#else
|
|
|
|
|
QString libName = QString("%1/lib%2.so").arg(location).arg(name);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#else //Q_NO_DEBUG
|
|
|
|
|
|
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
|
QString libName = QString("%1/%2d.dll").arg(location).arg(name);
|
|
|
|
|
#elif defined(Q_OS_MAC)
|
|
|
|
|
QString libName = QString("%1/lib%2_debug.dylib").arg(location).arg(name);
|
|
|
|
|
#else
|
|
|
|
|
QString libName = QString("%1/lib%2.so").arg(location).arg(name);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
2009-02-19 15:32:50 +01:00
|
|
|
PluginLoader loader(libName);
|
2008-12-02 12:01:29 +01:00
|
|
|
if (!loader.load()) {
|
|
|
|
|
hasError = true;
|
2009-10-06 17:40:30 +02:00
|
|
|
errorString = QDir::toNativeSeparators(libName)
|
|
|
|
|
+ QString::fromLatin1(": ") + loader.errorString();
|
2008-12-02 12:01:29 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
IPlugin *pluginObject = qobject_cast<IPlugin*>(loader.instance());
|
|
|
|
|
if (!pluginObject) {
|
|
|
|
|
hasError = true;
|
2009-09-29 12:17:37 +02:00
|
|
|
errorString = QCoreApplication::translate("PluginSpec", "Plugin is not valid (does not derive from IPlugin)");
|
2008-12-02 12:01:29 +01:00
|
|
|
loader.unload();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
state = PluginSpec::Loaded;
|
|
|
|
|
plugin = pluginObject;
|
|
|
|
|
plugin->d->pluginSpec = q;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn bool PluginSpecPrivate::initializePlugin()
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
bool PluginSpecPrivate::initializePlugin()
|
|
|
|
|
{
|
|
|
|
|
if (hasError)
|
|
|
|
|
return false;
|
|
|
|
|
if (state != PluginSpec::Loaded) {
|
|
|
|
|
if (state == PluginSpec::Initialized)
|
|
|
|
|
return true;
|
|
|
|
|
errorString = QCoreApplication::translate("PluginSpec", "Initializing the plugin failed because state != Loaded");
|
|
|
|
|
hasError = true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!plugin) {
|
|
|
|
|
errorString = QCoreApplication::translate("PluginSpec", "Internal error: have no plugin instance to initialize");
|
|
|
|
|
hasError = true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
QString err;
|
|
|
|
|
if (!plugin->initialize(arguments, &err)) {
|
|
|
|
|
errorString = QCoreApplication::translate("PluginSpec", "Plugin initialization failed: %1").arg(err);
|
|
|
|
|
hasError = true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
state = PluginSpec::Initialized;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn bool PluginSpecPrivate::initializeExtensions()
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
bool PluginSpecPrivate::initializeExtensions()
|
|
|
|
|
{
|
|
|
|
|
if (hasError)
|
|
|
|
|
return false;
|
|
|
|
|
if (state != PluginSpec::Initialized) {
|
|
|
|
|
if (state == PluginSpec::Running)
|
|
|
|
|
return true;
|
|
|
|
|
errorString = QCoreApplication::translate("PluginSpec", "Cannot perform extensionsInitialized because state != Initialized");
|
|
|
|
|
hasError = true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!plugin) {
|
|
|
|
|
errorString = QCoreApplication::translate("PluginSpec", "Internal error: have no plugin instance to perform extensionsInitialized");
|
|
|
|
|
hasError = true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
plugin->extensionsInitialized();
|
|
|
|
|
state = PluginSpec::Running;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-02 10:47:33 +01:00
|
|
|
/*!
|
|
|
|
|
\fn bool PluginSpecPrivate::delayedInitialize()
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
bool PluginSpecPrivate::delayedInitialize()
|
|
|
|
|
{
|
|
|
|
|
if (hasError)
|
|
|
|
|
return false;
|
|
|
|
|
if (state != PluginSpec::Running) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!plugin) {
|
|
|
|
|
errorString = QCoreApplication::translate("PluginSpec", "Internal error: have no plugin instance to perform delayedInitialize");
|
|
|
|
|
hasError = true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return plugin->delayedInitialize();
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
/*!
|
|
|
|
|
\fn bool PluginSpecPrivate::stop()
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
2010-07-13 13:36:47 +02:00
|
|
|
IPlugin::ShutdownFlag PluginSpecPrivate::stop()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
if (!plugin)
|
2010-07-13 13:36:47 +02:00
|
|
|
return IPlugin::SynchronousShutdown;
|
2008-12-02 12:01:29 +01:00
|
|
|
state = PluginSpec::Stopped;
|
2010-07-13 13:36:47 +02:00
|
|
|
return plugin->aboutToShutdown();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\fn bool PluginSpecPrivate::kill()
|
|
|
|
|
\internal
|
|
|
|
|
*/
|
|
|
|
|
void PluginSpecPrivate::kill()
|
|
|
|
|
{
|
|
|
|
|
if (!plugin)
|
|
|
|
|
return;
|
|
|
|
|
delete plugin;
|
|
|
|
|
plugin = 0;
|
|
|
|
|
state = PluginSpec::Deleted;
|
|
|
|
|
}
|