diff options
Diffstat (limited to 'src/libs/extensionsystem')
108 files changed, 6409 insertions, 0 deletions
diff --git a/src/libs/extensionsystem/ExtensionSystemInterfaces b/src/libs/extensionsystem/ExtensionSystemInterfaces new file mode 100644 index 00000000000..527148af8e1 --- /dev/null +++ b/src/libs/extensionsystem/ExtensionSystemInterfaces @@ -0,0 +1,6 @@ +#include "extensionsystem/pluginmanager.h" +#include "extensionsystem/pluginspec.h" +#include "extensionsystem/iplugin.h" +#include "extensionsystem/pluginview.h" +#include "extensionsystem/pluginerrorview.h" +#include "extensionsystem/plugindetailsview.h" diff --git a/src/libs/extensionsystem/extensionsystem.pri b/src/libs/extensionsystem/extensionsystem.pri new file mode 100644 index 00000000000..43855eb1688 --- /dev/null +++ b/src/libs/extensionsystem/extensionsystem.pri @@ -0,0 +1,3 @@ +include(extensionsystem_dependencies.pri) + +LIBS *= -l$$qtLibraryTarget(ExtensionSystem) diff --git a/src/libs/extensionsystem/extensionsystem.pro b/src/libs/extensionsystem/extensionsystem.pro new file mode 100644 index 00000000000..fb26b9c59cc --- /dev/null +++ b/src/libs/extensionsystem/extensionsystem.pro @@ -0,0 +1,32 @@ +TEMPLATE = lib +TARGET = ExtensionSystem +QT += xml +DEFINES += EXTENSIONSYSTEM_LIBRARY +include(../../qworkbenchlibrary.pri) +include(extensionsystem_dependencies.pri) + +DEFINES += IDE_TEST_DIR=\\\"$$IDE_SOURCE_TREE\\\" + +HEADERS += pluginerrorview.h \ + plugindetailsview.h \ + iplugin.h \ + iplugin_p.h \ + extensionsystem_global.h \ + pluginmanager.h \ + pluginmanager_p.h \ + pluginspec.h \ + pluginspec_p.h \ + pluginview.h \ + pluginview_p.h \ + optionsparser.h +SOURCES += pluginerrorview.cpp \ + plugindetailsview.cpp \ + iplugin.cpp \ + pluginmanager.cpp \ + pluginspec.cpp \ + pluginview.cpp \ + optionsparser.cpp +FORMS += pluginview.ui \ + pluginerrorview.ui \ + plugindetailsview.ui +RESOURCES += pluginview.qrc diff --git a/src/libs/extensionsystem/extensionsystem_dependencies.pri b/src/libs/extensionsystem/extensionsystem_dependencies.pri new file mode 100644 index 00000000000..63b2e339a36 --- /dev/null +++ b/src/libs/extensionsystem/extensionsystem_dependencies.pri @@ -0,0 +1 @@ +include(../aggregation/aggregation.pri) diff --git a/src/libs/extensionsystem/extensionsystem_global.h b/src/libs/extensionsystem/extensionsystem_global.h new file mode 100644 index 00000000000..ebd1f34da25 --- /dev/null +++ b/src/libs/extensionsystem/extensionsystem_global.h @@ -0,0 +1,44 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef EXTENSIONSYSTEM_GLOBAL_H +#define EXTENSIONSYSTEM_GLOBAL_H + +#include <QtCore/qglobal.h> + +#if defined(EXTENSIONSYSTEM_LIBRARY) +# define EXTENSIONSYSTEM_EXPORT Q_DECL_EXPORT +#else +# define EXTENSIONSYSTEM_EXPORT Q_DECL_IMPORT +#endif + +#endif // header diff --git a/src/libs/extensionsystem/images/error.png b/src/libs/extensionsystem/images/error.png Binary files differnew file mode 100644 index 00000000000..e2f85d98eb6 --- /dev/null +++ b/src/libs/extensionsystem/images/error.png diff --git a/src/libs/extensionsystem/images/ok.png b/src/libs/extensionsystem/images/ok.png Binary files differnew file mode 100644 index 00000000000..15cd35d27ba --- /dev/null +++ b/src/libs/extensionsystem/images/ok.png diff --git a/src/libs/extensionsystem/iplugin.cpp b/src/libs/extensionsystem/iplugin.cpp new file mode 100644 index 00000000000..47cb702e16b --- /dev/null +++ b/src/libs/extensionsystem/iplugin.cpp @@ -0,0 +1,325 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "iplugin.h" +#include "iplugin_p.h" +#include "pluginmanager.h" +#include "pluginspec.h" + +/*! + \class ExtensionSystem::IPlugin + \brief Base class for all plugins. + + The IPlugin class is an abstract class that must be implemented + once for each plugin. + A plugin consists of two parts: A description file, and a library + that at least contains the IPlugin implementation. + + \tableofcontents + + \section1 Plugin Specification + The plugin specification file is an xml file that contains all + information that are necessary for loading the plugin's library, + plus some textual descriptions. The file must be located in + (a subdir of) one of the plugin manager's plugin search paths, + and must have the \c .xml extension. + + \section2 Main Tag + The root tag is \c plugin. It has mandatory attributes \c name + and \c version, and an optional \c compatVersion. + \table + \header + \o Tag + \o Meaning + \row + \o plugin + \o Root element in a plugin's xml file. + \endtable + \table + \header + \o Attribute + \o Meaning + \row + \o name + \o This is used as an identifier for the plugin and can e.g. + be referenced in other plugin's dependencies. It is + also used to construct the name of the plugin library + as \c lib[name].[dll|.so|.dylib]. + \row + \o version + \o Version string in the form \c {"x.y.z_n"}, used for identifying + the plugin. + \row + \o compatVersion + \o Compatibility version. Optional. If not given, it is implicitly + set to the same value as \c version. The compatibility version + is used to resolve dependencies on this plugin. See + \l {Dependencies}{Dependencies} for details. + \endtable + + \section2 Plugin-describing Tags + These are direct children of the \c plugin tag, and are solely used + for more detailed (user centric) description of the plugin. All of these + are optional. + \table + \header + \o Tag + \o Meaning + \row + \o vendor + \o String that describes the plugin creator/vendor, + like \c {MyCompany}. + \row + \o copyright + \o A short copyright notice, like \c {(C) 2007-2008 MyCompany}. + \row + \o license + \o Possibly multi-line license information about the plugin. + \row + \o description + \o Possibly multi-line description of what the plugin is supposed + to provide. + \row + \o url + \o Link to further information about the plugin, like + \c {http://www.mycompany-online.com/products/greatplugin}. + \endtable + + \section2 Dependencies + A plugin can have dependencies on other plugins. These are + specified in the plugin's xml file as well, to ensure that + these other plugins are loaded before this plugin. + Dependency information consists of the name of the required plugin + (lets denote that as \c {dependencyName}), + and the required version of the plugin (\c {dependencyVersion}). + A plugin with given \c name, \c version and \c compatVersion matches + the dependency if + \list + \o it's \c name matches \c dependencyName, and + \o \c {compatVersion <= dependencyVersion <= version}. + \endlist + + The xml element that describes dependencies is the \c dependency tag, + with required attributes \c name and \c version. It is an + optional direct child of the \c plugin tag and can appear multiple times. + \table + \header + \o Tag + \o Meaning + \row + \o dependency + \o Describes a dependency on another plugin. + \endtable + \table + \header + \o Attribute + \o Meaning + \row + \o name + \o The name of the plugin, on which this plugin relies. + \row + \o version + \o The version to which the plugin must be compatible to + fill the dependency, in the form \c {"x.y.z_n"}. + \endtable + + \section2 Example \c plugin.xml + \code + <plugin name="test" version="1.0.1" compatVersion="1.0.0"> + <vendor>MyCompany</vendor> + <copyright>(C) 2007 MyCompany</copyright> + <license> + This is a default license bla + blubbblubb + end of terms + </license> + <description> + This plugin is just a test. + it demonstrates the great use of the plugin spec. + </description> + <url>http://www.mycompany-online.com/products/greatplugin</url> + <dependencyList> + <dependency name="SomeOtherPlugin" version="2.3.0_2"/> + <dependency name="EvenOther" version="1.0.0"/> + </dependencyList> + </plugin> + \endcode + The first dependency could for example be matched by a plugin with + \code + <plugin name="SomeOtherPlugin" version="3.1.0" compatVersion="2.2.0"> + </plugin> + \endcode + since the name matches, and the version \c "2.3.0_2" given in the dependency tag + lies in the range of \c "2.2.0" and \c "3.1.0". + + \section2 A Note on Plugin Versions + Plugin versions are in the form \c "x.y.z_n" where, x, y, z and n are + non-negative integer numbers. You don't have to specify the version + in this full form - any left-out part will implicitly be set to zero. + So, \c "2.10_2" is equal to \c "2.10.0_2", and "1" is the same as "1.0.0_0". + + \section1 Plugin Implementation + Plugins must provide one implementation of the IPlugin class, located + in a library that matches the \c name attribute given in their + xml description. The IPlugin implementation must be exported and + made known to Qt's plugin system via the Q_EXPORT_PLUGIN macro, see the + Qt documentation for details on that. + + After the plugins' xml files have been read, and dependencies have been + found, the plugin loading is done in three phases: + \list 1 + \o All plugin libraries are loaded in 'root-to-leaf' order of the + dependency tree. + \o All plugins' initialize methods are called in 'root-to-leaf' order + of the dependency tree. This is a good place to put + objects in the plugin manager's object pool. + \o All plugins' extensionsInitialized methods are called in 'leaf-to-root' + order of the dependency tree. At this point, plugins can + be sure that all plugins that depend on this plugin have + been initialized completely (implying that they have put + objects in the object pool, if they want that during the + initialization sequence). + \endlist + If library loading or initialization of a plugin fails, all plugins + that depend on that plugin also fail. + + Plugins have access to the plugin manager + (and it's object pool) via the PluginManager::instance() + method. +*/ + +/*! + \fn bool IPlugin::initialize(const QStringList &arguments, QString *errorString) + Called after the plugin has been loaded and the IPlugin instance + has been created. The initialize methods of plugins that depend + on this plugin are called after the initialize method of this plugin + has been called. Plugins should initialize their internal state in this + method. Returns if initialization of successful. If it wasn't successful, + the \a errorString should be set to a user-readable message + describing the reason. + \sa extensionsInitialized() +*/ + +/*! + \fn void IPlugin::extensionsInitialized() + Called after the IPlugin::initialize() method has been called, + and after both the IPlugin::initialize() and IPlugin::extensionsInitialized() + methods of plugins that depend on this plugin have been called. + In this method, the plugin can assume that plugins that depend on + this plugin are fully 'up and running'. It is a good place to + look in the plugin manager's object pool for objects that have + been provided by dependent plugins. + \sa initialize() +*/ + +/*! + \fn void IPlugin::shutdown() + Called during a shutdown sequence in the same order as initialization + before the plugins get deleted in reverse order. + This method can be used to optimize the shutdown down, e.g. to + disconnect from the PluginManager::aboutToRemoveObject() signal + if getting the signal (and probably doing lots of stuff to update + the internal and visible state) doesn't make sense during shutdown. +*/ + +using namespace ExtensionSystem; + +/*! + \fn IPlugin::IPlugin() + \internal +*/ +IPlugin::IPlugin() + : d(new Internal::IPluginPrivate()) +{ +} + +/*! + \fn IPlugin::~IPlugin() + \internal +*/ +IPlugin::~IPlugin() +{ + PluginManager *pm = PluginManager::instance(); + foreach (QObject *obj, d->addedObjectsInReverseOrder) + pm->removeObject(obj); + qDeleteAll(d->addedObjectsInReverseOrder); + d->addedObjectsInReverseOrder.clear(); + delete d; + d = 0; +} + +/*! + \fn PluginSpec *IPlugin::pluginSpec() const + Returns the PluginSpec corresponding to this plugin. + This is not available in the constructor. +*/ +PluginSpec *IPlugin::pluginSpec() const +{ + return d->pluginSpec; +} + +/*! + \fn void IPlugin::addObject(QObject *obj) + Convenience method that registers \a obj in the plugin manager's + plugin pool by just calling PluginManager::addObject(). +*/ +void IPlugin::addObject(QObject *obj) +{ + PluginManager::instance()->addObject(obj); +} + +/*! + \fn void IPlugin::addAutoReleasedObject(QObject *obj) + Convenience method for registering \a obj in the plugin manager's + plugin pool. Usually, registered objects must be removed from + the object pool and deleted by hand. + Objects added to the pool via addAutoReleasedObject are automatically + removed and deleted in \i reverse order of registration when + the IPlugin instance is destroyed. + \sa PluginManager::addObject() +*/ +void IPlugin::addAutoReleasedObject(QObject *obj) +{ + d->addedObjectsInReverseOrder.prepend(obj); + PluginManager::instance()->addObject(obj); +} + +/*! + \fn void IPlugin::removeObject(QObject *obj) + Convenience method that unregisters \a obj from the plugin manager's + plugin pool by just calling PluginManager::removeObject(). +*/ +void IPlugin::removeObject(QObject *obj) +{ + PluginManager::instance()->removeObject(obj); +} + diff --git a/src/libs/extensionsystem/iplugin.h b/src/libs/extensionsystem/iplugin.h new file mode 100644 index 00000000000..b263e7b0d29 --- /dev/null +++ b/src/libs/extensionsystem/iplugin.h @@ -0,0 +1,76 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef IPLUGIN_H +#define IPLUGIN_H + +#include "extensionsystem_global.h" + +#include <QtCore/QObject> + +namespace ExtensionSystem { + +namespace Internal { + class IPluginPrivate; + class PluginSpecPrivate; +} + +class PluginManager; +class PluginSpec; + +class EXTENSIONSYSTEM_EXPORT IPlugin : public QObject +{ + Q_OBJECT + +public: + IPlugin(); + virtual ~IPlugin(); + + virtual bool initialize(const QStringList &arguments, QString *errorString) = 0; + virtual void extensionsInitialized() = 0; + virtual void shutdown() { } + + PluginSpec *pluginSpec() const; + + void addObject(QObject *obj); + void addAutoReleasedObject(QObject *obj); + void removeObject(QObject *obj); + +private: + Internal::IPluginPrivate *d; + + friend class Internal::PluginSpecPrivate; +}; + +} // namespace ExtensionSystem + +#endif // IPLUGIN_H diff --git a/src/libs/extensionsystem/iplugin_p.h b/src/libs/extensionsystem/iplugin_p.h new file mode 100644 index 00000000000..461a903a398 --- /dev/null +++ b/src/libs/extensionsystem/iplugin_p.h @@ -0,0 +1,58 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef IPLUGIN_P_H +#define IPLUGIN_P_H + +#include "iplugin.h" + +#include <QtCore/QString> + +namespace ExtensionSystem { + +class PluginManager; +class PluginSpec; + +namespace Internal { + +class IPluginPrivate +{ +public: + PluginSpec *pluginSpec; + + QList<QObject *> addedObjectsInReverseOrder; +}; + +} // namespace Internal +} // namespace ExtensionSystem + +#endif // header guard diff --git a/src/libs/extensionsystem/optionsparser.cpp b/src/libs/extensionsystem/optionsparser.cpp new file mode 100644 index 00000000000..77b6ed869e4 --- /dev/null +++ b/src/libs/extensionsystem/optionsparser.cpp @@ -0,0 +1,192 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "optionsparser.h" + +#include <QtCore/QCoreApplication> + +using namespace ExtensionSystem; +using namespace ExtensionSystem::Internal; + +static const char *END_OF_OPTIONS = "--"; +const char *OptionsParser::NO_LOAD_OPTION = "-noload"; +const char *OptionsParser::TEST_OPTION = "-test"; + +OptionsParser::OptionsParser(const QStringList &args, + const QMap<QString, bool> &appOptions, + QMap<QString, QString> *foundAppOptions, + QString *errorString, + PluginManagerPrivate *pmPrivate) + : m_args(args), m_appOptions(appOptions), + m_foundAppOptions(foundAppOptions), + m_errorString(errorString), + m_pmPrivate(pmPrivate), + m_it(m_args.constBegin()), + m_end(m_args.constEnd()), + m_isDependencyRefreshNeeded(false), + m_hasError(false) +{ + ++m_it; // jump over program name + if (m_errorString) + m_errorString->clear(); + if (m_foundAppOptions) + m_foundAppOptions->clear(); + m_pmPrivate->arguments.clear(); +} + +bool OptionsParser::parse() +{ + while (!m_hasError) { + if (!nextToken()) // move forward + break; + if (checkForEndOfOptions()) + break; + if (checkForNoLoadOption()) + continue; + if (checkForTestOption()) + continue; + if (checkForAppOption()) + continue; + if (checkForPluginOption()) + continue; + if (checkForUnknownOption()) + break; + // probably a file or something + m_pmPrivate->arguments << m_currentArg; + } + if (m_isDependencyRefreshNeeded) + m_pmPrivate->resolveDependencies(); + return !m_hasError; +} + +bool OptionsParser::checkForEndOfOptions() +{ + if (m_currentArg != QLatin1String(END_OF_OPTIONS)) + return false; + while (nextToken()) { + m_pmPrivate->arguments << m_currentArg; + } + return true; +} + +bool OptionsParser::checkForTestOption() +{ + if (m_currentArg != QLatin1String(TEST_OPTION)) + return false; + if (nextToken(RequiredToken)) { + PluginSpec *spec = m_pmPrivate->pluginByName(m_currentArg); + if (!spec) { + if (m_errorString) + *m_errorString = QCoreApplication::translate("PluginManager", + "The plugin '%1' does not exist.").arg(m_currentArg); + m_hasError = true; + } else { + m_pmPrivate->testSpecs.append(spec); + } + } + return true; +} + +bool OptionsParser::checkForNoLoadOption() +{ + if (m_currentArg != QLatin1String(NO_LOAD_OPTION)) + return false; + if (nextToken(RequiredToken)) { + PluginSpec *spec = m_pmPrivate->pluginByName(m_currentArg); + if (!spec) { + if (m_errorString) + *m_errorString = QCoreApplication::translate("PluginManager", + "The plugin '%1' does not exist.").arg(m_currentArg); + m_hasError = true; + } else { + m_pmPrivate->pluginSpecs.remove(spec); + delete spec; + m_isDependencyRefreshNeeded = true; + } + } + return true; +} + +bool OptionsParser::checkForAppOption() +{ + if (!m_appOptions.contains(m_currentArg)) + return false; + QString option = m_currentArg; + QString argument; + if (m_appOptions.value(m_currentArg) && nextToken(RequiredToken)) { + //argument required + argument = m_currentArg; + } + if (m_foundAppOptions) + m_foundAppOptions->insert(option, argument); + return true; +} + +bool OptionsParser::checkForPluginOption() +{ + bool requiresParameter; + PluginSpec *spec = m_pmPrivate->pluginForOption(m_currentArg, &requiresParameter); + if (!spec) + return false; + spec->addArgument(m_currentArg); + if (requiresParameter && nextToken(RequiredToken)) { + spec->addArgument(m_currentArg); + } + return true; +} + +bool OptionsParser::checkForUnknownOption() +{ + if (!m_currentArg.startsWith(QLatin1Char('-'))) + return false; + if (m_errorString) + *m_errorString = QCoreApplication::translate("PluginManager", + "Unknown option %1").arg(m_currentArg); + m_hasError = true; + return true; +} + +bool OptionsParser::nextToken(OptionsParser::TokenType type) +{ + if (m_it == m_end) { + if (type == OptionsParser::RequiredToken) { + m_hasError = true; + if (m_errorString) + *m_errorString = QCoreApplication::translate("PluginManager", + "The option %1 requires an argument.").arg(m_currentArg); + } + return false; + } + m_currentArg = *m_it; + ++m_it; + return true; +} diff --git a/src/libs/extensionsystem/optionsparser.h b/src/libs/extensionsystem/optionsparser.h new file mode 100644 index 00000000000..65ea70c9ba2 --- /dev/null +++ b/src/libs/extensionsystem/optionsparser.h @@ -0,0 +1,87 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef OPTIONSPARSER_H +#define OPTIONSPARSER_H + +#include "pluginmanager_p.h" + +#include <QtCore/QStringList> +#include <QtCore/QMap> + +namespace ExtensionSystem { +namespace Internal { + +class OptionsParser +{ +public: + OptionsParser(const QStringList &args, + const QMap<QString, bool> &appOptions, + QMap<QString, QString> *foundAppOptions, + QString *errorString, + PluginManagerPrivate *pmPrivate); + + bool parse(); + + static const char *NO_LOAD_OPTION; + static const char *TEST_OPTION; +private: + // return value indicates if the option was processed + // it doesn't indicate success (--> m_hasError) + bool checkForEndOfOptions(); + bool checkForNoLoadOption(); + bool checkForTestOption(); + bool checkForAppOption(); + bool checkForPluginOption(); + bool checkForUnknownOption(); + + enum TokenType { OptionalToken, RequiredToken }; + bool nextToken(TokenType type = OptionalToken); + + const QStringList &m_args; + const QMap<QString, bool> &m_appOptions; + QMap<QString, QString> *m_foundAppOptions; + QString *m_errorString; + PluginManagerPrivate *m_pmPrivate; + + // state + QString m_currentArg; + QStringList::const_iterator m_it; + QStringList::const_iterator m_end; + bool m_isDependencyRefreshNeeded; + bool m_hasError; +}; + +} // namespace Internal +} // namespace ExtensionSystem + +#endif // OPTIONSPARSER_H diff --git a/src/libs/extensionsystem/plugindetailsview.cpp b/src/libs/extensionsystem/plugindetailsview.cpp new file mode 100644 index 00000000000..349cc48a12a --- /dev/null +++ b/src/libs/extensionsystem/plugindetailsview.cpp @@ -0,0 +1,89 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "plugindetailsview.h" +#include "ui_plugindetailsview.h" + +/*! + \class ExtensionSystem::PluginDetailsView + \brief Widget that displays the contents of a PluginSpec. + + Can be used for integration in the application that + uses the plugin manager. + + \sa ExtensionSystem::PluginView +*/ + +using namespace ExtensionSystem; + +/*! + \fn PluginDetailsView::PluginDetailsView(QWidget *parent) + Constructs a new view with given \a parent widget. +*/ +PluginDetailsView::PluginDetailsView(QWidget *parent) + : QWidget(parent), + m_ui(new Internal::Ui::PluginDetailsView()) +{ + m_ui->setupUi(this); +} + +/*! + \fn PluginDetailsView::~PluginDetailsView() + \internal +*/ +PluginDetailsView::~PluginDetailsView() +{ + delete m_ui; +} + +/*! + \fn void PluginDetailsView::update(PluginSpec *spec) + Reads the given \a spec and displays its values + in this PluginDetailsView. +*/ +void PluginDetailsView::update(PluginSpec *spec) +{ + m_ui->name->setText(spec->name()); + m_ui->version->setText(spec->version()); + m_ui->compatVersion->setText(spec->compatVersion()); + m_ui->vendor->setText(spec->vendor()); + m_ui->url->setText(spec->url()); + m_ui->location->setText(spec->filePath()); + m_ui->description->setText(spec->description()); + m_ui->copyright->setText(spec->copyright()); + m_ui->license->setText(spec->license()); + QStringList depStrings; + foreach (PluginDependency dep, spec->dependencies()) { + depStrings << QString("%1 (%2)").arg(dep.name).arg(dep.version); + } + m_ui->dependencies->addItems(depStrings); +} diff --git a/src/libs/extensionsystem/plugindetailsview.h b/src/libs/extensionsystem/plugindetailsview.h new file mode 100644 index 00000000000..99386f29d0f --- /dev/null +++ b/src/libs/extensionsystem/plugindetailsview.h @@ -0,0 +1,67 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef PLUGINDETAILSVIEW_H_ +#define PLUGINDETAILSVIEW_H_ + +#include "extensionsystem_global.h" +#include "pluginspec.h" + +#include <QtGui/QWidget> + +namespace ExtensionSystem +{ + +namespace Internal { +namespace Ui { + class PluginDetailsView; +} // namespace Ui +} // namespace Internal + + +class EXTENSIONSYSTEM_EXPORT PluginDetailsView : public QWidget +{ + Q_OBJECT + +public: + PluginDetailsView(QWidget *parent = 0); + ~PluginDetailsView(); + + void update(PluginSpec *spec); + +private: + Internal::Ui::PluginDetailsView *m_ui; +}; + +} // namespace ExtensionSystem + +#endif diff --git a/src/libs/extensionsystem/plugindetailsview.ui b/src/libs/extensionsystem/plugindetailsview.ui new file mode 100644 index 00000000000..e73c9de39b0 --- /dev/null +++ b/src/libs/extensionsystem/plugindetailsview.ui @@ -0,0 +1,258 @@ +<ui version="4.0" > + <class>ExtensionSystem::Internal::PluginDetailsView</class> + <widget class="QWidget" name="ExtensionSystem::Internal::PluginDetailsView" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>674</width> + <height>505</height> + </rect> + </property> + <property name="windowTitle" > + <string>Form</string> + </property> + <layout class="QGridLayout" > + <property name="leftMargin" > + <number>2</number> + </property> + <property name="topMargin" > + <number>2</number> + </property> + <property name="rightMargin" > + <number>2</number> + </property> + <property name="bottomMargin" > + <number>2</number> + </property> + <item row="0" column="0" > + <widget class="QLabel" name="label" > + <property name="text" > + <string>Name:</string> + </property> + <property name="alignment" > + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QLabel" name="name" > + <property name="text" > + <string>TextLabel</string> + </property> + </widget> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="label_2" > + <property name="text" > + <string>Version:</string> + </property> + <property name="alignment" > + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QLabel" name="version" > + <property name="text" > + <string>TextLabel</string> + </property> + </widget> + </item> + <item row="2" column="0" > + <widget class="QLabel" name="label_3" > + <property name="text" > + <string>Compatibility Version:</string> + </property> + <property name="alignment" > + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="2" column="1" > + <widget class="QLabel" name="compatVersion" > + <property name="text" > + <string>TextLabel</string> + </property> + </widget> + </item> + <item row="3" column="0" > + <widget class="QLabel" name="label_4" > + <property name="text" > + <string>Vendor:</string> + </property> + <property name="alignment" > + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="3" column="1" > + <widget class="QLabel" name="vendor" > + <property name="text" > + <string>TextLabel</string> + </property> + </widget> + </item> + <item row="4" column="0" > + <widget class="QLabel" name="label_6" > + <property name="text" > + <string>Url:</string> + </property> + <property name="alignment" > + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="4" column="1" > + <widget class="QLabel" name="url" > + <property name="text" > + <string>TextLabel</string> + </property> + </widget> + </item> + <item row="5" column="0" > + <widget class="QLabel" name="label_7" > + <property name="text" > + <string>Location:</string> + </property> + <property name="alignment" > + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="5" column="1" > + <widget class="QLabel" name="location" > + <property name="text" > + <string>TextLabel</string> + </property> + <property name="wordWrap" > + <bool>false</bool> + </property> + </widget> + </item> + <item row="6" column="0" > + <layout class="QVBoxLayout" > + <item> + <widget class="QLabel" name="label_8" > + <property name="text" > + <string>Description:</string> + </property> + <property name="alignment" > + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item row="6" column="1" > + <widget class="QTextEdit" name="description" > + <property name="tabChangesFocus" > + <bool>true</bool> + </property> + <property name="readOnly" > + <bool>true</bool> + </property> + </widget> + </item> + <item row="7" column="0" > + <widget class="QLabel" name="label_5" > + <property name="text" > + <string>Copyright:</string> + </property> + <property name="alignment" > + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="7" column="1" > + <widget class="QLabel" name="copyright" > + <property name="text" > + <string>TextLabel</string> + </property> + </widget> + </item> + <item row="8" column="0" > + <layout class="QVBoxLayout" > + <item> + <widget class="QLabel" name="label_9" > + <property name="text" > + <string>License:</string> + </property> + <property name="alignment" > + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>17</width> + <height>13</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item row="8" column="1" > + <widget class="QTextEdit" name="license" > + <property name="tabChangesFocus" > + <bool>true</bool> + </property> + <property name="readOnly" > + <bool>true</bool> + </property> + </widget> + </item> + <item row="9" column="0" > + <layout class="QVBoxLayout" > + <item> + <widget class="QLabel" name="label_10" > + <property name="text" > + <string>Dependencies:</string> + </property> + <property name="alignment" > + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item> + <spacer> + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item row="9" column="1" > + <widget class="QListWidget" name="dependencies" /> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/libs/extensionsystem/pluginerrorview.cpp b/src/libs/extensionsystem/pluginerrorview.cpp new file mode 100644 index 00000000000..c1572d88299 --- /dev/null +++ b/src/libs/extensionsystem/pluginerrorview.cpp @@ -0,0 +1,114 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "pluginerrorview.h" +#include "ui_pluginerrorview.h" + +#include <QtCore/QString> + +/*! + \class ExtensionSystem::PluginErrorView + \brief Widget that displays the state and error message of a PluginSpec. + + Can be used for integration in the application that + uses the plugin manager. + + \sa ExtensionSystem::PluginView +*/ + +using namespace ExtensionSystem; + +/*! + \fn PluginErrorView::PluginErrorView(QWidget *parent) + Constructs a new error view with given \a parent widget. +*/ +PluginErrorView::PluginErrorView(QWidget *parent) + : QWidget(parent), + m_ui(new Internal::Ui::PluginErrorView()) +{ + m_ui->setupUi(this); +} + +/*! + \fn PluginErrorView::~PluginErrorView() + \internal +*/ +PluginErrorView::~PluginErrorView() +{ + delete m_ui; +} + +/*! + \fn void PluginErrorView::update(PluginSpec *spec) + Reads the given \a spec and displays its state and + error information in this PluginErrorView. +*/ +void PluginErrorView::update(PluginSpec *spec) +{ + QString text; + QString tooltip; + switch (spec->state()) { + case PluginSpec::Invalid: + text = tr("Invalid"); + tooltip = tr("Description file found, but error on read"); + break; + case PluginSpec::Read: + text = tr("Read"); + tooltip = tr("Description successfully read"); + break; + case PluginSpec::Resolved: + text = tr("Resolved"); + tooltip = tr("Dependencies are successfully resolved"); + break; + case PluginSpec::Loaded: + text = tr("Loaded"); + tooltip = tr("Library is loaded"); + break; + case PluginSpec::Initialized: + text = tr("Initialized"); + tooltip = tr("Plugin's initialization method succeeded"); + break; + case PluginSpec::Running: + text = tr("Running"); + tooltip = tr("Plugin successfully loaded and running"); + break; + case PluginSpec::Stopped: + text = tr("Stopped"); + tooltip = tr("Plugin was shut down"); + case PluginSpec::Deleted: + text = tr("Deleted"); + tooltip = tr("Plugin ended it's life cycle and was deleted"); + } + m_ui->state->setText(text); + m_ui->state->setToolTip(tooltip); + m_ui->errorString->setText(spec->errorString()); +} diff --git a/src/libs/extensionsystem/pluginerrorview.h b/src/libs/extensionsystem/pluginerrorview.h new file mode 100644 index 00000000000..87b4097d033 --- /dev/null +++ b/src/libs/extensionsystem/pluginerrorview.h @@ -0,0 +1,66 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef PLUGINERRORVIEW_H_ +#define PLUGINERRORVIEW_H_ + +#include "extensionsystem_global.h" +#include "pluginspec.h" + +#include <QtGui/QWidget> + +namespace ExtensionSystem +{ + +namespace Internal { +namespace Ui { + class PluginErrorView; +} // namespace Ui +} // namespace Internal + +class EXTENSIONSYSTEM_EXPORT PluginErrorView : public QWidget +{ + Q_OBJECT + +public: + PluginErrorView(QWidget *parent = 0); + ~PluginErrorView(); + + void update(PluginSpec *spec); + +private: + Internal::Ui::PluginErrorView *m_ui; +}; + +} // namespace ExtensionSystem + +#endif /*PLUGINERRORVIEW_H_*/ diff --git a/src/libs/extensionsystem/pluginerrorview.ui b/src/libs/extensionsystem/pluginerrorview.ui new file mode 100644 index 00000000000..69f49e53c66 --- /dev/null +++ b/src/libs/extensionsystem/pluginerrorview.ui @@ -0,0 +1,77 @@ +<ui version="4.0" > + <class>ExtensionSystem::Internal::PluginErrorView</class> + <widget class="QWidget" name="ExtensionSystem::Internal::PluginErrorView" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>579</width> + <height>342</height> + </rect> + </property> + <property name="windowTitle" > + <string>Form</string> + </property> + <layout class="QGridLayout" name="gridLayout" > + <property name="margin" > + <number>2</number> + </property> + <item row="0" column="0" > + <widget class="QLabel" name="label" > + <property name="text" > + <string>State:</string> + </property> + <property name="alignment" > + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QLabel" name="state" > + <property name="text" > + <string>TextLabel</string> + </property> + </widget> + </item> + <item row="1" column="0" > + <layout class="QVBoxLayout" name="verticalLayout" > + <item> + <widget class="QLabel" name="label_2" > + <property name="text" > + <string>Error Message:</string> + </property> + <property name="alignment" > + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer" > + <property name="orientation" > + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0" > + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item row="1" column="1" > + <widget class="QTextEdit" name="errorString" > + <property name="tabChangesFocus" > + <bool>true</bool> + </property> + <property name="readOnly" > + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp new file mode 100644 index 00000000000..daf4169a80a --- /dev/null +++ b/src/libs/extensionsystem/pluginmanager.cpp @@ -0,0 +1,749 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "pluginmanager.h" +#include "pluginmanager_p.h" +#include "pluginspec.h" +#include "pluginspec_p.h" +#include "optionsparser.h" +#include "iplugin.h" + +#include <QtCore/QMetaProperty> +#include <QtCore/QPluginLoader> +#include <QtCore/QDir> +#include <QtCore/QTextStream> +#include <QtCore/QWriteLocker> +#include <QtDebug> +#ifdef WITH_TESTS +#include <QTest> +#endif + +typedef QSet<ExtensionSystem::PluginSpec *> PluginSpecSet; + +enum { debugLeaks = 0 }; + +/*! + \namespace ExtensionSystem + \brief Classes that belong to the core plugin system. + + The basic extension system contains of the plugin manager and its supporting classes, + and the IPlugin interface that must be implemented by plugin providers. +*/ + +/*! + \namespace ExtensionSystem::Internal + \internal +*/ + +/*! + \class ExtensionSystem::PluginManager + \mainclass + + \brief Core plugin system that manages the plugins, their life cycle and their registered objects. + + The plugin manager is used for the following tasks: + \list + \o Manage plugins and their state + \o Manipulate a 'common object pool' + \endlist + + \section1 Plugins + Plugins consist of an xml descriptor file, and of a library that contains a Qt plugin + (declared via Q_EXPORT_PLUGIN) that must derive from the IPlugin class. + The plugin manager is used to set a list of file system directories to search for + plugins, retrieve information about the state of these plugins, and to load them. + + Usually the application creates a PluginManager instance and initiates the loading. + \code + ExtensionSystem::PluginManager *manager = new ExtensionSystem::PluginManager(); + manager->setPluginPaths(QStringList() << "plugins"); // 'plugins' and subdirs will be searched for plugins + manager->loadPlugins(); // try to load all the plugins + \endcode + Additionally it is possible to directly access to the plugin specifications + (the information in the descriptor file), and the plugin instances (via PluginSpec), + and their state. + + \section1 Object Pool + Plugins (and everybody else) can add objects to a common 'pool' that is located in + the plugin manager. Objects in the pool must derive from QObject, there are no other + prerequisites. All objects of a specified type can be retrieved from the object pool + via the getObjects() and getObject() methods. They are aware of Aggregation::Aggregate, i.e. + these methods use the Aggregation::query methods instead of a qobject_cast to determine + the matching objects. + + Whenever the state of the object pool changes a corresponding signal is emitted by the plugin manager. + + A common usecase for the object pool is that a plugin (or the application) provides + an "extension point" for other plugins, which is a class / interface that can + be implemented and added to the object pool. The plugin that provides the + extension point looks for implementations of the class / interface in the object pool. + \code + // plugin A provides a "MimeTypeHandler" extension point + // in plugin B: + MyMimeTypeHandler *handler = new MyMimeTypeHandler(); + ExtensionSystem::PluginManager::instance()->addObject(handler); + // in plugin A: + QList<MimeTypeHandler *> mimeHandlers = + ExtensionSystem::PluginManager::instance()->getObjects<MimeTypeHandler>(); + \endcode + + \bold Note: The object pool manipulating functions are thread-safe. +*/ + +/*! + \fn void PluginManager::objectAdded(QObject *obj) + Signal that \a obj has been added to the object pool. +*/ + +/*! + \fn void PluginManager::aboutToRemoveObject(QObject *obj) + Signal that \a obj will be removed from the object pool. +*/ + +/*! + \fn void PluginManager::pluginsChanged() + Signal that the list of available plugins has changed. + + \sa plugins() +*/ + +/*! + \fn T *PluginManager::getObject() const + Retrieve the object of a given type from the object pool. + This method is aware of Aggregation::Aggregate, i.e. it uses + the Aggregation::query methods instead of qobject_cast to + determine the type of an object. + If there are more than one object of the given type in + the object pool, this method will choose an arbitrary one of them. + + \sa addObject() +*/ + +/*! + \fn QList<T *> PluginManager::getObjects() const + Retrieve all objects of a given type from the object pool. + This method is aware of Aggregation::Aggregate, i.e. it uses + the Aggregation::query methods instead of qobject_cast to + determine the type of an object. + + \sa addObject() +*/ + +using namespace ExtensionSystem; +using namespace ExtensionSystem::Internal; + +PluginManager *PluginManager::m_instance = 0; + +/*! + \fn PluginManager *PluginManager::instance() + Get the unique plugin manager instance. +*/ +PluginManager *PluginManager::instance() +{ + return m_instance; +} + +/*! + \fn PluginManager::PluginManager() + Create a plugin manager. Should be done only once per application. +*/ +PluginManager::PluginManager() + : d(new PluginManagerPrivate(this)) +{ + m_instance = this; +} + +/*! + \fn PluginManager::~PluginManager() + \internal +*/ +PluginManager::~PluginManager() +{ + delete d; + d = 0; +} + +/*! + \fn void PluginManager::addObject(QObject *obj) + Add the given object \a obj to the object pool, so it can be retrieved again from the pool by type. + The plugin manager does not do any memory management - added objects + must be removed from the pool and deleted manually by whoever is responsible for the object. + + Emits the objectAdded() signal. + + \sa PluginManager::removeObject() + \sa PluginManager::getObject() + \sa PluginManager::getObjects() +*/ +void PluginManager::addObject(QObject *obj) +{ + d->addObject(obj); +} + +/*! + \fn void PluginManager::removeObject(QObject *obj) + Emits aboutToRemoveObject() and removes the object \a obj from the object pool. + \sa PluginManager::addObject() +*/ +void PluginManager::removeObject(QObject *obj) +{ + d->removeObject(obj); +} + +/*! + \fn QList<QObject *> PluginManager::allObjects() const + Retrieve the list of all objects in the pool, unfiltered. + Usually clients do not need to call this. + \sa PluginManager::getObject() + \sa PluginManager::getObjects() +*/ +QList<QObject *> PluginManager::allObjects() const +{ + return d->allObjects; +} + +/*! + \fn void PluginManager::loadPlugins() + Tries to load all the plugins that were previously found when + setting the plugin search paths. The plugin specs of the plugins + can be used to retrieve error and state information about individual plugins. + + \sa setPluginPaths() + \sa plugins() +*/ +void PluginManager::loadPlugins() +{ + return d->loadPlugins(); +} + +/*! + \fn QStringList PluginManager::pluginPaths() const + The list of paths were the plugin manager searches for plugins. + + \sa setPluginPaths() +*/ +QStringList PluginManager::pluginPaths() const +{ + return d->pluginPaths; +} + +/*! + \fn void PluginManager::setPluginPaths(const QStringList &paths) + Sets the plugin search paths, i.e. the file system paths where the plugin manager + looks for plugin descriptions. All given \a paths and their sub directory trees + are searched for plugin xml description files. + + \sa pluginPaths() + \sa loadPlugins() +*/ +void PluginManager::setPluginPaths(const QStringList &paths) +{ + d->setPluginPaths(paths); +} + +/*! + \fn QString PluginManager::fileExtension() const + The file extension of plugin description files. + The default is "xml". + + \sa setFileExtension() +*/ +QString PluginManager::fileExtension() const +{ + return d->extension; +} + +/*! + \fn void PluginManager::setFileExtension(const QString &extension) + Sets the file extension of plugin description files. + The default is "xml". + At the moment this must be called before setPluginPaths() is called. + // ### TODO let this + setPluginPaths read the plugin specs lazyly whenever loadPlugins() or plugins() is called. +*/ +void PluginManager::setFileExtension(const QString &extension) +{ + d->extension = extension; +} + +/*! + \fn QStringList PluginManager::arguments() const + The arguments left over after parsing (Neither startup nor plugin + arguments). Typically, this will be the list of files to open. +*/ +QStringList PluginManager::arguments() const +{ + return d->arguments; +} + +/*! + \fn QSet<PluginSpec *> PluginManager::plugins() const + List of all plugin specifications that have been found in the plugin search paths. + This list is valid directly after the setPluginPaths() call. + The plugin specifications contain the information from the plugins' xml description files + and the current state of the plugins. If a plugin's library has been already successfully loaded, + the plugin specification has a reference to the created plugin instance as well. + + \sa setPluginPaths() +*/ +QSet<PluginSpec *> PluginManager::plugins() const +{ + return d->pluginSpecs; +} + +/*! + \fn bool PluginManager::parseOptions(const QStringList &args, const QMap<QString, bool> &appOptions, QMap<QString, QString> *foundAppOptions, QString *errorString) + Takes the list of command line options in \a args and parses them. + The plugin manager itself might process some options itself directly (-noload <plugin>), and + adds options that are registered by plugins to their plugin specs. + The caller (the application) may register itself for options via the \a appOptions list, containing pairs + of "option string" and a bool that indicates if the option requires an argument. + Application options always override any plugin's options. + + \a foundAppOptions is set to pairs of ("option string", "argument") for any application options that were found. + The command line options that were not processed can be retrieved via the arguments() method. + If an error occurred (like missing argument for an option that requires one), \a errorString contains + a descriptive message of the error. + + Returns if there was an error. + */ +bool PluginManager::parseOptions(const QStringList &args, + const QMap<QString, bool> &appOptions, + QMap<QString, QString> *foundAppOptions, + QString *errorString) +{ + OptionsParser options(args, appOptions, foundAppOptions, errorString, d); + return options.parse(); +} + + + +static inline void indent(QTextStream &str, int indent) +{ + const QChar blank = QLatin1Char(' '); + for (int i = 0 ; i < indent; i++) + str << blank; +} + +static inline void formatOption(QTextStream &str, + const QString &opt, const QString &parm, const QString &description, + int optionIndentation, int descriptionIndentation) +{ + int remainingIndent = descriptionIndentation - optionIndentation - opt.size(); + indent(str, optionIndentation); + str << opt; + if (!parm.isEmpty()) { + str << " <" << parm << '>'; + remainingIndent -= 3 + parm.size(); + } + indent(str, qMax(0, remainingIndent)); + str << description << '\n'; +} + +/*! + \fn static PluginManager::formatOptions(QTextStream &str, int optionIndentation, int descriptionIndentation) + + Format the startup options of the plugin manager for command line help. +*/ + +void PluginManager::formatOptions(QTextStream &str, int optionIndentation, int descriptionIndentation) +{ + formatOption(str, QLatin1String(OptionsParser::NO_LOAD_OPTION), + QLatin1String("plugin"), QLatin1String("Do not load <plugin>"), + optionIndentation, descriptionIndentation); +} + +/*! + \fn PluginManager::formatPluginOptions(QTextStream &str, int optionIndentation, int descriptionIndentation) const + + Format the plugin options of the plugin specs for command line help. +*/ + +void PluginManager::formatPluginOptions(QTextStream &str, int optionIndentation, int descriptionIndentation) const +{ + typedef PluginSpec::PluginArgumentDescriptions PluginArgumentDescriptions; + // Check plugins for options + const PluginSpecSet::const_iterator pcend = d->pluginSpecs.constEnd(); + for (PluginSpecSet::const_iterator pit = d->pluginSpecs.constBegin(); pit != pcend; ++pit) { + const PluginArgumentDescriptions pargs = (*pit)->argumentDescriptions(); + if (!pargs.empty()) { + str << "\nPlugin: " << (*pit)->name() << '\n'; + const PluginArgumentDescriptions::const_iterator acend = pargs.constEnd(); + for (PluginArgumentDescriptions::const_iterator ait =pargs.constBegin(); ait != acend; ++ait) + formatOption(str, ait->name, ait->parameter, ait->description, optionIndentation, descriptionIndentation); + } + } +} + +/*! + \fn PluginManager::formatPluginVersions(QTextStream &str) const + + Format the version of the plugin specs for command line help. +*/ + +void PluginManager::formatPluginVersions(QTextStream &str) const +{ + const PluginSpecSet::const_iterator cend = d->pluginSpecs.constEnd(); + for (PluginSpecSet::const_iterator it = d->pluginSpecs.constBegin(); it != cend; ++it) { + const PluginSpec *ps = *it; + str << " " << ps->name() << ' ' << ps->version() << ' ' << ps->description() << '\n'; + } +} + +void PluginManager::startTests() +{ +#ifdef WITH_TESTS + foreach(PluginSpec *pluginSpec, d->testSpecs) { + const QMetaObject *mo = pluginSpec->plugin()->metaObject(); + QStringList methods; + methods.append("arg0"); + // We only want slots starting with "test" + for(int i = mo->methodOffset(); i < mo->methodCount(); ++i) { + if (QByteArray(mo->method(i).signature()).startsWith("test")) { + QString method = QString::fromLatin1(mo->method(i).signature()); + methods.append(method.left(method.size()-2)); + } + } + QTest::qExec(pluginSpec->plugin(), methods); + + } +#endif +} + +bool PluginManager::runningTests() const +{ + return !d->testSpecs.isEmpty(); +} + +QString PluginManager::testDataDirectory() const +{ + QString s = QString::fromLocal8Bit(qgetenv("IDETESTDIR")); + if (s.isEmpty()) { + s = IDE_TEST_DIR; + s.append("/tests"); + } + s = QDir::cleanPath(s); + return s; +} + +//============PluginManagerPrivate=========== + +/*! + \fn PluginSpec *PluginManagerPrivate::createSpec() + \internal +*/ +PluginSpec *PluginManagerPrivate::createSpec() +{ + return new PluginSpec(); +} + +/*! + \fn PluginSpecPrivate *PluginManagerPrivate::privateSpec(PluginSpec *spec) + \internal +*/ +PluginSpecPrivate *PluginManagerPrivate::privateSpec(PluginSpec *spec) +{ + return spec->d; +} + +/*! + \fn PluginManagerPrivate::PluginManagerPrivate(PluginManager *pluginManager) + \internal +*/ +PluginManagerPrivate::PluginManagerPrivate(PluginManager *pluginManager) + : extension("xml"), q(pluginManager) +{ +} + +/*! + \fn PluginManagerPrivate::~PluginManagerPrivate() + \internal +*/ +PluginManagerPrivate::~PluginManagerPrivate() +{ + stopAll(); + qDeleteAll(pluginSpecs); + if (!allObjects.isEmpty()) { + qDebug() << "There are" << allObjects.size() << "objects left in the plugin manager pool: " << allObjects; + } +} + +void PluginManagerPrivate::stopAll() +{ + QList<PluginSpec *> queue = loadQueue(); + foreach (PluginSpec *spec, queue) { + loadPlugin(spec, PluginSpec::Stopped); + } + QListIterator<PluginSpec *> it(queue); + it.toBack(); + while (it.hasPrevious()) { + loadPlugin(it.previous(), PluginSpec::Deleted); + } +} + +/*! + \fn void PluginManagerPrivate::addObject(QObject *obj) + \internal +*/ +void PluginManagerPrivate::addObject(QObject *obj) +{ + { + QWriteLocker lock(&(q->m_lock)); + if (obj == 0) { + qWarning() << "PluginManagerPrivate::addObject(): trying to add null object"; + return; + } + if (allObjects.contains(obj)) { + qWarning() << "PluginManagerPrivate::addObject(): trying to add duplicate object"; + return; + } + + if (debugLeaks) + qDebug() << "PluginManagerPrivate::addObject" << obj << obj->objectName(); + + allObjects.append(obj); + } + emit q->objectAdded(obj); +} + +/*! + \fn void PluginManagerPrivate::removeObject(QObject *obj) + \internal +*/ +void PluginManagerPrivate::removeObject(QObject *obj) +{ + if (obj == 0) { + qWarning() << "PluginManagerPrivate::removeObject(): trying to remove null object"; + return; + } + + if (!allObjects.contains(obj)) { + qWarning() << "PluginManagerPrivate::removeObject(): object not in list:" + << obj << obj->objectName(); + return; + } + if (debugLeaks) + qDebug() << "PluginManagerPrivate::removeObject" << obj << obj->objectName(); + + emit q->aboutToRemoveObject(obj); + QWriteLocker lock(&(q->m_lock)); + allObjects.removeAll(obj); +} + +/*! + \fn void PluginManagerPrivate::loadPlugins() + \internal +*/ +void PluginManagerPrivate::loadPlugins() +{ + QList<PluginSpec *> queue = loadQueue(); + foreach (PluginSpec *spec, queue) { + loadPlugin(spec, PluginSpec::Loaded); + } + foreach (PluginSpec *spec, queue) { + loadPlugin(spec, PluginSpec::Initialized); + } + QListIterator<PluginSpec *> it(queue); + it.toBack(); + while (it.hasPrevious()) { + loadPlugin(it.previous(), PluginSpec::Running); + } + emit q->pluginsChanged(); +} + +/*! + \fn void PluginManagerPrivate::loadQueue() + \internal +*/ +QList<PluginSpec *> PluginManagerPrivate::loadQueue() +{ + QList<PluginSpec *> queue; + foreach (PluginSpec *spec, pluginSpecs) { + QList<PluginSpec *> circularityCheckQueue; + loadQueue(spec, queue, circularityCheckQueue); + } + return queue; +} + +/*! + \fn bool PluginManagerPrivate::loadQueue(PluginSpec *spec, QList<PluginSpec *> &queue, QList<PluginSpec *> &circularityCheckQueue) + \internal +*/ +bool PluginManagerPrivate::loadQueue(PluginSpec *spec, QList<PluginSpec *> &queue, + QList<PluginSpec *> &circularityCheckQueue) +{ + if (queue.contains(spec)) + return true; + // check for circular dependencies + if (circularityCheckQueue.contains(spec)) { + spec->d->hasError = true; + spec->d->errorString = q->tr("Circular dependency detected:\n"); + int index = circularityCheckQueue.indexOf(spec); + for (int i = index; i < circularityCheckQueue.size(); ++i) { + spec->d->errorString.append(q->tr("%1(%2) depends on\n") + .arg(circularityCheckQueue.at(i)->name()).arg(circularityCheckQueue.at(i)->version())); + } + spec->d->errorString.append(q->tr("%1(%2)").arg(spec->name()).arg(spec->version())); + return false; + } + circularityCheckQueue.append(spec); + // check if we have the dependencies + if (spec->state() == PluginSpec::Invalid || spec->state() == PluginSpec::Read) { + spec->d->hasError = true; + spec->d->errorString += "\n"; + spec->d->errorString += q->tr("Cannot load plugin because dependencies are not resolved"); + return false; + } + // add dependencies + foreach (PluginSpec *depSpec, spec->dependencySpecs()) { + if (!loadQueue(depSpec, queue, circularityCheckQueue)) { + spec->d->hasError = true; + spec->d->errorString = + q->tr("Cannot load plugin because dependency failed to load: %1(%2)\nReason: %3") + .arg(depSpec->name()).arg(depSpec->version()).arg(depSpec->errorString()); + return false; + } + } + // add self + queue.append(spec); + return true; +} + +/*! + \fn void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destState) + \internal +*/ +void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destState) +{ + if (spec->hasError()) + return; + if (destState == PluginSpec::Running) { + spec->d->initializeExtensions(); + return; + } else if (destState == PluginSpec::Deleted) { + spec->d->kill(); + return; + } + foreach (PluginSpec *depSpec, spec->dependencySpecs()) { + if (depSpec->state() != destState) { + spec->d->hasError = true; + spec->d->errorString = + q->tr("Cannot load plugin because dependency failed to load: %1(%2)\nReason: %3") + .arg(depSpec->name()).arg(depSpec->version()).arg(depSpec->errorString()); + return; + } + } + if (destState == PluginSpec::Loaded) + spec->d->loadLibrary(); + else if (destState == PluginSpec::Initialized) + spec->d->initializePlugin(); + else if (destState == PluginSpec::Stopped) + spec->d->stop(); +} + +/*! + \fn void PluginManagerPrivate::setPluginPaths(const QStringList &paths) + \internal +*/ +void PluginManagerPrivate::setPluginPaths(const QStringList &paths) +{ + pluginPaths = paths; + readPluginPaths(); +} + +/*! + \fn void PluginManagerPrivate::readPluginPaths() + \internal +*/ +void PluginManagerPrivate::readPluginPaths() +{ + qDeleteAll(pluginSpecs); + pluginSpecs.clear(); + + QStringList specFiles; + QStringList searchPaths = pluginPaths; + while (!searchPaths.isEmpty()) { + const QDir dir(searchPaths.takeFirst()); + const QFileInfoList files = dir.entryInfoList(QStringList() << QString("*.%1").arg(extension), QDir::Files); + foreach (const QFileInfo &file, files) + specFiles << file.absoluteFilePath(); + const QFileInfoList dirs = dir.entryInfoList(QDir::Dirs|QDir::NoDotAndDotDot); + foreach (const QFileInfo &subdir, dirs) + searchPaths << subdir.absoluteFilePath(); + } + foreach (const QString &specFile, specFiles) { + PluginSpec *spec = new PluginSpec; + spec->d->read(specFile); + pluginSpecs.insert(spec); + } + resolveDependencies(); + emit q->pluginsChanged(); +} + +void PluginManagerPrivate::resolveDependencies() +{ + foreach (PluginSpec *spec, pluginSpecs) { + spec->d->resolveDependencies(pluginSpecs); + } +} + + // Look in argument descriptions of the specs for the option. +PluginSpec *PluginManagerPrivate::pluginForOption(const QString &option, bool *requiresArgument) const +{ + // Look in the plugins for an option + typedef PluginSpec::PluginArgumentDescriptions PluginArgumentDescriptions; + + *requiresArgument = false; + const PluginSpecSet::const_iterator pcend = pluginSpecs.constEnd(); + for (PluginSpecSet::const_iterator pit = pluginSpecs.constBegin(); pit != pcend; ++pit) { + PluginSpec *ps = *pit; + const PluginArgumentDescriptions pargs = ps->argumentDescriptions(); + if (!pargs.empty()) { + const PluginArgumentDescriptions::const_iterator acend = pargs.constEnd(); + for (PluginArgumentDescriptions::const_iterator ait = pargs.constBegin(); ait != acend; ++ait) { + if (ait->name == option) { + *requiresArgument = !ait->parameter.isEmpty(); + return ps; + } + } + } + } + return 0; +} + +PluginSpec *PluginManagerPrivate::pluginByName(const QString &name) const +{ + foreach (PluginSpec *spec, pluginSpecs) + if (spec->name() == name) + return spec; + return 0; +} + diff --git a/src/libs/extensionsystem/pluginmanager.h b/src/libs/extensionsystem/pluginmanager.h new file mode 100644 index 00000000000..7f003b4f899 --- /dev/null +++ b/src/libs/extensionsystem/pluginmanager.h @@ -0,0 +1,138 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef EXTENSIONSYSTEM_PLUGINMANAGER_H +#define EXTENSIONSYSTEM_PLUGINMANAGER_H + +#include "extensionsystem_global.h" +#include <aggregation/aggregate.h> + +#include <QtCore/QObject> +#include <QtCore/QList> +#include <QtCore/QSet> +#include <QtCore/QStringList> +#include <QtCore/QWriteLocker> +#include <QtCore/QReadWriteLock> + +QT_BEGIN_NAMESPACE +class QTextStream; +QT_END_NAMESPACE + +namespace ExtensionSystem { + +namespace Internal { + class PluginManagerPrivate; +} + +class IPlugin; +class PluginSpec; + +class EXTENSIONSYSTEM_EXPORT PluginManager : public QObject +{ + Q_DISABLE_COPY(PluginManager) + Q_OBJECT + +public: + static PluginManager *instance(); + + PluginManager(); + virtual ~PluginManager(); + + // Object pool operations + void addObject(QObject *obj); + void removeObject(QObject *obj); + QList<QObject *> allObjects() const; + template <typename T> QList<T *> getObjects() const + { + QReadLocker lock(&m_lock); + QList<T *> results; + QList<QObject *> all = allObjects(); + QList<T *> result; + foreach (QObject *obj, all) { + result = Aggregation::query_all<T>(obj); + if (!result.isEmpty()) + results += result; + } + return results; + } + template <typename T> T *getObject() const + { + QReadLocker lock(&m_lock); + QList<QObject *> all = allObjects(); + T *result = 0; + foreach (QObject *obj, all) { + if ((result = Aggregation::query<T>(obj)) != 0) + break; + } + return result; + } + + // Plugin operations + void loadPlugins(); + QStringList pluginPaths() const; + void setPluginPaths(const QStringList &paths); + QSet<PluginSpec *> plugins() const; + void setFileExtension(const QString &extension); + QString fileExtension() const; + + // command line arguments + QStringList arguments() const; + bool parseOptions(const QStringList &args, + const QMap<QString, bool> &appOptions, + QMap<QString, QString> *foundAppOptions, + QString *errorString); + static void formatOptions(QTextStream &str, int optionIndentation, int descriptionIndentation); + void formatPluginOptions(QTextStream &str, int optionIndentation, int descriptionIndentation) const; + void formatPluginVersions(QTextStream &str) const; + + bool runningTests() const; + QString testDataDirectory() const; + +signals: + void objectAdded(QObject *obj); + void aboutToRemoveObject(QObject *obj); + + void pluginsChanged(); +private slots: + void startTests(); + +private: + Internal::PluginManagerPrivate *d; + static PluginManager *m_instance; + mutable QReadWriteLock m_lock; + + friend class Internal::PluginManagerPrivate; +}; + +} //namespace + +#endif // PLUGINMANAGER_H diff --git a/src/libs/extensionsystem/pluginmanager_p.h b/src/libs/extensionsystem/pluginmanager_p.h new file mode 100644 index 00000000000..6b8df8d2bee --- /dev/null +++ b/src/libs/extensionsystem/pluginmanager_p.h @@ -0,0 +1,96 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef PLUGINMANAGER_P_H +#define PLUGINMANAGER_P_H + +#include "pluginspec.h" + +#include <QtCore/QList> +#include <QtCore/QSet> +#include <QtCore/QStringList> +#include <QtCore/QObject> + +namespace ExtensionSystem { + +class PluginManager; + +namespace Internal { + +class PluginSpecPrivate; + +class EXTENSIONSYSTEM_EXPORT PluginManagerPrivate +{ +public: + PluginManagerPrivate(PluginManager *pluginManager); + virtual ~PluginManagerPrivate(); + + // Object pool operations + void addObject(QObject *obj); + void removeObject(QObject *obj); + + // Plugin operations + void loadPlugins(); + void setPluginPaths(const QStringList &paths); + QList<PluginSpec *> loadQueue(); + void loadPlugin(PluginSpec *spec, PluginSpec::State destState); + void resolveDependencies(); + + QSet<PluginSpec *> pluginSpecs; + QList<PluginSpec *> testSpecs; + QStringList pluginPaths; + QString extension; + QList<QObject *> allObjects; // ### make this a QList<QPointer<QObject> > > ? + + QStringList arguments; + + // Look in argument descriptions of the specs for the option. + PluginSpec *pluginForOption(const QString &option, bool *requiresArgument) const; + PluginSpec *pluginByName(const QString &name) const; + + // used by tests + static PluginSpec *createSpec(); + static PluginSpecPrivate *privateSpec(PluginSpec *spec); +private: + PluginManager *q; + + void readPluginPaths(); + bool loadQueue(PluginSpec *spec, + QList<PluginSpec *> &queue, + QList<PluginSpec *> &circularityCheckQueue); + void stopAll(); +}; + +} // namespace Internal +} // namespace ExtensionSystem + +#endif // PLUGINMANAGER_P_H diff --git a/src/libs/extensionsystem/pluginspec.cpp b/src/libs/extensionsystem/pluginspec.cpp new file mode 100644 index 00000000000..dfa7bdbe7c0 --- /dev/null +++ b/src/libs/extensionsystem/pluginspec.cpp @@ -0,0 +1,871 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "pluginspec.h" +#include "pluginspec.h" +#include "pluginspec_p.h" +#include "iplugin.h" +#include "iplugin_p.h" +#include "pluginmanager.h" + +#include <QtCore/QFile> +#include <QtCore/QFileInfo> +#include <QtCore/QXmlStreamReader> +#include <QtCore/QRegExp> +#include <QtCore/QPluginLoader> +#include <QtCore/QCoreApplication> +#include <QtDebug> + +/*! + \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. +*/ + +/*! + \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 + goes through it's loading process (see PluginSpec::State). + 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 + The xml description file has been successfully read, and it's + 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 + The plugin has been shut down, i.e. the plugin's IPlugin::shutdown() method has been called. + \value Deleted + The plugin instance has been deleted. +*/ +using namespace ExtensionSystem; +using namespace ExtensionSystem::Internal; + +/*! + \fn bool PluginDependency::operator==(const PluginDependency &other) + \internal +*/ +bool PluginDependency::operator==(const PluginDependency &other) +{ + return name == other.name && version == other.version; +} + +/*! + \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; +} + +/*! + \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; +} + +/*! + \fn PluginOptionDescriptions optionDescriptions() const + 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() +*/ +QList<PluginSpec *> PluginSpec::dependencySpecs() const +{ + return d->dependencySpecs; +} + +//==========PluginSpecPrivate================== + +namespace { + const char * const PLUGIN = "plugin"; + const char * const PLUGIN_NAME = "name"; + const char * const PLUGIN_VERSION = "version"; + const char * const PLUGIN_COMPATVERSION = "compatVersion"; + const char * const VENDOR = "vendor"; + const char * const COPYRIGHT = "copyright"; + const char * const LICENSE = "license"; + const char * const DESCRIPTION = "description"; + const char * const URL = "url"; + const char * const DEPENDENCYLIST = "dependencyList"; + const char * const DEPENDENCY = "dependency"; + const char * const DEPENDENCY_NAME = "name"; + const char * const DEPENDENCY_VERSION = "version"; + const char * const ARGUMENTLIST = "argumentList"; + const char * const ARGUMENT = "argument"; + const char * const ARGUMENT_NAME = "name"; + const char * const ARGUMENT_PARAMETER = "parameter"; +} +/*! + \fn PluginSpecPrivate::PluginSpecPrivate(PluginSpec *spec) + \internal +*/ +PluginSpecPrivate::PluginSpecPrivate(PluginSpec *spec) + : plugin(0), + 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 + = location + = ""; + state = PluginSpec::Invalid; + hasError = false; + errorString = ""; + dependencies.clear(); + QFile file(fileName); + if (!file.exists()) + return reportError(tr("File does not exist: %1").arg(file.fileName())); + if (!file.open(QIODevice::ReadOnly)) + return reportError(tr("Could not open file for read: %1").arg(file.fileName())); + 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") + .arg(file.fileName()) + .arg(reader.errorString()) + .arg(reader.lineNumber()) + .arg(reader.columnNumber())); + state = PluginSpec::Read; + return true; +} + +/*! + \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; + } + 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(); + 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; + } + 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; +} + +/*! + \fn bool PluginSpecPrivate::resolveDependencies(const QSet<PluginSpec *> &specs) + \internal +*/ +bool PluginSpecPrivate::resolveDependencies(const QSet<PluginSpec *> &specs) +{ + 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; + } + QList<PluginSpec *> resolvedDependencies; + foreach (const PluginDependency &dependency, dependencies) { + PluginSpec *found = 0; + foreach (PluginSpec *spec, specs) { + if (spec->provides(dependency.name, dependency.version)) { + found = spec; + break; + } + } + if (!found) { + hasError = true; + if (!errorString.isEmpty()) + errorString.append("\n"); + errorString.append(QCoreApplication::translate("PluginSpec", "Could not resolve dependency '%1(%2)'") + .arg(dependency.name).arg(dependency.version)); + continue; + } + resolvedDependencies.append(found); + } + if (hasError) + return false; + dependencySpecs = resolvedDependencies; + state = PluginSpec::Resolved; + return true; +} + +/*! + \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 + + QPluginLoader loader(libName); + if (!loader.load()) { + hasError = true; + errorString = loader.errorString(); + errorString.append(QCoreApplication::translate("PluginSpec", "\nLibrary base name: %1").arg(libName)); + return false; + } + IPlugin *pluginObject = qobject_cast<IPlugin*>(loader.instance()); + if (!pluginObject) { + hasError = true; + errorString = QCoreApplication::translate("PluginSpec", "Plugin is not valid (doesn't derive from IPlugin)"); + 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; +} + +/*! + \fn bool PluginSpecPrivate::stop() + \internal +*/ +void PluginSpecPrivate::stop() +{ + if (!plugin) + return; + plugin->shutdown(); + state = PluginSpec::Stopped; +} + +/*! + \fn bool PluginSpecPrivate::kill() + \internal +*/ +void PluginSpecPrivate::kill() +{ + if (!plugin) + return; + delete plugin; + plugin = 0; + state = PluginSpec::Deleted; +} + diff --git a/src/libs/extensionsystem/pluginspec.h b/src/libs/extensionsystem/pluginspec.h new file mode 100644 index 00000000000..06a219fe2d4 --- /dev/null +++ b/src/libs/extensionsystem/pluginspec.h @@ -0,0 +1,120 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef PLUGINSPEC_H +#define PLUGINSPEC_H + +#include "extensionsystem_global.h" + +#include <QtCore/QString> +#include <QtCore/QList> + +QT_BEGIN_NAMESPACE +class QStringList; +QT_END_NAMESPACE + +namespace ExtensionSystem { + +namespace Internal { + class PluginSpecPrivate; + class PluginManagerPrivate; +} + +class IPlugin; + +struct EXTENSIONSYSTEM_EXPORT PluginDependency +{ + QString name; + QString version; + bool operator==(const PluginDependency &other); +}; + +struct EXTENSIONSYSTEM_EXPORT PluginArgumentDescription +{ + QString name; + QString parameter; + QString description; +}; + +class EXTENSIONSYSTEM_EXPORT PluginSpec +{ +public: + enum State { Invalid, Read, Resolved, Loaded, Initialized, Running, Stopped, Deleted}; + + ~PluginSpec(); + + // information from the xml file, valid after 'Read' state is reached + QString name() const; + QString version() const; + QString compatVersion() const; + QString vendor() const; + QString copyright() const; + QString license() const; + QString description() const; + QString url() const; + QList<PluginDependency> dependencies() const; + + typedef QList<PluginArgumentDescription> PluginArgumentDescriptions; + PluginArgumentDescriptions argumentDescriptions() const; + + // other information, valid after 'Read' state is reached + QString location() const; + QString filePath() const; + + QStringList arguments() const; + void setArguments(const QStringList &arguments); + void addArgument(const QString &argument); + + bool provides(const QString &pluginName, const QString &version) const; + + // dependency specs, valid after 'Resolved' state is reached + QList<PluginSpec *> dependencySpecs() const; + + // linked plugin instance, valid after 'Loaded' state is reached + IPlugin *plugin() const; + + // state + State state() const; + bool hasError() const; + QString errorString() const; + +private: + PluginSpec(); + + Internal::PluginSpecPrivate *d; + friend class Internal::PluginManagerPrivate; +}; + +} // namespace ExtensionSystem + +#endif // PLUGINSPEC_H + diff --git a/src/libs/extensionsystem/pluginspec_p.h b/src/libs/extensionsystem/pluginspec_p.h new file mode 100644 index 00000000000..a11167e85e2 --- /dev/null +++ b/src/libs/extensionsystem/pluginspec_p.h @@ -0,0 +1,106 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef PLUGINSPEC_P_H +#define PLUGINSPEC_P_H + +#include "pluginspec.h" + +#include <QtCore/QObject> +#include <QtCore/QStringList> +#include <QtCore/QXmlStreamReader> + +namespace ExtensionSystem { + +class IPlugin; +class PluginManager; + +namespace Internal { + +class EXTENSIONSYSTEM_EXPORT PluginSpecPrivate : public QObject +{ + Q_OBJECT + +public: + PluginSpecPrivate(PluginSpec *spec); + + bool read(const QString &fileName); + bool provides(const QString &pluginName, const QString &version) const; + bool resolveDependencies(const QSet<PluginSpec *> &specs); + bool loadLibrary(); + bool initializePlugin(); + bool initializeExtensions(); + void stop(); + void kill(); + + QString name; + QString version; + QString compatVersion; + QString vendor; + QString copyright; + QString license; + QString description; + QString url; + QList<PluginDependency> dependencies; + + QString location; + QString filePath; + QStringList arguments; + + QList<PluginSpec *> dependencySpecs; + PluginSpec::PluginArgumentDescriptions argumentDescriptions; + IPlugin *plugin; + + PluginSpec::State state; + bool hasError; + QString errorString; + + static bool isValidVersion(const QString &version); + static int versionCompare(const QString &version1, const QString &version2); + +private: + PluginSpec *q; + + bool reportError(const QString &err); + void readPluginSpec(QXmlStreamReader &reader); + void readDependencies(QXmlStreamReader &reader); + void readDependencyEntry(QXmlStreamReader &reader); + void readArgumentDescriptions(QXmlStreamReader &reader); + void readArgumentDescription(QXmlStreamReader &reader); + + static QRegExp &versionRegExp(); +}; + +} // namespace Internal +} // namespace ExtensionSystem + +#endif // header guard diff --git a/src/libs/extensionsystem/pluginview.cpp b/src/libs/extensionsystem/pluginview.cpp new file mode 100644 index 00000000000..d75911ea37d --- /dev/null +++ b/src/libs/extensionsystem/pluginview.cpp @@ -0,0 +1,159 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "pluginview.h" +#include "pluginview_p.h" +#include "pluginmanager.h" +#include "pluginspec.h" +#include "ui_pluginview.h" + +#include <QtGui/QHeaderView> +#include <QtGui/QTreeWidgetItem> +#include <QtDebug> + +/*! + \class ExtensionSystem::PluginView + \brief Widget that shows a list of all plugins and their state. + + This can be embedded e.g. in a dialog in the application that + uses the plugin manager. + The class also provides notifications for interactions with the list. + + \sa ExtensionSystem::PluginDetailsView + \sa ExtensionSystem::PluginErrorView +*/ + +/*! + \fn void PluginView::currentPluginChanged(ExtensionSystem::PluginSpec *spec) + The current selection in the plugin list has changed to the + plugin corresponding to \a spec. +*/ + +/*! + \fn void PluginView::pluginActivated(ExtensionSystem::PluginSpec *spec) + The plugin list entry corresponding to \a spec has been activated, + e.g. by a double-click. +*/ + +using namespace ExtensionSystem; + +Q_DECLARE_METATYPE(ExtensionSystem::PluginSpec*); + +/*! + \fn PluginView::PluginView(PluginManager *manager, QWidget *parent) + Constructs a PluginView that gets the list of plugins from the + given plugin \a manager with a given \a parent widget. +*/ +PluginView::PluginView(PluginManager *manager, QWidget *parent) + : QWidget(parent), + m_ui(new Internal::Ui::PluginView), + p(new Internal::PluginViewPrivate) +{ + m_ui->setupUi(this); + QHeaderView *header = m_ui->pluginWidget->header(); + header->setResizeMode(0, QHeaderView::ResizeToContents); + header->setResizeMode(1, QHeaderView::ResizeToContents); + header->setResizeMode(2, QHeaderView::ResizeToContents); + m_ui->pluginWidget->sortItems(1, Qt::AscendingOrder); + p->manager = manager; + connect(p->manager, SIGNAL(pluginsChanged()), this, SLOT(updateList())); + connect(m_ui->pluginWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), + this, SLOT(selectPlugin(QTreeWidgetItem*))); + connect(m_ui->pluginWidget, SIGNAL(itemActivated(QTreeWidgetItem*,int)), + this, SLOT(activatePlugin(QTreeWidgetItem*))); + updateList(); +} + +/*! + \fn PluginView::~PluginView() + \internal +*/ +PluginView::~PluginView() +{ + delete p; + delete m_ui; +} + +/*! + \fn PluginSpec *PluginView::currentPlugin() const + Returns the current selection in the list of plugins. +*/ +PluginSpec *PluginView::currentPlugin() const +{ + if (!m_ui->pluginWidget->currentItem()) + return 0; + return m_ui->pluginWidget->currentItem()->data(0, Qt::UserRole).value<PluginSpec *>(); +} + +void PluginView::updateList() +{ + static QIcon okIcon(":/extensionsystem/images/ok.png"); + static QIcon errorIcon(":/extensionsystem/images/error.png"); + QList<QTreeWidgetItem *> items; + QTreeWidgetItem *currentItem = 0; + PluginSpec *currPlugin = currentPlugin(); + foreach (PluginSpec *spec, p->manager->plugins()) { + QTreeWidgetItem *item = new QTreeWidgetItem(QStringList() + << "" + << spec->name() + << QString("%1 (%2)").arg(spec->version()).arg(spec->compatVersion()) + << spec->vendor() + << spec->filePath()); + item->setToolTip(4, spec->filePath()); + item->setIcon(0, spec->hasError() ? errorIcon : okIcon); + item->setData(0, Qt::UserRole, qVariantFromValue(spec)); + items.append(item); + if (currPlugin == spec) + currentItem = item; + } + m_ui->pluginWidget->clear(); + if (!items.isEmpty()) + m_ui->pluginWidget->addTopLevelItems(items); + if (currentItem) + m_ui->pluginWidget->setCurrentItem(currentItem); + else if (!items.isEmpty()) + m_ui->pluginWidget->setCurrentItem(items.first()); +} + +void PluginView::selectPlugin(QTreeWidgetItem *current) +{ + if (!current) + emit currentPluginChanged(0); + else + emit currentPluginChanged(current->data(0, Qt::UserRole).value<PluginSpec *>()); +} + +void PluginView::activatePlugin(QTreeWidgetItem *item) +{ + emit pluginActivated(item->data(0, Qt::UserRole).value<PluginSpec *>()); +} + diff --git a/src/libs/extensionsystem/pluginview.h b/src/libs/extensionsystem/pluginview.h new file mode 100644 index 00000000000..eacf38edaa5 --- /dev/null +++ b/src/libs/extensionsystem/pluginview.h @@ -0,0 +1,82 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef PLUGINVIEW_H +#define PLUGINVIEW_H + +#include "extensionsystem_global.h" + +#include <QtGui/QWidget> + +QT_BEGIN_NAMESPACE +class QTreeWidgetItem; +QT_END_NAMESPACE + +namespace ExtensionSystem { + +class PluginManager; +class PluginSpec; + +namespace Internal { + class PluginViewPrivate; +namespace Ui { + class PluginView; +} // namespace Ui +} // namespace Internal + +class EXTENSIONSYSTEM_EXPORT PluginView : public QWidget +{ + Q_OBJECT + +public: + PluginView(PluginManager *manager, QWidget *parent = 0); + ~PluginView(); + + PluginSpec *currentPlugin() const; + +signals: + void currentPluginChanged(ExtensionSystem::PluginSpec *spec); + void pluginActivated(ExtensionSystem::PluginSpec *spec); + +private slots: + void updateList(); + void selectPlugin(QTreeWidgetItem *current); + void activatePlugin(QTreeWidgetItem *item); + +private: + Internal::Ui::PluginView *m_ui; + Internal::PluginViewPrivate *p; +}; + +} // namespae ExtensionSystem + +#endif diff --git a/src/libs/extensionsystem/pluginview.qrc b/src/libs/extensionsystem/pluginview.qrc new file mode 100644 index 00000000000..7b78566568f --- /dev/null +++ b/src/libs/extensionsystem/pluginview.qrc @@ -0,0 +1,6 @@ +<RCC> + <qresource prefix="/extensionsystem" > + <file>images/ok.png</file> + <file>images/error.png</file> + </qresource> +</RCC> diff --git a/src/libs/extensionsystem/pluginview.ui b/src/libs/extensionsystem/pluginview.ui new file mode 100644 index 00000000000..8d9123dfbf4 --- /dev/null +++ b/src/libs/extensionsystem/pluginview.ui @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ExtensionSystem::Internal::PluginView</class> + <widget class="QWidget" name="ExtensionSystem::Internal::PluginView"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>773</width> + <height>304</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <property name="margin"> + <number>2</number> + </property> + <item row="0" column="0"> + <widget class="QTreeWidget" name="pluginWidget"> + <property name="alternatingRowColors"> + <bool>true</bool> + </property> + <property name="indentation"> + <number>0</number> + </property> + <property name="rootIsDecorated"> + <bool>false</bool> + </property> + <property name="uniformRowHeights"> + <bool>true</bool> + </property> + <property name="itemsExpandable"> + <bool>false</bool> + </property> + <property name="sortingEnabled"> + <bool>true</bool> + </property> + <property name="columnCount"> + <number>5</number> + </property> + <column> + <property name="text"> + <string>State</string> + </property> + </column> + <column> + <property name="text"> + <string>Name</string> + </property> + </column> + <column> + <property name="text"> + <string>Version</string> + </property> + </column> + <column> + <property name="text"> + <string>Vendor</string> + </property> + </column> + <column> + <property name="text"> + <string>Location</string> + </property> + </column> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> +</ui> diff --git a/src/libs/extensionsystem/pluginview_p.h b/src/libs/extensionsystem/pluginview_p.h new file mode 100644 index 00000000000..48d63ba3593 --- /dev/null +++ b/src/libs/extensionsystem/pluginview_p.h @@ -0,0 +1,51 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef PLUGINVIEW_P_H +#define PLUGINVIEW_P_H + +namespace ExtensionSystem { + +class PluginManager; + +namespace Internal { + +class PluginViewPrivate +{ +public: + PluginManager *manager; +}; + +} // namespace +} // namespace + +#endif diff --git a/src/libs/extensionsystem/test/auto/auto.pro b/src/libs/extensionsystem/test/auto/auto.pro new file mode 100644 index 00000000000..2dd64002127 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/auto.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +SUBDIRS = pluginmanager pluginspec + diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/circularplugins.pro b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/circularplugins.pro new file mode 100644 index 00000000000..21f257cf083 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/circularplugins.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS = plugin1 plugin2 plugin3 diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin.xml b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin.xml new file mode 100644 index 00000000000..db201f34c39 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin.xml @@ -0,0 +1,6 @@ +<plugin name="plugin1" version="1.0.0" compatVersion="1.0.0"> + <dependencyList> + <dependency name="plugin2" version="1.0.0"/> + <dependency name="plugin3" version="1.0.0"/> + </dependencyList> +</plugin> diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin1.cpp b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin1.cpp new file mode 100644 index 00000000000..69b9821b3b1 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin1.cpp @@ -0,0 +1,53 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "plugin1.h" + +#include <QtCore/qplugin.h> + +using namespace Plugin1; + +MyPlugin1::MyPlugin1() +{ +} + +bool MyPlugin1::initialize(const QStringList & /*arguments*/, QString *errorString) +{ + return true; +} + +void MyPlugin1::extensionsInitialized() +{ +} + +Q_EXPORT_PLUGIN(MyPlugin1) + diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin1.h b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin1.h new file mode 100644 index 00000000000..d3c493aebaa --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin1.h @@ -0,0 +1,55 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef PLUGIN1_H +#define PLUGIN1_H + +#include <extensionsystem/iplugin.h> + +#include <QtCore/QObject> + +namespace Plugin1 { + +class MyPlugin1 : public ExtensionSystem::IPlugin +{ + Q_OBJECT + +public: + MyPlugin1(); + + bool initialize(const QStringList &arguments, QString *errorString); + void extensionsInitialized(); +}; + +} // namespace + +#endif // header guard diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin1.pro b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin1.pro new file mode 100644 index 00000000000..4181188287f --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin1.pro @@ -0,0 +1,8 @@ +TEMPLATE = lib +TARGET = plugin1 + +SOURCES += plugin1.cpp +HEADERS += plugin1.h + +include(../../../../extensionsystem_test.pri) + diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin.xml b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin.xml new file mode 100644 index 00000000000..5436967a80b --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin.xml @@ -0,0 +1,2 @@ +<plugin name="plugin2" version="1.0.0" compatVersion="1.0.0"> +</plugin> diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin2.cpp b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin2.cpp new file mode 100644 index 00000000000..c5af5f39a35 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin2.cpp @@ -0,0 +1,53 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "plugin2.h" + +#include <QtCore/qplugin.h> + +using namespace Plugin2; + +MyPlugin2::MyPlugin2() +{ +} + +bool MyPlugin2::initialize(const QStringList &, QString *) +{ + return true; +} + +void MyPlugin2::extensionsInitialized() +{ +} + +Q_EXPORT_PLUGIN(MyPlugin2) + diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin2.h b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin2.h new file mode 100644 index 00000000000..b1cd95c7627 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin2.h @@ -0,0 +1,55 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef PLUGIN2_H +#define PLUGIN2_H + +#include <extensionsystem/iplugin.h> + +#include <QtCore/QObject> + +namespace Plugin2 { + +class MyPlugin2 : public ExtensionSystem::IPlugin +{ + Q_OBJECT + +public: + MyPlugin2(); + + bool initialize(const QStringList &arguments, QString *errorString); + void extensionsInitialized(); +}; + +} // namespace + +#endif // header guard diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin2.pro b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin2.pro new file mode 100644 index 00000000000..58798b54f14 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin2.pro @@ -0,0 +1,8 @@ +TEMPLATE = lib +TARGET = plugin2 + +SOURCES += plugin2.cpp +HEADERS += plugin2.h + +include(../../../../extensionsystem_test.pri) + diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin.xml b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin.xml new file mode 100644 index 00000000000..f7e90978ba6 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin.xml @@ -0,0 +1,5 @@ +<plugin name="plugin3" version="1.0.0" compatVersion="1.0.0"> + <dependencyList> + <dependency name="plugin1" version="1.0.0"/> + </dependencyList> +</plugin> diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin3.cpp b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin3.cpp new file mode 100644 index 00000000000..9b38565c35c --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin3.cpp @@ -0,0 +1,53 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "plugin3.h" + +#include <QtCore/qplugin.h> + +using namespace Plugin3; + +MyPlugin3::MyPlugin3() +{ +} + +bool MyPlugin3::initialize(const QStringList &, QString *) +{ + return true; +} + +void MyPlugin3::extensionsInitialized() +{ +} + +Q_EXPORT_PLUGIN(MyPlugin3) + diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin3.h b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin3.h new file mode 100644 index 00000000000..7514d63bd71 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin3.h @@ -0,0 +1,55 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef PLUGIN3_H +#define PLUGIN3_H + +#include <extensionsystem/iplugin.h> + +#include <QtCore/QObject> + +namespace Plugin3 { + +class MyPlugin3 : public ExtensionSystem::IPlugin +{ + Q_OBJECT + +public: + MyPlugin3(); + + bool initialize(const QStringList &arguments, QString *errorString); + void extensionsInitialized(); +}; + +} // namespace + +#endif // header guard diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin3.pro b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin3.pro new file mode 100644 index 00000000000..f601f06162c --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin3.pro @@ -0,0 +1,8 @@ +TEMPLATE = lib +TARGET = plugin3 + +SOURCES += plugin3.cpp +HEADERS += plugin3.h + +include(../../../../extensionsystem_test.pri) + diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/correctplugins1.pro b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/correctplugins1.pro new file mode 100644 index 00000000000..f0d76950e86 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/correctplugins1.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +CONFIG += ordered +SUBDIRS = plugin2 plugin3 plugin1 diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin.spec b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin.spec new file mode 100644 index 00000000000..db201f34c39 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin.spec @@ -0,0 +1,6 @@ +<plugin name="plugin1" version="1.0.0" compatVersion="1.0.0"> + <dependencyList> + <dependency name="plugin2" version="1.0.0"/> + <dependency name="plugin3" version="1.0.0"/> + </dependencyList> +</plugin> diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin1.cpp b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin1.cpp new file mode 100644 index 00000000000..8149d046d21 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin1.cpp @@ -0,0 +1,86 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "plugin1.h" + +#include <extensionsystem/pluginmanager.h> + +#include <QtCore/qplugin.h> +#include <QtCore/QObject> + +using namespace Plugin1; + +MyPlugin1::MyPlugin1() + : initializeCalled(false) +{ +} + +bool MyPlugin1::initialize(const QStringList & /*arguments*/, QString *errorString) +{ + initializeCalled = true; + QObject *obj = new QObject; + obj->setObjectName("MyPlugin1"); + addAutoReleasedObject(obj); + + bool found2 = false; + bool found3 = false; + foreach (QObject *object, ExtensionSystem::PluginManager::instance()->allObjects()) { + if (object->objectName() == "MyPlugin2") + found2 = true; + else if (object->objectName() == "MyPlugin3") + found3 = true; + } + if (found2 && found3) + return true; + if (errorString) { + QString error = "object(s) missing from plugin(s):"; + if (!found2) + error.append(" plugin2"); + if (!found3) + error.append(" plugin3"); + *errorString = error; + } + return false; +} + +void MyPlugin1::extensionsInitialized() +{ + if (!initializeCalled) + return; + // don't do this at home, it's just done here for the test + QObject *obj = new QObject; + obj->setObjectName("MyPlugin1_running"); + addAutoReleasedObject(obj); +} + +Q_EXPORT_PLUGIN(MyPlugin1) + diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin1.h b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin1.h new file mode 100644 index 00000000000..4be9f9bbf7f --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin1.h @@ -0,0 +1,58 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef PLUGIN1_H +#define PLUGIN1_H + +#include <extensionsystem/iplugin.h> + +#include <QtCore/QObject> + +namespace Plugin1 { + +class MyPlugin1 : public ExtensionSystem::IPlugin +{ + Q_OBJECT + +public: + MyPlugin1(); + + bool initialize(const QStringList &arguments, QString *errorString); + void extensionsInitialized(); + +private: + bool initializeCalled; +}; + +} // namespace + +#endif // header guard diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin1.pro b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin1.pro new file mode 100644 index 00000000000..9101770f9ac --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin1.pro @@ -0,0 +1,15 @@ +TEMPLATE = lib +TARGET = plugin1 + +SOURCES += plugin1.cpp +HEADERS += plugin1.h + +include(../../../../extensionsystem_test.pri) + +LIBS += -L$${PWD}/../plugin2 -L$${PWD}/../plugin3 -lplugin2 -lplugin3 + +macx { +} else:unix { + QMAKE_RPATHDIR += $${PWD}/../plugin2 + QMAKE_RPATHDIR += $${PWD}/../plugin3 +} diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin.spec b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin.spec new file mode 100644 index 00000000000..5436967a80b --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin.spec @@ -0,0 +1,2 @@ +<plugin name="plugin2" version="1.0.0" compatVersion="1.0.0"> +</plugin> diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin2.cpp b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin2.cpp new file mode 100644 index 00000000000..99f192766a4 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin2.cpp @@ -0,0 +1,68 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "plugin2.h" + +#include <extensionsystem/pluginmanager.h> + +#include <QtCore/qplugin.h> +#include <QtCore/QObject> + +using namespace Plugin2; + +MyPlugin2::MyPlugin2() + : initializeCalled(false) +{ +} + +bool MyPlugin2::initialize(const QStringList &, QString *) +{ + initializeCalled = true; + QObject *obj = new QObject; + obj->setObjectName("MyPlugin2"); + addAutoReleasedObject(obj); + + return true; +} + +void MyPlugin2::extensionsInitialized() +{ + if (!initializeCalled) + return; + // don't do this at home, it's just done here for the test + QObject *obj = new QObject; + obj->setObjectName("MyPlugin2_running"); + addAutoReleasedObject(obj); +} + +Q_EXPORT_PLUGIN(MyPlugin2) + diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin2.h b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin2.h new file mode 100644 index 00000000000..08d77a38c70 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin2.h @@ -0,0 +1,58 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef PLUGIN2_H +#define PLUGIN2_H + +#include <extensionsystem/iplugin.h> + +#include <QtCore/QObject> + +namespace Plugin2 { + +class MyPlugin2 : public ExtensionSystem::IPlugin +{ + Q_OBJECT + +public: + MyPlugin2(); + + bool initialize(const QStringList &arguments, QString *errorString); + void extensionsInitialized(); + +private: + bool initializeCalled; +}; + +} // namespace + +#endif // header guard diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin2.pro b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin2.pro new file mode 100644 index 00000000000..a80f4a5c765 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin2.pro @@ -0,0 +1,12 @@ +TEMPLATE = lib +TARGET = plugin2 + +SOURCES += plugin2.cpp +HEADERS += plugin2.h + +include(../../../../extensionsystem_test.pri) + +macx { + QMAKE_LFLAGS_SONAME = -Wl,-install_name,$${PWD}/ +} + diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin.spec b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin.spec new file mode 100644 index 00000000000..234bf56ea2d --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin.spec @@ -0,0 +1,5 @@ +<plugin name="plugin3" version="1.0.0" compatVersion="1.0.0"> + <dependencyList> + <dependency name="plugin2" version="1.0.0"/> + </dependencyList> +</plugin> diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin3.cpp b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin3.cpp new file mode 100644 index 00000000000..4410c345113 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin3.cpp @@ -0,0 +1,77 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "plugin3.h" + +#include <extensionsystem/pluginmanager.h> + +#include <QtCore/qplugin.h> +#include <QtCore/QObject> + +using namespace Plugin3; + +MyPlugin3::MyPlugin3() + : initializeCalled(false) +{ +} + +bool MyPlugin3::initialize(const QStringList & /*arguments*/, QString *errorString) +{ + initializeCalled = true; + QObject *obj = new QObject; + obj->setObjectName("MyPlugin3"); + addAutoReleasedObject(obj); + + bool found2 = false; + foreach (QObject *object, ExtensionSystem::PluginManager::instance()->allObjects()) { + if (object->objectName() == "MyPlugin2") + found2 = true; + } + if (found2) + return true; + if (errorString) + *errorString = "object from plugin2 could not be found"; + return false; +} + +void MyPlugin3::extensionsInitialized() +{ + if (!initializeCalled) + return; + // don't do this at home, it's just done here for the test + QObject *obj = new QObject; + obj->setObjectName("MyPlugin3_running"); + addAutoReleasedObject(obj); +} + +Q_EXPORT_PLUGIN(MyPlugin3) + diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin3.h b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin3.h new file mode 100644 index 00000000000..0991b7a1526 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin3.h @@ -0,0 +1,58 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef PLUGIN3_H +#define PLUGIN3_H + +#include <extensionsystem/iplugin.h> + +#include <QtCore/QObject> + +namespace Plugin3 { + +class MyPlugin3 : public ExtensionSystem::IPlugin +{ + Q_OBJECT + +public: + MyPlugin3(); + + bool initialize(const QStringList &arguments, QString *errorString); + void extensionsInitialized(); + +private: + bool initializeCalled; +}; + +} // namespace + +#endif // header guard diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin3.pro b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin3.pro new file mode 100644 index 00000000000..c5ff581b1ba --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin3.pro @@ -0,0 +1,15 @@ +TEMPLATE = lib +TARGET = plugin3 + +SOURCES += plugin3.cpp +HEADERS += plugin3.h + +include(../../../../extensionsystem_test.pri) + +LIBS += -L$${PWD}/../plugin2 -lplugin2 + +macx { + QMAKE_LFLAGS_SONAME = -Wl,-install_name,$${PWD}/ +} else:unix { + QMAKE_RPATHDIR += $${PWD}/../plugin2 +} diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/pluginmanager.pro b/src/libs/extensionsystem/test/auto/pluginmanager/pluginmanager.pro new file mode 100644 index 00000000000..57b026f5fb8 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/pluginmanager.pro @@ -0,0 +1,6 @@ +TEMPLATE = subdirs + +SUBDIRS = test.pro \ + circularplugins \ + correctplugins1 + diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/plugins/myplug/myplug.xml b/src/libs/extensionsystem/test/auto/pluginmanager/plugins/myplug/myplug.xml new file mode 100644 index 00000000000..c79b29780d1 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/plugins/myplug/myplug.xml @@ -0,0 +1,2 @@ +<plugin name="dummyPlugin" version="1.1.1" compatVersion="1.0.0"> +</plugin> diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/plugins/otherplugin.xml b/src/libs/extensionsystem/test/auto/pluginmanager/plugins/otherplugin.xml new file mode 100644 index 00000000000..6f0483f0f82 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/plugins/otherplugin.xml @@ -0,0 +1,2 @@ +<plugin name="helloworld" version="1.0.0"> +</plugin> diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/plugins/plugin1.xml b/src/libs/extensionsystem/test/auto/pluginmanager/plugins/plugin1.xml new file mode 100644 index 00000000000..6bd573957b7 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/plugins/plugin1.xml @@ -0,0 +1,2 @@ +<plugin name="MyPlugin" version="2.2.3_9" compatVersion="2.0.0"> +</plugin> diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/test.pro b/src/libs/extensionsystem/test/auto/pluginmanager/test.pro new file mode 100644 index 00000000000..c5934b1331c --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/test.pro @@ -0,0 +1,14 @@ +###################################################################### +# Automatically generated by qmake (2.01a) Fr Jul 27 23:12:52 2007 +###################################################################### + +CONFIG += qtestlib +TEMPLATE = app +CONFIG -= app_bundle + +# Input + +include(../../extensionsystem_test.pri) + +SOURCES += tst_pluginmanager.cpp + diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/test.sh b/src/libs/extensionsystem/test/auto/pluginmanager/test.sh new file mode 100755 index 00000000000..426901ea74d --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/test.sh @@ -0,0 +1,5 @@ +# -- run the plugin test from this directory. + +export LD_LIBRARY_PATH=../../../../../../lib:$LD_LIBRARY_PATH +export DYLD_LIBRARY_PATH=../../../../../../bin/QtCreator.app/Contents/PlugIns:$DYLD_LIBRARY_PATH # mac +exec ./test diff --git a/src/libs/extensionsystem/test/auto/pluginmanager/tst_pluginmanager.cpp b/src/libs/extensionsystem/test/auto/pluginmanager/tst_pluginmanager.cpp new file mode 100644 index 00000000000..f54b978e9af --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginmanager/tst_pluginmanager.cpp @@ -0,0 +1,267 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include <QtTest/QtTest> + +#include <QtCore/QObject> + +#include <extensionsystem/pluginmanager.h> +#include <extensionsystem/pluginspec.h> +#include <extensionsystem/iplugin.h> + +using namespace ExtensionSystem; + +class SignalReceiver; + +class tst_PluginManager : public QObject +{ + Q_OBJECT + +private slots: + void init(); + void cleanup(); + void addRemoveObjects(); + void getObject(); + void getObjects(); + void plugins(); + void circularPlugins(); + void correctPlugins1(); + +private: + PluginManager *m_pm; + SignalReceiver *m_sr; +}; + +class SignalReceiver : public QObject +{ + Q_OBJECT + +public: + SignalReceiver() : + objectAddedCount(0), + aboutToRemoveObjectCount(0), + pluginsChangedCount(0), + objectAddedObj(0), + aboutToRemoveObjectObj(0) + { } + int objectAddedCount; + int aboutToRemoveObjectCount; + int pluginsChangedCount; + QObject *objectAddedObj; + QObject *aboutToRemoveObjectObj; +public slots: + void objectAdded(QObject *obj) { objectAddedCount++; objectAddedObj = obj; } + void aboutToRemoveObject(QObject *obj) { aboutToRemoveObjectCount++; aboutToRemoveObjectObj = obj; } + void pluginsChanged() { pluginsChangedCount++; } +}; + +class MyClass1 : public QObject +{ + Q_OBJECT +}; + +class MyClass2 : public QObject +{ + Q_OBJECT +}; + +class MyClass11 : public MyClass1 +{ + Q_OBJECT +}; + +void tst_PluginManager::init() +{ + m_pm = new PluginManager; + m_sr = new SignalReceiver; + connect(m_pm, SIGNAL(objectAdded(QObject*)), m_sr, SLOT(objectAdded(QObject*))); + connect(m_pm, SIGNAL(aboutToRemoveObject(QObject*)), m_sr, SLOT(aboutToRemoveObject(QObject*))); + connect(m_pm, SIGNAL(pluginsChanged()), m_sr, SLOT(pluginsChanged())); +} + +void tst_PluginManager::cleanup() +{ + delete m_pm; + delete m_sr; +} + +void tst_PluginManager::addRemoveObjects() +{ + QObject *object1 = new QObject; + QObject *object2 = new QObject; + QCOMPARE(m_pm->allObjects().size(), 0); + m_pm->addObject(object1); + QCOMPARE(m_sr->objectAddedCount, 1); + QCOMPARE(m_sr->objectAddedObj, object1); + QCOMPARE(m_sr->aboutToRemoveObjectCount, 0); + QVERIFY(m_pm->allObjects().contains(object1)); + QVERIFY(!m_pm->allObjects().contains(object2)); + QCOMPARE(m_pm->allObjects().size(), 1); + m_pm->addObject(object2); + QCOMPARE(m_sr->objectAddedCount, 2); + QCOMPARE(m_sr->objectAddedObj, object2); + QCOMPARE(m_sr->aboutToRemoveObjectCount, 0); + QVERIFY(m_pm->allObjects().contains(object1)); + QVERIFY(m_pm->allObjects().contains(object2)); + QCOMPARE(m_pm->allObjects().size(), 2); + m_pm->removeObject(object1); + QCOMPARE(m_sr->objectAddedCount, 2); + QCOMPARE(m_sr->aboutToRemoveObjectCount, 1); + QCOMPARE(m_sr->aboutToRemoveObjectObj, object1); + QVERIFY(!m_pm->allObjects().contains(object1)); + QVERIFY(m_pm->allObjects().contains(object2)); + QCOMPARE(m_pm->allObjects().size(), 1); + m_pm->removeObject(object2); + QCOMPARE(m_sr->objectAddedCount, 2); + QCOMPARE(m_sr->aboutToRemoveObjectCount, 2); + QCOMPARE(m_sr->aboutToRemoveObjectObj, object2); + QVERIFY(!m_pm->allObjects().contains(object1)); + QVERIFY(!m_pm->allObjects().contains(object2)); + QCOMPARE(m_pm->allObjects().size(), 0); + delete object1; + delete object2; +} + +void tst_PluginManager::getObject() +{ + MyClass2 *object2 = new MyClass2; + MyClass11 *object11 = new MyClass11; + m_pm->addObject(object2); + QCOMPARE(m_pm->getObject<MyClass11>(), (MyClass11*)0); + QCOMPARE(m_pm->getObject<MyClass1>(), (MyClass1*)0); + QCOMPARE(m_pm->getObject<MyClass2>(), object2); + m_pm->addObject(object11); + QCOMPARE(m_pm->getObject<MyClass11>(), object11); + QCOMPARE(m_pm->getObject<MyClass1>(), qobject_cast<MyClass1*>(object11)); + QCOMPARE(m_pm->getObject<MyClass2>(), object2); + m_pm->removeObject(object2); + m_pm->removeObject(object11); + delete object2; + delete object11; +} + +void tst_PluginManager::getObjects() +{ + MyClass1 *object1 = new MyClass1; + MyClass2 *object2 = new MyClass2; + MyClass11 *object11 = new MyClass11; + m_pm->addObject(object2); + QCOMPARE(m_pm->getObjects<MyClass11>(), QList<MyClass11*>()); + QCOMPARE(m_pm->getObjects<MyClass1>(), QList<MyClass1*>()); + QCOMPARE(m_pm->getObjects<MyClass2>(), QList<MyClass2*>() << object2); + QCOMPARE(m_pm->allObjects(), QList<QObject*>() << object2); + m_pm->addObject(object11); + QCOMPARE(m_pm->getObjects<MyClass11>(), QList<MyClass11*>() << object11); + QCOMPARE(m_pm->getObjects<MyClass1>(), QList<MyClass1*>() << object11); + QCOMPARE(m_pm->getObjects<MyClass2>(), QList<MyClass2*>() << object2); + QCOMPARE(m_pm->allObjects(), QList<QObject*>() << object2 << object11); + m_pm->addObject(object1); + QCOMPARE(m_pm->getObjects<MyClass11>(), QList<MyClass11*>() << object11); + QCOMPARE(m_pm->getObjects<MyClass1>(), QList<MyClass1*>() << object11 << object1); + QCOMPARE(m_pm->getObjects<MyClass2>(), QList<MyClass2*>() << object2); + QCOMPARE(m_pm->allObjects(), QList<QObject*>() << object2 << object11 << object1); + m_pm->removeObject(object2); + m_pm->removeObject(object11); + m_pm->removeObject(object1); + delete object1; + delete object2; + delete object11; +} + +void tst_PluginManager::plugins() +{ + m_pm->setPluginPaths(QStringList() << "plugins"); + QCOMPARE(m_sr->pluginsChangedCount, 1); + QSet<PluginSpec *> plugins = m_pm->plugins(); + QCOMPARE(plugins.count(), 3); + foreach (const QString &expected, QStringList() << "helloworld" << "MyPlugin" << "dummyPlugin") { + bool found = false; + foreach (PluginSpec *spec, plugins) { + if (spec->name() == expected) { + found = true; + break; + } + } + QVERIFY2(found, QString("plugin '%1' not found").arg(expected).toLocal8Bit().constData()); + } +} + +void tst_PluginManager::circularPlugins() +{ + m_pm->setPluginPaths(QStringList() << "circularplugins"); + m_pm->loadPlugins(); + foreach (PluginSpec *spec, m_pm->plugins()) { + if (spec->name() == "plugin1") { + QVERIFY(spec->hasError()); + QCOMPARE(spec->state(), PluginSpec::Resolved); + QCOMPARE(spec->plugin(), (IPlugin*)0); + } else if (spec->name() == "plugin2") { + QVERIFY(!spec->hasError()); + QCOMPARE(spec->state(), PluginSpec::Running); + } else if (spec->name() == "plugin3") { + QVERIFY(spec->hasError()); + QCOMPARE(spec->state(), PluginSpec::Resolved); + QCOMPARE(spec->plugin(), (IPlugin*)0); + } + } +} + +void tst_PluginManager::correctPlugins1() +{ + m_pm->setFileExtension("spec"); + m_pm->setPluginPaths(QStringList() << "correctplugins1"); + m_pm->loadPlugins(); + foreach (PluginSpec *spec, m_pm->plugins()) { + if (spec->hasError()) + qDebug() << spec->errorString(); + QVERIFY(!spec->hasError()); + QCOMPARE(spec->state(), PluginSpec::Running); + } + bool plugin1running = false; + bool plugin2running = false; + bool plugin3running = false; + foreach (QObject *obj, m_pm->allObjects()) { + if (obj->objectName() == "MyPlugin1_running") + plugin1running = true; + else if (obj->objectName() == "MyPlugin2_running") + plugin2running = true; + else if (obj->objectName() == "MyPlugin3_running") + plugin3running = true; + } + QVERIFY(plugin1running); + QVERIFY(plugin2running); + QVERIFY(plugin3running); +} + +QTEST_MAIN(tst_PluginManager) +#include "tst_pluginmanager.moc" + diff --git a/src/libs/extensionsystem/test/auto/pluginspec/pluginspec.pro b/src/libs/extensionsystem/test/auto/pluginspec/pluginspec.pro new file mode 100644 index 00000000000..d4b941b2320 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginspec/pluginspec.pro @@ -0,0 +1,4 @@ +TEMPLATE = subdirs +CONFIG += ordered + +SUBDIRS = testplugin test.pro diff --git a/src/libs/extensionsystem/test/auto/pluginspec/test.pro b/src/libs/extensionsystem/test/auto/pluginspec/test.pro new file mode 100644 index 00000000000..d8fda889176 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginspec/test.pro @@ -0,0 +1,14 @@ +CONFIG += qtestlib +TEMPLATE = app +CONFIG -= app_bundle +DESTDIR = $${PWD} +# Input +SOURCES += tst_pluginspec.cpp + +include(../../extensionsystem_test.pri) + +LIBS += -L$${PWD}/testplugin -ltest +macx { +} else:unix { + QMAKE_RPATHDIR += $${PWD}/testplugin +} diff --git a/src/libs/extensionsystem/test/auto/pluginspec/test.sh b/src/libs/extensionsystem/test/auto/pluginspec/test.sh new file mode 100755 index 00000000000..426901ea74d --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginspec/test.sh @@ -0,0 +1,5 @@ +# -- run the plugin test from this directory. + +export LD_LIBRARY_PATH=../../../../../../lib:$LD_LIBRARY_PATH +export DYLD_LIBRARY_PATH=../../../../../../bin/QtCreator.app/Contents/PlugIns:$DYLD_LIBRARY_PATH # mac +exec ./test diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec1.xml b/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec1.xml new file mode 100644 index 00000000000..137e1b494cf --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec1.xml @@ -0,0 +1,6 @@ +<plugin name="plugin1" version="1.0.1" compatVersion="1.0.0"> + <dependencyList> + <dependency name="plugin2" version="2.3.0_2"/> + <dependency name="plugin3" version="1.0.0"/> + </dependencyList> +</plugin> diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec2.xml b/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec2.xml new file mode 100644 index 00000000000..451f854185f --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec2.xml @@ -0,0 +1,2 @@ +<plugin name="plugin2" version="2.4.1" compatVersion="2.3.0"> +</plugin> diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec3.xml b/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec3.xml new file mode 100644 index 00000000000..9fa01a442f5 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec3.xml @@ -0,0 +1,2 @@ +<plugin name="plugin3" version="1.0.0" compatVersion="1.0.0"> +</plugin> diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec4.xml b/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec4.xml new file mode 100644 index 00000000000..b06bab2fa0e --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec4.xml @@ -0,0 +1,5 @@ +<plugin name="plugin4" version="1.0.1" compatVersion="1.0.0"> + <dependencyList> + <dependency name="plugin5" version="2.3.0_2"/> + </dependencyList> +</plugin> diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec5.xml b/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec5.xml new file mode 100644 index 00000000000..aab8f424c32 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec5.xml @@ -0,0 +1,2 @@ +<plugin name="plugin5" version="1.0.1" compatVersion="1.0.0"> +</plugin> diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testdir/spec.xml b/src/libs/extensionsystem/test/auto/pluginspec/testdir/spec.xml new file mode 100644 index 00000000000..6bd573957b7 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginspec/testdir/spec.xml @@ -0,0 +1,2 @@ +<plugin name="MyPlugin" version="2.2.3_9" compatVersion="2.0.0"> +</plugin> diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.cpp b/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.cpp new file mode 100644 index 00000000000..8c3db6c1895 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.cpp @@ -0,0 +1,56 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "testplugin.h" + +#include <QtCore/qplugin.h> + +using namespace MyPlugin; + +MyPluginImpl::MyPluginImpl() + : m_isInitialized(false), m_isExtensionsInitialized(false) +{ +} + +bool MyPluginImpl::initialize(const QStringList &, QString *) +{ + m_isInitialized = true; + return true; +} + +void MyPluginImpl::extensionsInitialized() +{ + m_isExtensionsInitialized = true; +} + +Q_EXPORT_PLUGIN(MyPluginImpl) + diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.h b/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.h new file mode 100644 index 00000000000..10fc0acf508 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.h @@ -0,0 +1,62 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef TESTPLUGIN_H +#define TESTPLUGIN_H + +#include "testplugin_global.h" +#include <extensionsystem/iplugin.h> + +#include <QtCore/QObject> + +namespace MyPlugin { + +class MYPLUGIN_EXPORT MyPluginImpl : public ExtensionSystem::IPlugin +{ + Q_OBJECT + +public: + MyPluginImpl(); + + bool initialize(const QStringList &arguments, QString *errorString); + void extensionsInitialized(); + + bool isInitialized() { return m_isInitialized; } + bool isExtensionsInitialized() { return m_isExtensionsInitialized; } +private: + bool m_isInitialized; + bool m_isExtensionsInitialized; +}; + +} // namespace + +#endif // header guard diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.pro b/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.pro new file mode 100644 index 00000000000..8b4d81a82ad --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.pro @@ -0,0 +1,13 @@ +TEMPLATE = lib +TARGET = test +DESTDIR = $${PWD} +DEFINES += MYPLUGIN_LIBRARY +SOURCES += testplugin.cpp +HEADERS += testplugin.h testplugin_global.h + +include(../../../extensionsystem_test.pri) + +macx { + QMAKE_LFLAGS_SONAME = -Wl,-install_name,$${PWD}/ +} + diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.xml b/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.xml new file mode 100644 index 00000000000..f8ab3f7a39e --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.xml @@ -0,0 +1,2 @@ +<plugin name="test" version="1.0.0"> +</plugin> diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin_global.h b/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin_global.h new file mode 100644 index 00000000000..ae40ac8ea8b --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin_global.h @@ -0,0 +1,44 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef TESTPLUGIN_GLOBAL_H +#define TESTPLUGIN_GLOBAL_H + +#include <QtCore/qglobal.h> + +#if defined(MYPLUGIN_LIBRARY) +# define MYPLUGIN_EXPORT Q_DECL_EXPORT +#else +# define MYPLUGIN_EXPORT Q_DECL_IMPORT +#endif + +#endif // header diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testspecs/simplespec.xml b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/simplespec.xml new file mode 100644 index 00000000000..6bd573957b7 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/simplespec.xml @@ -0,0 +1,2 @@ +<plugin name="MyPlugin" version="2.2.3_9" compatVersion="2.0.0"> +</plugin> diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec1.xml b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec1.xml new file mode 100644 index 00000000000..31cebf44146 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec1.xml @@ -0,0 +1,18 @@ +<plugin name="test" version="1.0.1" compatVersion="1.0.0"> + <vendor>Trolltech</vendor> + <copyright>(C) 2007 Trolltech ASA</copyright> + <license> +This is a default license bla +blubbblubb +end of terms + </license> + <description> +This plugin is just a test. + it demonstrates the great use of the plugin spec. + </description> + <url>http://www.trolltech.com</url> + <dependencyList> + <dependency name="SomeOtherPlugin" version="2.3.0_2"/> + <dependency name="EvenOther" version="1.0.0"/> + </dependencyList> +</plugin> diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec2.xml b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec2.xml new file mode 100644 index 00000000000..454f58cb755 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec2.xml @@ -0,0 +1,2 @@ +<plugin name="test" version="3.1.4_10"> +</plugin> diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong1.xml b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong1.xml new file mode 100644 index 00000000000..e6fe956c98e --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong1.xml @@ -0,0 +1,18 @@ +<something name="test" version="1.0.1" compatVersion="1.0.0"> + <vendor>Trolltech</vendor> + <copyright>(C) 2007 Trolltech ASA</copyright> + <license> +This is a default license bla +blubbblubb +end of terms + </license> + <description> +This plugin is just a test. + it demonstrates the great use of the plugin spec. + </description> + <url>http://www.trolltech.com</url> + <dependencyList> + <dependency name="SomeOtherPlugin" version="2.3.0_2"/> + <dependency name="EvenOther" version="1.0.0"/> + </dependencyList> +</something> diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong2.xml b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong2.xml new file mode 100644 index 00000000000..200a1fd1ac1 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong2.xml @@ -0,0 +1,18 @@ +<plugin version="1.0.1" compatVersion="1.0.0"> + <vendor>Trolltech</vendor> + <copyright>(C) 2007 Trolltech ASA</copyright> + <license> +This is a default license bla +blubbblubb +end of terms + </license> + <description> +This plugin is just a test. + it demonstrates the great use of the plugin spec. + </description> + <url>http://www.trolltech.com</url> + <dependencyList> + <dependency name="SomeOtherPlugin" version="2.3.0_2"/> + <dependency name="EvenOther" version="1.0.0"/> + </dependencyList> +</plugin> diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong3.xml b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong3.xml new file mode 100644 index 00000000000..13bbdb09a8d --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong3.xml @@ -0,0 +1,18 @@ +<plugin name="test" compatVersion="1.0.0"> + <vendor>Trolltech</vendor> + <copyright>(C) 2007 Trolltech ASA</copyright> + <license> +This is a default license bla +blubbblubb +end of terms + </license> + <description> +This plugin is just a test. + it demonstrates the great use of the plugin spec. + </description> + <url>http://www.trolltech.com</url> + <dependencyList> + <dependency name="SomeOtherPlugin" version="2.3.0_2"/> + <dependency name="EvenOther" version="1.0.0"/> + </dependencyList> +</plugin> diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong4.xml b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong4.xml new file mode 100644 index 00000000000..b904f901387 --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong4.xml @@ -0,0 +1,18 @@ +<plugin name="test" version="1.0.1" compatVersion="1.0.0"> + <vendor>Trolltech</vendor> + <copyright>(C) 2007 Trolltech ASA</copyright> + <license> +This is a default license bla +blubbblubb +end of terms + </license> + <description> +This plugin is just a test. + it demonstrates the great use of the plugin spec. + </description> + <url>http://www.trolltech.com</url> + <dependencyList> + <dependency version="2.3.0_2"/> + <dependency name="EvenOther" version="1.0.0"/> + </dependencyList> +</plugin> diff --git a/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong5.xml b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong5.xml new file mode 100644 index 00000000000..1c110d1eeae --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong5.xml @@ -0,0 +1,18 @@ +<plugin name="test" version="1.0.1" compatVersion="1.0.0"> + <vendor>Trolltech</vendor> + <copyright>(C) 2007 Trolltech ASA</copyright> + <license> +This is a default license bla +blubbblubb +end of terms + </license> + <description> +This plugin is just a test. + it demonstrates the great use of the plugin spec. + </description> + <url>http://www.trolltech.com</url> + <dependencyList> + <dependency name="SomeOtherPlugin" version="2.3aa.0_2"/> + <dependency name="EvenOther" version="1.0.0"/> + </dependencyList> +</plugin> diff --git a/src/libs/extensionsystem/test/auto/pluginspec/tst_pluginspec.cpp b/src/libs/extensionsystem/test/auto/pluginspec/tst_pluginspec.cpp new file mode 100644 index 00000000000..f3471edcaac --- /dev/null +++ b/src/libs/extensionsystem/test/auto/pluginspec/tst_pluginspec.cpp @@ -0,0 +1,278 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include <QtTest/QtTest> + +#include "testplugin/testplugin.h" + +#include <extensionsystem/pluginspec.h> +#include <extensionsystem/pluginspec_p.h> +#include <extensionsystem/pluginmanager_p.h> +#include <extensionsystem/pluginmanager.h> + +#include <QtCore/QObject> + +using namespace ExtensionSystem; + +class tst_PluginSpec : public QObject +{ + Q_OBJECT + +private slots: + void read(); + void readError(); + void isValidVersion(); + void versionCompare(); + void provides(); + void locationAndPath(); + void resolveDependencies(); + void loadLibrary(); + void initializePlugin(); + void initializeExtensions(); +}; + +void tst_PluginSpec::read() +{ + Internal::PluginSpecPrivate spec(0); + QCOMPARE(spec.state, PluginSpec::Invalid); + QVERIFY(spec.read("testspecs/spec1.xml")); + QCOMPARE(spec.state, PluginSpec::Read); + QVERIFY(!spec.hasError); + QVERIFY(spec.errorString.isEmpty()); + QCOMPARE(spec.name, QString("test")); + QCOMPARE(spec.version, QString("1.0.1")); + QCOMPARE(spec.compatVersion, QString("1.0.0")); + QCOMPARE(spec.vendor, QString("Trolltech")); + QCOMPARE(spec.copyright, QString("(C) 2007 Trolltech ASA")); + QCOMPARE(spec.license, QString("This is a default license bla\nblubbblubb\nend of terms")); + QCOMPARE(spec.description, QString("This plugin is just a test.\n it demonstrates the great use of the plugin spec.")); + QCOMPARE(spec.url, QString("http://www.trolltech.com")); + PluginDependency dep1; + dep1.name = QString("SomeOtherPlugin"); + dep1.version = QString("2.3.0_2"); + PluginDependency dep2; + dep2.name = QString("EvenOther"); + dep2.version = QString("1.0.0"); + QCOMPARE(spec.dependencies, QList<PluginDependency>() << dep1 << dep2); + + // test missing compatVersion behavior + QVERIFY(spec.read("testspecs/spec2.xml")); + QCOMPARE(spec.version, QString("3.1.4_10")); + QCOMPARE(spec.compatVersion, QString("3.1.4_10")); +} + +void tst_PluginSpec::readError() +{ + Internal::PluginSpecPrivate spec(0); + QCOMPARE(spec.state, PluginSpec::Invalid); + QVERIFY(!spec.read("non-existing-file.xml")); + QCOMPARE(spec.state, PluginSpec::Invalid); + QVERIFY(spec.hasError); + QVERIFY(!spec.errorString.isEmpty()); + QVERIFY(!spec.read("testspecs/spec_wrong1.xml")); + QCOMPARE(spec.state, PluginSpec::Invalid); + QVERIFY(spec.hasError); + QVERIFY(!spec.errorString.isEmpty()); + QVERIFY(!spec.read("testspecs/spec_wrong2.xml")); + QCOMPARE(spec.state, PluginSpec::Invalid); + QVERIFY(spec.hasError); + QVERIFY(!spec.errorString.isEmpty()); + QVERIFY(!spec.read("testspecs/spec_wrong3.xml")); + QCOMPARE(spec.state, PluginSpec::Invalid); + QVERIFY(spec.hasError); + QVERIFY(!spec.errorString.isEmpty()); + QVERIFY(!spec.read("testspecs/spec_wrong4.xml")); + QCOMPARE(spec.state, PluginSpec::Invalid); + QVERIFY(spec.hasError); + QVERIFY(!spec.errorString.isEmpty()); + QVERIFY(!spec.read("testspecs/spec_wrong5.xml")); + QCOMPARE(spec.state, PluginSpec::Invalid); + QVERIFY(spec.hasError); + QVERIFY(!spec.errorString.isEmpty()); +} + +void tst_PluginSpec::isValidVersion() +{ + QVERIFY(Internal::PluginSpecPrivate::isValidVersion("2")); + QVERIFY(Internal::PluginSpecPrivate::isValidVersion("53")); + QVERIFY(Internal::PluginSpecPrivate::isValidVersion("52_1")); + QVERIFY(Internal::PluginSpecPrivate::isValidVersion("3.12")); + QVERIFY(Internal::PluginSpecPrivate::isValidVersion("31.1_12")); + QVERIFY(Internal::PluginSpecPrivate::isValidVersion("31.1.0")); + QVERIFY(Internal::PluginSpecPrivate::isValidVersion("1.0.2_1")); + + QVERIFY(!Internal::PluginSpecPrivate::isValidVersion("")); + QVERIFY(!Internal::PluginSpecPrivate::isValidVersion("1..0")); + QVERIFY(!Internal::PluginSpecPrivate::isValidVersion("1.0_")); + QVERIFY(!Internal::PluginSpecPrivate::isValidVersion("1.0.0.0")); +} + +void tst_PluginSpec::versionCompare() +{ + QVERIFY(Internal::PluginSpecPrivate::versionCompare("3", "3") == 0); + QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.0.0", "3") == 0); + QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.0", "3") == 0); + QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.0.0_1", "3_1") == 0); + QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.0_21", "3_21") == 0); + + QVERIFY(Internal::PluginSpecPrivate::versionCompare("3", "1") > 0); + QVERIFY(Internal::PluginSpecPrivate::versionCompare("3", "1.0_12") > 0); + QVERIFY(Internal::PluginSpecPrivate::versionCompare("3_1", "3") > 0); + QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.1.0_23", "3.1") > 0); + QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.1_23", "3.1_12") > 0); + + QVERIFY(Internal::PluginSpecPrivate::versionCompare("1", "3") < 0); + QVERIFY(Internal::PluginSpecPrivate::versionCompare("1.0_12", "3") < 0); + QVERIFY(Internal::PluginSpecPrivate::versionCompare("3", "3_1") < 0); + QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.1", "3.1.0_23") < 0); + QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.1_12", "3.1_23") < 0); +} + +void tst_PluginSpec::provides() +{ + Internal::PluginSpecPrivate spec(0); + QVERIFY(spec.read("testspecs/simplespec.xml")); + QVERIFY(!spec.provides("SomeOtherPlugin", "2.2.3_9")); + QVERIFY(!spec.provides("MyPlugin", "2.2.3_10")); + QVERIFY(!spec.provides("MyPlugin", "2.2.4")); + QVERIFY(!spec.provides("MyPlugin", "2.3.11_1")); + QVERIFY(!spec.provides("MyPlugin", "2.3")); + QVERIFY(!spec.provides("MyPlugin", "3.0")); + QVERIFY(!spec.provides("MyPlugin", "1.9.9_99")); + QVERIFY(!spec.provides("MyPlugin", "1.9")); + QVERIFY(!spec.provides("MyPlugin", "0.9")); + QVERIFY(!spec.provides("MyPlugin", "1")); + + QVERIFY(spec.provides("myplugin", "2.2.3_9")); + QVERIFY(spec.provides("MyPlugin", "2.2.3_9")); + QVERIFY(spec.provides("MyPlugin", "2.2.3_8")); + QVERIFY(spec.provides("MyPlugin", "2.2.3")); + QVERIFY(spec.provides("MyPlugin", "2.2.2")); + QVERIFY(spec.provides("MyPlugin", "2.1.2_10")); + QVERIFY(spec.provides("MyPlugin", "2.0_10")); + QVERIFY(spec.provides("MyPlugin", "2")); +} + +void tst_PluginSpec::locationAndPath() +{ + Internal::PluginSpecPrivate spec(0); + QVERIFY(spec.read("testspecs/simplespec.xml")); + QCOMPARE(spec.location, QDir::currentPath()+"/testspecs"); + QCOMPARE(spec.filePath, QDir::currentPath()+"/testspecs/simplespec.xml"); + QVERIFY(spec.read("testdir/../testspecs/simplespec.xml")); + QCOMPARE(spec.location, QDir::currentPath()+"/testspecs"); + QCOMPARE(spec.filePath, QDir::currentPath()+"/testspecs/simplespec.xml"); + QVERIFY(spec.read("testdir/spec.xml")); + QCOMPARE(spec.location, QDir::currentPath()+"/testdir"); + QCOMPARE(spec.filePath, QDir::currentPath()+"/testdir/spec.xml"); +} + +void tst_PluginSpec::resolveDependencies() +{ + QSet<PluginSpec *> specs; + PluginSpec *spec1 = Internal::PluginManagerPrivate::createSpec(); + specs.insert(spec1); + Internal::PluginSpecPrivate *spec1Priv = Internal::PluginManagerPrivate::privateSpec(spec1); + spec1Priv->read("testdependencies/spec1.xml"); + PluginSpec *spec2 = Internal::PluginManagerPrivate::createSpec(); + specs.insert(spec2); + Internal::PluginManagerPrivate::privateSpec(spec2)->read("testdependencies/spec2.xml"); + PluginSpec *spec3 = Internal::PluginManagerPrivate::createSpec(); + specs.insert(spec3); + Internal::PluginManagerPrivate::privateSpec(spec3)->read("testdependencies/spec3.xml"); + PluginSpec *spec4 = Internal::PluginManagerPrivate::createSpec(); + specs.insert(spec4); + Internal::PluginSpecPrivate *spec4Priv = Internal::PluginManagerPrivate::privateSpec(spec4); + spec4Priv->read("testdependencies/spec4.xml"); + PluginSpec *spec5 = Internal::PluginManagerPrivate::createSpec(); + specs.insert(spec5); + Internal::PluginManagerPrivate::privateSpec(spec5)->read("testdependencies/spec5.xml"); + QVERIFY(spec1Priv->resolveDependencies(specs)); + QCOMPARE(spec1Priv->dependencySpecs.size(), 2); + QVERIFY(spec1Priv->dependencySpecs.contains(spec2)); + QVERIFY(spec1Priv->dependencySpecs.contains(spec3)); + QCOMPARE(spec1Priv->state, PluginSpec::Resolved); + QVERIFY(!spec4Priv->resolveDependencies(specs)); + QVERIFY(spec4Priv->hasError); + QCOMPARE(spec4Priv->state, PluginSpec::Read); +} + +void tst_PluginSpec::loadLibrary() +{ + PluginSpec *ps = Internal::PluginManagerPrivate::createSpec(); + Internal::PluginSpecPrivate *spec = Internal::PluginManagerPrivate::privateSpec(ps); + PluginManager *manager = new PluginManager(); + QVERIFY(spec->read("testplugin/testplugin.xml")); + QVERIFY(spec->resolveDependencies(QSet<PluginSpec *>())); + QVERIFY(spec->loadLibrary()); + QVERIFY(qobject_cast<MyPlugin::MyPluginImpl*>(spec->plugin) != 0); + QCOMPARE(spec->state, PluginSpec::Loaded); + QVERIFY(!spec->hasError); + QCOMPARE(spec->plugin->pluginSpec(), ps); + delete manager; + delete ps; +} + +void tst_PluginSpec::initializePlugin() +{ + Internal::PluginSpecPrivate spec(0); + MyPlugin::MyPluginImpl *impl; + QVERIFY(spec.read("testplugin/testplugin.xml")); + QVERIFY(spec.resolveDependencies(QSet<PluginSpec *>())); + QVERIFY(spec.loadLibrary()); + impl = qobject_cast<MyPlugin::MyPluginImpl*>(spec.plugin); + QVERIFY(impl != 0); + QVERIFY(!impl->isInitialized()); + QVERIFY(spec.initializePlugin()); + QCOMPARE(spec.state, PluginSpec::Initialized); + QVERIFY(!spec.hasError); + QVERIFY(impl->isInitialized()); +} + +void tst_PluginSpec::initializeExtensions() +{ + Internal::PluginSpecPrivate spec(0); + MyPlugin::MyPluginImpl *impl; + QVERIFY(spec.read("testplugin/testplugin.xml")); + QVERIFY(spec.resolveDependencies(QSet<PluginSpec *>())); + QVERIFY(spec.loadLibrary()); + impl = qobject_cast<MyPlugin::MyPluginImpl*>(spec.plugin); + QVERIFY(impl != 0); + QVERIFY(spec.initializePlugin()); + QVERIFY(spec.initializeExtensions()); + QCOMPARE(spec.state, PluginSpec::Running); + QVERIFY(!spec.hasError); + QVERIFY(impl->isExtensionsInitialized()); +} + +QTEST_MAIN(tst_PluginSpec) +#include "tst_pluginspec.moc" diff --git a/src/libs/extensionsystem/test/extensionsystem_test.pri b/src/libs/extensionsystem/test/extensionsystem_test.pri new file mode 100644 index 00000000000..6ad874add3e --- /dev/null +++ b/src/libs/extensionsystem/test/extensionsystem_test.pri @@ -0,0 +1,12 @@ + +INCLUDEPATH *= $$PWD/../.. +macx { + LIBPATH*= $$PWD/../../../../bin/QtCreator.app/Contents/PlugIns +} +else { + LIBPATH*= $$PWD/../../../../lib +} + +include(../extensionsystem.pri) + +QT *= xml diff --git a/src/libs/extensionsystem/test/manual/manual.pro b/src/libs/extensionsystem/test/manual/manual.pro new file mode 100644 index 00000000000..829f2fce579 --- /dev/null +++ b/src/libs/extensionsystem/test/manual/manual.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +SUBDIRS = pluginview + diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugindialog.cpp b/src/libs/extensionsystem/test/manual/pluginview/plugindialog.cpp new file mode 100644 index 00000000000..3282d9862e7 --- /dev/null +++ b/src/libs/extensionsystem/test/manual/pluginview/plugindialog.cpp @@ -0,0 +1,142 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "plugindialog.h" +#include <extensionsystem/plugindetailsview.h> +#include <extensionsystem/pluginerrorview.h> +#include <extensionsystem/pluginspec.h> + +#include <QtGui/QVBoxLayout> +#include <QtGui/QHBoxLayout> +#include <QtGui/QDialog> +#include <QtGui/QDialogButtonBox> +#include <QtGui/QApplication> +#include <QtDebug> + +PluginDialog::PluginDialog(ExtensionSystem::PluginManager *manager) + : m_view(new ExtensionSystem::PluginView(manager, this)) +{ + QVBoxLayout *vl = new QVBoxLayout(this); + vl->setMargin(0); + vl->setSpacing(0); + vl->addWidget(m_view); + + QHBoxLayout *hl = new QHBoxLayout; + vl->addLayout(hl); + hl->setMargin(0); + hl->setSpacing(6); + m_detailsButton = new QPushButton(tr("Details"), this); + m_errorDetailsButton = new QPushButton(tr("Error Details"), this); + m_detailsButton->setEnabled(false); + m_errorDetailsButton->setEnabled(false); + hl->addWidget(m_detailsButton); + hl->addWidget(m_errorDetailsButton); + hl->addStretch(5); + resize(650, 300); + setWindowTitle(tr("Installed Plugins")); + + connect(m_view, SIGNAL(currentPluginChanged(ExtensionSystem::PluginSpec*)), + this, SLOT(updateButtons())); + connect(m_view, SIGNAL(pluginActivated(ExtensionSystem::PluginSpec*)), + this, SLOT(openDetails(ExtensionSystem::PluginSpec*))); + connect(m_detailsButton, SIGNAL(clicked()), this, SLOT(openDetails())); + connect(m_errorDetailsButton, SIGNAL(clicked()), this, SLOT(openErrorDetails())); +} + +void PluginDialog::updateButtons() +{ + ExtensionSystem::PluginSpec *selectedSpec = m_view->currentPlugin(); + if (selectedSpec) { + m_detailsButton->setEnabled(true); + m_errorDetailsButton->setEnabled(selectedSpec->hasError()); + } else { + m_detailsButton->setEnabled(false); + m_errorDetailsButton->setEnabled(false); + } +} + + +void PluginDialog::openDetails() +{ + openDetails(m_view->currentPlugin()); +} + +void PluginDialog::openDetails(ExtensionSystem::PluginSpec *spec) +{ + if (!spec) + return; + QDialog dialog(this); + dialog.setWindowTitle(tr("Plugin Details of %1").arg(spec->name())); + QVBoxLayout *layout = new QVBoxLayout; + dialog.setLayout(layout); + ExtensionSystem::PluginDetailsView *details = new ExtensionSystem::PluginDetailsView(&dialog); + layout->addWidget(details); + details->update(spec); + QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Close, Qt::Horizontal, &dialog); + layout->addWidget(buttons); + connect(buttons, SIGNAL(accepted()), &dialog, SLOT(accept())); + connect(buttons, SIGNAL(rejected()), &dialog, SLOT(reject())); + dialog.resize(400, 500); + dialog.exec(); +} + +void PluginDialog::openErrorDetails() +{ + ExtensionSystem::PluginSpec *spec = m_view->currentPlugin(); + if (!spec) + return; + QDialog dialog(this); + dialog.setWindowTitle(tr("Plugin Errors of %1").arg(spec->name())); + QVBoxLayout *layout = new QVBoxLayout; + dialog.setLayout(layout); + ExtensionSystem::PluginErrorView *errors = new ExtensionSystem::PluginErrorView(&dialog); + layout->addWidget(errors); + errors->update(spec); + QDialogButtonBox *buttons = new QDialogButtonBox(QDialogButtonBox::Close, Qt::Horizontal, &dialog); + layout->addWidget(buttons); + connect(buttons, SIGNAL(accepted()), &dialog, SLOT(accept())); + connect(buttons, SIGNAL(rejected()), &dialog, SLOT(reject())); + dialog.resize(500, 300); + dialog.exec(); +} + +int main(int argc, char *argv[]) +{ + ExtensionSystem::PluginManager manager; + QApplication app(argc, argv); + PluginDialog dialog(&manager); + manager.setPluginPaths(QStringList() << "plugins"); + manager.loadPlugins(); + dialog.show(); + app.exec(); +} + diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugindialog.h b/src/libs/extensionsystem/test/manual/pluginview/plugindialog.h new file mode 100644 index 00000000000..8987230681a --- /dev/null +++ b/src/libs/extensionsystem/test/manual/pluginview/plugindialog.h @@ -0,0 +1,61 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef PLUGINDIALOG_H +#define PLUGINDIALOG_H + +#include <extensionsystem/pluginview.h> +#include <extensionsystem/pluginmanager.h> +#include <QtGui/QWidget> +#include <QtGui/QPushButton> + +class PluginDialog : public QWidget +{ + Q_OBJECT + +public: + PluginDialog(ExtensionSystem::PluginManager *manager); + +private slots: + void updateButtons(); + void openDetails(); + void openDetails(ExtensionSystem::PluginSpec *spec); + void openErrorDetails(); + +private: + ExtensionSystem::PluginView *m_view; + + QPushButton *m_detailsButton; + QPushButton *m_errorDetailsButton; +}; + +#endif diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin.xml b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin.xml new file mode 100644 index 00000000000..63faecdf52d --- /dev/null +++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin.xml @@ -0,0 +1,18 @@ +<plugin name="plugin1" version="2.1.0" compatVersion="1.0.0"> + <vendor>Blablubb Corp</vendor> + <copyright>(C) 2023 Blubb</copyright> + <license> +This is a default license bla +blubbblubb +end of terms + </license> + <description> +This plugin is just a test. + it demonstrates the great use of the plugin spec. + </description> + <url>http://www.blablubb-corp.com/greatplugin</url> + <dependencyList> + <dependency name="plugin2" version="1.0.0"/> + <dependency name="plugin3" version="1.0.0"/> + </dependencyList> +</plugin> diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin1.cpp b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin1.cpp new file mode 100644 index 00000000000..32d3bdf0701 --- /dev/null +++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin1.cpp @@ -0,0 +1,86 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "plugin1.h" + +#include <extensionsystem/pluginmanager.h> + +#include <QtCore/qplugin.h> +#include <QtCore/QObject> + +using namespace Plugin1; + +MyPlugin1::MyPlugin1() + : initializeCalled(false) +{ +} + +bool MyPlugin1::initialize(const QStringList & /*arguments*/, QString *errorString) +{ + initializeCalled = true; + QObject *obj = new QObject(this); + obj->setObjectName("MyPlugin1"); + addAutoReleasedObject(obj); + + bool found2 = false; + bool found3 = false; + foreach (QObject *object, ExtensionSystem::PluginManager::instance()->allObjects()) { + if (object->objectName() == "MyPlugin2") + found2 = true; + else if (object->objectName() == "MyPlugin3") + found3 = true; + } + if (found2 && found3) + return true; + if (errorString) { + QString error = "object(s) missing from plugin(s):"; + if (!found2) + error.append(" plugin2"); + if (!found3) + error.append(" plugin3"); + *errorString = error; + } + return false; +} + +void MyPlugin1::extensionsInitialized() +{ + if (!initializeCalled) + return; + // don't do this at home, it's just done here for the test + QObject *obj = new QObject(this); + obj->setObjectName("MyPlugin1_running"); + addAutoReleasedObject(obj); +} + +Q_EXPORT_PLUGIN(MyPlugin1) + diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin1.h b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin1.h new file mode 100644 index 00000000000..f993b25c9f2 --- /dev/null +++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin1.h @@ -0,0 +1,59 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef PLUGIN1_H +#define PLUGIN1_H + +#include <extensionsystem/iplugin.h> + +#include <QtCore/QObject> +#include <QtCore/QString> + +namespace Plugin1 { + +class MyPlugin1 : public ExtensionSystem::IPlugin +{ + Q_OBJECT + +public: + MyPlugin1(); + + bool initialize(const QStringList &arguments, QString *errorString); + void extensionsInitialized(); + +private: + bool initializeCalled; +}; + +} // namespace + +#endif // header guard diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin1.pro b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin1.pro new file mode 100644 index 00000000000..9101770f9ac --- /dev/null +++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin1.pro @@ -0,0 +1,15 @@ +TEMPLATE = lib +TARGET = plugin1 + +SOURCES += plugin1.cpp +HEADERS += plugin1.h + +include(../../../../extensionsystem_test.pri) + +LIBS += -L$${PWD}/../plugin2 -L$${PWD}/../plugin3 -lplugin2 -lplugin3 + +macx { +} else:unix { + QMAKE_RPATHDIR += $${PWD}/../plugin2 + QMAKE_RPATHDIR += $${PWD}/../plugin3 +} diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin.xml b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin.xml new file mode 100644 index 00000000000..1a230ad38d9 --- /dev/null +++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin.xml @@ -0,0 +1,4 @@ +<plugin name="plugin2" version="1.0.0" compatVersion="1.0.0"> + <vendor>1 < 2 GmbH</vendor> + <url>http://www.somewhereintheweb.com/dodo.php?q=p</url> +</plugin> diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin2.cpp b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin2.cpp new file mode 100644 index 00000000000..3ce6f258fa8 --- /dev/null +++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin2.cpp @@ -0,0 +1,69 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "plugin2.h" + +#include <extensionsystem/pluginmanager.h> + +#include <QtCore/qplugin.h> +#include <QtCore/QObject> + +using namespace Plugin2; + +MyPlugin2::MyPlugin2() + : initializeCalled(false) +{ +} + +bool MyPlugin2::initialize(const QStringList & /*arguments*/, QString *errorString) +{ + Q_UNUSED(errorString); + initializeCalled = true; + QObject *obj = new QObject(this); + obj->setObjectName("MyPlugin2"); + addAutoReleasedObject(obj); + + return true; +} + +void MyPlugin2::extensionsInitialized() +{ + if (!initializeCalled) + return; + // don't do this at home, it's just done here for the test + QObject *obj = new QObject(this); + obj->setObjectName("MyPlugin2_running"); + addAutoReleasedObject(obj); +} + +Q_EXPORT_PLUGIN(MyPlugin2) + diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin2.h b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin2.h new file mode 100644 index 00000000000..51200387546 --- /dev/null +++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin2.h @@ -0,0 +1,59 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef PLUGIN2_H +#define PLUGIN2_H + +#include <extensionsystem/iplugin.h> + +#include <QtCore/QObject> +#include <QtCore/QString> + +namespace Plugin2 { + +class MyPlugin2 : public ExtensionSystem::IPlugin +{ + Q_OBJECT + +public: + MyPlugin2(); + + bool initialize(const QStringList &arguments, QString *errorString); + void extensionsInitialized(); + +private: + bool initializeCalled; +}; + +} // namespace + +#endif // header guard diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin2.pro b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin2.pro new file mode 100644 index 00000000000..a80f4a5c765 --- /dev/null +++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin2.pro @@ -0,0 +1,12 @@ +TEMPLATE = lib +TARGET = plugin2 + +SOURCES += plugin2.cpp +HEADERS += plugin2.h + +include(../../../../extensionsystem_test.pri) + +macx { + QMAKE_LFLAGS_SONAME = -Wl,-install_name,$${PWD}/ +} + diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin.xml b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin.xml new file mode 100644 index 00000000000..fd2279824e2 --- /dev/null +++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin.xml @@ -0,0 +1,6 @@ +<plugin name="plugin3" version="1.0.0" compatVersion="1.0.0"> + <vendor>Günöl AG</vendor> + <dependencyList> + <dependency name="plugin2" version="1.0.0"/> + </dependencyList> +</plugin> diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin3.cpp b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin3.cpp new file mode 100644 index 00000000000..ff37d06096d --- /dev/null +++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin3.cpp @@ -0,0 +1,77 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#include "plugin3.h" + +#include <extensionsystem/pluginmanager.h> + +#include <QtCore/qplugin.h> +#include <QtCore/QObject> + +using namespace Plugin3; + +MyPlugin3::MyPlugin3() + : initializeCalled(false) +{ +} + +bool MyPlugin3::initialize(const QStringList & /*arguments*/, QString *errorString) +{ + initializeCalled = true; + QObject *obj = new QObject(this); + obj->setObjectName("MyPlugin3"); + addAutoReleasedObject(obj); + + bool found2 = false; + foreach (QObject *object, ExtensionSystem::PluginManager::instance()->allObjects()) { + if (object->objectName() == "MyPlugin2") + found2 = true; + } + if (found2) + return true; + if (errorString) + *errorString = "object from plugin2 could not be found"; + return false; +} + +void MyPlugin3::extensionsInitialized() +{ + if (!initializeCalled) + return; + // don't do this at home, it's just done here for the test + QObject *obj = new QObject(this); + obj->setObjectName("MyPlugin3_running"); + addAutoReleasedObject(obj); +} + +Q_EXPORT_PLUGIN(MyPlugin3) + diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin3.h b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin3.h new file mode 100644 index 00000000000..00bd6429125 --- /dev/null +++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin3.h @@ -0,0 +1,59 @@ +/*************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Qt Software Information ([email protected]) +** +** +** Non-Open Source Usage +** +** Licensees may use this file in accordance with the Qt Beta Version +** License Agreement, Agreement version 2.2 provided with the Software or, +** alternatively, in accordance with the terms contained in a written +** agreement between you and Nokia. +** +** GNU General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the packaging +** of this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt GPL Exception version +** 1.2, included in the file GPL_EXCEPTION.txt in this package. +** +***************************************************************************/ +#ifndef PLUGIN3_H +#define PLUGIN3_H + +#include <extensionsystem/iplugin.h> + +#include <QtCore/QObject> +#include <QtCore/QString> + +namespace Plugin3 { + +class MyPlugin3 : public ExtensionSystem::IPlugin +{ + Q_OBJECT + +public: + MyPlugin3(); + + bool initialize(const QStringList &arguments, QString *errorString); + void extensionsInitialized(); + +private: + bool initializeCalled; +}; + +} // namespace + +#endif // header guard diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin3.pro b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin3.pro new file mode 100644 index 00000000000..c5ff581b1ba --- /dev/null +++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin3.pro @@ -0,0 +1,15 @@ +TEMPLATE = lib +TARGET = plugin3 + +SOURCES += plugin3.cpp +HEADERS += plugin3.h + +include(../../../../extensionsystem_test.pri) + +LIBS += -L$${PWD}/../plugin2 -lplugin2 + +macx { + QMAKE_LFLAGS_SONAME = -Wl,-install_name,$${PWD}/ +} else:unix { + QMAKE_RPATHDIR += $${PWD}/../plugin2 +} diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin4/plugin.xml b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin4/plugin.xml new file mode 100644 index 00000000000..61f37bd706c --- /dev/null +++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugin4/plugin.xml @@ -0,0 +1,5 @@ +<plugin name="plugin4" version="1.0.0" compatVersion="1.0.0"> + <dependencyList> + <dependency name="plugin2" version="1.0.0"/> + </dependencyList> +</plugin> diff --git a/src/libs/extensionsystem/test/manual/pluginview/plugins/plugins.pro b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugins.pro new file mode 100644 index 00000000000..f0d76950e86 --- /dev/null +++ b/src/libs/extensionsystem/test/manual/pluginview/plugins/plugins.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +CONFIG += ordered +SUBDIRS = plugin2 plugin3 plugin1 diff --git a/src/libs/extensionsystem/test/manual/pluginview/pluginview.pro b/src/libs/extensionsystem/test/manual/pluginview/pluginview.pro new file mode 100644 index 00000000000..8527b82c47c --- /dev/null +++ b/src/libs/extensionsystem/test/manual/pluginview/pluginview.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +SUBDIRS = test.pro \ + plugins diff --git a/src/libs/extensionsystem/test/manual/pluginview/test.pro b/src/libs/extensionsystem/test/manual/pluginview/test.pro new file mode 100644 index 00000000000..4b9cd21d8ad --- /dev/null +++ b/src/libs/extensionsystem/test/manual/pluginview/test.pro @@ -0,0 +1,9 @@ +TEMPLATE = app + +macx:CONFIG-=app_bundle + +# Input +HEADERS += plugindialog.h +SOURCES += plugindialog.cpp + +include(../../extensionsystem_test.pri) diff --git a/src/libs/extensionsystem/test/manual/pluginview/test.sh b/src/libs/extensionsystem/test/manual/pluginview/test.sh new file mode 100755 index 00000000000..426901ea74d --- /dev/null +++ b/src/libs/extensionsystem/test/manual/pluginview/test.sh @@ -0,0 +1,5 @@ +# -- run the plugin test from this directory. + +export LD_LIBRARY_PATH=../../../../../../lib:$LD_LIBRARY_PATH +export DYLD_LIBRARY_PATH=../../../../../../bin/QtCreator.app/Contents/PlugIns:$DYLD_LIBRARY_PATH # mac +exec ./test diff --git a/src/libs/extensionsystem/test/test.pro b/src/libs/extensionsystem/test/test.pro new file mode 100644 index 00000000000..471ea892f1f --- /dev/null +++ b/src/libs/extensionsystem/test/test.pro @@ -0,0 +1,4 @@ +TEMPLATE = subdirs + +SUBDIRS = auto manual + |