aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/extensionsystem
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/extensionsystem')
-rw-r--r--src/libs/extensionsystem/ExtensionSystemInterfaces6
-rw-r--r--src/libs/extensionsystem/extensionsystem.pri3
-rw-r--r--src/libs/extensionsystem/extensionsystem.pro32
-rw-r--r--src/libs/extensionsystem/extensionsystem_dependencies.pri1
-rw-r--r--src/libs/extensionsystem/extensionsystem_global.h44
-rw-r--r--src/libs/extensionsystem/images/error.pngbin0 -> 111 bytes
-rw-r--r--src/libs/extensionsystem/images/ok.pngbin0 -> 103 bytes
-rw-r--r--src/libs/extensionsystem/iplugin.cpp325
-rw-r--r--src/libs/extensionsystem/iplugin.h76
-rw-r--r--src/libs/extensionsystem/iplugin_p.h58
-rw-r--r--src/libs/extensionsystem/optionsparser.cpp192
-rw-r--r--src/libs/extensionsystem/optionsparser.h87
-rw-r--r--src/libs/extensionsystem/plugindetailsview.cpp89
-rw-r--r--src/libs/extensionsystem/plugindetailsview.h67
-rw-r--r--src/libs/extensionsystem/plugindetailsview.ui258
-rw-r--r--src/libs/extensionsystem/pluginerrorview.cpp114
-rw-r--r--src/libs/extensionsystem/pluginerrorview.h66
-rw-r--r--src/libs/extensionsystem/pluginerrorview.ui77
-rw-r--r--src/libs/extensionsystem/pluginmanager.cpp749
-rw-r--r--src/libs/extensionsystem/pluginmanager.h138
-rw-r--r--src/libs/extensionsystem/pluginmanager_p.h96
-rw-r--r--src/libs/extensionsystem/pluginspec.cpp871
-rw-r--r--src/libs/extensionsystem/pluginspec.h120
-rw-r--r--src/libs/extensionsystem/pluginspec_p.h106
-rw-r--r--src/libs/extensionsystem/pluginview.cpp159
-rw-r--r--src/libs/extensionsystem/pluginview.h82
-rw-r--r--src/libs/extensionsystem/pluginview.qrc6
-rw-r--r--src/libs/extensionsystem/pluginview.ui74
-rw-r--r--src/libs/extensionsystem/pluginview_p.h51
-rw-r--r--src/libs/extensionsystem/test/auto/auto.pro3
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/circularplugins.pro2
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin.xml6
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin1.cpp53
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin1.h55
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin1/plugin1.pro8
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin.xml2
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin2.cpp53
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin2.h55
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin2/plugin2.pro8
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin.xml5
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin3.cpp53
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin3.h55
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/circularplugins/plugin3/plugin3.pro8
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/correctplugins1.pro3
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin.spec6
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin1.cpp86
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin1.h58
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin1/plugin1.pro15
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin.spec2
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin2.cpp68
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin2.h58
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin2/plugin2.pro12
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin.spec5
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin3.cpp77
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin3.h58
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/correctplugins1/plugin3/plugin3.pro15
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/pluginmanager.pro6
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/plugins/myplug/myplug.xml2
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/plugins/otherplugin.xml2
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/plugins/plugin1.xml2
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/test.pro14
-rwxr-xr-xsrc/libs/extensionsystem/test/auto/pluginmanager/test.sh5
-rw-r--r--src/libs/extensionsystem/test/auto/pluginmanager/tst_pluginmanager.cpp267
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/pluginspec.pro4
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/test.pro14
-rwxr-xr-xsrc/libs/extensionsystem/test/auto/pluginspec/test.sh5
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec1.xml6
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec2.xml2
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec3.xml2
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec4.xml5
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testdependencies/spec5.xml2
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testdir/spec.xml2
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.cpp56
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.h62
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.pro13
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin.xml2
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testplugin/testplugin_global.h44
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testspecs/simplespec.xml2
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec1.xml18
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec2.xml2
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong1.xml18
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong2.xml18
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong3.xml18
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong4.xml18
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/testspecs/spec_wrong5.xml18
-rw-r--r--src/libs/extensionsystem/test/auto/pluginspec/tst_pluginspec.cpp278
-rw-r--r--src/libs/extensionsystem/test/extensionsystem_test.pri12
-rw-r--r--src/libs/extensionsystem/test/manual/manual.pro3
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugindialog.cpp142
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugindialog.h61
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin.xml18
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin1.cpp86
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin1.h59
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugin1/plugin1.pro15
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin.xml4
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin2.cpp69
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin2.h59
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugin2/plugin2.pro12
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin.xml6
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin3.cpp77
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin3.h59
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugin3/plugin3.pro15
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugin4/plugin.xml5
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/plugins/plugins.pro3
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/pluginview.pro3
-rw-r--r--src/libs/extensionsystem/test/manual/pluginview/test.pro9
-rwxr-xr-xsrc/libs/extensionsystem/test/manual/pluginview/test.sh5
-rw-r--r--src/libs/extensionsystem/test/test.pro4
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
new file mode 100644
index 00000000000..e2f85d98eb6
--- /dev/null
+++ b/src/libs/extensionsystem/images/error.png
Binary files differ
diff --git a/src/libs/extensionsystem/images/ok.png b/src/libs/extensionsystem/images/ok.png
new file mode 100644
index 00000000000..15cd35d27ba
--- /dev/null
+++ b/src/libs/extensionsystem/images/ok.png
Binary files differ
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 &lt; 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
+