summaryrefslogtreecommitdiff
path: root/src/libs
diff options
context:
space:
mode:
authorcon <qtc-commiter@nokia.com>2008-12-02 12:01:29 +0100
committercon <qtc-commiter@nokia.com>2008-12-02 12:01:29 +0100
commit05c35356abc31549c5db6eba31fb608c0365c2a0 (patch)
treebe044530104267afaff13f8943889cb97f8c8bad /src/libs
downloadqt-creator-05c35356abc31549c5db6eba31fb608c0365c2a0.tar.gz
Initial import
Diffstat (limited to 'src/libs')
-rw-r--r--src/libs/aggregation/aggregate.cpp265
-rw-r--r--src/libs/aggregation/aggregate.h134
-rw-r--r--src/libs/aggregation/aggregation.pri1
-rw-r--r--src/libs/aggregation/aggregation.pro12
-rw-r--r--src/libs/aggregation/aggregation_global.h44
-rw-r--r--src/libs/aggregation/examples/examples.pro3
-rw-r--r--src/libs/aggregation/examples/text/main.cpp110
-rw-r--r--src/libs/aggregation/examples/text/main.h62
-rw-r--r--src/libs/aggregation/examples/text/main.ui128
-rw-r--r--src/libs/aggregation/examples/text/myinterfaces.h87
-rw-r--r--src/libs/aggregation/examples/text/text.pro14
-rw-r--r--src/libs/aggregation/test/test.pro12
-rw-r--r--src/libs/aggregation/test/tst_aggregate.cpp198
-rw-r--r--src/libs/cplusplus/CppDocument.cpp242
-rw-r--r--src/libs/cplusplus/CppDocument.h187
-rw-r--r--src/libs/cplusplus/ExpressionUnderCursor.cpp242
-rw-r--r--src/libs/cplusplus/ExpressionUnderCursor.h68
-rw-r--r--src/libs/cplusplus/Icons.cpp122
-rw-r--r--src/libs/cplusplus/Icons.h75
-rw-r--r--src/libs/cplusplus/LookupContext.cpp402
-rw-r--r--src/libs/cplusplus/LookupContext.h151
-rw-r--r--src/libs/cplusplus/NameOfExpression.cpp438
-rw-r--r--src/libs/cplusplus/NameOfExpression.h99
-rw-r--r--src/libs/cplusplus/NamePrettyPrinter.cpp255
-rw-r--r--src/libs/cplusplus/NamePrettyPrinter.h69
-rw-r--r--src/libs/cplusplus/Overview.cpp91
-rw-r--r--src/libs/cplusplus/Overview.h80
-rw-r--r--src/libs/cplusplus/OverviewModel.cpp183
-rw-r--r--src/libs/cplusplus/OverviewModel.h84
-rw-r--r--src/libs/cplusplus/ResolveExpression.cpp793
-rw-r--r--src/libs/cplusplus/ResolveExpression.h131
-rw-r--r--src/libs/cplusplus/SimpleLexer.cpp117
-rw-r--r--src/libs/cplusplus/SimpleLexer.h106
-rw-r--r--src/libs/cplusplus/TokenUnderCursor.cpp75
-rw-r--r--src/libs/cplusplus/TokenUnderCursor.h63
-rw-r--r--src/libs/cplusplus/TypeOfExpression.cpp114
-rw-r--r--src/libs/cplusplus/TypeOfExpression.h98
-rw-r--r--src/libs/cplusplus/TypePrettyPrinter.cpp309
-rw-r--r--src/libs/cplusplus/TypePrettyPrinter.h101
-rw-r--r--src/libs/cplusplus/cplusplus.pri3
-rw-r--r--src/libs/cplusplus/cplusplus.pro40
-rw-r--r--src/libs/cplusplus/cplusplus.qrc20
-rw-r--r--src/libs/cplusplus/images/class.pngbin0 -> 573 bytes
-rw-r--r--src/libs/cplusplus/images/enum.pngbin0 -> 359 bytes
-rw-r--r--src/libs/cplusplus/images/enumerator.pngbin0 -> 478 bytes
-rw-r--r--src/libs/cplusplus/images/func.pngbin0 -> 583 bytes
-rw-r--r--src/libs/cplusplus/images/func_priv.pngbin0 -> 656 bytes
-rw-r--r--src/libs/cplusplus/images/func_prot.pngbin0 -> 647 bytes
-rw-r--r--src/libs/cplusplus/images/keyword.pngbin0 -> 341 bytes
-rw-r--r--src/libs/cplusplus/images/macro.pngbin0 -> 505 bytes
-rw-r--r--src/libs/cplusplus/images/namespace.pngbin0 -> 377 bytes
-rw-r--r--src/libs/cplusplus/images/signal.pngbin0 -> 558 bytes
-rw-r--r--src/libs/cplusplus/images/slot.pngbin0 -> 646 bytes
-rw-r--r--src/libs/cplusplus/images/slot_priv.pngbin0 -> 709 bytes
-rw-r--r--src/libs/cplusplus/images/slot_prot.pngbin0 -> 681 bytes
-rw-r--r--src/libs/cplusplus/images/var.pngbin0 -> 530 bytes
-rw-r--r--src/libs/cplusplus/images/var_priv.pngbin0 -> 632 bytes
-rw-r--r--src/libs/cplusplus/images/var_prot.pngbin0 -> 619 bytes
-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
-rw-r--r--src/libs/libs.pro9
-rw-r--r--src/libs/qtconcurrent/QtConcurrentTools2
-rw-r--r--src/libs/qtconcurrent/multitask.h198
-rw-r--r--src/libs/qtconcurrent/qtconcurrent.pri1
-rw-r--r--src/libs/qtconcurrent/qtconcurrent.pro10
-rw-r--r--src/libs/qtconcurrent/qtconcurrent_global.h44
-rw-r--r--src/libs/qtconcurrent/runextensions.h397
-rw-r--r--src/libs/utils/basevalidatinglineedit.cpp157
-rw-r--r--src/libs/utils/basevalidatinglineedit.h100
-rw-r--r--src/libs/utils/classnamevalidatinglineedit.cpp137
-rw-r--r--src/libs/utils/classnamevalidatinglineedit.h79
-rw-r--r--src/libs/utils/codegeneration.cpp89
-rw-r--r--src/libs/utils/codegeneration.h70
-rw-r--r--src/libs/utils/fancylineedit.cpp317
-rw-r--r--src/libs/utils/fancylineedit.h115
-rw-r--r--src/libs/utils/filenamevalidatinglineedit.cpp97
-rw-r--r--src/libs/utils/filenamevalidatinglineedit.h56
-rw-r--r--src/libs/utils/filesearch.cpp216
-rw-r--r--src/libs/utils/filesearch.h69
-rw-r--r--src/libs/utils/filewizarddialog.cpp73
-rw-r--r--src/libs/utils/filewizarddialog.h69
-rw-r--r--src/libs/utils/filewizardpage.cpp129
-rw-r--r--src/libs/utils/filewizardpage.h86
-rw-r--r--src/libs/utils/filewizardpage.ui83
-rw-r--r--src/libs/utils/linecolumnlabel.cpp69
-rw-r--r--src/libs/utils/linecolumnlabel.h68
-rw-r--r--src/libs/utils/listutils.h54
-rw-r--r--src/libs/utils/newclasswidget.cpp462
-rw-r--r--src/libs/utils/newclasswidget.h150
-rw-r--r--src/libs/utils/newclasswidget.ui150
-rw-r--r--src/libs/utils/pathchooser.cpp185
-rw-r--r--src/libs/utils/pathchooser.h90
-rw-r--r--src/libs/utils/projectintropage.cpp215
-rw-r--r--src/libs/utils/projectintropage.h107
-rw-r--r--src/libs/utils/projectintropage.ui122
-rw-r--r--src/libs/utils/projectnamevalidatinglineedit.cpp66
-rw-r--r--src/libs/utils/projectnamevalidatinglineedit.h56
-rw-r--r--src/libs/utils/qtcolorbutton.cpp290
-rw-r--r--src/libs/utils/qtcolorbutton.h84
-rw-r--r--src/libs/utils/reloadpromptutils.cpp62
-rw-r--r--src/libs/utils/reloadpromptutils.h54
-rw-r--r--src/libs/utils/settingsutils.cpp53
-rw-r--r--src/libs/utils/settingsutils.h48
-rw-r--r--src/libs/utils/submiteditorwidget.cpp305
-rw-r--r--src/libs/utils/submiteditorwidget.h122
-rw-r--r--src/libs/utils/submiteditorwidget.ui59
-rw-r--r--src/libs/utils/synchronousprocess.cpp356
-rw-r--r--src/libs/utils/synchronousprocess.h139
-rw-r--r--src/libs/utils/utils.pri1
-rw-r--r--src/libs/utils/utils.pro53
-rw-r--r--src/libs/utils/utils_global.h57
217 files changed, 18317 insertions, 0 deletions
diff --git a/src/libs/aggregation/aggregate.cpp b/src/libs/aggregation/aggregate.cpp
new file mode 100644
index 0000000000..bfd9e0f4dc
--- /dev/null
+++ b/src/libs/aggregation/aggregate.cpp
@@ -0,0 +1,265 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "aggregate.h"
+
+#include <QtCore/QWriteLocker>
+
+/*!
+ \namespace Aggregation
+ \brief Contains support for bundling related components, such that
+ each component exposes the properties and behavior of the
+ other components to the outside.
+
+ Components that are bundled to an Aggregate can be "cast" to each other
+ and have a coupled life cycle. See the documentation of Aggregate for
+ details and examples.
+*/
+
+/*!
+ \class Aggregation::Aggregate
+ \mainclass
+ \threadsafe
+
+ \brief Defines a collection of related components that can be viewed as a unit.
+
+ An Aggregate is a collection of components that are handled as a unit,
+ such that each component exposes the properties and behavior of the
+ other components in the Aggregate to the outside.
+ Specifically that means:
+ \list
+ \o They can be "cast" to each other (using query and query_all methods).
+ \o Their life cycle is coupled, i.e. whenever one is deleted all of them are.
+ \endlist
+ Components can be of any QObject derived type.
+
+ You can use an Aggregate to simulate multiple inheritance by aggregation. Assume we have
+ \code
+ using namespace Aggregation;
+ class MyInterface : public QObject { ........ };
+ class MyInterfaceEx : public QObject { ........ };
+ [...]
+ MyInterface *object = new MyInterface; // this is single inheritance
+ \endcode
+ The query method works like a qobject_cast with normal objects:
+ \code
+ Q_ASSERT(query<MyInterface>(object) == object);
+ Q_ASSERT(query<MyInterfaceEx>(object) == 0);
+ \endcode
+ If we want 'object' to also implement the class MyInterfaceEx,
+ but don't want to or cannot use multiple inheritance, we can do it
+ at any point using an Aggregate:
+ \code
+ MyInterfaceEx *objectEx = new MyInterfaceEx;
+ Aggregate *aggregate = new Aggregate;
+ aggregate->add(object);
+ aggregate->add(objectEx);
+ \endcode
+ The Aggregate bundles the two objects together.
+ If we have any part of the collection we get all parts:
+ \code
+ Q_ASSERT(query<MyInterface>(object) == object);
+ Q_ASSERT(query<MyInterfaceEx>(object) == objectEx);
+ Q_ASSERT(query<MyInterface>(objectEx) == object);
+ Q_ASSERT(query<MyInterfaceEx>(objectEx) == objectEx);
+ \endcode
+ The following deletes all three: object, objectEx and aggregate:
+ \code
+ delete objectEx;
+ // or delete object;
+ // or delete aggregate;
+ \endcode
+
+ Aggregation aware code never uses qobject_cast, but always uses
+ Aggregation::query which behaves like a qobject_cast as a fallback.
+*/
+
+/*!
+ \fn T *Aggregate::component()
+
+ Template method that returns the component with the given type, if there is one.
+ If there are multiple components with that type a random one is returned.
+
+ \sa Aggregate::components()
+ \sa Aggregate::add()
+*/
+
+/*!
+ \fn QList<T *> Aggregate::components()
+
+ Template method that returns all components with the given type, if there are any.
+
+ \sa Aggregate::component()
+ \sa Aggregate::add()
+*/
+
+/*!
+ \fn T *Aggregation::query<T *>(Aggregate *obj)
+ \internal
+*/
+
+/*!
+ \fn QList<T *> Aggregation::query_all<T *>(Aggregate *obj)
+ \internal
+*/
+
+/*!
+ \relates Aggregation::Aggregate
+ \fn T *Aggregation::query<T *>(QObject *obj)
+
+ Performs a dynamic cast that is aware of a possible Aggregate that \a obj
+ might belong to. If \a obj itself is of the requested type then it is simply cast
+ and returned. Otherwise, if \a obj belongs to an Aggregate all its components are
+ checked, or if it doesn't belong to an Aggregate null is returned.
+
+ \sa Aggregate::component()
+*/
+
+/*!
+ \relates Aggregation::Aggregate
+ \fn QList<T *> Aggregation::query_all<T *>(QObject *obj)
+
+ If \a obj belongs to an Aggregate, all components that can be cast to the given
+ type are returned. Otherwise, \a obj is returned if it is of the requested type.
+
+ \sa Aggregate::components()
+*/
+
+using namespace Aggregation;
+
+/*!
+ \fn Aggregate *Aggregate::parentAggregate(QObject *obj)
+
+ Returns the Aggregate object of \a obj if there is one. Otherwise returns 0.
+*/
+Aggregate *Aggregate::parentAggregate(QObject *obj)
+{
+ QReadLocker locker(&lock());
+ return aggregateMap().value(obj);
+}
+
+QHash<QObject *, Aggregate *> &Aggregate::aggregateMap()
+{
+ static QHash<QObject *, Aggregate *> map;
+ return map;
+}
+
+/*!
+ \fn QReadWriteLock &Aggregate::lock()
+ \internal
+*/
+QReadWriteLock &Aggregate::lock()
+{
+ static QReadWriteLock lock;
+ return lock;
+}
+
+/*!
+ \fn Aggregate::Aggregate(QObject *parent)
+
+ Creates a new Aggregate with the given \a parent.
+ The \a parent is passed directly passed to the QObject part
+ of the class and is not used beside that.
+*/
+Aggregate::Aggregate(QObject *parent)
+ : QObject(parent)
+{
+ QWriteLocker locker(&lock());
+ aggregateMap().insert(this, this);
+}
+
+/*!
+ \fn Aggregate::~Aggregate()
+
+ Deleting the aggregate automatically deletes all its components.
+*/
+Aggregate::~Aggregate()
+{
+ QWriteLocker locker(&lock());
+ foreach (QObject *component, m_components) {
+ disconnect(component, SIGNAL(destroyed(QObject*)), this, SLOT(deleteSelf(QObject*)));
+ aggregateMap().remove(component);
+ }
+ qDeleteAll(m_components);
+ m_components.clear();
+ aggregateMap().remove(this);
+}
+
+void Aggregate::deleteSelf(QObject *obj)
+{
+ {
+ QWriteLocker locker(&lock());
+ aggregateMap().remove(obj);
+ m_components.removeAll(obj);
+ }
+ delete this;
+}
+
+/*!
+ \fn void Aggregate::add(QObject *component)
+
+ Adds the \a component to the aggregate.
+
+ \sa Aggregate::remove()
+*/
+void Aggregate::add(QObject *component)
+{
+ if (!component)
+ return;
+ QWriteLocker locker(&lock());
+ Aggregate *parentAggregation = aggregateMap().value(component);
+ if (parentAggregation == this)
+ return;
+ if (parentAggregation)
+ parentAggregation->remove(component);
+ m_components.append(component);
+ connect(component, SIGNAL(destroyed(QObject*)), this, SLOT(deleteSelf(QObject*)));
+ aggregateMap().insert(component, this);
+}
+
+/*!
+ \fn void Aggregate::remove(QObject *component)
+
+ Removes the \a component from the aggregate.
+
+ \sa Aggregate::add()
+*/
+void Aggregate::remove(QObject *component)
+{
+ if (!component)
+ return;
+ QWriteLocker locker(&lock());
+ aggregateMap().remove(component);
+ m_components.removeAll(component);
+ disconnect(component, SIGNAL(destroyed(QObject*)), this, SLOT(deleteSelf(QObject*)));
+}
+
diff --git a/src/libs/aggregation/aggregate.h b/src/libs/aggregation/aggregate.h
new file mode 100644
index 0000000000..5040aec8b2
--- /dev/null
+++ b/src/libs/aggregation/aggregate.h
@@ -0,0 +1,134 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 QAGGREGATION_H
+#define QAGGREGATION_H
+
+#include "aggregation_global.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QList>
+#include <QtCore/QHash>
+#include <QtCore/QReadWriteLock>
+#include <QtCore/QReadLocker>
+
+namespace Aggregation {
+
+class AGGREGATION_EXPORT Aggregate : public QObject
+{
+ Q_OBJECT
+
+public:
+ Aggregate(QObject *parent = 0);
+ virtual ~Aggregate();
+
+ void add(QObject *component);
+ void remove(QObject *component);
+
+ template <typename T> T *component() {
+ QReadLocker(&lock());
+ foreach (QObject *component, m_components) {
+ if (T *result = qobject_cast<T *>(component))
+ return result;
+ }
+ return (T *)0;
+ }
+
+ template <typename T> QList<T *> components() {
+ QReadLocker(&lock());
+ QList<T *> results;
+ foreach (QObject *component, m_components) {
+ if (T *result = qobject_cast<T *>(component)) {
+ results << result;
+ }
+ }
+ return results;
+ }
+
+ static Aggregate *parentAggregate(QObject *obj);
+ static QReadWriteLock &lock();
+
+private slots:
+ void deleteSelf(QObject *obj);
+
+private:
+ static QHash<QObject *, Aggregate *> &aggregateMap();
+
+ QList<QObject *> m_components;
+};
+
+// get a component via global template function
+template <typename T> T *query(Aggregate *obj)
+{
+ if (!obj)
+ return (T *)0;
+ return obj->template component<T>();
+}
+
+template <typename T> T *query(QObject *obj)
+{
+ if (!obj)
+ return (T *)0;
+ T *result = qobject_cast<T *>(obj);
+ if (!result) {
+ QReadLocker(&lock());
+ Aggregate *parentAggregation = Aggregate::parentAggregate(obj);
+ result = (parentAggregation ? query<T>(parentAggregation) : 0);
+ }
+ return result;
+}
+
+// get all components of a specific type via template function
+template <typename T> QList<T *> query_all(Aggregate *obj)
+{
+ if (!obj)
+ return QList<T *>();
+ return obj->template components<T>();
+}
+
+template <typename T> QList<T *> query_all(QObject *obj)
+{
+ if (!obj)
+ return QList<T *>();
+ QReadLocker(&lock());
+ Aggregate *parentAggregation = Aggregate::parentAggregate(obj);
+ QList<T *> results;
+ if (parentAggregation)
+ results = query_all<T>(parentAggregation);
+ else if (T *result = qobject_cast<T *>(obj))
+ results.append(result);
+ return results;
+}
+
+} // namespace Aggregation
+
+#endif // header guard
diff --git a/src/libs/aggregation/aggregation.pri b/src/libs/aggregation/aggregation.pri
new file mode 100644
index 0000000000..a6c48c59cb
--- /dev/null
+++ b/src/libs/aggregation/aggregation.pri
@@ -0,0 +1 @@
+LIBS *= -l$$qtLibraryTarget(Aggregation)
diff --git a/src/libs/aggregation/aggregation.pro b/src/libs/aggregation/aggregation.pro
new file mode 100644
index 0000000000..c970be0ed1
--- /dev/null
+++ b/src/libs/aggregation/aggregation.pro
@@ -0,0 +1,12 @@
+TEMPLATE = lib
+TARGET = Aggregation
+
+include(../../qworkbenchlibrary.pri)
+
+DEFINES += AGGREGATION_LIBRARY
+
+HEADERS = aggregate.h \
+ aggregation_global.h
+
+SOURCES = aggregate.cpp
+
diff --git a/src/libs/aggregation/aggregation_global.h b/src/libs/aggregation/aggregation_global.h
new file mode 100644
index 0000000000..cae0917d65
--- /dev/null
+++ b/src/libs/aggregation/aggregation_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 (qt-info@nokia.com)
+**
+**
+** 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 AGGREGATION_GLOBAL_H
+#define AGGREGATION_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(AGGREGATION_LIBRARY)
+# define AGGREGATION_EXPORT Q_DECL_EXPORT
+#else
+# define AGGREGATION_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // header
diff --git a/src/libs/aggregation/examples/examples.pro b/src/libs/aggregation/examples/examples.pro
new file mode 100644
index 0000000000..7389255366
--- /dev/null
+++ b/src/libs/aggregation/examples/examples.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+
+SUBDIRS = text
diff --git a/src/libs/aggregation/examples/text/main.cpp b/src/libs/aggregation/examples/text/main.cpp
new file mode 100644
index 0000000000..1a0ecac816
--- /dev/null
+++ b/src/libs/aggregation/examples/text/main.cpp
@@ -0,0 +1,110 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "main.h"
+
+#include <QtGui/QApplication>
+
+MyMain::MyMain(QWidget *parent, Qt::WFlags flags)
+ : QWidget(parent, flags)
+{
+ ui.setupUi(this);
+ connect(ui.comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(select(int)));
+}
+
+void MyMain::add(IComboEntry *obj)
+{
+ m_entries.append(obj);
+ ui.comboBox->addItem(obj->title());
+}
+
+void MyMain::select(int index)
+{
+ IComboEntry *entry = m_entries.at(index);
+ // with multiple inheritance we would use qobject_cast here
+ // instead we use query, to get the components if they exist
+ IText1 *t1 = Aggregation::query<IText1>(entry);
+ IText2 *t2 = Aggregation::query<IText2>(entry);
+ IText3 *t3 = Aggregation::query<IText3>(entry);
+ // set the label texts and enable/disable, depending on whether
+ // the respective interface implementations exist
+ ui.text1->setText(t1 ? t1->text() : tr("N/A"));
+ ui.text2->setText(t2 ? t2->text() : tr("N/A"));
+ ui.text3->setText(t3 ? t3->text() : tr("N/A"));
+ ui.text1->setEnabled(t1);
+ ui.text2->setEnabled(t2);
+ ui.text3->setEnabled(t3);
+}
+
+MyMain::~MyMain()
+{
+ // the following deletes all the Aggregate and IComboEntry and ITextX
+ // objects, as well as any other components we might have added
+ qDeleteAll(m_entries);
+}
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ MyMain w;
+ // create and set up some objects
+
+ // the first does only implement the required IComboEntry
+ // we don't need an aggregation for this
+ IComboEntry *obj1 = new IComboEntry("Entry without text");
+
+ // the second additionally provides an IText2 implementation
+ // adding a component to the aggregation is done by setting the aggregation as the parent of the component
+ Aggregation::Aggregate *obj2 = new Aggregation::Aggregate;
+ obj2->add(new IComboEntry("Entry with text 2"));
+ obj2->add(new IText2("This is a text for label 2"));
+
+ // and so on... two more objects...
+ Aggregation::Aggregate *obj3 = new Aggregation::Aggregate;
+ obj3->add(new IComboEntry("Entry with text 1 and 2"));
+ obj3->add(new IText1("I love Qt!"));
+ obj3->add(new IText2("There are software companies..."));
+ Aggregation::Aggregate *obj4 = new Aggregation::Aggregate;
+ obj4->add(new IComboEntry("Entry with text 1 and 3"));
+ obj4->add(new IText1("Some text written here."));
+ obj4->add(new IText3("I'm a troll."));
+
+ // the API takes IComboEntries, so we convert the them to it
+ // the MyMain object takes the ownership of the whole aggregations
+ w.add(Aggregation::query<IComboEntry>(obj1));
+ w.add(Aggregation::query<IComboEntry>(obj2));
+ w.add(Aggregation::query<IComboEntry>(obj3));
+ w.add(Aggregation::query<IComboEntry>(obj4));
+ w.show();
+ return app.exec();
+}
+
diff --git a/src/libs/aggregation/examples/text/main.h b/src/libs/aggregation/examples/text/main.h
new file mode 100644
index 0000000000..3a458923b4
--- /dev/null
+++ b/src/libs/aggregation/examples/text/main.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 (qt-info@nokia.com)
+**
+**
+** 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 MAIN_H
+#define MAIN_H
+
+#include "myinterfaces.h"
+
+#include <aggregate.h>
+
+#include <QtGui/QWidget>
+#include "ui_main.h"
+
+class MyMain : public QWidget
+{
+ Q_OBJECT
+
+public:
+ MyMain(QWidget *parent = 0, Qt::WFlags flags = 0);
+ ~MyMain();
+
+ void add(IComboEntry *obj);
+
+private slots:
+ void select(int index);
+
+private:
+ Ui::mainClass ui;
+
+ QList<IComboEntry *> m_entries;
+};
+
+#endif // MAIN_H
diff --git a/src/libs/aggregation/examples/text/main.ui b/src/libs/aggregation/examples/text/main.ui
new file mode 100644
index 0000000000..32d39511ee
--- /dev/null
+++ b/src/libs/aggregation/examples/text/main.ui
@@ -0,0 +1,128 @@
+<ui version="4.0" >
+ <class>mainClass</class>
+ <widget class="QWidget" name="mainClass" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>399</width>
+ <height>176</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>main</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="QComboBox" name="comboBox" />
+ </item>
+ <item>
+ <layout class="QVBoxLayout" >
+ <item>
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QLabel" name="label" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Text1:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="text1" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="MinimumExpanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>N/A</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QLabel" name="label_3" >
+ <property name="text" >
+ <string>Text2:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="text2" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="MinimumExpanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>N/A</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <item>
+ <widget class="QLabel" name="label_5" >
+ <property name="text" >
+ <string>Text3:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="text3" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Preferred" hsizetype="MinimumExpanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>N/A</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </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>
+ </widget>
+ <layoutdefault spacing="6" margin="11" />
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/libs/aggregation/examples/text/myinterfaces.h b/src/libs/aggregation/examples/text/myinterfaces.h
new file mode 100644
index 0000000000..62dad429e2
--- /dev/null
+++ b/src/libs/aggregation/examples/text/myinterfaces.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 (qt-info@nokia.com)
+**
+**
+** 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 MYINTERFACES_H
+#define MYINTERFACES_H
+
+#include <aggregate.h>
+
+#include <QtCore/QString>
+
+class IComboEntry : public QObject
+{
+ Q_OBJECT
+
+public:
+ IComboEntry(QString title) : m_title(title) {}
+ virtual ~IComboEntry() {}
+ QString title() const { return m_title; }
+private:
+ QString m_title;
+};
+
+class IText1 : public QObject
+{
+ Q_OBJECT
+
+public:
+ IText1(QString text) : m_text(text) {}
+ virtual ~IText1() {}
+ QString text() const { return m_text; }
+private:
+ QString m_text;
+};
+
+class IText2 : public QObject
+{
+ Q_OBJECT
+
+public:
+ IText2(QString text) : m_text(text) {}
+ QString text() const { return m_text; }
+private:
+ QString m_text;
+};
+
+class IText3 : public QObject
+{
+ Q_OBJECT
+
+public:
+ IText3(QString text) : m_text(text) {}
+ virtual ~IText3() {}
+ QString text() const { return m_text; }
+private:
+ QString m_text;
+};
+
+#endif // MYINTERFACES_H
diff --git a/src/libs/aggregation/examples/text/text.pro b/src/libs/aggregation/examples/text/text.pro
new file mode 100644
index 0000000000..3893c5e95f
--- /dev/null
+++ b/src/libs/aggregation/examples/text/text.pro
@@ -0,0 +1,14 @@
+TARGET = text
+TEMPLATE = app
+QT += core \
+ gui
+DEFINES += AGGREGATION_LIBRARY
+INCLUDEPATH += ../../
+SOURCES += main.cpp \
+ ../../aggregate.cpp
+HEADERS += main.h \
+ myinterfaces.h \
+ ../../aggregate.h \
+ ../../aggregation_global.h
+FORMS += main.ui
+
diff --git a/src/libs/aggregation/test/test.pro b/src/libs/aggregation/test/test.pro
new file mode 100644
index 0000000000..6143ca9805
--- /dev/null
+++ b/src/libs/aggregation/test/test.pro
@@ -0,0 +1,12 @@
+CONFIG += qtestlib
+TEMPLATE = app
+CONFIG -= app_bundle
+DEFINES += AGGREGATION_LIBRARY
+
+INCLUDEPATH += ../
+# Input
+SOURCES += tst_aggregate.cpp \
+ ../aggregate.cpp
+HEADERS += ../aggregate.h \
+ ../aggregation_global.h
+
diff --git a/src/libs/aggregation/test/tst_aggregate.cpp b/src/libs/aggregation/test/tst_aggregate.cpp
new file mode 100644
index 0000000000..098cc723af
--- /dev/null
+++ b/src/libs/aggregation/test/tst_aggregate.cpp
@@ -0,0 +1,198 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 <aggregate.h>
+
+class tst_Aggregate : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void deleteAggregation();
+ void queryAggregation();
+ void queryAll();
+ void parentAggregate();
+};
+
+class Interface1 : public QObject
+{
+ Q_OBJECT
+};
+
+class Interface11 : public Interface1
+{
+ Q_OBJECT
+};
+
+class Interface2 : public QObject
+{
+ Q_OBJECT
+};
+
+class Interface3 : public QObject
+{
+ Q_OBJECT
+};
+
+void tst_Aggregate::deleteAggregation()
+{
+ QPointer<Aggregation::Aggregate> aggregation;
+ QPointer<QObject> component1;
+ QPointer<QObject> component2;
+
+ aggregation = new Aggregation::Aggregate;
+ component1 = new Interface1;
+ component2 = new Interface2;
+ aggregation->add(component1);
+ aggregation->add(component2);
+ delete aggregation;
+ QVERIFY(aggregation == 0);
+ QVERIFY(component1 == 0);
+ QVERIFY(component2 == 0);
+
+ aggregation = new Aggregation::Aggregate;
+ component1 = new Interface1;
+ component2 = new Interface2;
+ aggregation->add(component1);
+ aggregation->add(component2);
+ delete component1;
+ QVERIFY(aggregation == 0);
+ QVERIFY(component1 == 0);
+ QVERIFY(component2 == 0);
+
+ aggregation = new Aggregation::Aggregate;
+ component1 = new Interface1;
+ component2 = new Interface2;
+ aggregation->add(component1);
+ aggregation->add(component2);
+ delete component2;
+ QVERIFY(aggregation == 0);
+ QVERIFY(component1 == 0);
+ QVERIFY(component2 == 0);
+
+ // if a component doesn't belong to an aggregation, it should simply delete itself
+ component1 = new Interface1;
+ delete component1;
+ QVERIFY(component1 == 0);
+}
+
+void tst_Aggregate::queryAggregation()
+{
+ Aggregation::Aggregate aggregation;
+ QObject *aggObject = &aggregation;
+ QObject *component1 = new Interface11;
+ QObject *component2 = new Interface2;
+ aggregation.add(component1);
+ aggregation.add(component2);
+ QCOMPARE(Aggregation::query<Interface1>(&aggregation), component1);
+ QCOMPARE(Aggregation::query<Interface2>(&aggregation), component2);
+ QCOMPARE(Aggregation::query<Interface11>(&aggregation), component1);
+ QCOMPARE(Aggregation::query<Interface3>(&aggregation), (Interface3 *)0);
+
+ QCOMPARE(Aggregation::query<Interface1>(aggObject), component1);
+ QCOMPARE(Aggregation::query<Interface2>(aggObject), component2);
+ QCOMPARE(Aggregation::query<Interface11>(aggObject), component1);
+ QCOMPARE(Aggregation::query<Interface3>(aggObject), (Interface3 *)0);
+
+ QCOMPARE(Aggregation::query<Interface1>(component1), component1);
+ QCOMPARE(Aggregation::query<Interface2>(component1), component2);
+ QCOMPARE(Aggregation::query<Interface11>(component1), component1);
+ QCOMPARE(Aggregation::query<Interface3>(component1), (Interface3 *)0);
+
+ QCOMPARE(Aggregation::query<Interface1>(component2), component1);
+ QCOMPARE(Aggregation::query<Interface2>(component2), component2);
+ QCOMPARE(Aggregation::query<Interface11>(component2), component1);
+ QCOMPARE(Aggregation::query<Interface3>(component2), (Interface3 *)0);
+
+ // components that don't belong to an aggregation should be query-able to itself only
+ QObject *component3 = new Interface3;
+ QCOMPARE(Aggregation::query<Interface1>(component3), (Interface1 *)0);
+ QCOMPARE(Aggregation::query<Interface2>(component3), (Interface2 *)0);
+ QCOMPARE(Aggregation::query<Interface11>(component3), (Interface11 *)0);
+ QCOMPARE(Aggregation::query<Interface3>(component3), component3);
+ delete component3;
+}
+
+void tst_Aggregate::queryAll()
+{
+ Aggregation::Aggregate aggregation;
+ QObject *aggObject = &aggregation;
+ Interface1 *component1 = new Interface1;
+ Interface11 *component11 = new Interface11;
+ Interface2 *component2 = new Interface2;
+ aggregation.add(component1);
+ aggregation.add(component11);
+ aggregation.add(component2);
+ QCOMPARE(Aggregation::query_all<Interface1>(&aggregation), QList<Interface1 *>() << component1 << component11);
+ QCOMPARE(Aggregation::query_all<Interface11>(&aggregation), QList<Interface11 *>() << component11);
+ QCOMPARE(Aggregation::query_all<Interface2>(&aggregation), QList<Interface2 *>() << component2);
+ QCOMPARE(Aggregation::query_all<Interface3>(&aggregation), QList<Interface3 *>());
+
+ QCOMPARE(Aggregation::query_all<Interface1>(aggObject), QList<Interface1 *>() << component1 << component11);
+ QCOMPARE(Aggregation::query_all<Interface11>(aggObject), QList<Interface11 *>() << component11);
+ QCOMPARE(Aggregation::query_all<Interface2>(aggObject), QList<Interface2 *>() << component2);
+ QCOMPARE(Aggregation::query_all<Interface3>(aggObject), QList<Interface3 *>());
+
+ QCOMPARE(Aggregation::query_all<Interface1>(component1), QList<Interface1 *>() << component1 << component11);
+ QCOMPARE(Aggregation::query_all<Interface11>(component1), QList<Interface11 *>() << component11);
+ QCOMPARE(Aggregation::query_all<Interface2>(component1), QList<Interface2 *>() << component2);
+ QCOMPARE(Aggregation::query_all<Interface3>(component1), QList<Interface3 *>());
+
+ QCOMPARE(Aggregation::query_all<Interface1>(component11), QList<Interface1 *>() << component1 << component11);
+ QCOMPARE(Aggregation::query_all<Interface11>(component11), QList<Interface11 *>() << component11);
+ QCOMPARE(Aggregation::query_all<Interface2>(component11), QList<Interface2 *>() << component2);
+ QCOMPARE(Aggregation::query_all<Interface3>(component11), QList<Interface3 *>());
+
+ QCOMPARE(Aggregation::query_all<Interface1>(component2), QList<Interface1 *>() << component1 << component11);
+ QCOMPARE(Aggregation::query_all<Interface11>(component2), QList<Interface11 *>() << component11);
+ QCOMPARE(Aggregation::query_all<Interface2>(component2), QList<Interface2 *>() << component2);
+ QCOMPARE(Aggregation::query_all<Interface3>(component2), QList<Interface3 *>());
+}
+
+void tst_Aggregate::parentAggregate()
+{
+ Aggregation::Aggregate aggregation;
+ Interface1 *component1 = new Interface1;
+ Interface11 *component11 = new Interface11;
+ QObject *component2 = new QObject;
+ aggregation.add(component1);
+ aggregation.add(component11);
+ QCOMPARE(Aggregation::Aggregate::parentAggregate(&aggregation), &aggregation);
+ QCOMPARE(Aggregation::Aggregate::parentAggregate(component1), &aggregation);
+ QCOMPARE(Aggregation::Aggregate::parentAggregate(component11), &aggregation);
+ QCOMPARE(Aggregation::Aggregate::parentAggregate(component2), (Aggregation::Aggregate *)0);
+}
+
+QTEST_MAIN(tst_Aggregate)
+#include "tst_aggregate.moc"
diff --git a/src/libs/cplusplus/CppDocument.cpp b/src/libs/cplusplus/CppDocument.cpp
new file mode 100644
index 0000000000..b2e0ca4be1
--- /dev/null
+++ b/src/libs/cplusplus/CppDocument.cpp
@@ -0,0 +1,242 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "CppDocument.h"
+#include <Control.h>
+#include <TranslationUnit.h>
+#include <DiagnosticClient.h>
+#include <Semantic.h>
+#include <Literals.h>
+#include <Symbols.h>
+#include <AST.h>
+#include <Scope.h>
+#include <QByteArray>
+#include <QFile>
+#include <QtDebug>
+
+using namespace CPlusPlus;
+
+namespace {
+ class DocumentDiagnosticClient: public DiagnosticClient
+ {
+ enum { MAX_MESSAGE_COUNT = 10 };
+
+ public:
+ DocumentDiagnosticClient(Document *doc, QList<Document::DiagnosticMessage> *messages)
+ : doc(doc),
+ messages(messages)
+ { }
+
+ virtual void report(int level,
+ StringLiteral *fileId,
+ unsigned line, unsigned column,
+ const char *format, va_list ap)
+ {
+ if (messages->count() == MAX_MESSAGE_COUNT)
+ return;
+
+ const QString fileName = QString::fromUtf8(fileId->chars(), fileId->size());
+
+ if (fileName != doc->fileName())
+ return;
+
+ QString message;
+ message.vsprintf(format, ap);
+
+ Document::DiagnosticMessage m(convertLevel(level), doc->fileName(),
+ line, column, message);
+ messages->append(m);
+ }
+
+ static int convertLevel(int level) {
+ switch (level) {
+ case Warning: return Document::DiagnosticMessage::Warning;
+ case Error: return Document::DiagnosticMessage::Error;
+ case Fatal: return Document::DiagnosticMessage::Fatal;
+ default: return Document::DiagnosticMessage::Error;
+ }
+ }
+
+ Document *doc;
+ QList<Document::DiagnosticMessage> *messages;
+ };
+} // end of anonymous namespace
+
+Document::Document(const QString &fileName)
+ : _fileName(fileName),
+ _globalNamespace(0)
+{
+ _control = new Control();
+
+ _control->setDiagnosticClient(new DocumentDiagnosticClient(this, &_diagnosticMessages));
+
+ const QByteArray localFileName = fileName.toUtf8();
+ StringLiteral *fileId = _control->findOrInsertFileName(localFileName.constData(),
+ localFileName.size());
+ _translationUnit = new TranslationUnit(_control, fileId);
+ _translationUnit->setQtMocRunEnabled(true);
+ (void) _control->switchTranslationUnit(_translationUnit);
+}
+
+Document::~Document()
+{
+ delete _translationUnit;
+ delete _control->diagnosticClient();
+ delete _control;
+}
+
+Control *Document::control() const
+{ return _control; }
+
+QString Document::fileName() const
+{ return _fileName; }
+
+QStringList Document::includedFiles() const
+{ return _includedFiles; }
+
+void Document::addIncludeFile(const QString &fileName)
+{ _includedFiles.append(fileName); }
+
+QByteArray Document::definedMacros() const
+{ return _definedMacros; }
+
+void Document::appendMacro(const QByteArray &macroName, const QByteArray &text)
+{
+ int index = macroName.indexOf('(');
+ if (index == -1)
+ _macroNames.insert(macroName);
+ else
+ _macroNames.insert(macroName.left(index));
+ _definedMacros += text;
+}
+
+TranslationUnit *Document::translationUnit() const
+{ return _translationUnit; }
+
+bool Document::skipFunctionBody() const
+{ return _translationUnit->skipFunctionBody(); }
+
+void Document::setSkipFunctionBody(bool skipFunctionBody)
+{ _translationUnit->setSkipFunctionBody(skipFunctionBody); }
+
+unsigned Document::globalSymbolCount() const
+{
+ if (! _globalNamespace)
+ return 0;
+
+ return _globalNamespace->memberCount();
+}
+
+Symbol *Document::globalSymbolAt(unsigned index) const
+{ return _globalNamespace->memberAt(index); }
+
+Scope *Document::globalSymbols() const
+{
+ if (! _globalNamespace)
+ return 0;
+
+ return _globalNamespace->members();
+}
+
+Namespace *Document::globalNamespace() const
+{ return _globalNamespace; }
+
+Symbol *Document::findSymbolAt(unsigned line, unsigned column) const
+{ return findSymbolAt(line, column, globalSymbols()); }
+
+Symbol *Document::findSymbolAt(unsigned line, unsigned column, Scope *scope) const
+{
+ Symbol *previousSymbol = 0;
+
+ for (unsigned i = 0; i < scope->symbolCount(); ++i) {
+ Symbol *symbol = scope->symbolAt(i);
+ if (symbol->line() > line)
+ break;
+
+ previousSymbol = symbol;
+ }
+
+ if (previousSymbol) {
+ if (ScopedSymbol *scoped = previousSymbol->asScopedSymbol()) {
+ if (Symbol *member = findSymbolAt(line, column, scoped->members()))
+ return member;
+ }
+ }
+
+ return previousSymbol;
+}
+
+Document::Ptr Document::create(const QString &fileName)
+{
+ Document::Ptr doc(new Document(fileName));
+ return doc;
+}
+
+void Document::setSource(const QByteArray &source)
+{ _translationUnit->setSource(source.constBegin(), source.size()); }
+
+void Document::startSkippingBlocks(unsigned start)
+{ _skippedBlocks.append(Block(start, 0)); }
+
+void Document::stopSkippingBlocks(unsigned stop)
+{
+ unsigned start = _skippedBlocks.back().begin();
+ if (start > stop)
+ _skippedBlocks.removeLast(); // Ignore this block, it's invalid.
+ else
+ _skippedBlocks.back() = Block(start, stop);
+}
+
+QSet<QByteArray> Document::macroNames() const
+{ return _macroNames; }
+
+void Document::parse()
+{ _translationUnit->parse(); }
+
+void Document::check()
+{
+ Q_ASSERT(! _globalNamespace);
+
+ Semantic semantic(_control);
+
+ _globalNamespace = _control->newNamespace(0);
+ Scope *globals = _globalNamespace->members();
+ if (TranslationUnitAST *ast = _translationUnit->ast()) {
+ for (DeclarationAST *decl = ast->declarations; decl; decl = decl->next) {
+ semantic.check(decl, globals);
+ }
+ }
+}
+
+void Document::releaseTranslationUnit()
+{ _translationUnit->release(); }
diff --git a/src/libs/cplusplus/CppDocument.h b/src/libs/cplusplus/CppDocument.h
new file mode 100644
index 0000000000..47f2366ddd
--- /dev/null
+++ b/src/libs/cplusplus/CppDocument.h
@@ -0,0 +1,187 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 CPPDOCUMENT_H
+#define CPPDOCUMENT_H
+
+#include <CPlusPlusForwardDeclarations.h>
+#include <QByteArray>
+#include <QSharedPointer>
+#include <QString>
+#include <QStringList>
+#include <QList>
+#include <QSet>
+
+namespace CPlusPlus {
+
+class CPLUSPLUS_EXPORT Document
+{
+ Document(const Document &other);
+ void operator =(const Document &other);
+
+ Document(const QString &fileName);
+
+public:
+ typedef QSharedPointer<Document> Ptr;
+
+public:
+ ~Document();
+
+ QString fileName() const;
+
+ QStringList includedFiles() const;
+ void addIncludeFile(const QString &fileName);
+
+ QByteArray definedMacros() const;
+ QSet<QByteArray> macroNames() const;
+
+ void appendMacro(const QByteArray &macroName, const QByteArray &text);
+
+ Control *control() const;
+ TranslationUnit *translationUnit() const;
+
+ bool skipFunctionBody() const;
+ void setSkipFunctionBody(bool skipFunctionBody);
+
+ unsigned globalSymbolCount() const;
+ Symbol *globalSymbolAt(unsigned index) const;
+ Scope *globalSymbols() const; // ### deprecate?
+ Namespace *globalNamespace() const;
+
+ Symbol *findSymbolAt(unsigned line, unsigned column) const;
+
+ void setSource(const QByteArray &source);
+ void startSkippingBlocks(unsigned offset);
+ void stopSkippingBlocks(unsigned offset);
+
+ void parse(); // ### remove
+ void check();
+ void releaseTranslationUnit();
+
+ static Ptr create(const QString &fileName);
+
+ class DiagnosticMessage
+ {
+ public:
+ enum Level {
+ Warning,
+ Error,
+ Fatal
+ };
+
+ public:
+ DiagnosticMessage(int level, const QString &fileName,
+ int line, int column,
+ const QString &text)
+ : _level(level),
+ _fileName(fileName),
+ _line(line),
+ _column(column),
+ _text(text)
+ { }
+
+ int level() const
+ { return _level; }
+
+ bool isWarning() const
+ { return _level == Warning; }
+
+ bool isError() const
+ { return _level == Error; }
+
+ bool isFatal() const
+ { return _level == Fatal; }
+
+ QString fileName() const
+ { return _fileName; }
+
+ int line() const
+ { return _line; }
+
+ int column() const
+ { return _column; }
+
+ QString text() const
+ { return _text; }
+
+ private:
+ int _level;
+ QString _fileName;
+ int _line;
+ int _column;
+ QString _text;
+ };
+
+ void addDiagnosticMessage(const DiagnosticMessage &d)
+ { _diagnosticMessages.append(d); }
+
+ QList<DiagnosticMessage> diagnosticMessages() const
+ { return _diagnosticMessages; }
+
+ class Block
+ {
+ unsigned _begin;
+ unsigned _end;
+
+ public:
+ inline Block(unsigned begin = 0, unsigned end = 0)
+ : _begin(begin), _end(end)
+ { }
+
+ inline unsigned begin() const
+ { return _begin; }
+
+ inline unsigned end() const
+ { return _end; }
+ };
+
+ QList<Block> skippedBlocks() const
+ { return _skippedBlocks; }
+
+private:
+ Symbol *findSymbolAt(unsigned line, unsigned column, Scope *scope) const;
+
+private:
+ QString _fileName;
+ QStringList _includedFiles;
+ Control *_control;
+ TranslationUnit *_translationUnit;
+ Namespace *_globalNamespace;
+ QList<DiagnosticMessage> _diagnosticMessages;
+ QByteArray _definedMacros;
+ QSet<QByteArray> _macroNames;
+ QList<Block> _skippedBlocks;
+};
+
+} // end of namespace CPlusPlus
+
+#endif // CPPDOCUMENT_H
diff --git a/src/libs/cplusplus/ExpressionUnderCursor.cpp b/src/libs/cplusplus/ExpressionUnderCursor.cpp
new file mode 100644
index 0000000000..92d2cd8893
--- /dev/null
+++ b/src/libs/cplusplus/ExpressionUnderCursor.cpp
@@ -0,0 +1,242 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "ExpressionUnderCursor.h"
+#include "SimpleLexer.h"
+#include <Token.h>
+
+#include <QTextCursor>
+#include <QTextBlock>
+
+using namespace CPlusPlus;
+
+ExpressionUnderCursor::ExpressionUnderCursor()
+{ }
+
+ExpressionUnderCursor::~ExpressionUnderCursor()
+{ }
+
+int ExpressionUnderCursor::startOfMatchingBrace(const QList<SimpleToken> &tk, int index)
+{
+ if (tk[index - 1].is(T_RPAREN)) {
+ int i = index - 1;
+ int count = 0;
+ do {
+ if (tk[i].is(T_LPAREN)) {
+ if (! ++count)
+ return i;
+ } else if (tk[i].is(T_RPAREN))
+ --count;
+ --i;
+ } while (count != 0 && i > -1);
+ } else if (tk[index - 1].is(T_RBRACKET)) {
+ int i = index - 1;
+ int count = 0;
+ do {
+ if (tk[i].is(T_LBRACKET)) {
+ if (! ++count)
+ return i;
+ } else if (tk[i].is(T_RBRACKET))
+ --count;
+ --i;
+ } while (count != 0 && i > -1);
+ } else if (tk[index - 1].is(T_GREATER)) {
+ int i = index - 1;
+ int count = 0;
+ do {
+ if (tk[i].is(T_LESS)) {
+ if (! ++count)
+ return i;
+ } else if (tk[i].is(T_GREATER))
+ --count;
+ --i;
+ } while (count != 0 && i > -1);
+ }
+
+ return index;
+}
+
+int ExpressionUnderCursor::startOfExpression(const QList<SimpleToken> &tk, int index)
+{
+ // tk is a reference to a const QList. So, don't worry about [] access.
+ // ### TODO implement multiline support. It should be pretty easy.
+ if (tk[index - 1].isLiteral()) {
+ return index - 1;
+ } else if (tk[index - 1].is(T_THIS)) {
+ return index - 1;
+ } else if (tk[index - 1].is(T_TYPEID)) {
+ return index - 1;
+ } else if (tk[index - 1].is(T_SIGNAL)) {
+ if (tk[index - 2].is(T_COMMA) && !_jumpedComma) {
+ _jumpedComma = true;
+ return startOfExpression(tk, index - 2);
+ }
+ return index - 1;
+ } else if (tk[index - 1].is(T_SLOT)) {
+ if (tk[index - 2].is(T_COMMA) && !_jumpedComma) {
+ _jumpedComma = true;
+ return startOfExpression(tk, index - 2);
+ }
+ return index - 1;
+ } else if (tk[index - 1].is(T_IDENTIFIER)) {
+ if (tk[index - 2].is(T_TILDE)) {
+ if (tk[index - 3].is(T_COLON_COLON)) {
+ return startOfExpression(tk, index - 3);
+ } else if (tk[index - 3].is(T_DOT) || tk[index - 3].is(T_ARROW)) {
+ return startOfExpression(tk, index - 3);
+ }
+ return index - 2;
+ } else if (tk[index - 2].is(T_COLON_COLON)) {
+ return startOfExpression(tk, index - 1);
+ } else if (tk[index - 2].is(T_DOT) || tk[index - 2].is(T_ARROW)) {
+ return startOfExpression(tk, index - 2);
+ } else if (tk[index - 2].is(T_DOT_STAR) || tk[index - 2].is(T_ARROW_STAR)) {
+ return startOfExpression(tk, index - 2);
+ }
+ return index - 1;
+ } else if (tk[index - 1].is(T_RPAREN)) {
+ int rparenIndex = startOfMatchingBrace(tk, index);
+ if (rparenIndex != index) {
+ if (tk[rparenIndex - 1].is(T_GREATER)) {
+ int lessIndex = startOfMatchingBrace(tk, rparenIndex);
+ if (lessIndex != rparenIndex - 1) {
+ if (tk[lessIndex - 1].is(T_DYNAMIC_CAST) ||
+ tk[lessIndex - 1].is(T_STATIC_CAST) ||
+ tk[lessIndex - 1].is(T_CONST_CAST) ||
+ tk[lessIndex - 1].is(T_REINTERPRET_CAST))
+ return lessIndex - 1;
+ else if (tk[lessIndex - 1].is(T_IDENTIFIER))
+ return startOfExpression(tk, lessIndex);
+ else if (tk[lessIndex - 1].is(T_SIGNAL))
+ return startOfExpression(tk, lessIndex);
+ else if (tk[lessIndex - 1].is(T_SLOT))
+ return startOfExpression(tk, lessIndex);
+ }
+ }
+ return startOfExpression(tk, rparenIndex);
+ }
+ return index;
+ } else if (tk[index - 1].is(T_RBRACKET)) {
+ int rbracketIndex = startOfMatchingBrace(tk, index);
+ if (rbracketIndex != index)
+ return startOfExpression(tk, rbracketIndex);
+ return index;
+ } else if (tk[index - 1].is(T_COLON_COLON)) {
+ if (tk[index - 2].is(T_GREATER)) { // ### not exactly
+ int lessIndex = startOfMatchingBrace(tk, index - 1);
+ if (lessIndex != index - 1)
+ return startOfExpression(tk, lessIndex);
+ return index - 1;
+ } else if (tk[index - 2].is(T_IDENTIFIER)) {
+ return startOfExpression(tk, index - 1);
+ }
+ return index - 1;
+ } else if (tk[index - 1].is(T_DOT) || tk[index - 1].is(T_ARROW)) {
+ return startOfExpression(tk, index - 1);
+ } else if (tk[index - 1].is(T_DOT_STAR) || tk[index - 1].is(T_ARROW_STAR)) {
+ return startOfExpression(tk, index - 1);
+ }
+
+ return index;
+}
+
+bool ExpressionUnderCursor::isAccessToken(const SimpleToken &tk)
+{
+ switch (tk.kind()) {
+ case T_COLON_COLON:
+ case T_DOT: case T_ARROW:
+ case T_DOT_STAR: case T_ARROW_STAR:
+ return true;
+ default:
+ return false;
+ } // switch
+}
+
+int ExpressionUnderCursor::previousBlockState(const QTextBlock &block)
+{
+ const QTextBlock prevBlock = block.previous();
+ if (prevBlock.isValid()) {
+ int state = prevBlock.userState();
+
+ if (state != -1)
+ return state;
+ }
+ return 0;
+}
+
+QString ExpressionUnderCursor::operator()(const QTextCursor &cursor)
+{
+ enum { MAX_BLOCK_COUNT = 5 };
+
+ QTextBlock block = cursor.block();
+ QTextBlock initialBlock = block;
+ for (int i = 0; i < MAX_BLOCK_COUNT; ++i) {
+ if (! initialBlock.previous().isValid())
+ break;
+
+ initialBlock = initialBlock.previous();
+ }
+
+ QString text;
+
+ QTextBlock it = initialBlock;
+ for (; it.isValid(); it = it.next()) {
+ QString textBlock = it.text();
+
+ if (it == block)
+ textBlock = textBlock.left(cursor.position() - cursor.block().position());
+
+ text += textBlock;
+
+ if (it == block)
+ break;
+
+ text += QLatin1Char('\n');
+ }
+
+ SimpleLexer tokenize;
+ tokenize.setSkipComments(true);
+ QList<SimpleToken> tokens = tokenize(text, previousBlockState(initialBlock));
+ tokens.prepend(SimpleToken()); // sentinel
+
+ _jumpedComma = false;
+
+ const int i = startOfExpression(tokens, tokens.size());
+ if (i == tokens.size())
+ return QString();
+
+ return text.mid(tokens.at(i).position(),
+ tokens.last().position() + tokens.last().length()
+ - tokens.at(i).position());
+}
+
diff --git a/src/libs/cplusplus/ExpressionUnderCursor.h b/src/libs/cplusplus/ExpressionUnderCursor.h
new file mode 100644
index 0000000000..e3fa442326
--- /dev/null
+++ b/src/libs/cplusplus/ExpressionUnderCursor.h
@@ -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 (qt-info@nokia.com)
+**
+**
+** 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 EXPRESSIONUNDERCURSOR_H
+#define EXPRESSIONUNDERCURSOR_H
+
+#include "CPlusPlusForwardDeclarations.h"
+#include <QList>
+
+QT_BEGIN_NAMESPACE
+class QString;
+class QTextCursor;
+class QTextBlock;
+QT_END_NAMESPACE
+
+namespace CPlusPlus {
+
+class SimpleToken;
+
+class CPLUSPLUS_EXPORT ExpressionUnderCursor
+{
+public:
+ ExpressionUnderCursor();
+ ~ExpressionUnderCursor();
+
+ QString operator()(const QTextCursor &cursor);
+
+private:
+ int startOfMatchingBrace(const QList<SimpleToken> &tk, int index);
+ int startOfExpression(const QList<SimpleToken> &tk, int index);
+ int previousBlockState(const QTextBlock &block);
+ bool isAccessToken(const SimpleToken &tk);
+
+ bool _jumpedComma;
+};
+
+} // namespace CPlusPlus
+
+#endif // EXPRESSIONUNDERCURSOR_H
diff --git a/src/libs/cplusplus/Icons.cpp b/src/libs/cplusplus/Icons.cpp
new file mode 100644
index 0000000000..70c4214259
--- /dev/null
+++ b/src/libs/cplusplus/Icons.cpp
@@ -0,0 +1,122 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "Icons.h"
+
+#include <FullySpecifiedType.h>
+#include <Scope.h>
+#include <Symbols.h>
+#include <Type.h>
+
+using namespace CPlusPlus;
+using CPlusPlus::Icons;
+
+Icons::Icons()
+ : _classIcon(QLatin1String(":/codemodel/images/class.png")),
+ _enumIcon(QLatin1String(":/codemodel/images/enum.png")),
+ _enumeratorIcon(QLatin1String(":/codemodel/images/enumerator.png")),
+ _funcPublicIcon(QLatin1String(":/codemodel/images/func.png")),
+ _funcProtectedIcon(QLatin1String(":/codemodel/images/func_prot.png")),
+ _funcPrivateIcon(QLatin1String(":/codemodel/images/func_priv.png")),
+ _namespaceIcon(QLatin1String(":/codemodel/images/namespace.png")),
+ _varPublicIcon(QLatin1String(":/codemodel/images/var.png")),
+ _varProtectedIcon(QLatin1String(":/codemodel/images/var_prot.png")),
+ _varPrivateIcon(QLatin1String(":/codemodel/images/var_priv.png")),
+ _signalIcon(QLatin1String(":/codemodel/images/signal.png")),
+ _slotPublicIcon(QLatin1String(":/codemodel/images/slot.png")),
+ _slotProtectedIcon(QLatin1String(":/codemodel/images/slot_prot.png")),
+ _slotPrivateIcon(QLatin1String(":/codemodel/images/slot_priv.png")),
+ _keywordIcon(QLatin1String(":/codemodel/images/keyword.png")),
+ _macroIcon(QLatin1String(":/codemodel/images/macro.png"))
+{
+}
+
+QIcon Icons::iconForSymbol(Symbol *symbol) const
+{
+ if (symbol->isFunction() || (symbol->isDeclaration() && symbol->type()->isFunction()))
+ {
+ Function *function = symbol->asFunction();
+ if (!function)
+ function = symbol->type()->asFunction();
+
+ if (function->isSlot()) {
+ if (function->isPublic()) {
+ return _slotPublicIcon;
+ } else if (function->isProtected()) {
+ return _slotProtectedIcon;
+ } else if (function->isPrivate()) {
+ return _slotPrivateIcon;
+ }
+ } else if (function->isSignal()) {
+ return _signalIcon;
+ } else if (symbol->isPublic()) {
+ return _funcPublicIcon;
+ } else if (symbol->isProtected()) {
+ return _funcProtectedIcon;
+ } else if (symbol->isPrivate()) {
+ return _funcPrivateIcon;
+ }
+ } else if (symbol->scope()->isEnumScope()) {
+ return _enumeratorIcon;
+ } else if (symbol->isDeclaration() || symbol->isArgument()) {
+ if (symbol->isPublic()) {
+ return _varPublicIcon;
+ } else if (symbol->isProtected()) {
+ return _varProtectedIcon;
+ } else if (symbol->isPrivate()) {
+ return _varPrivateIcon;
+ }
+ } else if (symbol->isEnum()) {
+ return _enumIcon;
+ } else if (symbol->isClass()) {
+ return _classIcon;
+ } else if (symbol->isNamespace()) {
+ return _namespaceIcon;
+ } else if (symbol->isUsingNamespaceDirective() ||
+ symbol->isUsingDeclaration()) {
+ // TODO: Might be nice to have a different icons for these things
+ return _namespaceIcon;
+ }
+
+ return QIcon();
+}
+
+QIcon Icons::keywordIcon() const
+{
+ return _keywordIcon;
+}
+
+QIcon Icons::macroIcon() const
+{
+ return _macroIcon;
+}
diff --git a/src/libs/cplusplus/Icons.h b/src/libs/cplusplus/Icons.h
new file mode 100644
index 0000000000..c549c1c429
--- /dev/null
+++ b/src/libs/cplusplus/Icons.h
@@ -0,0 +1,75 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 CPLUSPLUS_ICONS_H
+#define CPLUSPLUS_ICONS_H
+
+#include "CPlusPlusForwardDeclarations.h"
+
+#include <QIcon>
+
+namespace CPlusPlus {
+
+class Symbol;
+
+class CPLUSPLUS_EXPORT Icons
+{
+public:
+ Icons();
+
+ QIcon iconForSymbol(Symbol *symbol) const;
+
+ QIcon keywordIcon() const;
+ QIcon macroIcon() const;
+
+private:
+ QIcon _classIcon;
+ QIcon _enumIcon;
+ QIcon _enumeratorIcon;
+ QIcon _funcPublicIcon;
+ QIcon _funcProtectedIcon;
+ QIcon _funcPrivateIcon;
+ QIcon _namespaceIcon;
+ QIcon _varPublicIcon;
+ QIcon _varProtectedIcon;
+ QIcon _varPrivateIcon;
+ QIcon _signalIcon;
+ QIcon _slotPublicIcon;
+ QIcon _slotProtectedIcon;
+ QIcon _slotPrivateIcon;
+ QIcon _keywordIcon;
+ QIcon _macroIcon;
+};
+
+} // namespace CPlusPlus
+
+#endif // CPLUSPLUS_ICONS_H
diff --git a/src/libs/cplusplus/LookupContext.cpp b/src/libs/cplusplus/LookupContext.cpp
new file mode 100644
index 0000000000..027cfb577d
--- /dev/null
+++ b/src/libs/cplusplus/LookupContext.cpp
@@ -0,0 +1,402 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "LookupContext.h"
+#include <CoreTypes.h>
+#include <Symbols.h>
+#include <Literals.h>
+#include <Names.h>
+#include <Scope.h>
+#include <Control.h>
+#include <cplusplus/Overview.h>
+#include <QFile>
+#include <QtDebug>
+
+using namespace CPlusPlus;
+
+/////////////////////////////////////////////////////////////////////
+// LookupUtils
+/////////////////////////////////////////////////////////////////////
+bool LookupUtils::isNameCompatibleWithIdentifier(Name *name, Identifier *id)
+{
+ if (! name) {
+ return false;
+ } else if (NameId *nameId = name->asNameId()) {
+ Identifier *identifier = nameId->identifier();
+ return identifier->isEqualTo(id);
+ } else if (DestructorNameId *nameId = name->asDestructorNameId()) {
+ Identifier *identifier = nameId->identifier();
+ return identifier->isEqualTo(id);
+ } else if (TemplateNameId *templNameId = name->asTemplateNameId()) {
+ Identifier *identifier = templNameId->identifier();
+ return identifier->isEqualTo(id);
+ }
+
+ return false;
+}
+
+/////////////////////////////////////////////////////////////////////
+// LookupContext
+/////////////////////////////////////////////////////////////////////
+LookupContext::LookupContext(Control *control)
+ : _control(control),
+ _symbol(0)
+{ }
+
+LookupContext::LookupContext(Symbol *symbol,
+ Document::Ptr expressionDocument,
+ Document::Ptr thisDocument,
+ const QMap<QString, Document::Ptr> &documents)
+ : _symbol(symbol),
+ _expressionDocument(expressionDocument),
+ _thisDocument(thisDocument),
+ _documents(documents)
+{
+ _control = _expressionDocument->control();
+ _visibleScopes = buildVisibleScopes();
+}
+
+LookupContext::LookupContext(Symbol *symbol,
+ const LookupContext &context)
+ : _control(context._control),
+ _symbol(symbol),
+ _expressionDocument(context._expressionDocument),
+ _documents(context._documents)
+{
+ const QString fn = QString::fromUtf8(symbol->fileName(), symbol->fileNameLength());
+ _thisDocument = _documents.value(fn);
+ _visibleScopes = buildVisibleScopes();
+}
+
+LookupContext::LookupContext(Symbol *symbol,
+ Document::Ptr thisDocument,
+ const LookupContext &context)
+ : _control(context._control),
+ _symbol(symbol),
+ _expressionDocument(context._expressionDocument),
+ _thisDocument(thisDocument),
+ _documents(context._documents)
+{
+ _visibleScopes = buildVisibleScopes();
+}
+
+bool LookupContext::isValid() const
+{ return _control != 0; }
+
+LookupContext::operator bool() const
+{ return _control != 0; }
+
+Control *LookupContext::control() const
+{ return _control; }
+
+Symbol *LookupContext::symbol() const
+{ return _symbol; }
+
+Document::Ptr LookupContext::expressionDocument() const
+{ return _expressionDocument; }
+
+Document::Ptr LookupContext::thisDocument() const
+{ return _thisDocument; }
+
+Document::Ptr LookupContext::document(const QString &fileName) const
+{ return _documents.value(fileName); }
+
+Identifier *LookupContext::identifier(Name *name) const
+{
+ if (NameId *nameId = name->asNameId())
+ return nameId->identifier();
+ else if (TemplateNameId *templId = name->asTemplateNameId())
+ return templId->identifier();
+ else if (DestructorNameId *dtorId = name->asDestructorNameId())
+ return dtorId->identifier();
+ else if (QualifiedNameId *q = name->asQualifiedNameId())
+ return identifier(q->unqualifiedNameId());
+ return 0;
+}
+
+QList<Symbol *> LookupContext::resolve(Name *name, const QList<Scope *> &visibleScopes,
+ ResolveMode mode) const
+{
+ if (QualifiedNameId *q = name->asQualifiedNameId()) {
+ QList<Scope *> scopes = visibleScopes;
+ for (unsigned i = 0; i < q->nameCount(); ++i) {
+ Name *name = q->nameAt(i);
+
+ QList<Symbol *> candidates;
+ if (i + 1 == q->nameCount())
+ candidates = resolve(name, scopes, mode);
+ else
+ candidates = resolveClassOrNamespace(name, scopes);
+
+ if (candidates.isEmpty() || i + 1 == q->nameCount())
+ return candidates;
+
+ scopes.clear();
+ foreach (Symbol *candidate, candidates) {
+ if (ScopedSymbol *scoped = candidate->asScopedSymbol()) {
+ expand(scoped->members(), visibleScopes, &scopes);
+ }
+ }
+ }
+
+ return QList<Symbol *>();
+ }
+
+ QList<Symbol *> candidates;
+ if (Identifier *id = identifier(name)) {
+ for (int scopeIndex = 0; scopeIndex < visibleScopes.size(); ++scopeIndex) {
+ Scope *scope = visibleScopes.at(scopeIndex);
+ for (Symbol *symbol = scope->lookat(id); symbol; symbol = symbol->next()) {
+ if (! symbol->name())
+ continue;
+ else if (symbol->name()->isQualifiedNameId())
+ continue;
+ else if (! isNameCompatibleWithIdentifier(symbol->name(), id))
+ continue;
+ else if (symbol->name()->isDestructorNameId() != name->isDestructorNameId())
+ continue;
+ else if ((((mode & ResolveNamespace) && symbol->isNamespace()) ||
+ ((mode & ResolveClass) && symbol->isClass()) ||
+ (mode & ResolveSymbol)) && ! candidates.contains(symbol)) {
+ candidates.append(symbol);
+ }
+ }
+ }
+ } else if (OperatorNameId *opId = name->asOperatorNameId()) {
+ for (int scopeIndex = 0; scopeIndex < visibleScopes.size(); ++scopeIndex) {
+ Scope *scope = visibleScopes.at(scopeIndex);
+ for (Symbol *symbol = scope->lookat(opId->kind()); symbol; symbol = symbol->next()) {
+ if (! opId->isEqualTo(symbol->name()))
+ continue;
+ else if (! candidates.contains(symbol))
+ candidates.append(symbol);
+ }
+ }
+ }
+
+ return candidates;
+}
+
+QList<Scope *> LookupContext::buildVisibleScopes()
+{
+ QList<Scope *> scopes;
+
+ if (_symbol) {
+ for (Scope *scope = _symbol->scope(); scope; scope = scope->enclosingScope()) {
+ scopes.append(scope);
+ }
+ }
+
+ QSet<QString> processed;
+ processed.insert(_thisDocument->fileName());
+
+ QList<QString> todo = _thisDocument->includedFiles();
+ while (! todo.isEmpty()) {
+ QString fn = todo.last();
+ todo.removeLast();
+
+ if (processed.contains(fn))
+ continue;
+
+ processed.insert(fn);
+ if (Document::Ptr doc = document(fn)) {
+ scopes.append(doc->globalNamespace()->members());
+ todo += doc->includedFiles();
+ }
+ }
+
+ while (true) {
+ QList<Scope *> expandedScopes;
+ expand(scopes, &expandedScopes);
+
+ if (expandedScopes.size() == scopes.size())
+ return expandedScopes;
+
+ scopes = expandedScopes;
+ }
+
+ return scopes;
+}
+
+QList<Scope *> LookupContext::visibleScopes(const QPair<FullySpecifiedType, Symbol *> &result) const
+{
+ Symbol *symbol = result.second;
+ QList<Scope *> scopes;
+ for (Scope *scope = symbol->scope(); scope; scope = scope->enclosingScope())
+ scopes.append(scope);
+ scopes += visibleScopes();
+ scopes = expand(scopes);
+ return scopes;
+}
+
+QList<Scope *> LookupContext::expand(const QList<Scope *> &scopes) const
+{
+ QList<Scope *> expanded;
+ expand(scopes, &expanded);
+ return expanded;
+}
+
+void LookupContext::expand(const QList<Scope *> &scopes, QList<Scope *> *expandedScopes) const
+{
+ for (int i = 0; i < scopes.size(); ++i) {
+ expand(scopes.at(i), scopes, expandedScopes);
+ }
+}
+
+void LookupContext::expand(Scope *scope,
+ const QList<Scope *> &visibleScopes,
+ QList<Scope *> *expandedScopes) const
+{
+ Overview overview;
+
+ if (expandedScopes->contains(scope)) {
+ //qDebug() << "skipped:" << overview.prettyName(scope->owner()->name());
+ return;
+ }
+
+ expandedScopes->append(scope);
+
+ if (scope->isNamespaceScope()) {
+ Namespace *ns = scope->owner()->asNamespace();
+ Name *nsName = ns->name();
+ if (nsName) {
+ QList<Symbol *> namespaceList = resolveNamespace(nsName, visibleScopes);
+ foreach (Symbol *otherNs, namespaceList) {
+ if (otherNs == ns)
+ continue;
+ expand(otherNs->asNamespace()->members(), visibleScopes, expandedScopes);
+ }
+ //qDebug() << "*** found:" << namespaceList.count() << "namespace aliases";
+ }
+ //qDebug() << "namespace scope" << overview.prettyName(ns->name())
+ //<< ns->fileName() << ns->line();
+ for (unsigned i = 0; i < scope->symbolCount(); ++i) { // ### make me fast
+ Symbol *symbol = scope->symbolAt(i);
+ if (Namespace *ns = symbol->asNamespace()) {
+ if (! ns->name()) {
+ expand(ns->members(), visibleScopes, expandedScopes);
+ }
+ } else if (UsingNamespaceDirective *u = symbol->asUsingNamespaceDirective()) {
+ QList<Symbol *> candidates = resolveNamespace(u->name(), visibleScopes);
+ //qDebug() << "found:" << candidates.count() << "namespaces to import for:"
+ //<< overview.prettyName(u->name());
+ for (int j = 0; j < candidates.size(); ++j) {
+ expand(candidates.at(j)->asNamespace()->members(),
+ visibleScopes, expandedScopes);
+ }
+ } else if (Enum *e = symbol->asEnum()) {
+ expand(e->members(), visibleScopes, expandedScopes);
+ }
+ }
+ } else if (scope->isClassScope()) {
+ Class *klass = scope->owner()->asClass();
+ for (unsigned i = 0; i < scope->symbolCount(); ++i) {
+ Symbol *symbol = scope->symbolAt(i);
+ if (Class *nestedClass = symbol->asClass()) {
+ if (! nestedClass->name()) {
+ expand(nestedClass->members(), visibleScopes, expandedScopes);
+ }
+ } else if (Enum *e = symbol->asEnum()) {
+ expand(e->members(), visibleScopes, expandedScopes);
+ }
+ }
+
+ if (klass->baseClassCount()) {
+ QList<Scope *> classVisibleScopes = visibleScopes;
+ for (Scope *scope = klass->scope(); scope; scope = scope->enclosingScope()) {
+ if (scope->isNamespaceScope()) {
+ Namespace *enclosingNamespace = scope->owner()->asNamespace();
+ if (enclosingNamespace->name()) {
+ QList<Symbol *> nsList = resolveNamespace(enclosingNamespace->name(),
+ visibleScopes);
+ foreach (Symbol *ns, nsList) {
+ expand(ns->asNamespace()->members(), classVisibleScopes, &classVisibleScopes);
+ }
+ }
+ }
+ }
+
+ for (unsigned i = 0; i < klass->baseClassCount(); ++i) {
+ BaseClass *baseClass = klass->baseClassAt(i);
+ Name *baseClassName = baseClass->name();
+ QList<Symbol *> baseClassCandidates = resolveClass(baseClassName, classVisibleScopes);
+ if (baseClassCandidates.isEmpty()) {
+ Overview overview;
+ qDebug() << "unresolved base class:" << overview.prettyName(baseClassName);
+ }
+ for (int j = 0; j < baseClassCandidates.size(); ++j) {
+ Class *baseClassSymbol = baseClassCandidates.at(j)->asClass();
+ expand(baseClassSymbol->members(), visibleScopes, expandedScopes);
+ }
+ }
+ }
+ } else if (scope->isBlockScope()) {
+ //qDebug() << "block scope" << overview.prettyName(scope->owner()->name());
+ for (unsigned i = 0; i < scope->symbolCount(); ++i) {
+ Symbol *symbol = scope->symbolAt(i);
+ if (UsingNamespaceDirective *u = symbol->asUsingNamespaceDirective()) {
+ QList<Symbol *> candidates = resolveNamespace(u->name(), visibleScopes);
+ //qDebug() << "found:" << candidates.count() << "namespaces to import for:"
+ //<< overview.prettyName(u->name());
+ for (int j = 0; j < candidates.size(); ++j) {
+ expand(candidates.at(j)->asNamespace()->members(),
+ visibleScopes, expandedScopes);
+ }
+ }
+
+ }
+ } else if (scope->isFunctionScope()) {
+ Function *function = scope->owner()->asFunction();
+ //qDebug() << "function scope" << overview.prettyName(function->name());
+ if (! expandedScopes->contains(function->arguments()))
+ expandedScopes->append(function->arguments());
+ if (QualifiedNameId *q = function->name()->asQualifiedNameId()) {
+ //qDebug() << "**** here:" << overview.prettyName(function->name());
+ Name *nestedNameSpec = 0;
+ if (q->nameCount() == 1 && q->isGlobal())
+ nestedNameSpec = q->nameAt(0);
+ else
+ nestedNameSpec = control()->qualifiedNameId(q->names(), q->nameCount() - 1,
+ q->isGlobal());
+ QList<Symbol *> candidates = resolveClassOrNamespace(nestedNameSpec, visibleScopes);
+ //qDebug() << "**** found:" << candidates.count() << "class or namespace for:"
+ //<< overview.prettyName(nestedNameSpec);
+ for (int j = 0; j < candidates.size(); ++j) {
+ expand(candidates.at(j)->asScopedSymbol()->members(),
+ visibleScopes, expandedScopes);
+ }
+ }
+ } else if (scope->isPrototypeScope()) {
+ //qDebug() << "prototype scope" << overview.prettyName(scope->owner()->name());
+ }
+}
diff --git a/src/libs/cplusplus/LookupContext.h b/src/libs/cplusplus/LookupContext.h
new file mode 100644
index 0000000000..d2fe8b7bef
--- /dev/null
+++ b/src/libs/cplusplus/LookupContext.h
@@ -0,0 +1,151 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 CPLUSPLUS_LOOKUPCONTEXT_H
+#define CPLUSPLUS_LOOKUPCONTEXT_H
+
+#include <SymbolVisitor.h>
+#include <cplusplus/CppDocument.h>
+
+#include <QList>
+#include <QSet>
+#include <QMap>
+
+namespace CPlusPlus {
+
+class CPLUSPLUS_EXPORT LookupUtils
+{
+public:
+ static bool isNameCompatibleWithIdentifier(Name *name,
+ Identifier *id);
+};
+
+class CPLUSPLUS_EXPORT LookupContext: LookupUtils
+{
+public:
+ LookupContext(Control *control = 0);
+
+ LookupContext(Symbol *symbol,
+ Document::Ptr expressionDocument,
+ Document::Ptr thisDocument,
+ const QMap<QString, Document::Ptr> &documents);
+
+ LookupContext(Symbol *symbol,
+ const LookupContext &context);
+
+ LookupContext(Symbol *symbol,
+ Document::Ptr thisDocument,
+ const LookupContext &context);
+
+ bool isValid() const;
+ operator bool() const;
+
+ Control *control() const;
+ Symbol *symbol() const;
+ Document::Ptr expressionDocument() const;
+ Document::Ptr thisDocument() const;
+ Document::Ptr document(const QString &fileName) const;
+
+ QList<Symbol *> resolve(Name *name) const
+ { return resolve(name, visibleScopes()); }
+
+ QList<Symbol *> resolveNamespace(Name *name) const
+ { return resolveNamespace(name, visibleScopes()); }
+
+ QList<Symbol *> resolveClass(Name *name) const
+ { return resolveClass(name, visibleScopes()); }
+
+ QList<Symbol *> resolveClassOrNamespace(Name *name) const
+ { return resolveClassOrNamespace(name, visibleScopes()); }
+
+ QMap<QString, Document::Ptr> documents() const
+ { return _documents; }
+
+ enum ResolveMode {
+ ResolveSymbol = 0x01,
+ ResolveClass = 0x02,
+ ResolveNamespace = 0x04,
+ ResolveClassOrNamespace = ResolveClass | ResolveNamespace,
+ ResolveAll = ResolveSymbol | ResolveClassOrNamespace
+ };
+
+ Identifier *identifier(Name *name) const;
+
+ QList<Symbol *> resolve(Name *name, const QList<Scope *> &visibleScopes,
+ ResolveMode mode = ResolveAll) const;
+
+ QList<Symbol *> resolveNamespace(Name *name, const QList<Scope *> &visibleScopes) const
+ { return resolve(name, visibleScopes, ResolveNamespace); }
+
+ QList<Symbol *> resolveClass(Name *name, const QList<Scope *> &visibleScopes) const
+ { return resolve(name, visibleScopes, ResolveClass); }
+
+ QList<Symbol *> resolveClassOrNamespace(Name *name, const QList<Scope *> &visibleScopes) const
+ { return resolve(name, visibleScopes, ResolveClassOrNamespace); }
+
+ QList<Scope *> visibleScopes() const
+ { return _visibleScopes; }
+
+ QList<Scope *> visibleScopes(const QPair<FullySpecifiedType, Symbol *> &result) const;
+
+ QList<Scope *> expand(const QList<Scope *> &scopes) const;
+
+ void expand(const QList<Scope *> &scopes, QList<Scope *> *expandedScopes) const;
+
+ void expand(Scope *scope, const QList<Scope *> &visibleScopes,
+ QList<Scope *> *expandedScopes) const;
+
+private:
+ QList<Scope *> buildVisibleScopes();
+
+private:
+ Control *_control;
+
+ // The current symbol.
+ Symbol *_symbol;
+
+ // The current expression.
+ Document::Ptr _expressionDocument;
+
+ // The current document.
+ Document::Ptr _thisDocument;
+
+ // All documents.
+ QMap<QString, Document::Ptr> _documents;
+
+ // Visible scopes.
+ QList<Scope *> _visibleScopes;
+};
+
+} // end of namespace CPlusPlus
+
+#endif // CPLUSPLUS_LOOKUPCONTEXT_H
diff --git a/src/libs/cplusplus/NameOfExpression.cpp b/src/libs/cplusplus/NameOfExpression.cpp
new file mode 100644
index 0000000000..d54e7f5521
--- /dev/null
+++ b/src/libs/cplusplus/NameOfExpression.cpp
@@ -0,0 +1,438 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "NameOfExpression.h"
+#include "LookupContext.h"
+
+#include <cplusplus/Overview.h>
+#include <Control.h>
+#include <AST.h>
+#include <Scope.h>
+#include <Names.h>
+#include <Symbols.h>
+#include <Literals.h>
+#include <CoreTypes.h>
+#include <TypeVisitor.h>
+#include <NameVisitor.h>
+#include <QList>
+#include <QtDebug>
+
+using namespace CPlusPlus;
+
+NameOfExpression::NameOfExpression(const LookupContext &context)
+ : ASTVisitor(context.expressionDocument()->control()),
+ _context(context),
+ sem(_context.control())
+{ }
+
+NameOfExpression::~NameOfExpression()
+{ }
+
+QList<FullySpecifiedType> ResolveExpression::operator()(ExpressionAST *ast)
+{
+ QList<FullySpecifiedType> previousResolvedSymbols = switchResolvedSymbols(QList<FullySpecifiedType>());
+ accept(ast);
+ return switchResolvedSymbols(previousResolvedSymbols);
+}
+
+QList<FullySpecifiedType> ResolveExpression::switchResolvedSymbols(const QList<FullySpecifiedType> &symbols)
+{
+ QList<FullySpecifiedType> previousResolvedSymbols = _resolvedSymbols;
+ _resolvedSymbols = symbols;
+ return previousResolvedSymbols;
+}
+
+bool ResolveExpression::visit(ExpressionListAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(BinaryExpressionAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(CastExpressionAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(ConditionAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(ConditionalExpressionAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(CppCastExpressionAST *)
+{
+ // ### resolve ast->type_id
+ return false;
+}
+
+bool ResolveExpression::visit(DeleteExpressionAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(ArrayInitializerAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(NewExpressionAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(TypeidExpressionAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(TypenameCallExpressionAST *)
+{
+ // nothing to do
+ return false;
+}
+
+bool ResolveExpression::visit(TypeConstructorCallAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(PostfixExpressionAST *ast)
+{
+ accept(ast->base_expression);
+
+ for (PostfixAST *fx = ast->postfix_expressions; fx; fx = fx->next) {
+ accept(fx);
+ }
+
+ return false;
+}
+
+bool ResolveExpression::visit(SizeofExpressionAST *)
+{
+ FullySpecifiedType ty(control()->integerType(IntegerType::Int));
+ ty.setUnsigned(true);
+ _resolvedSymbols.append(ty);
+ return false;
+}
+
+bool ResolveExpression::visit(NumericLiteralAST *)
+{
+ _resolvedSymbols.append(control()->integerType(IntegerType::Int)); // ### handle short, long, floats, ...
+ return false;
+}
+
+bool ResolveExpression::visit(BoolLiteralAST *)
+{
+ _resolvedSymbols.append(control()->integerType(IntegerType::Bool));
+ return false;
+}
+
+bool ResolveExpression::visit(ThisExpressionAST *)
+{
+ if (! _context.symbol())
+ return false;
+
+ Scope *scope = _context.symbol()->scope();
+ for (; scope; scope = scope->enclosingScope()) {
+ if (scope->isFunctionScope()) {
+ Function *fun = scope->owner()->asFunction();
+ if (Scope *cscope = scope->enclosingClassScope()) {
+ Class *klass = cscope->owner()->asClass();
+ FullySpecifiedType classTy(control()->namedType(klass->name()));
+ FullySpecifiedType ptrTy(control()->pointerType(classTy));
+ _resolvedSymbols.append(ptrTy);
+ break;
+ } else if (QualifiedNameId *q = fun->name()->asQualifiedNameId()) {
+ Name *nestedNameSpecifier = 0;
+ if (q->nameCount() == 2)
+ nestedNameSpecifier = q->nameAt(0);
+ else
+ nestedNameSpecifier = control()->qualifiedNameId(&q->names()[0], q->nameCount() - 1);
+ FullySpecifiedType classTy(control()->namedType(nestedNameSpecifier));
+ FullySpecifiedType ptrTy(control()->pointerType(classTy));
+ _resolvedSymbols.append(ptrTy);
+ break;
+ }
+ }
+ }
+ return false;
+}
+
+bool ResolveExpression::visit(NestedExpressionAST *ast)
+{
+ accept(ast->expression);
+ return false;
+}
+
+bool ResolveExpression::visit(StringLiteralAST *)
+{
+ FullySpecifiedType charTy = control()->integerType(IntegerType::Char);
+ charTy.setConst(true);
+ FullySpecifiedType ty(control()->pointerType(charTy));
+ _resolvedSymbols.append(ty);
+ return false;
+}
+
+bool ResolveExpression::visit(ThrowExpressionAST *)
+{
+ return false;
+}
+
+bool ResolveExpression::visit(TypeIdAST *)
+{
+ return false;
+}
+
+bool ResolveExpression::visit(UnaryExpressionAST *ast)
+{
+ accept(ast->expression);
+ unsigned unaryOp = tokenKind(ast->unary_op_token);
+ if (unaryOp == T_AMPER) {
+ QMutableListIterator<FullySpecifiedType> it(_resolvedSymbols);
+ while (it.hasNext()) {
+ FullySpecifiedType ty = it.next();
+ ty.setType(control()->pointerType(ty));
+ it.setValue(ty);
+ }
+ } else if (unaryOp == T_STAR) {
+ QMutableListIterator<FullySpecifiedType> it(_resolvedSymbols);
+ while (it.hasNext()) {
+ FullySpecifiedType ty = it.next();
+ if (PointerType *ptrTy = ty->asPointerType()) {
+ it.setValue(ptrTy->elementType());
+ } else {
+ it.remove();
+ }
+ }
+ }
+ return false;
+}
+
+bool ResolveExpression::visit(QualifiedNameAST *ast)
+{
+ Scope dummy;
+ Name *name = sem.check(ast, &dummy);
+
+ QList<Symbol *> symbols = _context.resolve(name);
+ foreach (Symbol *symbol, symbols) {
+ if (symbol->isTypedef()) {
+ if (NamedType *namedTy = symbol->type()->asNamedType()) {
+ LookupContext symbolContext(symbol, _context);
+ QList<Symbol *> resolvedClasses = symbolContext.resolveClass(namedTy->name());
+ if (resolvedClasses.count()) {
+ foreach (Symbol *s, resolvedClasses) {
+ _resolvedSymbols.append(s->type());
+ }
+ continue;
+ }
+ }
+ }
+ _resolvedSymbols.append(symbol->type());
+ }
+ return false;
+}
+
+bool ResolveExpression::visit(OperatorFunctionIdAST *)
+{
+ return false;
+}
+
+bool ResolveExpression::visit(ConversionFunctionIdAST *)
+{
+ return false;
+}
+
+bool ResolveExpression::visit(SimpleNameAST *ast)
+{
+ Scope dummy;
+ Name *name = sem.check(ast, &dummy);
+
+ QList<Symbol *> symbols = _context.resolve(name);
+ foreach (Symbol *symbol, symbols)
+ _resolvedSymbols.append(symbol->type());
+
+ return false;
+}
+
+bool ResolveExpression::visit(DestructorNameAST *)
+{
+ FullySpecifiedType ty(control()->voidType());
+ _resolvedSymbols.append(ty);
+ return false;
+}
+
+bool ResolveExpression::visit(TemplateIdAST *ast)
+{
+ Scope dummy;
+ Name *name = sem.check(ast, &dummy);
+
+ QList<Symbol *> symbols = _context.resolve(name);
+ foreach (Symbol *symbol, symbols)
+ _resolvedSymbols.append(symbol->type());
+
+ return false;
+}
+
+bool ResolveExpression::visit(CallAST *)
+{
+ QMutableListIterator<FullySpecifiedType> it(_resolvedSymbols);
+ while (it.hasNext()) {
+ FullySpecifiedType ty = it.next();
+ if (Function *funTy = ty->asFunction()) {
+ it.setValue(funTy->returnType());
+ } else {
+ it.remove();
+ }
+ }
+ return false;
+}
+
+bool ResolveExpression::visit(ArrayAccessAST * /* ast */)
+{
+ QMutableListIterator<FullySpecifiedType> it(_resolvedSymbols);
+ while (it.hasNext()) {
+ FullySpecifiedType ty = it.next();
+ if (PointerType *ptrTy = ty->asPointerType()) {
+ it.setValue(ptrTy->elementType());
+ } else {
+ it.remove();
+ }
+ }
+ return false;
+}
+
+bool ResolveExpression::visit(MemberAccessAST *ast)
+{
+ Scope dummy;
+ Name *memberName = sem.check(ast->member_name, &dummy);
+ unsigned accessOp = tokenKind(ast->access_token);
+
+ Overview overview;
+
+ QList<FullySpecifiedType> candidates = _resolvedSymbols;
+ _resolvedSymbols.clear();
+
+ foreach (FullySpecifiedType ty, candidates) {
+ NamedType *namedTy = 0;
+
+ if (accessOp == T_ARROW) {
+ if (PointerType *ptrTy = ty->asPointerType())
+ namedTy = ptrTy->elementType()->asNamedType();
+ } else if (accessOp == T_DOT) {
+ if (ReferenceType *refTy = ty->asReferenceType())
+ ty = refTy->elementType();
+ namedTy = ty->asNamedType();
+ if (! namedTy) {
+ Function *fun = ty->asFunction();
+ if (fun && (fun->scope()->isBlockScope() || fun->scope()->isNamespaceScope()))
+ namedTy = fun->returnType()->asNamedType();
+ }
+ }
+
+ if (namedTy) {
+ QList<Symbol *> symbols = _context.resolveClass(namedTy->name());
+ if (symbols.isEmpty())
+ return false;
+
+ Class *klass = symbols.first()->asClass();
+ QList<Scope *> allScopes;
+ QSet<Class *> processed;
+ QList<Class *> todo;
+ todo.append(klass);
+
+ while (! todo.isEmpty()) {
+ Class *klass = todo.last();
+ todo.removeLast();
+
+ if (processed.contains(klass))
+ continue;
+
+ processed.insert(klass);
+ allScopes.append(klass->members());
+
+ for (unsigned i = 0; i < klass->baseClassCount(); ++i) {
+ BaseClass *baseClass = klass->baseClassAt(i);
+ Name *baseClassName = baseClass->name();
+ QList<Symbol *> baseClasses = _context.resolveClass(baseClassName/*, allScopes*/);
+ if (baseClasses.isEmpty())
+ qWarning() << "unresolved base class:" << overview.prettyName(baseClassName);
+ foreach (Symbol *symbol, baseClasses) {
+ todo.append(symbol->asClass());
+ }
+ }
+ }
+
+ QList<Symbol *> candidates = _context.resolve(memberName, allScopes);
+ foreach (Symbol *candidate, candidates) {
+ FullySpecifiedType ty = candidate->type();
+ if (TemplateNameId *templId = namedTy->name()->asTemplateNameId()) {
+ Substitution subst;
+ for (unsigned i = 0; i < templId->templateArgumentCount(); ++i) {
+ FullySpecifiedType templArgTy = templId->templateArgumentAt(i);
+ if (i < klass->templateParameterCount()) {
+ subst.append(qMakePair(klass->templateParameterAt(i)->name(),
+ templArgTy));
+ }
+ }
+ Instantiation inst(control(), subst);
+ ty = inst(ty);
+ }
+ _resolvedSymbols.append(ty);
+ }
+ }
+ }
+ return false;
+}
+
+bool ResolveExpression::visit(PostIncrDecrAST *)
+{
+ return false;
+}
diff --git a/src/libs/cplusplus/NameOfExpression.h b/src/libs/cplusplus/NameOfExpression.h
new file mode 100644
index 0000000000..f68795cea0
--- /dev/null
+++ b/src/libs/cplusplus/NameOfExpression.h
@@ -0,0 +1,99 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 CPLUSPLUS_NAMEOFEXPRESSION_H
+#define CPLUSPLUS_NAMEOFEXPRESSION_H
+
+#include "LookupContext.h"
+#include <ASTVisitor.h>
+#include <Semantic.h>
+#include <FullySpecifiedType.h>
+
+namespace CPlusPlus {
+
+class CPLUSPLUS_EXPORT NameOfExpression : protected ASTVisitor
+{
+public:
+ NameOfExpression(const LookupContext &context);
+ virtual ~NameOfExpression();
+
+ Name* operator()(ExpressionAST *ast);
+
+protected:
+ QList<FullySpecifiedType> switchResolvedSymbols(const QList<FullySpecifiedType> &symbols);
+
+ virtual bool visit(ExpressionListAST *ast);
+ virtual bool visit(BinaryExpressionAST *ast);
+ virtual bool visit(CastExpressionAST *ast);
+ virtual bool visit(ConditionAST *ast);
+ virtual bool visit(ConditionalExpressionAST *ast);
+ virtual bool visit(CppCastExpressionAST *ast);
+ virtual bool visit(DeleteExpressionAST *ast);
+ virtual bool visit(ArrayInitializerAST *ast);
+ virtual bool visit(NewExpressionAST *ast);
+ virtual bool visit(TypeidExpressionAST *ast);
+ virtual bool visit(TypenameCallExpressionAST *ast);
+ virtual bool visit(TypeConstructorCallAST *ast);
+ virtual bool visit(PostfixExpressionAST *ast);
+ virtual bool visit(SizeofExpressionAST *ast);
+ virtual bool visit(NumericLiteralAST *ast);
+ virtual bool visit(BoolLiteralAST *ast);
+ virtual bool visit(ThisExpressionAST *ast);
+ virtual bool visit(NestedExpressionAST *ast);
+ virtual bool visit(StringLiteralAST *ast);
+ virtual bool visit(ThrowExpressionAST *ast);
+ virtual bool visit(TypeIdAST *ast);
+ virtual bool visit(UnaryExpressionAST *ast);
+
+ //names
+ virtual bool visit(QualifiedNameAST *ast);
+ virtual bool visit(OperatorFunctionIdAST *ast);
+ virtual bool visit(ConversionFunctionIdAST *ast);
+ virtual bool visit(SimpleNameAST *ast);
+ virtual bool visit(DestructorNameAST *ast);
+ virtual bool visit(TemplateIdAST *ast);
+
+ // postfix expressions
+ virtual bool visit(CallAST *ast);
+ virtual bool visit(ArrayAccessAST *ast);
+ virtual bool visit(PostIncrDecrAST *ast);
+ virtual bool visit(MemberAccessAST *ast);
+
+private:
+ LookupContext _context;
+ Semantic sem;
+ QList<FullySpecifiedType> _resolvedSymbols;
+};
+
+} // end of namespace CPlusPlus
+
+#endif // CPLUSPLUS_NAMEOFEXPRESSION_H
diff --git a/src/libs/cplusplus/NamePrettyPrinter.cpp b/src/libs/cplusplus/NamePrettyPrinter.cpp
new file mode 100644
index 0000000000..5d6fddfb63
--- /dev/null
+++ b/src/libs/cplusplus/NamePrettyPrinter.cpp
@@ -0,0 +1,255 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "NamePrettyPrinter.h"
+#include <Names.h>
+#include <Overview.h>
+#include <NameVisitor.h>
+#include <Literals.h>
+
+using namespace CPlusPlus;
+
+NamePrettyPrinter::NamePrettyPrinter(const Overview *overview)
+ : _overview(overview)
+{ }
+
+NamePrettyPrinter::~NamePrettyPrinter()
+{ }
+
+const Overview *NamePrettyPrinter::overview() const
+{ return _overview; }
+
+QString NamePrettyPrinter::operator()(Name *name)
+{
+ QString previousName = switchName();
+ accept(name);
+ return switchName(previousName);
+}
+
+QString NamePrettyPrinter::switchName(const QString &name)
+{
+ QString previousName = _name;
+ _name = name;
+ return previousName;
+}
+
+void NamePrettyPrinter::visit(NameId *name)
+{
+ Identifier *id = name->identifier();
+ if (id)
+ _name = QString::fromLatin1(id->chars(), id->size());
+ else
+ _name = QLatin1String("anonymous");
+}
+
+void NamePrettyPrinter::visit(TemplateNameId *name)
+{
+ Identifier *id = name->identifier();
+ if (id)
+ _name = QString::fromLatin1(id->chars(), id->size());
+ else
+ _name = QLatin1String("anonymous");
+ _name += QLatin1Char('<');
+ for (unsigned index = 0; index < name->templateArgumentCount(); ++index) {
+ if (index != 0)
+ _name += QLatin1String(", ");
+
+ FullySpecifiedType argTy = name->templateArgumentAt(index);
+ QString arg = overview()->prettyType(argTy);
+ if (arg.isEmpty())
+ _name += QString::fromLatin1("_Tp%1").arg(index + 1);
+ else
+ _name += arg;
+ }
+ _name += QLatin1Char('>');
+}
+
+void NamePrettyPrinter::visit(DestructorNameId *name)
+{
+ Identifier *id = name->identifier();
+ _name += QLatin1Char('~');
+ _name += QString::fromLatin1(id->chars(), id->size());
+}
+
+void NamePrettyPrinter::visit(OperatorNameId *name)
+{
+ _name += QLatin1String("operator ");
+ switch (name->kind()) { // ### i should probably do this in OperatorNameId
+ case OperatorNameId::InvalidOp:
+ _name += QLatin1String("<invalid>");
+ break;
+ case OperatorNameId::NewOp:
+ _name += QLatin1String("new");
+ break;
+ case OperatorNameId::DeleteOp:
+ _name += QLatin1String("delete");
+ break;
+ case OperatorNameId::NewArrayOp:
+ _name += QLatin1String("new[]");
+ break;
+ case OperatorNameId::DeleteArrayOp:
+ _name += QLatin1String("delete[]");
+ break;
+ case OperatorNameId::PlusOp:
+ _name += QLatin1String("+");
+ break;
+ case OperatorNameId::MinusOp:
+ _name += QLatin1String("-");
+ break;
+ case OperatorNameId::StarOp:
+ _name += QLatin1String("*");
+ break;
+ case OperatorNameId::SlashOp:
+ _name += QLatin1String("/");
+ break;
+ case OperatorNameId::PercentOp:
+ _name += QLatin1String("%");
+ break;
+ case OperatorNameId::CaretOp:
+ _name += QLatin1String("^");
+ break;
+ case OperatorNameId::AmpOp:
+ _name += QLatin1String("&");
+ break;
+ case OperatorNameId::PipeOp:
+ _name += QLatin1String("|");
+ break;
+ case OperatorNameId::TildeOp:
+ _name += QLatin1String("~");
+ break;
+ case OperatorNameId::ExclaimOp:
+ _name += QLatin1String("!");
+ break;
+ case OperatorNameId::EqualOp:
+ _name += QLatin1String("=");
+ break;
+ case OperatorNameId::LessOp:
+ _name += QLatin1String("<");
+ break;
+ case OperatorNameId::GreaterOp:
+ _name += QLatin1String(">");
+ break;
+ case OperatorNameId::PlusEqualOp:
+ _name += QLatin1String("+=");
+ break;
+ case OperatorNameId::MinusEqualOp:
+ _name += QLatin1String("-=");
+ break;
+ case OperatorNameId::StarEqualOp:
+ _name += QLatin1String("*=");
+ break;
+ case OperatorNameId::SlashEqualOp:
+ _name += QLatin1String("/=");
+ break;
+ case OperatorNameId::PercentEqualOp:
+ _name += QLatin1String("%=");
+ break;
+ case OperatorNameId::CaretEqualOp:
+ _name += QLatin1String("^=");
+ break;
+ case OperatorNameId::AmpEqualOp:
+ _name += QLatin1String("&=");
+ break;
+ case OperatorNameId::PipeEqualOp:
+ _name += QLatin1String("|=");
+ break;
+ case OperatorNameId::LessLessOp:
+ _name += QLatin1String("<<");
+ break;
+ case OperatorNameId::GreaterGreaterOp:
+ _name += QLatin1String(">>");
+ break;
+ case OperatorNameId::LessLessEqualOp:
+ _name += QLatin1String("<<=");
+ break;
+ case OperatorNameId::GreaterGreaterEqualOp:
+ _name += QLatin1String(">>=");
+ break;
+ case OperatorNameId::EqualEqualOp:
+ _name += QLatin1String("==");
+ break;
+ case OperatorNameId::ExclaimEqualOp:
+ _name += QLatin1String("!=");
+ break;
+ case OperatorNameId::LessEqualOp:
+ _name += QLatin1String("<=");
+ break;
+ case OperatorNameId::GreaterEqualOp:
+ _name += QLatin1String(">=");
+ break;
+ case OperatorNameId::AmpAmpOp:
+ _name += QLatin1String("&&");
+ break;
+ case OperatorNameId::PipePipeOp:
+ _name += QLatin1String("||");
+ break;
+ case OperatorNameId::PlusPlusOp:
+ _name += QLatin1String("++");
+ break;
+ case OperatorNameId::MinusMinusOp:
+ _name += QLatin1String("--");
+ break;
+ case OperatorNameId::CommaOp:
+ _name += QLatin1String(",");
+ break;
+ case OperatorNameId::ArrowStarOp:
+ _name += QLatin1String("->*");
+ break;
+ case OperatorNameId::ArrowOp:
+ _name += QLatin1String("->");
+ break;
+ case OperatorNameId::FunctionCallOp:
+ _name += QLatin1String("()");
+ break;
+ case OperatorNameId::ArrayAccessOp:
+ _name += QLatin1String("[]");
+ break;
+ } // switch
+}
+
+void NamePrettyPrinter::visit(ConversionNameId *name)
+{
+ _name += QLatin1String("operator ");
+ _name += overview()->prettyType(name->type());
+}
+
+void NamePrettyPrinter::visit(QualifiedNameId *name)
+{
+ if (name->isGlobal())
+ _name += QLatin1String("::");
+
+ for (unsigned index = 0; index < name->nameCount(); ++index) {
+ if (index != 0)
+ _name += QLatin1String("::");
+ _name += operator()(name->nameAt(index));
+ }
+}
diff --git a/src/libs/cplusplus/NamePrettyPrinter.h b/src/libs/cplusplus/NamePrettyPrinter.h
new file mode 100644
index 0000000000..3868432650
--- /dev/null
+++ b/src/libs/cplusplus/NamePrettyPrinter.h
@@ -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 (qt-info@nokia.com)
+**
+**
+** 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 CPLUSPLUS_NAMEPRETTYPRINTER_H
+#define CPLUSPLUS_NAMEPRETTYPRINTER_H
+
+#include <NameVisitor.h>
+#include <QString>
+
+namespace CPlusPlus {
+
+class Overview;
+
+class CPLUSPLUS_EXPORT NamePrettyPrinter: protected NameVisitor
+{
+public:
+ NamePrettyPrinter(const Overview *overview);
+ virtual ~NamePrettyPrinter();
+
+ const Overview *overview() const;
+ QString operator()(Name *name);
+
+protected:
+ QString switchName(const QString &name = QString());
+
+ virtual void visit(NameId *name);
+ virtual void visit(TemplateNameId *name);
+ virtual void visit(DestructorNameId *name);
+ virtual void visit(OperatorNameId *name);
+ virtual void visit(ConversionNameId *name);
+ virtual void visit(QualifiedNameId *name);
+
+private:
+ const Overview *_overview;
+ QString _name;
+};
+
+} // end of namespace CPlusPlus
+
+#endif // CPLUSPLUS_NAMEPRETTYPRINTER_H
diff --git a/src/libs/cplusplus/Overview.cpp b/src/libs/cplusplus/Overview.cpp
new file mode 100644
index 0000000000..ec40f75b51
--- /dev/null
+++ b/src/libs/cplusplus/Overview.cpp
@@ -0,0 +1,91 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "Overview.h"
+#include "NamePrettyPrinter.h"
+#include "TypePrettyPrinter.h"
+#include <FullySpecifiedType.h>
+
+using namespace CPlusPlus;
+
+Overview::Overview()
+ : _markArgument(0),
+ _showArgumentNames(false),
+ _showReturnTypes(false),
+ _showFunctionSignatures(true)
+{ }
+
+Overview::~Overview()
+{ }
+
+bool Overview::showArgumentNames() const
+{ return _showArgumentNames; }
+
+void Overview::setShowArgumentNames(bool showArgumentNames)
+{ _showArgumentNames = showArgumentNames; }
+
+void Overview::setShowReturnTypes(bool showReturnTypes)
+{ _showReturnTypes = showReturnTypes; }
+
+bool Overview::showReturnTypes() const
+{ return _showReturnTypes; }
+
+void Overview::setMarkArgument(unsigned position)
+{ _markArgument = position; }
+
+bool Overview::showFunctionSignatures() const
+{ return _showFunctionSignatures; }
+
+void Overview::setShowFunctionSignatures(bool showFunctionSignatures)
+{ _showFunctionSignatures = showFunctionSignatures; }
+
+QString Overview::prettyName(Name *name) const
+{
+ NamePrettyPrinter pp(this);
+ return pp(name);
+}
+
+QString Overview::prettyType(const FullySpecifiedType &ty,
+ Name *name) const
+{ return prettyType(ty, prettyName(name)); }
+
+QString Overview::prettyType(const FullySpecifiedType &ty,
+ const QString &name) const
+{
+ TypePrettyPrinter pp(this);
+ pp.setMarkArgument(_markArgument);
+ pp.setShowArgumentNames(_showArgumentNames);
+ pp.setShowReturnTypes(_showReturnTypes);
+ pp.setShowFunctionSignatures(_showFunctionSignatures);
+ return pp(ty, name);
+}
diff --git a/src/libs/cplusplus/Overview.h b/src/libs/cplusplus/Overview.h
new file mode 100644
index 0000000000..6b84a4b53f
--- /dev/null
+++ b/src/libs/cplusplus/Overview.h
@@ -0,0 +1,80 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 OVERVIEW_H
+#define OVERVIEW_H
+
+#include <CPlusPlusForwardDeclarations.h>
+#include <QString>
+
+namespace CPlusPlus {
+
+class CPLUSPLUS_EXPORT Overview
+{
+ Overview(const Overview &other);
+ void operator =(const Overview &other);
+
+public:
+ Overview();
+ ~Overview();
+
+ bool showArgumentNames() const;
+ void setShowArgumentNames(bool showArgumentNames);
+
+ bool showReturnTypes() const;
+ void setShowReturnTypes(bool showReturnTypes);
+
+ bool showFunctionSignatures() const;
+ void setShowFunctionSignatures(bool showFunctionSignatures);
+
+ void setMarkArgument(unsigned position); // 1-based
+
+ QString operator()(Name *name) const
+ { return prettyName(name); }
+
+ QString operator()(const FullySpecifiedType &type, Name *name = 0) const
+ { return prettyType(type, name); }
+
+ QString prettyName(Name *name) const;
+ QString prettyType(const FullySpecifiedType &type, Name *name = 0) const;
+ QString prettyType(const FullySpecifiedType &type, const QString &name) const;
+
+private:
+ unsigned _markArgument;
+ bool _showArgumentNames: 1;
+ bool _showReturnTypes: 1;
+ bool _showFunctionSignatures: 1;
+};
+
+} // end of namespace CPlusPlus
+
+#endif // OVERVIEW_H
diff --git a/src/libs/cplusplus/OverviewModel.cpp b/src/libs/cplusplus/OverviewModel.cpp
new file mode 100644
index 0000000000..028811e6ae
--- /dev/null
+++ b/src/libs/cplusplus/OverviewModel.cpp
@@ -0,0 +1,183 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "OverviewModel.h"
+#include "Overview.h"
+#include <Scope.h>
+#include <Semantic.h>
+#include <Literals.h>
+#include <Symbols.h>
+#include <QFile>
+#include <QtDebug>
+
+using namespace CPlusPlus;
+
+OverviewModel::OverviewModel(QObject *parent)
+ : QAbstractItemModel(parent)
+{ }
+
+OverviewModel::~OverviewModel()
+{ }
+
+bool OverviewModel::hasDocument() const
+{ return _cppDocument; }
+
+Document::Ptr OverviewModel::document() const
+{ return _cppDocument; }
+
+unsigned OverviewModel::globalSymbolCount() const
+{
+ unsigned count = 0;
+ if (_cppDocument)
+ count += _cppDocument->globalSymbolCount();
+ return count;
+}
+
+Symbol *OverviewModel::globalSymbolAt(unsigned index) const
+{ return _cppDocument->globalSymbolAt(index); }
+
+QModelIndex OverviewModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if (! hasDocument()) {
+ return QModelIndex();
+ } else if (! parent.isValid()) {
+ Symbol *symbol = globalSymbolAt(row);
+ return createIndex(row, column, symbol);
+ } else {
+ Symbol *parentSymbol = static_cast<Symbol *>(parent.internalPointer());
+ Q_ASSERT(parentSymbol != 0);
+
+ ScopedSymbol *scopedSymbol = parentSymbol->asScopedSymbol();
+ Q_ASSERT(scopedSymbol != 0);
+
+ Scope *scope = scopedSymbol->members();
+ Q_ASSERT(scope != 0);
+
+ return createIndex(row, 0, scope->symbolAt(row));
+ }
+}
+
+QModelIndex OverviewModel::parent(const QModelIndex &child) const
+{
+ Symbol *symbol = static_cast<Symbol *>(child.internalPointer());
+ Q_ASSERT(symbol != 0);
+
+ if (Scope *scope = symbol->scope()) {
+ Symbol *parentSymbol = scope->owner();
+ if (parentSymbol && parentSymbol->scope())
+ return createIndex(parentSymbol->index(), 0, parentSymbol);
+ }
+
+ return QModelIndex();
+}
+
+int OverviewModel::rowCount(const QModelIndex &parent) const
+{
+ if (hasDocument()) {
+ if (! parent.isValid()) {
+ return globalSymbolCount();
+ } else {
+ Symbol *parentSymbol = static_cast<Symbol *>(parent.internalPointer());
+ Q_ASSERT(parentSymbol != 0);
+
+ if (ScopedSymbol *scopedSymbol = parentSymbol->asScopedSymbol()) {
+ if (! scopedSymbol->isFunction()) {
+ Scope *parentScope = scopedSymbol->members();
+ Q_ASSERT(parentScope != 0);
+
+ return parentScope->symbolCount();
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+int OverviewModel::columnCount(const QModelIndex &) const
+{ return 1; }
+
+QVariant OverviewModel::data(const QModelIndex &index, int role) const
+{
+ switch (role) {
+ case Qt::DisplayRole: {
+ Symbol *symbol = static_cast<Symbol *>(index.internalPointer());
+ QString name = _overview.prettyName(symbol->name());
+ if (name.isEmpty())
+ name = QLatin1String("anonymous");
+ if (! symbol->isScopedSymbol() || symbol->isFunction()) {
+ QString type = _overview.prettyType(symbol->type());
+ if (! type.isEmpty()) {
+ if (! symbol->type()->isFunction())
+ name += QLatin1String(": ");
+ name += type;
+ }
+ }
+ return name;
+ }
+
+ case Qt::EditRole: {
+ Symbol *symbol = static_cast<Symbol *>(index.internalPointer());
+ QString name = _overview.prettyName(symbol->name());
+ if (name.isEmpty())
+ name = QLatin1String("anonymous");
+ return name;
+ }
+
+ case Qt::DecorationRole: {
+ Symbol *symbol = static_cast<Symbol *>(index.internalPointer());
+ return _icons.iconForSymbol(symbol);
+ } break;
+
+ case FileNameRole: {
+ Symbol *symbol = static_cast<Symbol *>(index.internalPointer());
+ return QString::fromUtf8(symbol->fileName(), symbol->fileNameLength());
+ }
+
+ case LineNumberRole: {
+ Symbol *symbol = static_cast<Symbol *>(index.internalPointer());
+ return symbol->line();
+ }
+
+ default:
+ return QVariant();
+ } // switch
+}
+
+Symbol *OverviewModel::symbolFromIndex(const QModelIndex &index) const
+{ return static_cast<Symbol *>(index.internalPointer()); }
+
+void OverviewModel::rebuild(Document::Ptr doc)
+{
+ _cppDocument = doc;
+ reset();
+}
diff --git a/src/libs/cplusplus/OverviewModel.h b/src/libs/cplusplus/OverviewModel.h
new file mode 100644
index 0000000000..9ff920487b
--- /dev/null
+++ b/src/libs/cplusplus/OverviewModel.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 CPLUSPLUS_OVERVIEWMODEL_H
+#define CPLUSPLUS_OVERVIEWMODEL_H
+
+#include "CppDocument.h"
+#include "Overview.h"
+#include "Icons.h"
+
+#include <QAbstractItemModel>
+#include <QIcon>
+
+namespace CPlusPlus {
+
+class CPLUSPLUS_EXPORT OverviewModel: public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+ enum Role {
+ FileNameRole = Qt::UserRole + 1,
+ LineNumberRole
+ };
+
+public:
+ OverviewModel(QObject *parent = 0);
+ virtual ~OverviewModel();
+
+ virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
+ virtual QModelIndex parent(const QModelIndex &child) const;
+ virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+ Document::Ptr document() const;
+ Symbol *symbolFromIndex(const QModelIndex &index) const;
+
+public Q_SLOTS:
+ void rebuild(CPlusPlus::Document::Ptr doc);
+
+private:
+ bool hasDocument() const;
+ unsigned globalSymbolCount() const;
+ Symbol *globalSymbolAt(unsigned index) const;
+
+private:
+ Document::Ptr _cppDocument;
+ Overview _overview;
+ Icons _icons;
+};
+
+} // end of namespace CPlusPlus
+
+#endif // CPLUSPLUS_OVERVIEWMODEL_H
diff --git a/src/libs/cplusplus/ResolveExpression.cpp b/src/libs/cplusplus/ResolveExpression.cpp
new file mode 100644
index 0000000000..6071f235c4
--- /dev/null
+++ b/src/libs/cplusplus/ResolveExpression.cpp
@@ -0,0 +1,793 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "ResolveExpression.h"
+#include "LookupContext.h"
+#include "Overview.h"
+
+#include <Control.h>
+#include <AST.h>
+#include <Scope.h>
+#include <Names.h>
+#include <Symbols.h>
+#include <Literals.h>
+#include <CoreTypes.h>
+#include <TypeVisitor.h>
+#include <NameVisitor.h>
+#include <QList>
+#include <QtDebug>
+
+using namespace CPlusPlus;
+
+namespace {
+
+typedef QList< QPair<Name *, FullySpecifiedType> > Substitution;
+
+class Instantiation: protected TypeVisitor, protected NameVisitor
+{
+ Control *_control;
+ FullySpecifiedType _type;
+ const Substitution _substitution;
+
+public:
+ Instantiation(Control *control, const Substitution &substitution)
+ : _control(control),
+ _substitution(substitution)
+ { }
+
+ FullySpecifiedType operator()(const FullySpecifiedType &ty)
+ { return subst(ty); }
+
+protected:
+ FullySpecifiedType subst(Name *name)
+ {
+ for (int i = 0; i < _substitution.size(); ++i) {
+ const QPair<Name *, FullySpecifiedType> s = _substitution.at(i);
+ if (name->isEqualTo(s.first))
+ return s.second;
+ }
+
+ return _control->namedType(name);
+ }
+
+ FullySpecifiedType subst(const FullySpecifiedType &ty)
+ {
+ FullySpecifiedType previousType = switchType(ty);
+ TypeVisitor::accept(ty.type());
+ return switchType(previousType);
+ }
+
+ FullySpecifiedType switchType(const FullySpecifiedType &type)
+ {
+ FullySpecifiedType previousType = _type;
+ _type = type;
+ return previousType;
+ }
+
+ // types
+ virtual void visit(PointerToMemberType * /*ty*/)
+ {
+ Q_ASSERT(0);
+ }
+
+ virtual void visit(PointerType *ty)
+ {
+ FullySpecifiedType elementType = subst(ty->elementType());
+ _type.setType(_control->pointerType(elementType));
+ }
+
+ virtual void visit(ReferenceType *ty)
+ {
+ FullySpecifiedType elementType = subst(ty->elementType());
+ _type.setType(_control->referenceType(elementType));
+ }
+
+ virtual void visit(ArrayType *ty)
+ {
+ FullySpecifiedType elementType = subst(ty->elementType());
+ _type.setType(_control->arrayType(elementType, ty->size()));
+ }
+
+ virtual void visit(NamedType *ty)
+ { _type.setType(subst(ty->name()).type()); } // ### merge the specifiers
+
+ virtual void visit(Function *ty)
+ {
+ Name *name = ty->name();
+ FullySpecifiedType returnType = subst(ty->returnType());
+
+ Function *fun = _control->newFunction(0, name);
+ fun->setScope(ty->scope());
+ fun->setReturnType(returnType);
+ for (unsigned i = 0; i < ty->argumentCount(); ++i) {
+ Symbol *arg = ty->argumentAt(i);
+ FullySpecifiedType argTy = subst(arg->type());
+ Argument *newArg = _control->newArgument(0, arg->name());
+ newArg->setType(argTy);
+ fun->arguments()->enterSymbol(newArg);
+ }
+ _type.setType(fun);
+ }
+
+ virtual void visit(VoidType *)
+ { /* nothing to do*/ }
+
+ virtual void visit(IntegerType *)
+ { /* nothing to do*/ }
+
+ virtual void visit(FloatType *)
+ { /* nothing to do*/ }
+
+ virtual void visit(Namespace *)
+ { Q_ASSERT(0); }
+
+ virtual void visit(Class *)
+ { Q_ASSERT(0); }
+
+ virtual void visit(Enum *)
+ { Q_ASSERT(0); }
+
+ // names
+ virtual void visit(NameId *)
+ { Q_ASSERT(0); }
+
+ virtual void visit(TemplateNameId *)
+ { Q_ASSERT(0); }
+
+ virtual void visit(DestructorNameId *)
+ { Q_ASSERT(0); }
+
+ virtual void visit(OperatorNameId *)
+ { Q_ASSERT(0); }
+
+ virtual void visit(ConversionNameId *)
+ { Q_ASSERT(0); }
+
+ virtual void visit(QualifiedNameId *)
+ { Q_ASSERT(0); }
+};
+
+} // end of anonymous namespace
+
+/////////////////////////////////////////////////////////////////////
+// ResolveExpression
+/////////////////////////////////////////////////////////////////////
+ResolveExpression::ResolveExpression(const LookupContext &context)
+ : ASTVisitor(context.expressionDocument()->control()),
+ _context(context),
+ sem(_context.control())
+{ }
+
+ResolveExpression::~ResolveExpression()
+{ }
+
+QList<ResolveExpression::Result> ResolveExpression::operator()(ExpressionAST *ast)
+{
+ const QList<Result> previousResults = switchResults(QList<Result>());
+ accept(ast);
+ return switchResults(previousResults);
+}
+
+QList<ResolveExpression::Result>
+ResolveExpression::switchResults(const QList<ResolveExpression::Result> &results)
+{
+ const QList<Result> previousResults = _results;
+ _results = results;
+ return previousResults;
+}
+
+void ResolveExpression::addResults(const QList<Result> &results)
+{
+ foreach (const Result r, results)
+ addResult(r);
+}
+
+void ResolveExpression::addResult(const FullySpecifiedType &ty, Symbol *symbol)
+{ return addResult(Result(ty, symbol)); }
+
+void ResolveExpression::addResult(const Result &r)
+{
+ Result p = r;
+ if (! p.second)
+ p.second = _context.symbol();
+
+ if (! _results.contains(p))
+ _results.append(p);
+}
+
+QList<Scope *> ResolveExpression::visibleScopes(const Result &result) const
+{ return _context.visibleScopes(result); }
+
+bool ResolveExpression::visit(ExpressionListAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(BinaryExpressionAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(CastExpressionAST *ast)
+{
+ Scope dummy;
+ addResult(sem.check(ast->type_id, &dummy));
+ return false;
+}
+
+bool ResolveExpression::visit(ConditionAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(ConditionalExpressionAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(CppCastExpressionAST *ast)
+{
+ Scope dummy;
+ addResult(sem.check(ast->type_id, &dummy));
+ return false;
+}
+
+bool ResolveExpression::visit(DeleteExpressionAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(ArrayInitializerAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(NewExpressionAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(TypeidExpressionAST *)
+{
+ Name *std_type_info[2];
+ std_type_info[0] = control()->nameId(control()->findOrInsertIdentifier("std"));
+ std_type_info[1] = control()->nameId(control()->findOrInsertIdentifier("type_info"));
+
+ Name *q = control()->qualifiedNameId(std_type_info, 2, /*global=*/ true);
+ FullySpecifiedType ty(control()->namedType(q));
+ addResult(ty);
+
+ return false;
+}
+
+bool ResolveExpression::visit(TypenameCallExpressionAST *)
+{
+ // nothing to do
+ return false;
+}
+
+bool ResolveExpression::visit(TypeConstructorCallAST *)
+{
+ // nothing to do.
+ return false;
+}
+
+bool ResolveExpression::visit(PostfixExpressionAST *ast)
+{
+ accept(ast->base_expression);
+
+ for (PostfixAST *fx = ast->postfix_expressions; fx; fx = fx->next) {
+ accept(fx);
+ }
+
+ return false;
+}
+
+bool ResolveExpression::visit(SizeofExpressionAST *)
+{
+ FullySpecifiedType ty(control()->integerType(IntegerType::Int));
+ ty.setUnsigned(true);
+ addResult(ty);
+ return false;
+}
+
+bool ResolveExpression::visit(NumericLiteralAST *)
+{
+ FullySpecifiedType ty(control()->integerType(IntegerType::Int));
+ addResult(ty);
+ return false;
+}
+
+bool ResolveExpression::visit(BoolLiteralAST *)
+{
+ FullySpecifiedType ty(control()->integerType(IntegerType::Bool));
+ addResult(ty);
+ return false;
+}
+
+bool ResolveExpression::visit(ThisExpressionAST *)
+{
+ if (! _context.symbol())
+ return false;
+
+ Scope *scope = _context.symbol()->scope();
+ for (; scope; scope = scope->enclosingScope()) {
+ if (scope->isFunctionScope()) {
+ Function *fun = scope->owner()->asFunction();
+ if (Scope *cscope = scope->enclosingClassScope()) {
+ Class *klass = cscope->owner()->asClass();
+ FullySpecifiedType classTy(control()->namedType(klass->name()));
+ FullySpecifiedType ptrTy(control()->pointerType(classTy));
+ addResult(ptrTy, fun);
+ break;
+ } else if (QualifiedNameId *q = fun->name()->asQualifiedNameId()) {
+ Name *nestedNameSpecifier = 0;
+ if (q->nameCount() == 1 && q->isGlobal())
+ nestedNameSpecifier = q->nameAt(0);
+ else
+ nestedNameSpecifier = control()->qualifiedNameId(q->names(), q->nameCount() - 1);
+ FullySpecifiedType classTy(control()->namedType(nestedNameSpecifier));
+ FullySpecifiedType ptrTy(control()->pointerType(classTy));
+ addResult(ptrTy, fun);
+ break;
+ }
+ }
+ }
+ return false;
+}
+
+bool ResolveExpression::visit(NestedExpressionAST *ast)
+{
+ accept(ast->expression);
+ return false;
+}
+
+bool ResolveExpression::visit(StringLiteralAST *)
+{
+ FullySpecifiedType charTy = control()->integerType(IntegerType::Char);
+ charTy.setConst(true);
+ FullySpecifiedType ty(control()->pointerType(charTy));
+ addResult(ty);
+ return false;
+}
+
+bool ResolveExpression::visit(ThrowExpressionAST *)
+{
+ return false;
+}
+
+bool ResolveExpression::visit(TypeIdAST *)
+{
+ return false;
+}
+
+bool ResolveExpression::visit(UnaryExpressionAST *ast)
+{
+ accept(ast->expression);
+ unsigned unaryOp = tokenKind(ast->unary_op_token);
+ if (unaryOp == T_AMPER) {
+ QMutableListIterator<Result > it(_results);
+ while (it.hasNext()) {
+ Result p = it.next();
+ p.first.setType(control()->pointerType(p.first));
+ it.setValue(p);
+ }
+ } else if (unaryOp == T_STAR) {
+ QMutableListIterator<Result > it(_results);
+ while (it.hasNext()) {
+ Result p = it.next();
+ if (PointerType *ptrTy = p.first->asPointerType()) {
+ p.first = ptrTy->elementType();
+ it.setValue(p);
+ } else {
+ it.remove();
+ }
+ }
+ }
+ return false;
+}
+
+bool ResolveExpression::visit(QualifiedNameAST *ast)
+{
+ Scope dummy;
+ Name *name = sem.check(ast, &dummy);
+
+ QList<Symbol *> symbols = _context.resolve(name);
+ foreach (Symbol *symbol, symbols) {
+ if (symbol->isTypedef()) {
+ if (NamedType *namedTy = symbol->type()->asNamedType()) {
+ LookupContext symbolContext(symbol, _context);
+ QList<Symbol *> resolvedClasses = symbolContext.resolveClass(namedTy->name());
+ if (resolvedClasses.count()) {
+ foreach (Symbol *s, resolvedClasses) {
+ addResult(s->type(), s);
+ }
+ continue;
+ }
+ }
+ }
+ addResult(symbol->type(), symbol);
+ }
+ return false;
+}
+
+bool ResolveExpression::visit(OperatorFunctionIdAST *)
+{
+ return false;
+}
+
+bool ResolveExpression::visit(ConversionFunctionIdAST *)
+{
+ return false;
+}
+
+bool ResolveExpression::visit(SimpleNameAST *ast)
+{
+ Scope dummy;
+ Name *name = sem.check(ast, &dummy);
+
+ QList<Symbol *> symbols = _context.resolve(name);
+ foreach (Symbol *symbol, symbols)
+ addResult(symbol->type(), symbol);
+
+ return false;
+}
+
+bool ResolveExpression::visit(DestructorNameAST *)
+{
+ FullySpecifiedType ty(control()->voidType());
+ addResult(ty);
+ return false;
+}
+
+bool ResolveExpression::visit(TemplateIdAST *ast)
+{
+ Scope dummy;
+ Name *name = sem.check(ast, &dummy);
+
+ QList<Symbol *> symbols = _context.resolve(name);
+ foreach (Symbol *symbol, symbols)
+ addResult(symbol->type(), symbol);
+
+ return false;
+}
+
+bool ResolveExpression::visit(CallAST *ast)
+{
+ // Compute the types of the actual arguments.
+ QList< QList<Result> > arguments;
+ for (ExpressionListAST *exprIt = ast->expression_list; exprIt;
+ exprIt = exprIt->next) {
+ arguments.append(operator()(exprIt->expression));
+ }
+
+ QList<Result> baseResults = _results;
+ _results.clear();
+
+ foreach (Result p, baseResults) {
+ if (Function *funTy = p.first->asFunction()) {
+ unsigned minNumberArguments = 0;
+ for (; minNumberArguments < funTy->argumentCount(); ++minNumberArguments) {
+ Argument *arg = funTy->argumentAt(minNumberArguments)->asArgument();
+ if (arg->hasInitializer())
+ break;
+ }
+ const unsigned actualArgumentCount = arguments.count();
+ if (actualArgumentCount < minNumberArguments) {
+ // not enough arguments.
+ } else if (! funTy->isVariadic() && actualArgumentCount > funTy->argumentCount()) {
+ // too many arguments.
+ } else {
+ p.first = funTy->returnType();
+ addResult(p);
+ }
+ } else if (Class *classTy = p.first->asClass()) {
+ // Constructor call
+ p.first = control()->namedType(classTy->name());
+ addResult(p);
+ }
+ }
+
+ return false;
+}
+
+bool ResolveExpression::visit(ArrayAccessAST *ast)
+{
+ const QList<Result> baseResults = _results;
+ _results.clear();
+
+ const QList<Result> indexResults = operator()(ast->expression);
+
+ foreach (Result p, baseResults) {
+ FullySpecifiedType ty = p.first;
+ Symbol *contextSymbol = p.second;
+
+ if (ReferenceType *refTy = ty->asReferenceType())
+ ty = refTy->elementType();
+
+ if (PointerType *ptrTy = ty->asPointerType()) {
+ addResult(ptrTy->elementType(), contextSymbol);
+ } else if (ArrayType *arrTy = ty->asArrayType()) {
+ addResult(arrTy->elementType(), contextSymbol);
+ } else if (NamedType *namedTy = ty->asNamedType()) {
+ Name *className = namedTy->name();
+ const QList<Scope *> scopes = visibleScopes(p);
+ const QList<Symbol *> classObjectCandidates = _context.resolveClass(className, scopes);
+
+ foreach (Symbol *classObject, classObjectCandidates) {
+ const QList<Result> overloads = resolveArrayOperator(p, namedTy,
+ classObject->asClass());
+ foreach (Result r, overloads) {
+ FullySpecifiedType ty = r.first;
+ Function *funTy = ty->asFunction();
+ if (! funTy)
+ continue;
+
+ ty = funTy->returnType();
+ addResult(ty, funTy);
+ }
+ }
+ }
+ }
+ return false;
+}
+
+bool ResolveExpression::visit(MemberAccessAST *ast)
+{
+ // The candidate types for the base expression are stored in
+ // _results.
+ QList<Result> baseResults = _results;
+
+ // Evaluate the expression-id that follows the access operator.
+ Scope dummy;
+ Name *memberName = sem.check(ast->member_name, &dummy);
+
+ // Remember the access operator.
+ const unsigned accessOp = tokenKind(ast->access_token);
+
+ _results = resolveMemberExpression(baseResults, accessOp, memberName);
+
+ return false;
+}
+
+QList<ResolveExpression::Result>
+ResolveExpression::resolveMemberExpression(const QList<Result> &baseResults,
+ unsigned accessOp,
+ Name *memberName) const
+{
+ QList<Result> results;
+
+ if (accessOp == T_ARROW) {
+ foreach (Result p, baseResults) {
+ FullySpecifiedType ty = p.first;
+
+ if (ReferenceType *refTy = ty->asReferenceType())
+ ty = refTy->elementType();
+
+ if (NamedType *namedTy = ty->asNamedType()) {
+ Name *className = namedTy->name();
+ const QList<Scope *> scopes = visibleScopes(p);
+ const QList<Symbol *> classObjectCandidates = _context.resolveClass(className, scopes);
+
+ foreach (Symbol *classObject, classObjectCandidates) {
+ const QList<Result> overloads = resolveArrowOperator(p, namedTy,
+ classObject->asClass());
+ foreach (Result r, overloads) {
+ FullySpecifiedType ty = r.first;
+ Function *funTy = ty->asFunction();
+ if (! funTy)
+ continue;
+
+ ty = funTy->returnType();
+
+ if (ReferenceType *refTy = ty->asReferenceType())
+ ty = refTy->elementType();
+
+ if (PointerType *ptrTy = ty->asPointerType()) {
+ if (NamedType *namedTy = ptrTy->elementType()->asNamedType())
+ results += resolveMember(r, memberName, namedTy);
+ }
+ }
+ }
+ } else if (PointerType *ptrTy = ty->asPointerType()) {
+ if (NamedType *namedTy = ptrTy->elementType()->asNamedType())
+ results += resolveMember(p, memberName, namedTy);
+ }
+ }
+ } else if (accessOp == T_DOT) {
+ // The base expression shall be a "class object" of a complete type.
+ foreach (Result p, baseResults) {
+ FullySpecifiedType ty = p.first;
+
+ if (ReferenceType *refTy = ty->asReferenceType())
+ ty = refTy->elementType();
+
+ if (NamedType *namedTy = ty->asNamedType())
+ results += resolveMember(p, memberName, namedTy);
+ else if (Function *fun = ty->asFunction()) {
+ if (fun->scope()->isBlockScope() || fun->scope()->isNamespaceScope()) {
+ ty = fun->returnType();
+
+ if (ReferenceType *refTy = ty->asReferenceType())
+ ty = refTy->elementType();
+
+ if (NamedType *namedTy = ty->asNamedType())
+ results += resolveMember(p, memberName, namedTy);
+ }
+ }
+
+ }
+ }
+
+ return results;
+}
+
+QList<ResolveExpression::Result>
+ResolveExpression::resolveMember(const Result &p,
+ Name *memberName,
+ NamedType *namedTy) const
+{
+ QList<Result> results;
+ Name *className = namedTy->name();
+ const QList<Scope *> scopes = visibleScopes(p);
+ const QList<Symbol *> classObjectCandidates = _context.resolveClass(className, scopes);
+ foreach (Symbol *classObject, classObjectCandidates) {
+ results += resolveMember(p, memberName, namedTy, classObject->asClass());
+ }
+ return results;
+}
+
+QList<ResolveExpression::Result>
+ResolveExpression::resolveMember(const Result &,
+ Name *memberName,
+ NamedType *namedTy,
+ Class *klass) const
+{
+ QList<Scope *> scopes;
+ _context.expand(klass->members(), _context.visibleScopes(), &scopes);
+ QList<Result> results;
+
+ QList<Symbol *> candidates = _context.resolve(memberName, scopes);
+ foreach (Symbol *candidate, candidates) {
+ FullySpecifiedType ty = candidate->type();
+ Name *unqualifiedNameId = namedTy->name();
+ if (QualifiedNameId *q = namedTy->name()->asQualifiedNameId())
+ unqualifiedNameId = q->unqualifiedNameId();
+ if (TemplateNameId *templId = unqualifiedNameId->asTemplateNameId()) {
+ Substitution subst;
+ for (unsigned i = 0; i < templId->templateArgumentCount(); ++i) {
+ FullySpecifiedType templArgTy = templId->templateArgumentAt(i);
+ if (i < klass->templateParameterCount()) {
+ subst.append(qMakePair(klass->templateParameterAt(i)->name(),
+ templArgTy));
+ }
+ }
+ Instantiation inst(control(), subst);
+ ty = inst(ty);
+ }
+
+ const Result result(ty, candidate);
+ if (! results.contains(result))
+ results.append(result);
+ }
+
+ return results;
+}
+
+QList<ResolveExpression::Result>
+ResolveExpression::resolveArrowOperator(const Result &,
+ NamedType *namedTy,
+ Class *klass) const
+{
+ QList<Scope *> scopes;
+ _context.expand(klass->members(), _context.visibleScopes(), &scopes);
+ QList<Result> results;
+
+ Name *memberName = control()->operatorNameId(OperatorNameId::ArrowOp);
+ QList<Symbol *> candidates = _context.resolve(memberName, scopes);
+ foreach (Symbol *candidate, candidates) {
+ FullySpecifiedType ty = candidate->type();
+ Name *unqualifiedNameId = namedTy->name();
+ if (QualifiedNameId *q = namedTy->name()->asQualifiedNameId())
+ unqualifiedNameId = q->unqualifiedNameId();
+ if (TemplateNameId *templId = unqualifiedNameId->asTemplateNameId()) {
+ Substitution subst;
+ for (unsigned i = 0; i < templId->templateArgumentCount(); ++i) {
+ FullySpecifiedType templArgTy = templId->templateArgumentAt(i);
+ if (i < klass->templateParameterCount()) {
+ subst.append(qMakePair(klass->templateParameterAt(i)->name(),
+ templArgTy));
+ }
+ }
+ Instantiation inst(control(), subst);
+ ty = inst(ty);
+ }
+
+ const Result result(ty, candidate);
+ if (! results.contains(result))
+ results.append(result);
+ }
+
+ return results;
+}
+
+QList<ResolveExpression::Result>
+ResolveExpression::resolveArrayOperator(const Result &,
+ NamedType *namedTy,
+ Class *klass) const
+{
+ // ### todo handle index expressions.
+
+ QList<Scope *> scopes;
+ _context.expand(klass->members(), _context.visibleScopes(), &scopes);
+ QList<Result> results;
+
+ Name *memberName = control()->operatorNameId(OperatorNameId::ArrayAccessOp);
+ QList<Symbol *> candidates = _context.resolve(memberName, scopes);
+ foreach (Symbol *candidate, candidates) {
+ FullySpecifiedType ty = candidate->type();
+ Name *unqualifiedNameId = namedTy->name();
+ if (QualifiedNameId *q = namedTy->name()->asQualifiedNameId())
+ unqualifiedNameId = q->unqualifiedNameId();
+ if (TemplateNameId *templId = unqualifiedNameId->asTemplateNameId()) {
+ Substitution subst;
+ for (unsigned i = 0; i < templId->templateArgumentCount(); ++i) {
+ FullySpecifiedType templArgTy = templId->templateArgumentAt(i);
+ if (i < klass->templateParameterCount()) {
+ subst.append(qMakePair(klass->templateParameterAt(i)->name(),
+ templArgTy));
+ }
+ }
+ Instantiation inst(control(), subst);
+ ty = inst(ty);
+ }
+
+ const Result result(ty, candidate);
+ if (! results.contains(result))
+ results.append(result);
+ }
+
+ return results;
+}
+
+bool ResolveExpression::visit(PostIncrDecrAST *)
+{
+ return false;
+}
diff --git a/src/libs/cplusplus/ResolveExpression.h b/src/libs/cplusplus/ResolveExpression.h
new file mode 100644
index 0000000000..75963bb2fe
--- /dev/null
+++ b/src/libs/cplusplus/ResolveExpression.h
@@ -0,0 +1,131 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 CPLUSPLUS_RESOLVEEXPRESSION_H
+#define CPLUSPLUS_RESOLVEEXPRESSION_H
+
+#include "LookupContext.h"
+#include <ASTVisitor.h>
+#include <Semantic.h>
+#include <FullySpecifiedType.h>
+
+namespace CPlusPlus {
+
+class CPLUSPLUS_EXPORT ResolveExpression: protected ASTVisitor
+{
+public:
+ typedef QPair<FullySpecifiedType, Symbol *> Result;
+
+public:
+ ResolveExpression(const LookupContext &context);
+ virtual ~ResolveExpression();
+
+ QList<Result> operator()(ExpressionAST *ast);
+
+ QList<Result> resolveMemberExpression(const QList<Result> &baseResults,
+ unsigned accessOp,
+ Name *memberName) const;
+
+ QList<Result> resolveMember(const Result &result,
+ Name *memberName,
+ NamedType *namedTy) const;
+
+ QList<Result> resolveMember(const Result &result,
+ Name *memberName,
+ NamedType *namedTy,
+ Class *klass) const;
+
+ QList<Result> resolveArrowOperator(const Result &result,
+ NamedType *namedTy,
+ Class *klass) const;
+
+ QList<Result> resolveArrayOperator(const Result &result,
+ NamedType *namedTy,
+ Class *klass) const;
+
+protected:
+ QList<Result> switchResults(const QList<Result> &symbols);
+
+ void addResult(const FullySpecifiedType &ty, Symbol *symbol = 0);
+ void addResult(const Result &result);
+ void addResults(const QList<Result> &results);
+
+ using ASTVisitor::visit;
+
+ virtual bool visit(ExpressionListAST *ast);
+ virtual bool visit(BinaryExpressionAST *ast);
+ virtual bool visit(CastExpressionAST *ast);
+ virtual bool visit(ConditionAST *ast);
+ virtual bool visit(ConditionalExpressionAST *ast);
+ virtual bool visit(CppCastExpressionAST *ast);
+ virtual bool visit(DeleteExpressionAST *ast);
+ virtual bool visit(ArrayInitializerAST *ast);
+ virtual bool visit(NewExpressionAST *ast);
+ virtual bool visit(TypeidExpressionAST *ast);
+ virtual bool visit(TypenameCallExpressionAST *ast);
+ virtual bool visit(TypeConstructorCallAST *ast);
+ virtual bool visit(PostfixExpressionAST *ast);
+ virtual bool visit(SizeofExpressionAST *ast);
+ virtual bool visit(NumericLiteralAST *ast);
+ virtual bool visit(BoolLiteralAST *ast);
+ virtual bool visit(ThisExpressionAST *ast);
+ virtual bool visit(NestedExpressionAST *ast);
+ virtual bool visit(StringLiteralAST *ast);
+ virtual bool visit(ThrowExpressionAST *ast);
+ virtual bool visit(TypeIdAST *ast);
+ virtual bool visit(UnaryExpressionAST *ast);
+
+ //names
+ virtual bool visit(QualifiedNameAST *ast);
+ virtual bool visit(OperatorFunctionIdAST *ast);
+ virtual bool visit(ConversionFunctionIdAST *ast);
+ virtual bool visit(SimpleNameAST *ast);
+ virtual bool visit(DestructorNameAST *ast);
+ virtual bool visit(TemplateIdAST *ast);
+
+ // postfix expressions
+ virtual bool visit(CallAST *ast);
+ virtual bool visit(ArrayAccessAST *ast);
+ virtual bool visit(PostIncrDecrAST *ast);
+ virtual bool visit(MemberAccessAST *ast);
+
+ QList<Scope *> visibleScopes(const Result &result) const;
+
+private:
+ LookupContext _context;
+ Semantic sem;
+ QList<Result> _results;
+};
+
+} // end of namespace CPlusPlus
+
+#endif // CPLUSPLUS_RESOLVEEXPRESSION_H
diff --git a/src/libs/cplusplus/SimpleLexer.cpp b/src/libs/cplusplus/SimpleLexer.cpp
new file mode 100644
index 0000000000..f047d540c9
--- /dev/null
+++ b/src/libs/cplusplus/SimpleLexer.cpp
@@ -0,0 +1,117 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "SimpleLexer.h"
+#include <Lexer.h>
+#include <Token.h>
+#include <QtDebug>
+
+using namespace CPlusPlus;
+
+bool SimpleToken::isLiteral() const
+{ return _kind >= T_FIRST_LITERAL && _kind <= T_LAST_LITERAL; }
+
+bool SimpleToken::isOperator() const
+{ return _kind >= T_FIRST_OPERATOR && _kind <= T_LAST_OPERATOR; }
+
+bool SimpleToken::isKeyword() const
+{ return _kind >= T_FIRST_KEYWORD && _kind < T_FIRST_QT_KEYWORD; }
+
+SimpleLexer::SimpleLexer()
+ : _lastState(0),
+ _skipComments(false),
+ _qtMocRunEnabled(true)
+{ }
+
+SimpleLexer::~SimpleLexer()
+{ }
+
+bool SimpleLexer::qtMocRunEnabled() const
+{ return _qtMocRunEnabled; }
+
+void SimpleLexer::setQtMocRunEnabled(bool enabled)
+{ _qtMocRunEnabled = enabled; }
+
+bool SimpleLexer::skipComments() const
+{ return _skipComments; }
+
+void SimpleLexer::setSkipComments(bool skipComments)
+{ _skipComments = skipComments; }
+
+QList<SimpleToken> SimpleLexer::operator()(const QString &text, int state)
+{
+ QList<SimpleToken> tokens;
+
+ const QByteArray bytes = text.toLatin1();
+ const char *firstChar = bytes.constData();
+ const char *lastChar = firstChar + bytes.size();
+
+ Lexer lex(firstChar, lastChar);
+ lex.setQtMocRunEnabled(_qtMocRunEnabled);
+
+ if (! _skipComments)
+ lex.setScanCommentTokens(true);
+
+ if (state != -1)
+ lex.setState(state & 0xff);
+
+ bool inPreproc = false;
+
+ for (;;) {
+ Token tk;
+ lex(&tk);
+ if (tk.is(T_EOF_SYMBOL))
+ break;
+
+ SimpleToken simpleTk;
+ simpleTk._kind = int(tk.kind);
+ simpleTk._position = int(lex.tokenOffset());
+ simpleTk._length = int(lex.tokenLength());
+ simpleTk._text = text.midRef(simpleTk._position, simpleTk._length);
+
+ lex.setScanAngleStringLiteralTokens(false);
+
+ if (tk.newline && tk.is(T_POUND))
+ inPreproc = true;
+ else if (inPreproc && tokens.size() == 1 && simpleTk.is(T_IDENTIFIER) &&
+ simpleTk.text() == QLatin1String("include"))
+ lex.setScanAngleStringLiteralTokens(true);
+
+ tokens.append(simpleTk);
+ }
+
+ _lastState = lex.state();
+ return tokens;
+}
+
+
diff --git a/src/libs/cplusplus/SimpleLexer.h b/src/libs/cplusplus/SimpleLexer.h
new file mode 100644
index 0000000000..9bbba41950
--- /dev/null
+++ b/src/libs/cplusplus/SimpleLexer.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 (qt-info@nokia.com)
+**
+**
+** 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 SIMPLELEXER_H
+#define SIMPLELEXER_H
+
+#include <CPlusPlusForwardDeclarations.h>
+#include <QString>
+#include <QList>
+
+namespace CPlusPlus {
+
+class SimpleLexer;
+
+class CPLUSPLUS_EXPORT SimpleToken
+{
+public:
+ SimpleToken()
+ : _kind(0),
+ _position(0),
+ _length(0)
+ { }
+
+ inline int kind() const
+ { return _kind; }
+
+ inline int position() const
+ { return _position; }
+
+ inline int length() const
+ { return _length; }
+
+ inline QStringRef text() const
+ { return _text; }
+
+ inline bool is(int k) const { return _kind == k; }
+ inline bool isNot(int k) const { return _kind != k; }
+
+ bool isLiteral() const;
+ bool isOperator() const;
+ bool isKeyword() const;
+
+public:
+ int _kind;
+ int _position;
+ int _length;
+ QStringRef _text;
+
+ friend class SimpleLexer;
+};
+
+class CPLUSPLUS_EXPORT SimpleLexer
+{
+public:
+ SimpleLexer();
+ ~SimpleLexer();
+
+ bool skipComments() const;
+ void setSkipComments(bool skipComments);
+
+ bool qtMocRunEnabled() const;
+ void setQtMocRunEnabled(bool enabled);
+
+ QList<SimpleToken> operator()(const QString &text, int state = 0);
+
+ int state() const
+ { return _lastState; }
+
+private:
+ int _lastState;
+ bool _skipComments: 1;
+ bool _qtMocRunEnabled: 1;
+};
+
+} // end of namespace CPlusPlus
+
+#endif // SIMPLELEXER_H
diff --git a/src/libs/cplusplus/TokenUnderCursor.cpp b/src/libs/cplusplus/TokenUnderCursor.cpp
new file mode 100644
index 0000000000..84a1992244
--- /dev/null
+++ b/src/libs/cplusplus/TokenUnderCursor.cpp
@@ -0,0 +1,75 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "TokenUnderCursor.h"
+#include <Token.h>
+
+#include <QTextCursor>
+#include <QTextBlock>
+#include <climits>
+
+using namespace CPlusPlus;
+
+TokenUnderCursor::TokenUnderCursor()
+{ }
+
+TokenUnderCursor::~TokenUnderCursor()
+{ }
+
+SimpleToken TokenUnderCursor::operator()(const QTextCursor &cursor) const
+{
+ SimpleLexer tokenize;
+ QTextBlock block = cursor.block();
+ int column = cursor.columnNumber();
+
+ QList<SimpleToken> tokens = tokenize(block.text(), previousBlockState(block));
+ for (int index = tokens.size() - 1; index != -1; --index) {
+ const SimpleToken &tk = tokens.at(index);
+ if (tk.position() < column)
+ return tk;
+ }
+
+ return SimpleToken();
+}
+
+int TokenUnderCursor::previousBlockState(const QTextBlock &block) const
+{
+ const QTextBlock prevBlock = block.previous();
+ if (prevBlock.isValid()) {
+ int state = prevBlock.userState();
+
+ if (state != -1)
+ return state;
+ }
+ return 0;
+}
diff --git a/src/libs/cplusplus/TokenUnderCursor.h b/src/libs/cplusplus/TokenUnderCursor.h
new file mode 100644
index 0000000000..cd08833d21
--- /dev/null
+++ b/src/libs/cplusplus/TokenUnderCursor.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 TOKENUNDERCURSOR_H
+#define TOKENUNDERCURSOR_H
+
+#include "SimpleLexer.h"
+#include <QList>
+
+QT_BEGIN_NAMESPACE
+class QString;
+class QTextCursor;
+class QTextBlock;
+QT_END_NAMESPACE
+
+namespace CPlusPlus {
+
+class SimpleToken;
+
+class CPLUSPLUS_EXPORT TokenUnderCursor
+{
+public:
+ TokenUnderCursor();
+ ~TokenUnderCursor();
+
+ SimpleToken operator()(const QTextCursor &cursor) const;
+
+private:
+ int previousBlockState(const QTextBlock &block) const;
+};
+
+} // end of namespace CPlusPlus
+
+#endif // TOKENUNDERCURSOR_H
diff --git a/src/libs/cplusplus/TypeOfExpression.cpp b/src/libs/cplusplus/TypeOfExpression.cpp
new file mode 100644
index 0000000000..f6ad3bdc53
--- /dev/null
+++ b/src/libs/cplusplus/TypeOfExpression.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 (qt-info@nokia.com)
+**
+**
+** 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 "TypeOfExpression.h"
+
+#include <AST.h>
+#include <TranslationUnit.h>
+#include <cplusplus/LookupContext.h>
+#include <cplusplus/ResolveExpression.h>
+
+using namespace CPlusPlus;
+
+TypeOfExpression::TypeOfExpression():
+ m_ast(0)
+{
+}
+
+void TypeOfExpression::setDocuments(const QMap<QString, Document::Ptr> &documents)
+{
+ m_documents = documents;
+}
+
+QList<TypeOfExpression::Result> TypeOfExpression::operator()(const QString &expression,
+ Document::Ptr document,
+ Symbol *lastVisibleSymbol)
+{
+ Document::Ptr expressionDoc = documentForExpression(expression);
+ m_ast = extractExpressionAST(expressionDoc);
+
+ m_lookupContext = LookupContext(lastVisibleSymbol, expressionDoc,
+ document, m_documents);
+
+ ResolveExpression resolveExpression(m_lookupContext);
+ return resolveExpression(m_ast);
+}
+
+ExpressionAST *TypeOfExpression::ast() const
+{
+ return m_ast;
+}
+
+const LookupContext &TypeOfExpression::lookupContext() const
+{
+ return m_lookupContext;
+}
+
+ExpressionAST *TypeOfExpression::expressionAST() const
+{
+ return extractExpressionAST(m_lookupContext.expressionDocument());
+}
+
+ExpressionAST *TypeOfExpression::extractExpressionAST(Document::Ptr doc) const
+{
+ TranslationUnitAST *translationUnitAST = doc->translationUnit()->ast();
+
+ // ### evaluate the expression
+ ExpressionAST *expressionAST = 0;
+ if (translationUnitAST) {
+ DeclarationAST *declaration = translationUnitAST->declarations;
+ SimpleDeclarationAST *simpleDecl = 0;
+ if (declaration)
+ simpleDecl = declaration->asSimpleDeclaration();
+ if (simpleDecl && simpleDecl->decl_specifier_seq) {
+ if (TypeofSpecifierAST *typeOfSpec = simpleDecl->decl_specifier_seq->asTypeofSpecifier())
+ expressionAST = typeOfSpec->expression;
+ }
+ }
+ return expressionAST;
+}
+
+Document::Ptr TypeOfExpression::documentForExpression(const QString &expression) const
+{
+ // create a __typeof__ specifier
+ QByteArray declaration;
+ declaration += "__typeof__ ";
+ declaration += expression.toLatin1(); // C++ code needs to be in latin1
+ declaration += ";";
+
+ // create the expression's AST.
+ Document::Ptr doc = Document::create(QLatin1String("<completion>"));
+ doc->setSource(declaration);
+ doc->parse();
+ return doc;
+}
diff --git a/src/libs/cplusplus/TypeOfExpression.h b/src/libs/cplusplus/TypeOfExpression.h
new file mode 100644
index 0000000000..87df28f1ba
--- /dev/null
+++ b/src/libs/cplusplus/TypeOfExpression.h
@@ -0,0 +1,98 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 CPLUSPLUS_TYPEOFEXPRESSION_H
+#define CPLUSPLUS_TYPEOFEXPRESSION_H
+
+#include <ASTfwd.h>
+#include <cplusplus/CppDocument.h>
+#include <cplusplus/LookupContext.h>
+
+#include <QtCore/QMap>
+#include <QtCore/QObject>
+#include <QtCore/QString>
+
+namespace CPlusPlus {
+
+class CPLUSPLUS_EXPORT TypeOfExpression
+{
+public:
+ typedef QPair<FullySpecifiedType, Symbol *> Result;
+
+public:
+ TypeOfExpression();
+
+ /**
+ * Sets the documents used to evaluate expressions. Should be set before
+ * calling this functor.
+ */
+ void setDocuments(const QMap<QString, Document::Ptr> &documents);
+
+ /**
+ * Returns a list of possible fully specified types associated with the
+ * given expression.
+ *
+ * NOTE: The fully specified types only stay valid for as long as this
+ * expression evaluator instance still exists, and no new call to evaluate
+ * has been made!
+ *
+ * @param expression The expression to evaluate.
+ * @param document The document the expression is part of.
+ * @param lastVisibleSymbol The last visible symbol in the document.
+ */
+ QList<Result> operator()(const QString &expression, Document::Ptr document,
+ Symbol *lastVisibleSymbol);
+
+ /**
+ * Returns the AST of the last evaluated expression.
+ */
+ ExpressionAST *ast() const;
+
+ /**
+ * Returns the lookup context of the last evaluated expression.
+ */
+ const LookupContext &lookupContext() const;
+
+ ExpressionAST *expressionAST() const;
+
+private:
+ ExpressionAST *extractExpressionAST(Document::Ptr doc) const;
+ Document::Ptr documentForExpression(const QString &expression) const;
+
+ QMap<QString, Document::Ptr> m_documents;
+ ExpressionAST *m_ast;
+ LookupContext m_lookupContext;
+};
+
+} // namespace CPlusPlus
+
+#endif // CPLUSPLUS_TYPEOFEXPRESSION_H
diff --git a/src/libs/cplusplus/TypePrettyPrinter.cpp b/src/libs/cplusplus/TypePrettyPrinter.cpp
new file mode 100644
index 0000000000..3301a8c8d1
--- /dev/null
+++ b/src/libs/cplusplus/TypePrettyPrinter.cpp
@@ -0,0 +1,309 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "Overview.h"
+#include "TypePrettyPrinter.h"
+#include <FullySpecifiedType.h>
+#include <CoreTypes.h>
+#include <Symbols.h>
+#include <Scope.h>
+
+using namespace CPlusPlus;
+
+TypePrettyPrinter::TypePrettyPrinter(const Overview *overview)
+ : _overview(overview),
+ _name(0),
+ _markArgument(0),
+ _showArgumentNames(false),
+ _showReturnTypes(false),
+ _showFunctionSignatures(true)
+{ }
+
+TypePrettyPrinter::~TypePrettyPrinter()
+{ }
+
+bool TypePrettyPrinter::showArgumentNames() const
+{ return _showArgumentNames; }
+
+void TypePrettyPrinter::setShowArgumentNames(bool showArgumentNames)
+{ _showArgumentNames = showArgumentNames; }
+
+bool TypePrettyPrinter::showReturnTypes() const
+{ return _showReturnTypes; }
+
+void TypePrettyPrinter::setShowReturnTypes(bool showReturnTypes)
+{ _showReturnTypes = showReturnTypes; }
+
+bool TypePrettyPrinter::showFunctionSignatures() const
+{ return _showFunctionSignatures; }
+
+void TypePrettyPrinter::setShowFunctionSignatures(bool showFunctionSignatures)
+{ _showFunctionSignatures = showFunctionSignatures; }
+
+void TypePrettyPrinter::setMarkArgument(unsigned position)
+{ _markArgument = position; }
+
+const Overview *TypePrettyPrinter::overview() const
+{ return _overview; }
+
+QString TypePrettyPrinter::operator()(const FullySpecifiedType &ty)
+{
+ QString previousName = switchText();
+ acceptType(ty);
+ return switchText(previousName).trimmed();
+}
+
+QString TypePrettyPrinter::operator()(const FullySpecifiedType &type, const QString &name)
+{
+ QString previousName = switchName(name);
+ QString text = operator()(type);
+ if (! _name.isEmpty() && ! text.isEmpty()) {
+ QChar ch = text.at(text.size() - 1);
+ if (ch.isLetterOrNumber() || ch == QLatin1Char('_'))
+ text += QLatin1Char(' ');
+ text += _name;
+ }
+ (void) switchName(previousName);
+ return text;
+}
+
+
+void TypePrettyPrinter::acceptType(const FullySpecifiedType &ty)
+{
+ if (ty.isConst())
+ _text += QLatin1String("const ");
+ if (ty.isVolatile())
+ _text += QLatin1String("volatile ");
+ if (ty.isSigned())
+ _text += QLatin1String("signed ");
+ if (ty.isUnsigned())
+ _text += QLatin1String("unsigned ");
+ accept(ty.type());
+}
+
+QString TypePrettyPrinter::switchName(const QString &name)
+{
+ const QString previousName = _name;
+ _name = name;
+ return previousName;
+}
+
+QString TypePrettyPrinter::switchText(const QString &name)
+{
+ QString previousName = _text;
+ _text = name;
+ return previousName;
+}
+
+QList<Type *> TypePrettyPrinter::switchPtrOperators(const QList<Type *> &ptrOperators)
+{
+ QList<Type *> previousPtrOperators = _ptrOperators;
+ _ptrOperators = ptrOperators;
+ return previousPtrOperators;
+}
+
+void TypePrettyPrinter::applyPtrOperators(bool wantSpace)
+{
+ for (int i = _ptrOperators.size() - 1; i != -1; --i) {
+ Type *op = _ptrOperators.at(i);
+
+ if (i == 0 && wantSpace)
+ _text += QLatin1Char(' ');
+
+ if (PointerType *ptrTy = op->asPointerType()) {
+ _text += QLatin1Char('*');
+ if (ptrTy->elementType().isConst())
+ _text += " const";
+ if (ptrTy->elementType().isVolatile())
+ _text += " volatile";
+ } else if (op->isReferenceType()) {
+ _text += QLatin1Char('&');
+ } else if (PointerToMemberType *memPtrTy = op->asPointerToMemberType()) {
+ _text += QLatin1Char(' ');
+ _text += _overview->prettyName(memPtrTy->memberName());
+ _text += QLatin1Char('*');
+ }
+ }
+}
+
+void TypePrettyPrinter::visit(VoidType *)
+{
+ _text += QLatin1String("void");
+
+ applyPtrOperators();
+}
+
+void TypePrettyPrinter::visit(IntegerType *type)
+{
+ switch (type->kind()) {
+ case IntegerType::Char:
+ _text += QLatin1String("char");
+ break;
+ case IntegerType::WideChar:
+ _text += QLatin1String("wchar_t");
+ break;
+ case IntegerType::Bool:
+ _text += QLatin1String("bool");
+ break;
+ case IntegerType::Short:
+ _text += QLatin1String("short");
+ break;
+ case IntegerType::Int:
+ _text += QLatin1String("int");
+ break;
+ case IntegerType::Long:
+ _text += QLatin1String("long");
+ break;
+ case IntegerType::LongLong:
+ _text += QLatin1String("long long");
+ break;
+ }
+
+ applyPtrOperators();
+}
+
+void TypePrettyPrinter::visit(FloatType *type)
+{
+ switch (type->kind()) {
+ case FloatType::Float:
+ _text += QLatin1String("float");
+ break;
+ case FloatType::Double:
+ _text += QLatin1String("double");
+ break;
+ case FloatType::LongDouble:
+ _text += QLatin1String("long double");
+ break;
+ }
+
+ applyPtrOperators();
+}
+
+void TypePrettyPrinter::visit(PointerToMemberType *type)
+{
+ _ptrOperators.append(type);
+ acceptType(type->elementType());
+}
+
+void TypePrettyPrinter::visit(PointerType *type)
+{
+ _ptrOperators.append(type);
+ acceptType(type->elementType());
+}
+
+void TypePrettyPrinter::visit(ReferenceType *type)
+{
+ _ptrOperators.append(type);
+ acceptType(type->elementType());
+}
+
+void TypePrettyPrinter::visit(ArrayType *type)
+{
+ _text += overview()->prettyType(type->elementType());
+ if (! _ptrOperators.isEmpty()) {
+ _text += QLatin1Char('(');
+ applyPtrOperators(false);
+ if (! _name.isEmpty()) {
+ _text += _name;
+ _name.clear();
+ }
+ _text += QLatin1Char(')');
+ }
+ _text += QLatin1String("[]");
+}
+
+void TypePrettyPrinter::visit(NamedType *type)
+{
+ _text += overview()->prettyName(type->name());
+ applyPtrOperators();
+}
+
+void TypePrettyPrinter::visit(Function *type)
+{
+ if (_showReturnTypes)
+ _text += _overview->prettyType(type->returnType());
+
+ if (! _ptrOperators.isEmpty()) {
+ _text += QLatin1Char('(');
+ applyPtrOperators(false);
+ if (! _name.isEmpty()) {
+ _text += _name;
+ _name.clear();
+ }
+ _text += QLatin1Char(')');
+ } else if (! _name.isEmpty() && _showFunctionSignatures) {
+ _text += QLatin1Char(' '); // ### fixme
+ _text += _name;
+ _name.clear();
+ }
+
+ if (_showFunctionSignatures) {
+ Overview argumentText;
+ _text += QLatin1Char('(');
+ for (unsigned index = 0; index < type->argumentCount(); ++index) {
+ if (index != 0)
+ _text += QLatin1String(", ");
+
+ if (Argument *arg = type->argumentAt(index)->asArgument()) {
+ if (index + 1 == _markArgument)
+ _text += QLatin1String("<b>");
+ Name *name = 0;
+ if (_showArgumentNames)
+ name = arg->name();
+ _text += argumentText(arg->type(), name);
+ if (index + 1 == _markArgument)
+ _text += QLatin1String("</b>");
+ }
+ }
+
+ if (type->isVariadic())
+ _text += QLatin1String("...");
+
+ _text += QLatin1Char(')');
+
+ if (type->isConst())
+ _text += QLatin1String(" const");
+
+ if (type->isVolatile())
+ _text += QLatin1String(" volatile");
+ }
+}
+
+void TypePrettyPrinter::visit(Namespace *type)
+{ _text += overview()->prettyName(type->name()); }
+
+void TypePrettyPrinter::visit(Class *type)
+{ _text += overview()->prettyName(type->name()); }
+
+void TypePrettyPrinter::visit(Enum *type)
+{ _text += overview()->prettyName(type->name()); }
diff --git a/src/libs/cplusplus/TypePrettyPrinter.h b/src/libs/cplusplus/TypePrettyPrinter.h
new file mode 100644
index 0000000000..fd00338184
--- /dev/null
+++ b/src/libs/cplusplus/TypePrettyPrinter.h
@@ -0,0 +1,101 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 TYPEPRETTYPRINTER_H
+#define TYPEPRETTYPRINTER_H
+
+#include "TypeVisitor.h"
+#include <QString>
+#include <QList>
+
+namespace CPlusPlus {
+
+class Overview;
+class FullySpecifiedType;
+
+class CPLUSPLUS_EXPORT TypePrettyPrinter: protected TypeVisitor
+{
+public:
+ TypePrettyPrinter(const Overview *overview);
+ virtual ~TypePrettyPrinter();
+
+ const Overview *overview() const;
+
+ bool showArgumentNames() const;
+ void setShowArgumentNames(bool showArgumentNames);
+
+ bool showReturnTypes() const;
+ void setShowReturnTypes(bool showReturnTypes);
+
+ bool showFunctionSignatures() const;
+ void setShowFunctionSignatures(bool showFunctionSignatures);
+
+ void setMarkArgument(unsigned position); // 1-based
+
+ QString operator()(const FullySpecifiedType &type);
+ QString operator()(const FullySpecifiedType &type, const QString &name);
+
+protected:
+ QString switchText(const QString &text = QString());
+ QList<Type *> switchPtrOperators(const QList<Type *> &ptrOperators);
+ QString switchName(const QString &name);
+
+ void applyPtrOperators(bool wantSpace = true);
+ void acceptType(const FullySpecifiedType &ty);
+
+ virtual void visit(VoidType *type);
+ virtual void visit(IntegerType *type);
+ virtual void visit(FloatType *type);
+ virtual void visit(PointerToMemberType *type);
+ virtual void visit(PointerType *type);
+ virtual void visit(ReferenceType *type);
+ virtual void visit(ArrayType *type);
+ virtual void visit(NamedType *type);
+ virtual void visit(Function *type);
+ virtual void visit(Namespace *type);
+ virtual void visit(Class *type);
+ virtual void visit(Enum *type);
+
+private:
+ const Overview *_overview;
+ QString _name;
+ QString _text;
+ QList<Type *> _ptrOperators;
+ unsigned _markArgument;
+ bool _showArgumentNames: 1;
+ bool _showReturnTypes: 1;
+ bool _showFunctionSignatures: 1;
+};
+
+} // end of namespace CPlusPlus
+
+#endif // TYPEPRETTYPRINTER_H
diff --git a/src/libs/cplusplus/cplusplus.pri b/src/libs/cplusplus/cplusplus.pri
new file mode 100644
index 0000000000..e2d0f6f033
--- /dev/null
+++ b/src/libs/cplusplus/cplusplus.pri
@@ -0,0 +1,3 @@
+INCLUDEPATH += $$PWD/../../../shared/cplusplus
+DEFINES += HAVE_QT CPLUSPLUS_WITH_NAMESPACE
+LIBS *= -l$$qtLibraryTarget(CPlusPlus)
diff --git a/src/libs/cplusplus/cplusplus.pro b/src/libs/cplusplus/cplusplus.pro
new file mode 100644
index 0000000000..1a2b532662
--- /dev/null
+++ b/src/libs/cplusplus/cplusplus.pro
@@ -0,0 +1,40 @@
+TEMPLATE = lib
+
+TARGET = CPlusPlus
+
+DEFINES += HAVE_QT CPLUSPLUS_WITH_NAMESPACE CPLUSPLUS_BUILD_LIB
+DEFINES += NDEBUG
+unix:QMAKE_CXXFLAGS_DEBUG += -O3
+
+include(../../qworkbenchlibrary.pri)
+include(../../../shared/cplusplus/cplusplus.pri)
+
+HEADERS += \
+ SimpleLexer.h \
+ ExpressionUnderCursor.h \
+ TokenUnderCursor.h \
+ CppDocument.h \
+ Icons.h \
+ Overview.h \
+ OverviewModel.h \
+ NamePrettyPrinter.h \
+ TypeOfExpression.h \
+ TypePrettyPrinter.h \
+ ResolveExpression.h \
+ LookupContext.h
+
+SOURCES += \
+ SimpleLexer.cpp \
+ ExpressionUnderCursor.cpp \
+ TokenUnderCursor.cpp \
+ CppDocument.cpp \
+ Icons.cpp \
+ Overview.cpp \
+ OverviewModel.cpp \
+ NamePrettyPrinter.cpp \
+ TypeOfExpression.cpp \
+ TypePrettyPrinter.cpp \
+ ResolveExpression.cpp \
+ LookupContext.cpp
+
+RESOURCES += cplusplus.qrc
diff --git a/src/libs/cplusplus/cplusplus.qrc b/src/libs/cplusplus/cplusplus.qrc
new file mode 100644
index 0000000000..73d4c6395e
--- /dev/null
+++ b/src/libs/cplusplus/cplusplus.qrc
@@ -0,0 +1,20 @@
+<RCC>
+ <qresource prefix="/codemodel" >
+ <file>images/class.png</file>
+ <file>images/enum.png</file>
+ <file>images/enumerator.png</file>
+ <file>images/func.png</file>
+ <file>images/func_priv.png</file>
+ <file>images/func_prot.png</file>
+ <file>images/keyword.png</file>
+ <file>images/macro.png</file>
+ <file>images/namespace.png</file>
+ <file>images/signal.png</file>
+ <file>images/slot.png</file>
+ <file>images/slot_priv.png</file>
+ <file>images/slot_prot.png</file>
+ <file>images/var.png</file>
+ <file>images/var_priv.png</file>
+ <file>images/var_prot.png</file>
+ </qresource>
+</RCC>
diff --git a/src/libs/cplusplus/images/class.png b/src/libs/cplusplus/images/class.png
new file mode 100644
index 0000000000..88432d2cb1
--- /dev/null
+++ b/src/libs/cplusplus/images/class.png
Binary files differ
diff --git a/src/libs/cplusplus/images/enum.png b/src/libs/cplusplus/images/enum.png
new file mode 100644
index 0000000000..42a9e83bc7
--- /dev/null
+++ b/src/libs/cplusplus/images/enum.png
Binary files differ
diff --git a/src/libs/cplusplus/images/enumerator.png b/src/libs/cplusplus/images/enumerator.png
new file mode 100644
index 0000000000..25fc49c659
--- /dev/null
+++ b/src/libs/cplusplus/images/enumerator.png
Binary files differ
diff --git a/src/libs/cplusplus/images/func.png b/src/libs/cplusplus/images/func.png
new file mode 100644
index 0000000000..e515e76e61
--- /dev/null
+++ b/src/libs/cplusplus/images/func.png
Binary files differ
diff --git a/src/libs/cplusplus/images/func_priv.png b/src/libs/cplusplus/images/func_priv.png
new file mode 100644
index 0000000000..49dda7dfea
--- /dev/null
+++ b/src/libs/cplusplus/images/func_priv.png
Binary files differ
diff --git a/src/libs/cplusplus/images/func_prot.png b/src/libs/cplusplus/images/func_prot.png
new file mode 100644
index 0000000000..f8add65e07
--- /dev/null
+++ b/src/libs/cplusplus/images/func_prot.png
Binary files differ
diff --git a/src/libs/cplusplus/images/keyword.png b/src/libs/cplusplus/images/keyword.png
new file mode 100644
index 0000000000..e5a51858d9
--- /dev/null
+++ b/src/libs/cplusplus/images/keyword.png
Binary files differ
diff --git a/src/libs/cplusplus/images/macro.png b/src/libs/cplusplus/images/macro.png
new file mode 100644
index 0000000000..53e42af63d
--- /dev/null
+++ b/src/libs/cplusplus/images/macro.png
Binary files differ
diff --git a/src/libs/cplusplus/images/namespace.png b/src/libs/cplusplus/images/namespace.png
new file mode 100644
index 0000000000..18d2941572
--- /dev/null
+++ b/src/libs/cplusplus/images/namespace.png
Binary files differ
diff --git a/src/libs/cplusplus/images/signal.png b/src/libs/cplusplus/images/signal.png
new file mode 100644
index 0000000000..a4de5dddfe
--- /dev/null
+++ b/src/libs/cplusplus/images/signal.png
Binary files differ
diff --git a/src/libs/cplusplus/images/slot.png b/src/libs/cplusplus/images/slot.png
new file mode 100644
index 0000000000..5534bbfe08
--- /dev/null
+++ b/src/libs/cplusplus/images/slot.png
Binary files differ
diff --git a/src/libs/cplusplus/images/slot_priv.png b/src/libs/cplusplus/images/slot_priv.png
new file mode 100644
index 0000000000..8f585e875d
--- /dev/null
+++ b/src/libs/cplusplus/images/slot_priv.png
Binary files differ
diff --git a/src/libs/cplusplus/images/slot_prot.png b/src/libs/cplusplus/images/slot_prot.png
new file mode 100644
index 0000000000..469e9c18d0
--- /dev/null
+++ b/src/libs/cplusplus/images/slot_prot.png
Binary files differ
diff --git a/src/libs/cplusplus/images/var.png b/src/libs/cplusplus/images/var.png
new file mode 100644
index 0000000000..089cfb45e5
--- /dev/null
+++ b/src/libs/cplusplus/images/var.png
Binary files differ
diff --git a/src/libs/cplusplus/images/var_priv.png b/src/libs/cplusplus/images/var_priv.png
new file mode 100644
index 0000000000..8c6cf64fe7
--- /dev/null
+++ b/src/libs/cplusplus/images/var_priv.png
Binary files differ
diff --git a/src/libs/cplusplus/images/var_prot.png b/src/libs/cplusplus/images/var_prot.png
new file mode 100644
index 0000000000..a7496aada0
--- /dev/null
+++ b/src/libs/cplusplus/images/var_prot.png
Binary files differ
diff --git a/src/libs/extensionsystem/ExtensionSystemInterfaces b/src/libs/extensionsystem/ExtensionSystemInterfaces
new file mode 100644
index 0000000000..527148af8e
--- /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 0000000000..43855eb168
--- /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 0000000000..fb26b9c59c
--- /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 0000000000..63b2e339a3
--- /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 0000000000..ebd1f34da2
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..e2f85d98eb
--- /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 0000000000..15cd35d27b
--- /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 0000000000..47cb702e16
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..b263e7b0d2
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..461a903a39
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..77b6ed869e
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..65ea70c9ba
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..349cc48a12
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..99386f29d0
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..e73c9de39b
--- /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 0000000000..c1572d8829
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..87b4097d03
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..69f49e53c6
--- /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 0000000000..daf4169a80
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..7f003b4f89
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..6b8df8d2be
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..dfa7bdbe7c
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..06a219fe2d
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..a11167e85e
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..d75911ea37
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..eacf38edaa
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..7b78566568
--- /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 0000000000..8d9123dfbf
--- /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 0000000000..48d63ba359
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..2dd6400212
--- /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 0000000000..21f257cf08
--- /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 0000000000..db201f34c3
--- /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 0000000000..69b9821b3b
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..d3c493aeba
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..4181188287
--- /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 0000000000..5436967a80
--- /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 0000000000..c5af5f39a3
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..b1cd95c762
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..58798b54f1
--- /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 0000000000..f7e90978ba
--- /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 0000000000..9b38565c35
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..7514d63bd7
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..f601f06162
--- /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 0000000000..f0d76950e8
--- /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 0000000000..db201f34c3
--- /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 0000000000..8149d046d2
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..4be9f9bbf7
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..9101770f9a
--- /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 0000000000..5436967a80
--- /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 0000000000..99f192766a
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..08d77a38c7
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..a80f4a5c76
--- /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 0000000000..234bf56ea2
--- /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 0000000000..4410c34511
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..0991b7a152
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..c5ff581b1b
--- /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 0000000000..57b026f5fb
--- /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 0000000000..c79b29780d
--- /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 0000000000..6f0483f0f8
--- /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 0000000000..6bd573957b
--- /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 0000000000..c5934b1331
--- /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 0000000000..426901ea74
--- /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 0000000000..f54b978e9a
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..d4b941b232
--- /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 0000000000..d8fda88917
--- /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 0000000000..426901ea74
--- /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 0000000000..137e1b494c
--- /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 0000000000..451f854185
--- /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 0000000000..9fa01a442f
--- /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 0000000000..b06bab2fa0
--- /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 0000000000..aab8f424c3
--- /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 0000000000..6bd573957b
--- /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 0000000000..8c3db6c189
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..10fc0acf50
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..8b4d81a82a
--- /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 0000000000..f8ab3f7a39
--- /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 0000000000..ae40ac8ea8
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..6bd573957b
--- /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 0000000000..31cebf4414
--- /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 0000000000..454f58cb75
--- /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 0000000000..e6fe956c98
--- /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 0000000000..200a1fd1ac
--- /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 0000000000..13bbdb09a8
--- /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 0000000000..b904f90138
--- /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 0000000000..1c110d1eea
--- /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 0000000000..f3471edcaa
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..6ad874add3
--- /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 0000000000..829f2fce57
--- /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 0000000000..3282d9862e
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..8987230681
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..63faecdf52
--- /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 0000000000..32d3bdf070
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..f993b25c9f
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..9101770f9a
--- /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 0000000000..1a230ad38d
--- /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 0000000000..3ce6f258fa
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..5120038754
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..a80f4a5c76
--- /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 0000000000..fd2279824e
--- /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 0000000000..ff37d06096
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..00bd642912
--- /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 (qt-info@nokia.com)
+**
+**
+** 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 0000000000..c5ff581b1b
--- /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 0000000000..61f37bd706
--- /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 0000000000..f0d76950e8
--- /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 0000000000..8527b82c47
--- /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 0000000000..4b9cd21d8a
--- /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 0000000000..426901ea74
--- /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 0000000000..471ea892f1
--- /dev/null
+++ b/src/libs/extensionsystem/test/test.pro
@@ -0,0 +1,4 @@
+TEMPLATE = subdirs
+
+SUBDIRS = auto manual
+
diff --git a/src/libs/libs.pro b/src/libs/libs.pro
new file mode 100644
index 0000000000..0bb942edad
--- /dev/null
+++ b/src/libs/libs.pro
@@ -0,0 +1,9 @@
+TEMPLATE = subdirs
+CONFIG += ordered
+
+SUBDIRS = \
+ qtconcurrent \
+ aggregation \
+ extensionsystem \
+ utils \
+ cplusplus
diff --git a/src/libs/qtconcurrent/QtConcurrentTools b/src/libs/qtconcurrent/QtConcurrentTools
new file mode 100644
index 0000000000..ffd0cb10a7
--- /dev/null
+++ b/src/libs/qtconcurrent/QtConcurrentTools
@@ -0,0 +1,2 @@
+#include "qtconcurrent/multitask.h"
+#include "qtconcurrent/runextensions.h"
diff --git a/src/libs/qtconcurrent/multitask.h b/src/libs/qtconcurrent/multitask.h
new file mode 100644
index 0000000000..fc66de1715
--- /dev/null
+++ b/src/libs/qtconcurrent/multitask.h
@@ -0,0 +1,198 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 MULTITASK_H
+#define MULTITASK_H
+
+#include "qtconcurrent_global.h"
+#include "runextensions.h"
+#include <QtCore/QObject>
+#include <QtCore/QList>
+#include <QtCore/QEventLoop>
+#include <QtCore/QFutureWatcher>
+#include <QtCore/QtConcurrentRun>
+#include <QtCore/QThreadPool>
+
+#include <QtDebug>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtConcurrent {
+
+class QTCONCURRENT_EXPORT MultiTaskBase : public QObject, public QRunnable
+{
+ Q_OBJECT
+protected slots:
+ virtual void cancelSelf() = 0;
+ virtual void setFinished() = 0;
+ virtual void setProgressRange(int min, int max) = 0;
+ virtual void setProgressValue(int value) = 0;
+ virtual void setProgressText(QString value) = 0;
+};
+
+template <typename Class, typename R>
+class MultiTask : public MultiTaskBase
+{
+public:
+ MultiTask(void (Class::*fn)(QFutureInterface<R> &), const QList<Class *> &objects)
+ : fn(fn),
+ objects(objects)
+ {
+ maxProgress = 100*objects.size();
+ }
+
+ QFuture<R> future()
+ {
+ futureInterface.reportStarted();
+ return futureInterface.future();
+ }
+
+ void run()
+ {
+ QThreadPool::globalInstance()->releaseThread();
+ futureInterface.setProgressRange(0, maxProgress);
+ foreach (Class *object, objects) {
+ QFutureWatcher<R> *watcher = new QFutureWatcher<R>();
+ watchers.insert(object, watcher);
+ finished.insert(watcher, false);
+ connect(watcher, SIGNAL(finished()), this, SLOT(setFinished()));
+ connect(watcher, SIGNAL(progressRangeChanged(int,int)), this, SLOT(setProgressRange(int,int)));
+ connect(watcher, SIGNAL(progressValueChanged(int)), this, SLOT(setProgressValue(int)));
+ connect(watcher, SIGNAL(progressTextChanged(QString)), this, SLOT(setProgressText(QString)));
+ watcher->setFuture(QtConcurrent::run(fn, object));
+ }
+ selfWatcher = new QFutureWatcher<R>();
+ connect(selfWatcher, SIGNAL(canceled()), this, SLOT(cancelSelf()));
+ selfWatcher->setFuture(futureInterface.future());
+ loop = new QEventLoop;
+ loop->exec();
+ futureInterface.reportFinished();
+ QThreadPool::globalInstance()->reserveThread();
+ qDeleteAll(watchers.values());
+ delete selfWatcher;
+ delete loop;
+ }
+protected:
+ void cancelSelf()
+ {
+ foreach (QFutureWatcher<R> *watcher, watchers)
+ watcher->future().cancel();
+ }
+
+ void setFinished()
+ {
+ updateProgress();
+ QFutureWatcher<R> *watcher = static_cast<QFutureWatcher<R> *>(sender());
+ if (finished.contains(watcher))
+ finished[watcher] = true;
+ bool allFinished = true;
+ const QList<bool> finishedValues = finished.values();
+ foreach (bool isFinished, finishedValues) {
+ if (!isFinished) {
+ allFinished = false;
+ break;
+ }
+ }
+ if (allFinished)
+ loop->quit();
+ }
+
+ void setProgressRange(int min, int max)
+ {
+ Q_UNUSED(min);
+ Q_UNUSED(max);
+ updateProgress();
+ }
+
+ void setProgressValue(int value)
+ {
+ Q_UNUSED(value);
+ updateProgress();
+ }
+
+ void setProgressText(QString value)
+ {
+ Q_UNUSED(value);
+ updateProgressText();
+ }
+private:
+ void updateProgress()
+ {
+ int progressSum = 0;
+ const QList<QFutureWatcher<R> *> watchersValues = watchers.values();
+ foreach (QFutureWatcher<R> *watcher, watchersValues) {
+ if (watcher->progressMinimum() == watcher->progressMaximum()) {
+ if (watcher->future().isFinished() && !watcher->future().isCanceled())
+ progressSum += 100;
+ } else {
+ progressSum += 100*(watcher->progressValue()-watcher->progressMinimum())/(watcher->progressMaximum()-watcher->progressMinimum());
+ }
+ }
+ futureInterface.setProgressValue(progressSum);
+ }
+
+ void updateProgressText()
+ {
+ QString text;
+ const QList<QFutureWatcher<R> *> watchersValues = watchers.values();
+ foreach (QFutureWatcher<R> *watcher, watchersValues) {
+ if (!watcher->progressText().isEmpty())
+ text += watcher->progressText() + "\n";
+ }
+ text = text.trimmed();
+ futureInterface.setProgressValueAndText(futureInterface.progressValue(), text);
+ }
+
+ QFutureInterface<R> futureInterface;
+ void (Class::*fn)(QFutureInterface<R> &);
+ QList<Class *> objects;
+
+ QFutureWatcher<R> *selfWatcher;
+ QMap<Class *, QFutureWatcher<R> *> watchers;
+ QMap<QFutureWatcher<R> *, bool> finished;
+ QEventLoop *loop;
+ int maxProgress;
+};
+
+template <typename Class, typename T>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &), const QList<Class *> &objects, int priority = 0) {
+ MultiTask<Class, T> *task = new MultiTask<Class, T>(fn, objects);
+ QFuture<T> future = task->future();
+ QThreadPool::globalInstance()->start(task, priority);
+ return future;
+}
+
+} //namespace
+
+QT_END_NAMESPACE
+
+#endif // MULTITASK_H
diff --git a/src/libs/qtconcurrent/qtconcurrent.pri b/src/libs/qtconcurrent/qtconcurrent.pri
new file mode 100644
index 0000000000..57929a4cf1
--- /dev/null
+++ b/src/libs/qtconcurrent/qtconcurrent.pri
@@ -0,0 +1 @@
+LIBS *= -l$$qtLibraryTarget(QtConcurrent)
diff --git a/src/libs/qtconcurrent/qtconcurrent.pro b/src/libs/qtconcurrent/qtconcurrent.pro
new file mode 100644
index 0000000000..46302f11cd
--- /dev/null
+++ b/src/libs/qtconcurrent/qtconcurrent.pro
@@ -0,0 +1,10 @@
+TEMPLATE = lib
+TARGET = QtConcurrent
+DEFINES += BUILD_QTCONCURRENT
+
+include(../../qworkbenchlibrary.pri)
+
+HEADERS += \
+ qtconcurrent_global.h \
+ multitask.h \
+ runextensions.h
diff --git a/src/libs/qtconcurrent/qtconcurrent_global.h b/src/libs/qtconcurrent/qtconcurrent_global.h
new file mode 100644
index 0000000000..15d47af5f3
--- /dev/null
+++ b/src/libs/qtconcurrent/qtconcurrent_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 (qt-info@nokia.com)
+**
+**
+** 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 QTCONCURRENT_GLOBAL_H
+#define QTCONCURRENT_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(BUILD_QTCONCURRENT)
+# define QTCONCURRENT_EXPORT Q_DECL_EXPORT
+#else
+# define QTCONCURRENT_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // QTCONCURRENT_GLOBAL_H
diff --git a/src/libs/qtconcurrent/runextensions.h b/src/libs/qtconcurrent/runextensions.h
new file mode 100644
index 0000000000..43707c14d5
--- /dev/null
+++ b/src/libs/qtconcurrent/runextensions.h
@@ -0,0 +1,397 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 QTCONCURRENT_RUNEX_H
+#define QTCONCURRENT_RUNEX_H
+
+#include <qrunnable.h>
+#include <qfutureinterface.h>
+#include <qthreadpool.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtConcurrent {
+
+template <typename T, typename FunctionPointer>
+class StoredInterfaceFunctionCall0 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall0(void (fn)(QFutureInterface<T> &))
+ : fn(fn) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+
+};
+template <typename T, typename FunctionPointer, typename Class>
+class StoredInterfaceMemberFunctionCall0 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall0(void (Class::*fn)(QFutureInterface<T> &), Class *object)
+ : fn(fn), object(object) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+
+};
+
+template <typename T, typename FunctionPointer, typename Arg1>
+class StoredInterfaceFunctionCall1 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall1(void (fn)(QFutureInterface<T> &, Arg1), Arg1 arg1)
+ : fn(fn), arg1(arg1) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface, arg1);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Arg1 arg1;
+};
+template <typename T, typename FunctionPointer, typename Class, typename Arg1>
+class StoredInterfaceMemberFunctionCall1 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall1(void (Class::*fn)(QFutureInterface<T> &, Arg1), Class *object, Arg1 arg1)
+ : fn(fn), object(object), arg1(arg1) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface, arg1);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+ Arg1 arg1;
+};
+
+template <typename T, typename FunctionPointer, typename Arg1, typename Arg2>
+class StoredInterfaceFunctionCall2 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall2(void (fn)(QFutureInterface<T> &, Arg1, Arg2), Arg1 arg1, Arg2 arg2)
+ : fn(fn), arg1(arg1), arg2(arg2) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface, arg1, arg2);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Arg1 arg1; Arg2 arg2;
+};
+template <typename T, typename FunctionPointer, typename Class, typename Arg1, typename Arg2>
+class StoredInterfaceMemberFunctionCall2 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall2(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2), Class *object, Arg1 arg1, Arg2 arg2)
+ : fn(fn), object(object), arg1(arg1), arg2(arg2) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface, arg1, arg2);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+ Arg1 arg1; Arg2 arg2;
+};
+
+template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3>
+class StoredInterfaceFunctionCall3 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall3(void (fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3), Arg1 arg1, Arg2 arg2, Arg3 arg3)
+ : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface, arg1, arg2, arg3);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3;
+};
+template <typename T, typename FunctionPointer, typename Class, typename Arg1, typename Arg2, typename Arg3>
+class StoredInterfaceMemberFunctionCall3 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall3(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3), Class *object, Arg1 arg1, Arg2 arg2, Arg3 arg3)
+ : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface, arg1, arg2, arg3);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3;
+};
+
+template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+class StoredInterfaceFunctionCall4 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall4(void (fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
+ : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface, arg1, arg2, arg3, arg4);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4;
+};
+template <typename T, typename FunctionPointer, typename Class, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+class StoredInterfaceMemberFunctionCall4 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall4(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), Class *object, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
+ : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface, arg1, arg2, arg3, arg4);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4;
+};
+
+template <typename T, typename FunctionPointer, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+class StoredInterfaceFunctionCall5 : public QRunnable
+{
+public:
+ StoredInterfaceFunctionCall5(void (fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5)
+ : fn(fn), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ fn(futureInterface, arg1, arg2, arg3, arg4, arg5);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5;
+};
+template <typename T, typename FunctionPointer, typename Class, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+class StoredInterfaceMemberFunctionCall5 : public QRunnable
+{
+public:
+ StoredInterfaceMemberFunctionCall5(void (Class::*fn)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), Class *object, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5)
+ : fn(fn), object(object), arg1(arg1), arg2(arg2), arg3(arg3), arg4(arg4), arg5(arg5) { }
+
+ QFuture<T> start()
+ {
+ futureInterface.reportStarted();
+ QFuture<T> future = futureInterface.future();
+ QThreadPool::globalInstance()->start(this);
+ return future;
+ }
+
+ void run()
+ {
+ (object->*fn)(futureInterface, arg1, arg2, arg3, arg4, arg5);
+ futureInterface.reportFinished();
+ }
+private:
+ QFutureInterface<T> futureInterface;
+ FunctionPointer fn;
+ Class *object;
+ Arg1 arg1; Arg2 arg2; Arg3 arg3; Arg4 arg4; Arg5 arg5;
+};
+
+template <typename T>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &))
+{
+ return (new StoredInterfaceFunctionCall0<T, void (*)(QFutureInterface<T> &)>(functionPointer))->start();
+}
+template <typename T, typename Arg1>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1), Arg1 arg1)
+{
+ return (new StoredInterfaceFunctionCall1<T, void (*)(QFutureInterface<T> &, Arg1), Arg1>(functionPointer, arg1))->start();
+}
+template <typename T, typename Arg1, typename Arg2>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1, Arg2), Arg1 arg1, Arg2 arg2)
+{
+ return (new StoredInterfaceFunctionCall2<T, void (*)(QFutureInterface<T> &, Arg1, Arg2), Arg1, Arg2>(functionPointer, arg1, arg2))->start();
+}
+template <typename T, typename Arg1, typename Arg2, typename Arg3>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1, Arg2, Arg3), Arg1 arg1, Arg2 arg2, Arg3 arg3)
+{
+ return (new StoredInterfaceFunctionCall3<T, void (*)(QFutureInterface<T> &, Arg1, Arg2, Arg3), Arg1, Arg2, Arg3>(functionPointer, arg1, arg2, arg3))->start();
+}
+template <typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
+{
+ return (new StoredInterfaceFunctionCall4<T, void (*)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4), Arg1, Arg2, Arg3, Arg4>(functionPointer, arg1, arg2, arg3, arg4))->start();
+}
+template <typename T, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+QFuture<T> run(void (*functionPointer)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5)
+{
+ return (new StoredInterfaceFunctionCall5<T, void (*)(QFutureInterface<T> &, Arg1, Arg2, Arg3, Arg4, Arg5), Arg1, Arg2, Arg3, Arg4, Arg5>(functionPointer, arg1, arg2, arg3, arg4, arg5))->start();
+}
+
+template <typename Class, typename T>
+QFuture<T> run(void (Class::*fn)(QFutureInterface<T> &), Class *object)
+{
+ return (new StoredInterfaceMemberFunctionCall0<T, void (Class::*)(QFutureInterface<T> &), Class>(fn, object))->start();
+}
+
+} //namespace QtConcurrent
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/libs/utils/basevalidatinglineedit.cpp b/src/libs/utils/basevalidatinglineedit.cpp
new file mode 100644
index 0000000000..cb936e3c2d
--- /dev/null
+++ b/src/libs/utils/basevalidatinglineedit.cpp
@@ -0,0 +1,157 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "basevalidatinglineedit.h"
+
+#include <QtCore/QDebug>
+
+enum { debug = 0 };
+
+namespace Core {
+namespace Utils {
+
+struct BaseValidatingLineEditPrivate {
+ explicit BaseValidatingLineEditPrivate(const QWidget *w);
+
+ const QColor m_okTextColor;
+ QColor m_errorTextColor;
+
+ BaseValidatingLineEdit::State m_state;
+ QString m_errorMessage;
+ QString m_initialText;
+ bool m_firstChange;
+};
+
+BaseValidatingLineEditPrivate::BaseValidatingLineEditPrivate(const QWidget *w) :
+ m_okTextColor(BaseValidatingLineEdit::textColor(w)),
+ m_errorTextColor(Qt::red),
+ m_state(BaseValidatingLineEdit::Invalid),
+ m_firstChange(true)
+{
+}
+
+BaseValidatingLineEdit::BaseValidatingLineEdit(QWidget *parent) :
+ QLineEdit(parent),
+ m_bd(new BaseValidatingLineEditPrivate(this))
+{
+ // Note that textChanged() is also triggered automagically by
+ // QLineEdit::setText(), no need to trigger manually.
+ connect(this, SIGNAL(textChanged(QString)), this, SLOT(slotChanged(QString)));
+}
+
+BaseValidatingLineEdit::~BaseValidatingLineEdit()
+{
+ delete m_bd;
+}
+
+QString BaseValidatingLineEdit::initialText() const
+{
+ return m_bd->m_initialText;
+}
+
+void BaseValidatingLineEdit::setInitialText(const QString &t)
+{
+ if (m_bd->m_initialText != t) {
+ m_bd->m_initialText = t;
+ m_bd->m_firstChange = true;
+ setText(t);
+ }
+}
+
+QColor BaseValidatingLineEdit::errorColor() const
+{
+ return m_bd->m_errorTextColor;
+}
+
+void BaseValidatingLineEdit::setErrorColor(const QColor &c)
+{
+ m_bd->m_errorTextColor = c;
+}
+
+QColor BaseValidatingLineEdit::textColor(const QWidget *w)
+{
+ return w->palette().color(QPalette::Active, QPalette::Text);
+}
+
+void BaseValidatingLineEdit::setTextColor(QWidget *w, const QColor &c)
+{
+ QPalette palette = w->palette();
+ palette.setColor(QPalette::Active, QPalette::Text, c);
+ w->setPalette(palette);
+}
+
+BaseValidatingLineEdit::State BaseValidatingLineEdit::state() const
+{
+ return m_bd->m_state;
+}
+
+bool BaseValidatingLineEdit::isValid() const
+{
+ return m_bd->m_state == Valid;
+}
+
+QString BaseValidatingLineEdit::errorMessage() const
+{
+ return m_bd->m_errorMessage;
+}
+
+void BaseValidatingLineEdit::slotChanged(const QString &t)
+{
+ m_bd->m_errorMessage.clear();
+ // Are we displaying the initial text?
+ const bool isDisplayingInitialText = !m_bd->m_initialText.isEmpty() && t == m_bd->m_initialText;
+ const State newState = isDisplayingInitialText ?
+ DisplayingInitialText :
+ (validate(t, &m_bd->m_errorMessage) ? Valid : Invalid);
+ setToolTip(m_bd->m_errorMessage);
+ if (debug)
+ qDebug() << Q_FUNC_INFO << t << "State" << m_bd->m_state << "->" << newState << m_bd->m_errorMessage;
+ // Changed..figure out if valid changed. DisplayingInitialText is not valid,
+ // but should not show error color. Also trigger on the first change.
+ if (newState != m_bd->m_state || m_bd->m_firstChange) {
+ const bool validHasChanged = (m_bd->m_state == Valid) != (newState == Valid);
+ m_bd->m_state = newState;
+ m_bd->m_firstChange = false;
+ setTextColor(this, newState == Invalid ? m_bd->m_errorTextColor : m_bd->m_okTextColor);
+ if (validHasChanged)
+ emit validChanged();
+ }
+}
+
+void BaseValidatingLineEdit::slotReturnPressed()
+{
+ if (isValid())
+ emit validReturnPressed();
+}
+
+}
+}
diff --git a/src/libs/utils/basevalidatinglineedit.h b/src/libs/utils/basevalidatinglineedit.h
new file mode 100644
index 0000000000..3482687011
--- /dev/null
+++ b/src/libs/utils/basevalidatinglineedit.h
@@ -0,0 +1,100 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 BASEVALIDATINGLINEEDIT_H
+#define BASEVALIDATINGLINEEDIT_H
+
+#include "utils_global.h"
+
+#include <QtGui/QLineEdit>
+
+namespace Core {
+namespace Utils {
+
+struct BaseValidatingLineEditPrivate;
+
+/* Base class for validating line edits that performs validation in a virtual
+ * validate() function to be implemented in derived classes.
+ * When invalid, the text color will turn red and a tooltip will
+ * contain the error message. This approach is less intrusive than a
+ * QValidator which will prevent the user from entering certain characters.
+ *
+ * The widget has a concept of an "initialText" which can be something like
+ * "<Enter name here>". This results in state 'DisplayingInitialText', which
+ * is not valid, but is not marked red. */
+
+class QWORKBENCH_UTILS_EXPORT BaseValidatingLineEdit : public QLineEdit {
+ Q_OBJECT
+ Q_DISABLE_COPY(BaseValidatingLineEdit)
+ Q_PROPERTY(QString initialText READ initialText WRITE setInitialText DESIGNABLE true)
+ Q_PROPERTY(QColor errorColor READ errorColor WRITE setErrorColor DESIGNABLE true)
+
+public:
+ enum State { Invalid, DisplayingInitialText, Valid };
+
+ explicit BaseValidatingLineEdit(QWidget *parent = 0);
+ virtual ~BaseValidatingLineEdit();
+
+
+ State state() const;
+ bool isValid() const;
+ QString errorMessage() const;
+
+ QString initialText() const;
+ void setInitialText(const QString &);
+
+ QColor errorColor() const;
+ void setErrorColor(const QColor &);
+
+ static QColor textColor(const QWidget *w);
+ static void setTextColor(QWidget *w, const QColor &c);
+
+signals:
+ void validChanged();
+ void validReturnPressed();
+
+protected:
+ virtual bool validate(const QString &value, QString *errorMessage) const = 0;
+
+protected slots:
+ // Custom behaviour can be added here. The base implementation must
+ // be called.
+ virtual void slotReturnPressed();
+ virtual void slotChanged(const QString &t);
+
+private:
+ BaseValidatingLineEditPrivate *m_bd;
+};
+
+}
+}
+#endif // BASEVALIDATINGLINEEDIT_H
diff --git a/src/libs/utils/classnamevalidatinglineedit.cpp b/src/libs/utils/classnamevalidatinglineedit.cpp
new file mode 100644
index 0000000000..b52758eda5
--- /dev/null
+++ b/src/libs/utils/classnamevalidatinglineedit.cpp
@@ -0,0 +1,137 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "classnamevalidatinglineedit.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QRegExp>
+
+namespace Core {
+namespace Utils {
+
+struct ClassNameValidatingLineEditPrivate {
+ ClassNameValidatingLineEditPrivate();
+
+ const QRegExp m_nameRegexp;
+ const QString m_namespaceDelimiter;
+ bool m_namespacesEnabled;
+};
+
+// Match something like "Namespace1::Namespace2::ClassName".
+ClassNameValidatingLineEditPrivate:: ClassNameValidatingLineEditPrivate() :
+ m_nameRegexp(QLatin1String("[a-zA-Z_][a-zA-Z0-9_]*(::[a-zA-Z_][a-zA-Z0-9_]*)*")),
+ m_namespaceDelimiter(QLatin1String("::")),
+ m_namespacesEnabled(false)
+{
+ Q_ASSERT(m_nameRegexp.isValid());
+}
+
+// --------------------- ClassNameValidatingLineEdit
+ClassNameValidatingLineEdit::ClassNameValidatingLineEdit(QWidget *parent) :
+ Core::Utils::BaseValidatingLineEdit(parent),
+ m_d(new ClassNameValidatingLineEditPrivate)
+{
+}
+
+ClassNameValidatingLineEdit::~ClassNameValidatingLineEdit()
+{
+ delete m_d;
+}
+
+bool ClassNameValidatingLineEdit::namespacesEnabled() const
+{
+ return m_d->m_namespacesEnabled;
+}
+
+void ClassNameValidatingLineEdit::setNamespacesEnabled(bool b)
+{
+ m_d->m_namespacesEnabled = b;
+}
+
+bool ClassNameValidatingLineEdit::validate(const QString &value, QString *errorMessage) const
+{
+ if (!m_d->m_namespacesEnabled && value.contains(QLatin1Char(':'))) {
+ if (errorMessage)
+ *errorMessage = tr("The class name must not contain namespace delimiters.");
+ return false;
+ }
+ if (!m_d->m_nameRegexp.exactMatch(value)) {
+ if (errorMessage)
+ *errorMessage = tr("The class name contains invalid characters.");
+ return false;
+ }
+ return true;
+}
+
+void ClassNameValidatingLineEdit::slotChanged(const QString &t)
+{
+ Core::Utils::BaseValidatingLineEdit::slotChanged(t);
+ if (isValid()) {
+ // Suggest file names, strip namespaces
+ QString fileName = t.toLower();
+ if (m_d->m_namespacesEnabled) {
+ const int namespaceIndex = fileName.lastIndexOf(m_d->m_namespaceDelimiter);
+ if (namespaceIndex != -1)
+ fileName.remove(0, namespaceIndex + m_d->m_namespaceDelimiter.size());
+ }
+ emit updateFileName(fileName);
+ }
+}
+
+QString ClassNameValidatingLineEdit::createClassName(const QString &name)
+{
+ // Remove spaces and convert the adjacent characters to uppercase
+ QString className = name;
+ QRegExp spaceMatcher(QLatin1String(" +(\\w)"), Qt::CaseSensitive, QRegExp::RegExp2);
+ Q_ASSERT(spaceMatcher.isValid());
+ int pos;
+ while ((pos = spaceMatcher.indexIn(className)) != -1) {
+ className.replace(pos, spaceMatcher.matchedLength(),
+ spaceMatcher.cap(1).toUpper());
+ }
+
+ // Filter out any remaining invalid characters
+ className.remove(QRegExp(QLatin1String("[^a-zA-Z0-9_]")));
+
+ // If the first character is numeric, prefix the name with a "_"
+ if (className.at(0).isNumber()) {
+ className.prepend(QLatin1Char('_'));
+ } else {
+ // Convert the first character to uppercase
+ className.replace(0, 1, className.left(1).toUpper());
+ }
+
+ return className;
+}
+
+}
+}
diff --git a/src/libs/utils/classnamevalidatinglineedit.h b/src/libs/utils/classnamevalidatinglineedit.h
new file mode 100644
index 0000000000..c0a209d0d7
--- /dev/null
+++ b/src/libs/utils/classnamevalidatinglineedit.h
@@ -0,0 +1,79 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 CLASSNAMEVALIDATINGLINEEDIT_H
+#define CLASSNAMEVALIDATINGLINEEDIT_H
+
+#include "utils_global.h"
+#include "basevalidatinglineedit.h"
+
+namespace Core {
+namespace Utils {
+
+struct ClassNameValidatingLineEditPrivate;
+
+/* A Line edit that validates a C++ class name and emits a signal
+ * to derive suggested file names from it. */
+
+class QWORKBENCH_UTILS_EXPORT ClassNameValidatingLineEdit :
+ public Core::Utils::BaseValidatingLineEdit {
+ Q_DISABLE_COPY(ClassNameValidatingLineEdit)
+ Q_PROPERTY(bool namespacesEnabled READ namespacesEnabled WRITE setNamespacesEnabled DESIGNABLE true)
+ Q_OBJECT
+
+public:
+ explicit ClassNameValidatingLineEdit(QWidget *parent = 0);
+ virtual ~ClassNameValidatingLineEdit();
+
+ bool namespacesEnabled() const;
+ void setNamespacesEnabled(bool b);
+
+ // Clean an input string to get a valid class name.
+ static QString createClassName(const QString &name);
+
+signals:
+ // Will be emitted with a suggestion for a base name of the
+ // source/header file of the class.
+ void updateFileName(const QString &t);
+
+protected:
+ virtual bool validate(const QString &value, QString *errorMessage) const;
+ virtual void slotChanged(const QString &t);
+
+private:
+ ClassNameValidatingLineEditPrivate *m_d;
+};
+
+}
+}
+
+#endif // CLASSNAMEVALIDATINGLINEEDIT_H
diff --git a/src/libs/utils/codegeneration.cpp b/src/libs/utils/codegeneration.cpp
new file mode 100644
index 0000000000..3af484935a
--- /dev/null
+++ b/src/libs/utils/codegeneration.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 (qt-info@nokia.com)
+**
+**
+** 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 "codegeneration.h"
+
+#include <QtCore/QTextStream>
+#include <QtCore/QStringList>
+#include <QtCore/QFileInfo>
+
+namespace Core {
+namespace Utils {
+
+QWORKBENCH_UTILS_EXPORT QString headerGuard(const QString &file)
+{
+ QString rc = QFileInfo(file).baseName().toUpper();
+ rc += QLatin1String("_H");
+ return rc;
+}
+
+QWORKBENCH_UTILS_EXPORT
+void writeIncludeFileDirective(const QString &file, bool globalInclude,
+ QTextStream &str)
+{
+ const QChar opening = globalInclude ? QLatin1Char('<') : QLatin1Char('"');
+ const QChar closing = globalInclude ? QLatin1Char('>') : QLatin1Char('"');
+ str << QLatin1String("#include ") << opening << file << closing << QLatin1Char('\n');
+}
+
+QWORKBENCH_UTILS_EXPORT
+QString writeOpeningNameSpaces(const QStringList &l, const QString &indent,
+ QTextStream &str)
+{
+ const int count = l.size();
+ QString rc;
+ if (count) {
+ str << '\n';
+ for (int i = 0; i < count; i++) {
+ str << rc << "namespace " << l.at(i) << " {\n";
+ rc += indent;
+ }
+ str << '\n';
+ }
+ return rc;
+}
+
+QWORKBENCH_UTILS_EXPORT
+void writeClosingNameSpaces(const QStringList &l, const QString &indent,
+ QTextStream &str)
+{
+ if (!l.empty())
+ str << '\n';
+ for (int i = l.size() - 1; i >= 0; i--) {
+ if (i)
+ str << QString(indent.size() * i, QLatin1Char(' '));
+ str << "} // namespace " << l.at(i) << '\n';
+ }
+}
+
+} // namespace Utils
+} // namespace Core
diff --git a/src/libs/utils/codegeneration.h b/src/libs/utils/codegeneration.h
new file mode 100644
index 0000000000..1a20c76d08
--- /dev/null
+++ b/src/libs/utils/codegeneration.h
@@ -0,0 +1,70 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 CODEGENERATION_H
+#define CODEGENERATION_H
+
+#include "utils_global.h"
+#include <QtCore/QString>
+
+QT_BEGIN_NAMESPACE
+class QTextStream;
+class QStringList;
+QT_END_NAMESPACE
+
+namespace Core {
+namespace Utils {
+
+QWORKBENCH_UTILS_EXPORT QString headerGuard(const QString &file);
+
+QWORKBENCH_UTILS_EXPORT
+void writeIncludeFileDirective(const QString &file,
+ bool globalInclude,
+ QTextStream &str);
+
+// Write opening namespaces and return an indentation string to be used
+// in the following code if there are any.
+QWORKBENCH_UTILS_EXPORT
+QString writeOpeningNameSpaces(const QStringList &namespaces,
+ const QString &indent,
+ QTextStream &str);
+
+// Close namespacesnamespaces
+QWORKBENCH_UTILS_EXPORT
+void writeClosingNameSpaces(const QStringList &namespaces,
+ const QString &indent,
+ QTextStream &str);
+
+} // namespace Utils
+} // namespace Core
+
+#endif // CODEGENERATION_H
diff --git a/src/libs/utils/fancylineedit.cpp b/src/libs/utils/fancylineedit.cpp
new file mode 100644
index 0000000000..e7e930c544
--- /dev/null
+++ b/src/libs/utils/fancylineedit.cpp
@@ -0,0 +1,317 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "fancylineedit.h"
+
+#include <QtCore/QEvent>
+#include <QtCore/QDebug>
+#include <QtCore/QString>
+#include <QtGui/QApplication>
+#include <QtGui/QMenu>
+#include <QtGui/QMouseEvent>
+#include <QtGui/QLabel>
+
+enum { margin = 6 };
+
+namespace Core {
+namespace Utils {
+
+static inline QString sideToStyleSheetString(FancyLineEdit::Side side)
+{
+ return side == FancyLineEdit::Left ? QLatin1String("left") : QLatin1String("right");
+}
+
+// Format style sheet for the label containing the pixmap. It has a margin on
+// the outer side of the whole FancyLineEdit.
+static QString labelStyleSheet(FancyLineEdit::Side side)
+{
+ QString rc = QLatin1String("QLabel { margin-");
+ rc += sideToStyleSheetString(side);
+ rc += QLatin1String(": ");
+ rc += QString::number(margin);
+ rc += QLatin1Char('}');
+ return rc;
+}
+
+// --------- FancyLineEditPrivate as QObject with label
+// event filter
+
+class FancyLineEditPrivate : public QObject {
+public:
+ explicit FancyLineEditPrivate(QLineEdit *parent);
+
+ virtual bool eventFilter(QObject *obj, QEvent *event);
+
+ const QString m_leftLabelStyleSheet;
+ const QString m_rightLabelStyleSheet;
+
+ QLineEdit *m_lineEdit;
+ QPixmap m_pixmap;
+ QMenu *m_menu;
+ QLabel *m_menuLabel;
+ FancyLineEdit::Side m_side;
+ bool m_useLayoutDirection;
+ bool m_menuTabFocusTrigger;
+ QString m_hintText;
+ bool m_showingHintText;
+};
+
+
+FancyLineEditPrivate::FancyLineEditPrivate(QLineEdit *parent) :
+ QObject(parent),
+ m_leftLabelStyleSheet(labelStyleSheet(FancyLineEdit::Left)),
+ m_rightLabelStyleSheet(labelStyleSheet(FancyLineEdit::Right)),
+ m_lineEdit(parent),
+ m_menu(0),
+ m_menuLabel(0),
+ m_side(FancyLineEdit::Left),
+ m_useLayoutDirection(false),
+ m_menuTabFocusTrigger(false),
+ m_showingHintText(false)
+{
+}
+
+bool FancyLineEditPrivate::eventFilter(QObject *obj, QEvent *event)
+{
+ if (!m_menu || obj != m_menuLabel)
+ return QObject::eventFilter(obj, event);
+
+ switch (event->type()) {
+ case QEvent::MouseButtonPress: {
+ const QMouseEvent *me = static_cast<QMouseEvent *>(event);
+ m_menu->exec(me->globalPos());
+ return true;
+ }
+ case QEvent::FocusIn:
+ if (m_menuTabFocusTrigger) {
+ m_lineEdit->setFocus();
+ m_menu->exec(m_menuLabel->mapToGlobal(m_menuLabel->rect().center()));
+ return true;
+ }
+ default:
+ break;
+ }
+ return QObject::eventFilter(obj, event);
+}
+
+// --------- FancyLineEdit
+FancyLineEdit::FancyLineEdit(QWidget *parent) :
+ QLineEdit(parent),
+ m_d(new FancyLineEditPrivate(this))
+{
+ m_d->m_menuLabel = new QLabel(this);
+ m_d->m_menuLabel->installEventFilter(m_d);
+ updateMenuLabel();
+ showHintText();
+}
+
+FancyLineEdit::~FancyLineEdit()
+{
+}
+
+// Position the menu label left or right according to size.
+// Called when switching side and from resizeEvent.
+void FancyLineEdit::positionMenuLabel()
+{
+ switch (side()) {
+ case Left:
+ m_d->m_menuLabel->setGeometry(0, 0, m_d->m_pixmap.width()+margin, height());
+ break;
+ case Right:
+ m_d->m_menuLabel->setGeometry(width() - m_d->m_pixmap.width() - margin, 0,
+ m_d->m_pixmap.width()+margin, height());
+ break;
+ }
+}
+
+void FancyLineEdit::updateStyleSheet(Side side)
+{
+ // Udate the LineEdit style sheet. Make room for the label on the
+ // respective side and set color according to whether we are showing the
+ // hint text
+ QString sheet = QLatin1String("QLineEdit{ padding-");
+ sheet += sideToStyleSheetString(side);
+ sheet += QLatin1String(": ");
+ sheet += QString::number(m_d->m_pixmap.width() + margin);
+ sheet += QLatin1Char(';');
+ if (m_d->m_showingHintText)
+ sheet += QLatin1String(" color: #BBBBBB;");
+ sheet += QLatin1Char('}');
+ setStyleSheet(sheet);
+}
+
+void FancyLineEdit::updateMenuLabel()
+{
+ m_d->m_menuLabel->setPixmap(m_d->m_pixmap);
+ const Side s = side();
+ switch (s) {
+ case Left:
+ m_d->m_menuLabel->setAlignment(Qt::AlignVCenter | Qt::AlignLeft);
+ m_d->m_menuLabel->setStyleSheet(m_d->m_leftLabelStyleSheet);
+ break;
+ case Right:
+ m_d->m_menuLabel->setAlignment(Qt::AlignVCenter | Qt::AlignRight);
+ m_d->m_menuLabel->setStyleSheet(m_d->m_rightLabelStyleSheet);
+ break;
+ }
+ updateStyleSheet(s);
+ positionMenuLabel();
+}
+
+void FancyLineEdit::setSide(Side side)
+{
+ m_d->m_side = side;
+ updateMenuLabel();
+}
+
+FancyLineEdit::Side FancyLineEdit::side() const
+{
+ if (m_d->m_useLayoutDirection)
+ return qApp->layoutDirection() == Qt::LeftToRight ? Left : Right;
+ return m_d->m_side;
+}
+
+void FancyLineEdit::resizeEvent(QResizeEvent *)
+{
+ positionMenuLabel();
+}
+
+void FancyLineEdit::setPixmap(const QPixmap &pixmap)
+{
+ m_d->m_pixmap = pixmap;
+ updateMenuLabel();
+}
+
+QPixmap FancyLineEdit::pixmap() const
+{
+ return m_d->m_pixmap;
+}
+
+void FancyLineEdit::setMenu(QMenu *menu)
+{
+ m_d->m_menu = menu;
+}
+
+QMenu *FancyLineEdit::menu() const
+{
+ return m_d->m_menu;
+}
+
+bool FancyLineEdit::useLayoutDirection() const
+{
+ return m_d->m_useLayoutDirection;
+}
+
+void FancyLineEdit::setUseLayoutDirection(bool v)
+{
+ m_d->m_useLayoutDirection = v;
+}
+
+bool FancyLineEdit::isSideStored() const
+{
+ return !m_d->m_useLayoutDirection;
+}
+
+bool FancyLineEdit::hasMenuTabFocusTrigger() const
+{
+ return m_d->m_menuTabFocusTrigger;
+}
+
+void FancyLineEdit::setMenuTabFocusTrigger(bool v)
+{
+ if (m_d->m_menuTabFocusTrigger == v)
+ return;
+
+ m_d->m_menuTabFocusTrigger = v;
+ m_d->m_menuLabel->setFocusPolicy(v ? Qt::TabFocus : Qt::NoFocus);
+}
+
+QString FancyLineEdit::hintText() const
+{
+ return m_d->m_hintText;
+}
+
+void FancyLineEdit::setHintText(const QString &ht)
+{
+ // Updating magic to make the property work in Designer.
+ if (ht == m_d->m_hintText)
+ return;
+ hideHintText();
+ m_d->m_hintText = ht;
+ if (!hasFocus() && !ht.isEmpty())
+ showHintText();
+}
+
+void FancyLineEdit::showHintText()
+{
+ if (!m_d->m_showingHintText && text().isEmpty() && !m_d->m_hintText.isEmpty()) {
+ m_d->m_showingHintText = true;
+ setText(m_d->m_hintText);
+ updateStyleSheet(side());
+ }
+}
+
+void FancyLineEdit::hideHintText()
+{
+ if (m_d->m_showingHintText && !m_d->m_hintText.isEmpty()) {
+ m_d->m_showingHintText = false;
+ setText(QString());
+ updateStyleSheet(side());
+ }
+}
+
+void FancyLineEdit::focusInEvent(QFocusEvent *e)
+{
+ hideHintText();
+ QLineEdit::focusInEvent(e);
+}
+
+void FancyLineEdit::focusOutEvent(QFocusEvent *e)
+{
+ // Focus out: Switch to displaying the hint text unless
+ // there is user input
+ showHintText();
+ QLineEdit::focusOutEvent(e);
+}
+
+bool FancyLineEdit::isShowingHintText() const
+{
+ return m_d->m_showingHintText;
+}
+
+QString FancyLineEdit::typedText() const
+{
+ return m_d->m_showingHintText ? QString() : text();
+}
+
+} // namespace Utils
+} // namespace Core
diff --git a/src/libs/utils/fancylineedit.h b/src/libs/utils/fancylineedit.h
new file mode 100644
index 0000000000..24a109eada
--- /dev/null
+++ b/src/libs/utils/fancylineedit.h
@@ -0,0 +1,115 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 FANCYLINEEDIT_H
+#define FANCYLINEEDIT_H
+
+#include "utils_global.h"
+
+#include <QtGui/QLineEdit>
+
+namespace Core {
+namespace Utils {
+
+class FancyLineEditPrivate;
+
+/* A line edit with an embedded pixmap on one side that is connected to
+ * a menu. Additionally, it can display a grayed hintText (like "Type Here to")
+ * when not focussed and empty. When connecting to the changed signals and
+ * querying text, one has to be aware that the text is set to that hint
+ * text if isShowingHintText() returns true (that is, does not contain
+ * valid user input).
+ */
+class QWORKBENCH_UTILS_EXPORT FancyLineEdit : public QLineEdit
+{
+ Q_DISABLE_COPY(FancyLineEdit)
+ Q_OBJECT
+ Q_ENUMS(Side)
+ Q_PROPERTY(QPixmap pixmap READ pixmap WRITE setPixmap DESIGNABLE true)
+ Q_PROPERTY(Side side READ side WRITE setSide DESIGNABLE isSideStored STORED isSideStored)
+ Q_PROPERTY(bool useLayoutDirection READ useLayoutDirection WRITE setUseLayoutDirection DESIGNABLE true)
+ Q_PROPERTY(bool menuTabFocusTrigger READ hasMenuTabFocusTrigger WRITE setMenuTabFocusTrigger DESIGNABLE true)
+ Q_PROPERTY(QString hintText READ hintText WRITE setHintText DESIGNABLE true)
+
+public:
+ enum Side {Left, Right};
+
+ explicit FancyLineEdit(QWidget *parent = 0);
+ ~FancyLineEdit();
+
+ QPixmap pixmap() const;
+
+ void setMenu(QMenu *menu);
+ QMenu *menu() const;
+
+ void setSide(Side side);
+ Side side() const;
+
+ bool useLayoutDirection() const;
+ void setUseLayoutDirection(bool v);
+
+ /* Set whether tabbing in will trigger the menu. */
+ bool hasMenuTabFocusTrigger() const;
+ void setMenuTabFocusTrigger(bool v);
+
+ /* Hint text that is displayed when no focus is set */
+ QString hintText() const;
+
+ bool isShowingHintText() const;
+
+ // Convenience for accessing the text that returns "" in case of isShowingHintText().
+ QString typedText() const;
+
+public slots:
+ void setPixmap(const QPixmap &pixmap);
+ void setHintText(const QString &ht);
+ void showHintText();
+ void hideHintText();
+
+protected:
+ virtual void resizeEvent(QResizeEvent *e);
+ virtual void focusInEvent(QFocusEvent *e);
+ virtual void focusOutEvent(QFocusEvent *e);
+
+private:
+ bool isSideStored() const;
+ void updateMenuLabel();
+ void positionMenuLabel();
+ void updateStyleSheet(Side side);
+
+ FancyLineEditPrivate *m_d;
+};
+
+} // namespace Utils
+} // namespace Core
+
+#endif // FANCYLINEEDIT_H
diff --git a/src/libs/utils/filenamevalidatinglineedit.cpp b/src/libs/utils/filenamevalidatinglineedit.cpp
new file mode 100644
index 0000000000..1beed717ef
--- /dev/null
+++ b/src/libs/utils/filenamevalidatinglineedit.cpp
@@ -0,0 +1,97 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "filenamevalidatinglineedit.h"
+
+namespace Core {
+namespace Utils {
+
+FileNameValidatingLineEdit::FileNameValidatingLineEdit(QWidget *parent) :
+ BaseValidatingLineEdit(parent)
+{
+
+}
+
+/* Validate a file base name, check for forbidden characters/strings. */
+
+static const char *notAllowedChars = "/?:&\\*\"|#%<> ";
+static const char *notAllowedSubStrings[] = {".."};
+
+// Naming a file like a device name will break on Windows, even if it is
+// "com1.txt". Since we are cross-platform, we generally disallow such file
+// names.
+static const char *notAllowedStrings[] = {"CON", "AUX", "PRN", "COM1", "COM2", "LPT1", "LPT2" };
+
+bool FileNameValidatingLineEdit::validateFileName(const QString &name, QString *errorMessage /* = 0*/)
+{
+ if (name.isEmpty()) {
+ if (errorMessage)
+ *errorMessage = tr("The name must not be empty");
+ return false;
+ }
+ // Characters
+ for (const char *c = notAllowedChars; *c; c++)
+ if (name.contains(QLatin1Char(*c))) {
+ if (errorMessage)
+ *errorMessage = tr("The name must not contain any of the characters '%1'.").arg(QLatin1String(notAllowedChars));
+ return false;
+ }
+ // Substrings
+ const int notAllowedSubStringCount = sizeof(notAllowedSubStrings)/sizeof(const char *);
+ for (int s = 0; s < notAllowedSubStringCount; s++) {
+ const QLatin1String notAllowedSubString(notAllowedSubStrings[s]);
+ if (name.contains(notAllowedSubString)) {
+ if (errorMessage)
+ *errorMessage = tr("The name must not contain '%1'.").arg(QString(notAllowedSubString));
+ return false;
+ }
+ }
+ // Strings
+ const int notAllowedStringCount = sizeof(notAllowedStrings)/sizeof(const char *);
+ for (int s = 0; s < notAllowedStringCount; s++) {
+ const QLatin1String notAllowedString(notAllowedStrings[s]);
+ if (name == notAllowedString) {
+ if (errorMessage)
+ *errorMessage = tr("The name must not be '%1'.").arg(QString(notAllowedString));
+ return false;
+ }
+ }
+ return true;
+}
+
+bool FileNameValidatingLineEdit::validate(const QString &value, QString *errorMessage) const
+{
+ return validateFileName(value, errorMessage);
+}
+
+}
+}
diff --git a/src/libs/utils/filenamevalidatinglineedit.h b/src/libs/utils/filenamevalidatinglineedit.h
new file mode 100644
index 0000000000..7535fc196d
--- /dev/null
+++ b/src/libs/utils/filenamevalidatinglineedit.h
@@ -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 (qt-info@nokia.com)
+**
+**
+** 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 FILENAMEVALIDATINGLINEEDIT_H
+#define FILENAMEVALIDATINGLINEEDIT_H
+
+#include "basevalidatinglineedit.h"
+
+namespace Core {
+namespace Utils {
+
+class QWORKBENCH_UTILS_EXPORT FileNameValidatingLineEdit : public BaseValidatingLineEdit {
+ Q_OBJECT
+ Q_DISABLE_COPY(FileNameValidatingLineEdit)
+
+public:
+ explicit FileNameValidatingLineEdit(QWidget *parent = 0);
+
+ static bool validateFileName(const QString &name, QString *errorMessage /* = 0*/);
+
+protected:
+ virtual bool validate(const QString &value, QString *errorMessage) const;
+};
+
+}
+}
+#endif // FILENAMEVALIDATINGLINEEDIT_H
diff --git a/src/libs/utils/filesearch.cpp b/src/libs/utils/filesearch.cpp
new file mode 100644
index 0000000000..9756984b4b
--- /dev/null
+++ b/src/libs/utils/filesearch.cpp
@@ -0,0 +1,216 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "filesearch.h"
+
+#include <QtCore/QFile>
+#include <QtCore/QDir>
+#include <QtCore/QFutureInterface>
+#include <QtCore/QtConcurrentRun>
+#include <QtCore/QRegExp>
+#include <QtGui/QApplication>
+
+#include <qtconcurrent/runextensions.h>
+
+using namespace Core::Utils;
+
+namespace {
+ void runFileSearch(QFutureInterface<FileSearchResult> &future,
+ QString searchTerm,
+ QStringList files,
+ QTextDocument::FindFlags flags)
+ {
+ future.setProgressRange(0, files.size());
+ int numFilesSearched = 0;
+ int numMatches = 0;
+
+ bool caseInsensitive = !(flags & QTextDocument::FindCaseSensitively);
+ bool wholeWord = (flags & QTextDocument::FindWholeWords);
+
+ QByteArray sa = searchTerm.toUtf8();
+ int scMaxIndex = sa.length()-1;
+ const char *sc = sa.constData();
+
+ QByteArray sal = searchTerm.toLower().toUtf8();
+ const char *scl = sal.constData();
+
+ QByteArray sau = searchTerm.toUpper().toUtf8();
+ const char *scu = sau.constData();
+
+ int chunkSize = qMax(100000, sa.length());
+
+ foreach (QString s, files) {
+ if (future.isPaused())
+ future.waitForResume();
+ if (future.isCanceled()) {
+ future.setProgressValueAndText(numFilesSearched,
+ qApp->translate("FileSearch", "%1: canceled. %2 occurrences found in %3 files.").
+ arg(searchTerm).arg(numMatches).arg(numFilesSearched));
+ break;
+ }
+ QFile file(s);
+ if (!file.open(QIODevice::ReadOnly))
+ continue;
+ int lineNr = 1;
+ const char *startOfLastLine = NULL;
+
+ bool firstChunk = true;
+ while (!file.atEnd()) {
+ if (!firstChunk)
+ file.seek(file.pos()-sa.length()+1);
+
+ const QByteArray chunk = file.read(chunkSize);
+ const char *chunkPtr = chunk.constData();
+ startOfLastLine = chunkPtr;
+ for (const char *regionPtr = chunkPtr; regionPtr < chunkPtr + chunk.length()-scMaxIndex; ++regionPtr) {
+ const char *regionEnd = regionPtr + scMaxIndex;
+
+ if (*regionPtr == '\n') {
+ startOfLastLine = regionPtr + 1;
+ ++lineNr;
+ }
+ else if (
+ // case sensitive
+ (!caseInsensitive && *regionPtr == sc[0] && *regionEnd == sc[scMaxIndex])
+ ||
+ // case insensitive
+ (caseInsensitive && (*regionPtr == scl[0] || *regionPtr == scu[0])
+ && (*regionEnd == scl[scMaxIndex] || *regionEnd == scu[scMaxIndex]))
+ ) {
+ const char *afterRegion = regionEnd + 1;
+ const char *beforeRegion = regionPtr - 1;
+ bool equal = true;
+ if (wholeWord &&
+ ( ((*beforeRegion >= '0' && *beforeRegion <= '9') || *beforeRegion >= 'A')
+ || ((*afterRegion >= '0' && *afterRegion <= '9') || *afterRegion >= 'A')))
+ {
+ equal = false;
+ }
+
+ int regionIndex = 1;
+ for (const char *regionCursor = regionPtr + 1; regionCursor < regionEnd; ++regionCursor, ++regionIndex) {
+ if ( // case sensitive
+ (!caseInsensitive && equal && *regionCursor != sc[regionIndex])
+ ||
+ // case insensitive
+ (caseInsensitive && equal && *regionCursor != sc[regionIndex] && *regionCursor != scl[regionIndex] && *regionCursor != scu[regionIndex])
+ ) {
+ equal = false;
+ }
+ }
+ if (equal) {
+ int textLength = chunk.length() - (startOfLastLine - chunkPtr);
+ if (textLength > 0) {
+ QByteArray res;
+ res.reserve(256);
+ int i = 0;
+ int n = 0;
+ while (startOfLastLine[i] != '\n' && startOfLastLine[i] != '\r' && i < textLength && n++ < 256)
+ res.append(startOfLastLine[i++]);
+ future.reportResult(FileSearchResult(QDir::toNativeSeparators(s), lineNr, QString(res),
+ regionPtr - startOfLastLine, sa.length()));
+ ++numMatches;
+ }
+ }
+ }
+ }
+ firstChunk = false;
+ }
+ ++numFilesSearched;
+ future.setProgressValueAndText(numFilesSearched, qApp->translate("FileSearch", "%1: %2 occurrences found in %3 of %4 files.").
+ arg(searchTerm).arg(numMatches).arg(numFilesSearched).arg(files.size()));
+ }
+ if (!future.isCanceled())
+ future.setProgressValueAndText(numFilesSearched, qApp->translate("FileSearch", "%1: %2 occurrences found in %3 files.").
+ arg(searchTerm).arg(numMatches).arg(numFilesSearched));
+ }
+
+ void runFileSearchRegExp(QFutureInterface<FileSearchResult> &future,
+ QString searchTerm,
+ QStringList files,
+ QTextDocument::FindFlags flags)
+ {
+ future.setProgressRange(0, files.size());
+ int numFilesSearched = 0;
+ int numMatches = 0;
+ if (flags & QTextDocument::FindWholeWords)
+ searchTerm = QString("\b%1\b").arg(searchTerm);
+ Qt::CaseSensitivity caseSensitivity = (flags & QTextDocument::FindCaseSensitively) ? Qt::CaseSensitive : Qt::CaseInsensitive;
+ QRegExp expression(searchTerm, caseSensitivity);
+
+ foreach (QString s, files) {
+ if (future.isPaused())
+ future.waitForResume();
+ if (future.isCanceled()) {
+ future.setProgressValueAndText(numFilesSearched,
+ qApp->translate("FileSearch", "%1: canceled. %2 occurrences found in %3 files.").
+ arg(searchTerm).arg(numMatches).arg(numFilesSearched));
+ break;
+ }
+ QFile file(s);
+ if (!file.open(QIODevice::ReadOnly))
+ continue;
+ QTextStream stream(&file);
+ int lineNr = 1;
+ QString line;
+ while (!stream.atEnd()) {
+ line = stream.readLine();
+ int pos = 0;
+ while ((pos = expression.indexIn(line, pos)) != -1) {
+ future.reportResult(FileSearchResult(QDir::toNativeSeparators(s), lineNr, line,
+ pos, expression.matchedLength()));
+ pos += expression.matchedLength();
+ }
+ ++lineNr;
+ }
+ ++numFilesSearched;
+ future.setProgressValueAndText(numFilesSearched, qApp->translate("FileSearch", "%1: %2 occurrences found in %3 of %4 files.").
+ arg(searchTerm).arg(numMatches).arg(numFilesSearched).arg(files.size()));
+ }
+ if (!future.isCanceled())
+ future.setProgressValueAndText(numFilesSearched, qApp->translate("FileSearch", "%1: %2 occurrences found in %3 files.").
+ arg(searchTerm).arg(numMatches).arg(numFilesSearched));
+ }
+} // namespace
+
+
+QFuture<FileSearchResult> Core::Utils::findInFiles(const QString &searchTerm, const QStringList &files,
+ QTextDocument::FindFlags flags)
+{
+ return QtConcurrent::run<FileSearchResult, QString, QStringList, QTextDocument::FindFlags>(runFileSearch, searchTerm, files, flags);
+}
+
+QFuture<FileSearchResult> Core::Utils::findInFilesRegExp(const QString &searchTerm, const QStringList &files,
+ QTextDocument::FindFlags flags)
+{
+ return QtConcurrent::run<FileSearchResult, QString, QStringList, QTextDocument::FindFlags>(runFileSearchRegExp, searchTerm, files, flags);
+}
diff --git a/src/libs/utils/filesearch.h b/src/libs/utils/filesearch.h
new file mode 100644
index 0000000000..3b747fb548
--- /dev/null
+++ b/src/libs/utils/filesearch.h
@@ -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 (qt-info@nokia.com)
+**
+**
+** 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 FILESEARCH_H
+#define FILESEARCH_H
+
+#include "utils_global.h"
+
+#include <QtCore/QStringList>
+#include <QtCore/QFuture>
+#include <QtGui/QTextDocument>
+
+namespace Core {
+namespace Utils {
+
+class QWORKBENCH_UTILS_EXPORT FileSearchResult
+{
+public:
+ FileSearchResult() {}
+ FileSearchResult(QString fileName, int lineNumber, QString matchingLine, int matchStart, int matchLength)
+ : fileName(fileName), lineNumber(lineNumber), matchingLine(matchingLine), matchStart(matchStart), matchLength(matchLength)
+ {
+ }
+ QString fileName;
+ int lineNumber;
+ QString matchingLine;
+ int matchStart;
+ int matchLength;
+};
+
+QWORKBENCH_UTILS_EXPORT QFuture<FileSearchResult> findInFiles(const QString &searchTerm, const QStringList &files,
+ QTextDocument::FindFlags flags);
+
+QWORKBENCH_UTILS_EXPORT QFuture<FileSearchResult> findInFilesRegExp(const QString &searchTerm, const QStringList &files,
+ QTextDocument::FindFlags flags);
+
+} //Utils
+} //Core
+
+#endif
diff --git a/src/libs/utils/filewizarddialog.cpp b/src/libs/utils/filewizarddialog.cpp
new file mode 100644
index 0000000000..2843a304e5
--- /dev/null
+++ b/src/libs/utils/filewizarddialog.cpp
@@ -0,0 +1,73 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "filewizarddialog.h"
+#include "filewizardpage.h"
+
+#include <QtGui/QAbstractButton>
+
+namespace Core {
+namespace Utils {
+
+FileWizardDialog::FileWizardDialog(QWidget *parent) :
+ QWizard(parent),
+ m_filePage(new FileWizardPage)
+{
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ setPixmap(QWizard::WatermarkPixmap, QPixmap(QLatin1String(":/qworkbench/images/qtwatermark.png")));
+ addPage(m_filePage);
+ connect(m_filePage, SIGNAL(activated()), button(QWizard::FinishButton), SLOT(animateClick()));
+}
+
+QString FileWizardDialog::name() const
+{
+ return m_filePage->name();
+}
+
+QString FileWizardDialog::path() const
+{
+ return m_filePage->path();
+}
+
+void FileWizardDialog::setPath(const QString &path)
+{
+ m_filePage->setPath(path);
+
+}
+
+void FileWizardDialog::setName(const QString &name)
+{
+ m_filePage->setName(name);
+}
+
+} // namespace Utils
+} // namespace Core
diff --git a/src/libs/utils/filewizarddialog.h b/src/libs/utils/filewizarddialog.h
new file mode 100644
index 0000000000..6a4a7d9ba6
--- /dev/null
+++ b/src/libs/utils/filewizarddialog.h
@@ -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 (qt-info@nokia.com)
+**
+**
+** 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 FILEWIZARDDIALOG_H
+#define FILEWIZARDDIALOG_H
+
+#include "utils_global.h"
+
+#include <QtGui/QWizard>
+
+namespace Core {
+namespace Utils {
+
+class FileWizardPage;
+
+/*
+ Standard wizard for a single file letting the user choose name
+ and path. Custom pages can be added via Core::IWizardExtension.
+*/
+
+class QWORKBENCH_UTILS_EXPORT FileWizardDialog : public QWizard {
+ Q_OBJECT
+ Q_DISABLE_COPY(FileWizardDialog)
+public:
+ explicit FileWizardDialog(QWidget *parent = 0);
+
+ QString name() const;
+ QString path() const;
+
+public slots:
+ void setPath(const QString &path);
+ void setName(const QString &name);
+
+private:
+ FileWizardPage *m_filePage;
+};
+
+}
+}
+#endif // FILEWIZARDDIALOG_H
diff --git a/src/libs/utils/filewizardpage.cpp b/src/libs/utils/filewizardpage.cpp
new file mode 100644
index 0000000000..a448ebe739
--- /dev/null
+++ b/src/libs/utils/filewizardpage.cpp
@@ -0,0 +1,129 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "filewizardpage.h"
+#include "ui_filewizardpage.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtGui/QMessageBox>
+
+namespace Core {
+namespace Utils {
+
+struct FileWizardPagePrivate
+{
+ FileWizardPagePrivate();
+ Ui::WizardPage m_ui;
+ bool m_complete;
+};
+
+FileWizardPagePrivate::FileWizardPagePrivate() :
+ m_complete(false)
+{
+}
+
+FileWizardPage::FileWizardPage(QWidget *parent) :
+ QWizardPage(parent),
+ m_d(new FileWizardPagePrivate)
+{
+ m_d->m_ui.setupUi(this);
+ connect(m_d->m_ui.pathChooser, SIGNAL(validChanged()), this, SLOT(slotValidChanged()));
+ connect(m_d->m_ui.nameLineEdit, SIGNAL(validChanged()), this, SLOT(slotValidChanged()));
+
+ connect(m_d->m_ui.pathChooser, SIGNAL(returnPressed()), this, SLOT(slotActivated()));
+ connect(m_d->m_ui.nameLineEdit, SIGNAL(validReturnPressed()), this, SLOT(slotActivated()));
+}
+
+FileWizardPage::~FileWizardPage()
+{
+ delete m_d;
+}
+
+QString FileWizardPage::name() const
+{
+ return m_d->m_ui.nameLineEdit->text();
+}
+
+QString FileWizardPage::path() const
+{
+ return m_d->m_ui.pathChooser->path();
+}
+
+void FileWizardPage::setPath(const QString &path)
+{
+ m_d->m_ui.pathChooser->setPath(path);
+}
+
+void FileWizardPage::setName(const QString &name)
+{
+ m_d->m_ui.nameLineEdit->setText(name);
+}
+
+void FileWizardPage::changeEvent(QEvent *e)
+{
+ switch(e->type()) {
+ case QEvent::LanguageChange:
+ m_d->m_ui.retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+}
+
+bool FileWizardPage::isComplete() const
+{
+ return m_d->m_complete;
+}
+
+void FileWizardPage::slotValidChanged()
+{
+ const bool newComplete = m_d->m_ui.pathChooser->isValid() && m_d->m_ui.nameLineEdit->isValid();
+ if (newComplete != m_d->m_complete) {
+ m_d->m_complete = newComplete;
+ emit completeChanged();
+ }
+}
+
+void FileWizardPage::slotActivated()
+{
+ if (m_d->m_complete)
+ emit activated();
+}
+
+bool FileWizardPage::validateBaseName(const QString &name, QString *errorMessage /* = 0*/)
+{
+ return FileNameValidatingLineEdit::validateFileName(name, errorMessage);
+}
+
+} // namespace Utils
+} // namespace Core
diff --git a/src/libs/utils/filewizardpage.h b/src/libs/utils/filewizardpage.h
new file mode 100644
index 0000000000..b2ae28a9d0
--- /dev/null
+++ b/src/libs/utils/filewizardpage.h
@@ -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 (qt-info@nokia.com)
+**
+**
+** 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 FILEWIZARDPAGE_H
+#define FILEWIZARDPAGE_H
+
+#include "utils_global.h"
+
+#include <QtGui/QWizardPage>
+
+namespace Core {
+namespace Utils {
+
+struct FileWizardPagePrivate;
+
+/* Standard wizard page for a single file letting the user choose name
+ * and path. Sets the "FileNames" QWizard field. */
+
+class QWORKBENCH_UTILS_EXPORT FileWizardPage : public QWizardPage {
+ Q_OBJECT
+ Q_DISABLE_COPY(FileWizardPage)
+ Q_PROPERTY(QString path READ path WRITE setPath DESIGNABLE true)
+ Q_PROPERTY(QString name READ name WRITE setName DESIGNABLE true)
+public:
+ explicit FileWizardPage(QWidget *parent = 0);
+ virtual ~FileWizardPage();
+
+ QString name() const;
+ QString path() const;
+
+ virtual bool isComplete() const;
+
+ // Validate a base name entry field (potentially containing extension)
+ static bool validateBaseName(const QString &name, QString *errorMessage = 0);
+
+signals:
+ void activated();
+ void pathChanged();
+
+public slots:
+ void setPath(const QString &path);
+ void setName(const QString &name);
+
+private slots:
+ void slotValidChanged();
+ void slotActivated();
+
+protected:
+ virtual void changeEvent(QEvent *e);
+
+private:
+ FileWizardPagePrivate *m_d;
+};
+
+}
+}
+#endif // FILEWIZARDPAGE_H
diff --git a/src/libs/utils/filewizardpage.ui b/src/libs/utils/filewizardpage.ui
new file mode 100644
index 0000000000..2e614c6f55
--- /dev/null
+++ b/src/libs/utils/filewizardpage.ui
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Core::Utils::WizardPage</class>
+ <widget class="QWizardPage" name="Core::Utils::WizardPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>WizardPage</string>
+ </property>
+ <property name="title">
+ <string>Choose the location</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QWidget" name="widget" native="true">
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="nameLabel">
+ <property name="text">
+ <string>Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="Core::Utils::FileNameValidatingLineEdit" name="nameLineEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="pathLabel">
+ <property name="text">
+ <string>Path:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="Core::Utils::PathChooser" name="pathChooser" native="true"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>201</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>Core::Utils::PathChooser</class>
+ <extends>QWidget</extends>
+ <header>pathchooser.h</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>Core::Utils::FileNameValidatingLineEdit</class>
+ <extends>QLineEdit</extends>
+ <header>filenamevalidatinglineedit.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/libs/utils/linecolumnlabel.cpp b/src/libs/utils/linecolumnlabel.cpp
new file mode 100644
index 0000000000..c6028ab13f
--- /dev/null
+++ b/src/libs/utils/linecolumnlabel.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 (qt-info@nokia.com)
+**
+**
+** 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 "linecolumnlabel.h"
+
+namespace Core {
+namespace Utils {
+
+LineColumnLabel::LineColumnLabel(QWidget *parent) :
+ QLabel(parent),
+ m_unused(0)
+{
+}
+
+LineColumnLabel::~LineColumnLabel()
+{
+}
+
+void LineColumnLabel::setText(const QString &text, const QString &maxText)
+{
+ QLabel::setText(text);
+ m_maxText = maxText;
+}
+QSize LineColumnLabel::sizeHint() const
+{
+ return fontMetrics().boundingRect(m_maxText).size();
+}
+
+QString LineColumnLabel::maxText() const
+{
+ return m_maxText;
+}
+
+void LineColumnLabel::setMaxText(const QString &maxText)
+{
+ m_maxText = maxText;
+}
+
+}
+}
diff --git a/src/libs/utils/linecolumnlabel.h b/src/libs/utils/linecolumnlabel.h
new file mode 100644
index 0000000000..d5dea084cc
--- /dev/null
+++ b/src/libs/utils/linecolumnlabel.h
@@ -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 (qt-info@nokia.com)
+**
+**
+** 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 LINECOLUMNLABEL_H
+#define LINECOLUMNLABEL_H
+
+#include "utils_global.h"
+#include <QtGui/QLabel>
+
+namespace Core {
+namespace Utils {
+
+/* A label suitable for displaying cursor positions, etc. with a fixed
+ * with derived from a sample text. */
+
+class QWORKBENCH_UTILS_EXPORT LineColumnLabel : public QLabel {
+ Q_DISABLE_COPY(LineColumnLabel)
+ Q_OBJECT
+ Q_PROPERTY(QString maxText READ maxText WRITE setMaxText DESIGNABLE true)
+
+public:
+ explicit LineColumnLabel(QWidget *parent = 0);
+ virtual ~LineColumnLabel();
+
+ void setText(const QString &text, const QString &maxText);
+ QSize sizeHint() const;
+
+ QString maxText() const;
+ void setMaxText(const QString &maxText);
+
+private:
+ QString m_maxText;
+ void *m_unused;
+};
+
+}
+}
+
+#endif // LINECOLUMNLABEL_H
diff --git a/src/libs/utils/listutils.h b/src/libs/utils/listutils.h
new file mode 100644
index 0000000000..3b688f336d
--- /dev/null
+++ b/src/libs/utils/listutils.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 LISTUTILS_H
+#define LISTUTILS_H
+
+#include <QtCore/QList>
+
+namespace Core {
+namespace Utils {
+
+template <class T1, class T2>
+QList<T1> qwConvertList(const QList<T2> &list)
+{
+ QList<T1> convertedList;
+ foreach (T2 listEntry, list) {
+ convertedList << qobject_cast<T1>(listEntry);
+ }
+ return convertedList;
+}
+
+} // Utils
+} // Core
+
+#endif // LISTUTILS_H
diff --git a/src/libs/utils/newclasswidget.cpp b/src/libs/utils/newclasswidget.cpp
new file mode 100644
index 0000000000..67cd1f8691
--- /dev/null
+++ b/src/libs/utils/newclasswidget.cpp
@@ -0,0 +1,462 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "newclasswidget.h"
+#include "ui_newclasswidget.h"
+
+#include <utils/filewizardpage.h>
+
+#include <QtGui/QFileDialog>
+#include <QtCore/QFileInfo>
+#include <QtCore/QStringList>
+#include <QtCore/QDir>
+#include <QtCore/QDebug>
+#include <QtCore/QRegExp>
+
+enum { debugNewClassWidget = 0 };
+
+namespace Core {
+namespace Utils {
+
+struct NewClassWidgetPrivate {
+ NewClassWidgetPrivate();
+
+ Ui::NewClassWidget m_ui;
+ QString m_headerExtension;
+ QString m_sourceExtension;
+ QString m_formExtension;
+ bool m_valid;
+ bool m_classEdited;
+ // Store the "visible" values to prevent the READ accessors from being
+ // fooled by a temporarily hidden widget
+ bool m_baseClassInputVisible;
+ bool m_formInputVisible;
+ bool m_pathInputVisible;
+ bool m_formInputCheckable;
+};
+
+NewClassWidgetPrivate:: NewClassWidgetPrivate() :
+ m_headerExtension(QLatin1String("h")),
+ m_sourceExtension(QLatin1String("cpp")),
+ m_formExtension(QLatin1String("ui")),
+ m_valid(false),
+ m_classEdited(false),
+ m_baseClassInputVisible(true),
+ m_formInputVisible(true),
+ m_pathInputVisible(true),
+ m_formInputCheckable(false)
+{
+}
+
+// --------------------- NewClassWidget
+NewClassWidget::NewClassWidget(QWidget *parent) :
+ QWidget(parent),
+ m_d(new NewClassWidgetPrivate)
+{
+ m_d->m_ui.setupUi(this);
+
+ m_d->m_ui.baseClassComboBox->setEditable(false);
+
+ connect(m_d->m_ui.classLineEdit, SIGNAL(updateFileName(QString)),
+ this, SLOT(updateFileNames(QString)));
+ connect(m_d->m_ui.classLineEdit, SIGNAL(textEdited(QString)),
+ this, SLOT(classNameEdited()));
+ connect(m_d->m_ui.baseClassComboBox, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(suggestClassNameFromBase()));
+ connect(m_d->m_ui.baseClassComboBox, SIGNAL(editTextChanged(QString)),
+ this, SLOT(slotValidChanged()));
+ connect(m_d->m_ui.classLineEdit, SIGNAL(validChanged()),
+ this, SLOT(slotValidChanged()));
+ connect(m_d->m_ui.headerFileLineEdit, SIGNAL(validChanged()),
+ this, SLOT(slotValidChanged()));
+ connect(m_d->m_ui.sourceFileLineEdit, SIGNAL(validChanged()),
+ this, SLOT(slotValidChanged()));
+ connect(m_d->m_ui.formFileLineEdit, SIGNAL(validChanged()),
+ this, SLOT(slotValidChanged()));
+ connect(m_d->m_ui.pathChooser, SIGNAL(validChanged()),
+ this, SLOT(slotValidChanged()));
+
+ connect(m_d->m_ui.classLineEdit, SIGNAL(validReturnPressed()),
+ this, SLOT(slotActivated()));
+ connect(m_d->m_ui.headerFileLineEdit, SIGNAL(validReturnPressed()),
+ this, SLOT(slotActivated()));
+ connect(m_d->m_ui.sourceFileLineEdit, SIGNAL(validReturnPressed()),
+ this, SLOT(slotActivated()));
+ connect(m_d->m_ui.formFileLineEdit, SIGNAL(validReturnPressed()),
+ this, SLOT(slotActivated()));
+ connect(m_d->m_ui.formFileLineEdit, SIGNAL(validReturnPressed()),
+ this, SLOT(slotActivated()));
+ connect(m_d->m_ui.pathChooser, SIGNAL(returnPressed()),
+ this, SLOT(slotActivated()));
+
+ connect(m_d->m_ui.generateFormCheckBox, SIGNAL(stateChanged(int)),
+ this, SLOT(slotFormInputChecked()));
+
+ m_d->m_ui.generateFormCheckBox->setChecked(true);
+ setFormInputCheckable(false, true);
+}
+
+NewClassWidget::~NewClassWidget()
+{
+ delete m_d;
+}
+
+void NewClassWidget::classNameEdited()
+{
+ if (debugNewClassWidget)
+ qDebug() << Q_FUNC_INFO << m_d->m_headerExtension << m_d->m_sourceExtension;
+ m_d->m_classEdited = true;
+}
+
+void NewClassWidget::suggestClassNameFromBase()
+{
+ if (debugNewClassWidget)
+ qDebug() << Q_FUNC_INFO << m_d->m_headerExtension << m_d->m_sourceExtension;
+ if (m_d->m_classEdited)
+ return;
+ // Suggest a class unless edited ("QMainWindow"->"MainWindow")
+ QString base = baseClassName();
+ if (base.startsWith(QLatin1Char('Q'))) {
+ base.remove(0, 1);
+ setClassName(base);
+ }
+}
+
+QStringList NewClassWidget::baseClassChoices() const
+{
+ QStringList rc;
+ const int count = m_d->m_ui.baseClassComboBox->count();
+ for (int i = 0; i < count; i++)
+ rc.push_back(m_d->m_ui.baseClassComboBox->itemText(i));
+ return rc;
+}
+
+void NewClassWidget::setBaseClassChoices(const QStringList &choices)
+{
+ m_d->m_ui.baseClassComboBox->clear();
+ m_d->m_ui.baseClassComboBox->addItems(choices);
+}
+
+void NewClassWidget::setBaseClassInputVisible(bool visible)
+{
+ m_d->m_baseClassInputVisible = visible;
+ m_d->m_ui.baseClassLabel->setVisible(visible);
+ m_d->m_ui.baseClassComboBox->setVisible(visible);
+}
+
+void NewClassWidget::setBaseClassEditable(bool editable)
+{
+ m_d->m_ui.baseClassComboBox->setEditable(editable);
+}
+
+bool NewClassWidget::isBaseClassInputVisible() const
+{
+ return m_d->m_baseClassInputVisible;
+}
+
+bool NewClassWidget::isBaseClassEditable() const
+{
+ return m_d->m_ui.baseClassComboBox->isEditable();
+}
+
+void NewClassWidget::setFormInputVisible(bool visible)
+{
+ m_d->m_formInputVisible = visible;
+ m_d->m_ui.formLabel->setVisible(visible);
+ m_d->m_ui.formFileLineEdit->setVisible(visible);
+}
+
+bool NewClassWidget::isFormInputVisible() const
+{
+ return m_d->m_formInputVisible;
+}
+
+void NewClassWidget::setFormInputCheckable(bool checkable)
+{
+ setFormInputCheckable(checkable, false);
+}
+
+void NewClassWidget::setFormInputCheckable(bool checkable, bool force)
+{
+ if (!force && checkable == m_d->m_formInputCheckable)
+ return;
+ m_d->m_formInputCheckable = checkable;
+ m_d->m_ui.generateFormLabel->setVisible(checkable);
+ m_d->m_ui.generateFormCheckBox->setVisible(checkable);
+}
+
+void NewClassWidget::setFormInputChecked(bool v)
+{
+ m_d->m_ui.generateFormCheckBox->setChecked(v);
+}
+
+bool NewClassWidget::formInputCheckable() const
+{
+ return m_d->m_formInputCheckable;
+}
+
+bool NewClassWidget::formInputChecked() const
+{
+ return m_d->m_ui.generateFormCheckBox->isChecked();
+}
+
+void NewClassWidget::slotFormInputChecked()
+{
+ const bool checked = formInputChecked();
+ m_d->m_ui.formLabel->setEnabled(checked);
+ m_d->m_ui.formFileLineEdit->setEnabled(checked);
+}
+
+void NewClassWidget::setPathInputVisible(bool visible)
+{
+ m_d->m_pathInputVisible = visible;
+ m_d->m_ui.pathLabel->setVisible(visible);
+ m_d->m_ui.pathChooser->setVisible(visible);
+}
+
+bool NewClassWidget::isPathInputVisible() const
+{
+ return m_d->m_pathInputVisible;
+}
+
+void NewClassWidget::setClassName(const QString &suggestedName)
+{
+ if (debugNewClassWidget)
+ qDebug() << Q_FUNC_INFO << suggestedName << m_d->m_headerExtension << m_d->m_sourceExtension;
+ m_d->m_ui.classLineEdit->setText(ClassNameValidatingLineEdit::createClassName(suggestedName));
+}
+
+QString NewClassWidget::className() const
+{
+ return m_d->m_ui.classLineEdit->text();
+}
+
+QString NewClassWidget::baseClassName() const
+{
+ return m_d->m_ui.baseClassComboBox->currentText();
+}
+
+void NewClassWidget::setBaseClassName(const QString &c)
+{
+ const int index = m_d->m_ui.baseClassComboBox->findText(c);
+ if (index != -1) {
+ m_d->m_ui.baseClassComboBox->setCurrentIndex(index);
+ suggestClassNameFromBase();
+ }
+}
+
+QString NewClassWidget::sourceFileName() const
+{
+ return m_d->m_ui.sourceFileLineEdit->text();
+}
+
+QString NewClassWidget::headerFileName() const
+{
+ return m_d->m_ui.headerFileLineEdit->text();
+}
+
+QString NewClassWidget::formFileName() const
+{
+ return m_d->m_ui.formFileLineEdit->text();
+}
+
+QString NewClassWidget::path() const
+{
+ return m_d->m_ui.pathChooser->path();
+}
+
+void NewClassWidget::setPath(const QString &path)
+{
+ m_d->m_ui.pathChooser->setPath(path);
+}
+
+bool NewClassWidget::namespacesEnabled() const
+{
+ return m_d->m_ui.classLineEdit->namespacesEnabled();
+}
+
+void NewClassWidget::setNamespacesEnabled(bool b)
+{
+ m_d->m_ui.classLineEdit->setNamespacesEnabled(b);
+}
+
+QString NewClassWidget::sourceExtension() const
+{
+ return m_d->m_sourceExtension;
+}
+
+void NewClassWidget::setSourceExtension(const QString &e)
+{
+ if (debugNewClassWidget)
+ qDebug() << Q_FUNC_INFO << e;
+ m_d->m_sourceExtension = fixSuffix(e);
+}
+
+QString NewClassWidget::headerExtension() const
+{
+ return m_d->m_headerExtension;
+}
+
+void NewClassWidget::setHeaderExtension(const QString &e)
+{
+ if (debugNewClassWidget)
+ qDebug() << Q_FUNC_INFO << e;
+ m_d->m_headerExtension = fixSuffix(e);
+}
+
+QString NewClassWidget::formExtension() const
+{
+ return m_d->m_formExtension;
+}
+
+void NewClassWidget::setFormExtension(const QString &e)
+{
+ if (debugNewClassWidget)
+ qDebug() << Q_FUNC_INFO << e;
+ m_d->m_formExtension = fixSuffix(e);
+}
+
+void NewClassWidget::slotValidChanged()
+{
+ const bool newValid = isValid();
+ if (newValid != m_d->m_valid) {
+ m_d->m_valid = newValid;
+ emit validChanged();
+ }
+}
+
+bool NewClassWidget::isValid(QString *error) const
+{
+ if (!m_d->m_ui.classLineEdit->isValid()) {
+ if (error)
+ *error = m_d->m_ui.classLineEdit->errorMessage();
+ return false;
+ }
+
+ if (isBaseClassInputVisible() && isBaseClassEditable()) {
+ // TODO: Should this be a ClassNameValidatingComboBox?
+ QRegExp classNameValidator(QLatin1String("[a-zA-Z_][a-zA-Z0-9_]*(::[a-zA-Z_][a-zA-Z0-9_]*)*"));
+ const QString baseClass = m_d->m_ui.baseClassComboBox->currentText().trimmed();
+ if (!baseClass.isEmpty() && !classNameValidator.exactMatch(baseClass)) {
+ if (error)
+ *error = tr("Invalid base class name");
+ return false;
+ }
+ }
+
+ if (!m_d->m_ui.headerFileLineEdit->isValid()) {
+ if (error)
+ *error = tr("Invalid header file name: %1").arg(m_d->m_ui.headerFileLineEdit->errorMessage());
+ return false;
+ }
+
+ if (!m_d->m_ui.sourceFileLineEdit->isValid()) {
+ if (error)
+ *error = tr("Invalid source file name: %1").arg(m_d->m_ui.sourceFileLineEdit->errorMessage());
+ return false;
+ }
+
+ if (isFormInputVisible()) {
+ if (!m_d->m_ui.formFileLineEdit->isValid()) {
+ if (error)
+ *error = tr("Invalid form file name: %1").arg(m_d->m_ui.formFileLineEdit->errorMessage());
+ return false;
+ }
+ }
+
+ if (isPathInputVisible()) {
+ if (!m_d->m_ui.pathChooser->isValid()) {
+ if (error)
+ *error = m_d->m_ui.pathChooser->errorMessage();
+ return false;
+ }
+ }
+ return true;
+}
+
+void NewClassWidget::updateFileNames(const QString &baseName)
+{
+ if (debugNewClassWidget)
+ qDebug() << Q_FUNC_INFO << baseName << m_d->m_headerExtension << m_d->m_sourceExtension;
+ const QChar dot = QLatin1Char('.');
+ m_d->m_ui.sourceFileLineEdit->setText(baseName + dot + m_d->m_sourceExtension);
+ m_d->m_ui.headerFileLineEdit->setText(baseName + dot + m_d->m_headerExtension);
+ m_d->m_ui.formFileLineEdit->setText(baseName + dot + m_d->m_formExtension);
+}
+
+void NewClassWidget::slotActivated()
+{
+ if (m_d->m_valid)
+ emit activated();
+}
+
+QString NewClassWidget::fixSuffix(const QString &suffix)
+{
+ QString s = suffix;
+ if (s.startsWith(QLatin1Char('.')))
+ s.remove(0, 1);
+ return s;
+}
+
+// Utility to add a suffix to a file unless the user specified one
+static QString ensureSuffix(QString f, const QString &extension)
+{
+ const QChar dot = QLatin1Char('.');
+ if (f.contains(dot))
+ return f;
+ f += dot;
+ f += extension;
+ return f;
+}
+
+// If a non-empty name was passed, expand to directory and suffix
+static QString expandFileName(const QDir &dir, const QString name, const QString &extension)
+{
+ if (name.isEmpty())
+ return QString();
+ return dir.absoluteFilePath(ensureSuffix(name, extension));
+}
+
+QStringList NewClassWidget::files() const
+{
+ QStringList rc;
+ const QDir dir = QDir(path());
+ rc.push_back(expandFileName(dir, headerFileName(), headerExtension()));
+ rc.push_back(expandFileName(dir, sourceFileName(), sourceExtension()));
+ if (isFormInputVisible())
+ rc.push_back(expandFileName(dir, formFileName(), formExtension()));
+ return rc;
+}
+
+
+} // namespace Utils
+} // namespace Core
diff --git a/src/libs/utils/newclasswidget.h b/src/libs/utils/newclasswidget.h
new file mode 100644
index 0000000000..e534189d77
--- /dev/null
+++ b/src/libs/utils/newclasswidget.h
@@ -0,0 +1,150 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 NEWCLASSWIDGET_H
+#define NEWCLASSWIDGET_H
+
+#include "utils_global.h"
+
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+class QStringList;
+QT_END_NAMESPACE
+
+namespace Core {
+namespace Utils {
+
+struct NewClassWidgetPrivate;
+
+/* NewClassWidget: Utility widget for 'New Class' wizards. Prompts the user
+ * to enter a class name (optionally derived from some base class) and file
+ * names for header, source and form files. Has some smart logic to derive
+ * the file names from the class name. */
+
+class QWORKBENCH_UTILS_EXPORT NewClassWidget : public QWidget
+{
+ Q_DISABLE_COPY(NewClassWidget)
+ Q_OBJECT
+ Q_PROPERTY(bool namespacesEnabled READ namespacesEnabled WRITE setNamespacesEnabled DESIGNABLE true)
+ Q_PROPERTY(bool baseClassInputVisible READ isBaseClassInputVisible WRITE setBaseClassInputVisible DESIGNABLE true)
+ Q_PROPERTY(bool baseClassEditable READ isBaseClassEditable WRITE setBaseClassEditable DESIGNABLE false)
+ Q_PROPERTY(bool formInputVisible READ isFormInputVisible WRITE setFormInputVisible DESIGNABLE true)
+ Q_PROPERTY(bool pathInputVisible READ isPathInputVisible WRITE setPathInputVisible DESIGNABLE true)
+ Q_PROPERTY(QString className READ className WRITE setClassName DESIGNABLE true)
+ Q_PROPERTY(QString baseClassName READ baseClassName WRITE setBaseClassName DESIGNABLE true)
+ Q_PROPERTY(QString sourceFileName READ sourceFileName DESIGNABLE false)
+ Q_PROPERTY(QString headerFileName READ headerFileName DESIGNABLE false)
+ Q_PROPERTY(QString formFileName READ formFileName DESIGNABLE false)
+ Q_PROPERTY(QString path READ path WRITE setPath DESIGNABLE true)
+ Q_PROPERTY(QStringList baseClassChoices READ baseClassChoices WRITE setBaseClassChoices DESIGNABLE true)
+ Q_PROPERTY(QString sourceExtension READ sourceExtension WRITE setSourceExtension DESIGNABLE true)
+ Q_PROPERTY(QString headerExtension READ headerExtension WRITE setHeaderExtension DESIGNABLE true)
+ Q_PROPERTY(QString formExtension READ formExtension WRITE setFormExtension DESIGNABLE true)
+ Q_PROPERTY(bool formInputCheckable READ formInputCheckable WRITE setFormInputCheckable DESIGNABLE true)
+ Q_PROPERTY(bool formInputChecked READ formInputChecked WRITE setFormInputChecked DESIGNABLE true)
+ // Utility "USER" property for wizards containing file names.
+ Q_PROPERTY(QStringList files READ files DESIGNABLE false USER true)
+public:
+ explicit NewClassWidget(QWidget *parent = 0);
+ ~NewClassWidget();
+
+ bool namespacesEnabled() const;
+ bool isBaseClassInputVisible() const;
+ bool isBaseClassEditable() const;
+ bool isFormInputVisible() const;
+ bool isPathInputVisible() const;
+ bool formInputCheckable() const;
+ bool formInputChecked() const;
+
+ QString className() const;
+ QString baseClassName() const;
+ QString sourceFileName() const;
+ QString headerFileName() const;
+ QString formFileName() const;
+ QString path() const;
+ QStringList baseClassChoices() const;
+ QString sourceExtension() const;
+ QString headerExtension() const;
+ QString formExtension() const;
+
+
+ bool isValid(QString *error = 0) const;
+
+ QStringList files() const;
+
+signals:
+ void validChanged();
+ void activated();
+
+public slots:
+ void setNamespacesEnabled(bool b);
+ void setBaseClassInputVisible(bool visible);
+ void setBaseClassEditable(bool editable);
+ void setFormInputVisible(bool visible);
+ void setPathInputVisible(bool visible);
+ void setFormInputCheckable(bool v);
+ void setFormInputChecked(bool v);
+
+ /* The name passed into the new class widget will be reformatted to be a
+ * valid class name. */
+ void setClassName(const QString &suggestedName);
+ void setBaseClassName(const QString &);
+ void setPath(const QString &path);
+ void setBaseClassChoices(const QStringList &choices);
+ void setSourceExtension(const QString &e);
+ void setHeaderExtension(const QString &e);
+ void setFormExtension(const QString &e);
+
+ /* Suggest a class name from the base class by stripping the leading 'Q'
+ * character. This will happen automagically if the base class combo
+ * changes until the class line edited is manually edited. */
+ void suggestClassNameFromBase();
+
+private slots:
+ void updateFileNames(const QString &t);
+ void slotValidChanged();
+ void slotActivated();
+ void classNameEdited();
+ void slotFormInputChecked();
+
+private:
+ void setFormInputCheckable(bool checkable, bool force);
+
+ QString fixSuffix(const QString &suffix);
+ NewClassWidgetPrivate *m_d;
+};
+
+} // namespace Utils
+} // namespace Core
+
+#endif // NEWCLASSWIDGET_H
diff --git a/src/libs/utils/newclasswidget.ui b/src/libs/utils/newclasswidget.ui
new file mode 100644
index 0000000000..14e0a6574b
--- /dev/null
+++ b/src/libs/utils/newclasswidget.ui
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Core::Utils::NewClassWidget</class>
+ <widget class="QWidget" name="Core::Utils::NewClassWidget">
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::ExpandingFieldsGrow</enum>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="classNameLabel">
+ <property name="text">
+ <string>Class name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="Core::Utils::ClassNameValidatingLineEdit" name="classLineEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="baseClassLabel">
+ <property name="text">
+ <string>Base class:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QComboBox" name="baseClassComboBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="1">
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="headerLabel">
+ <property name="text">
+ <string>Header file:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="Core::Utils::FileNameValidatingLineEdit" name="headerFileLineEdit"/>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="sourceLabel">
+ <property name="text">
+ <string>Source file:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="Core::Utils::FileNameValidatingLineEdit" name="sourceFileLineEdit"/>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="generateFormLabel">
+ <property name="text">
+ <string>Generate form:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="0">
+ <widget class="QLabel" name="formLabel">
+ <property name="text">
+ <string>Form file:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="1">
+ <widget class="Core::Utils::FileNameValidatingLineEdit" name="formFileLineEdit"/>
+ </item>
+ <item row="7" column="0">
+ <widget class="QLabel" name="pathLabel">
+ <property name="text">
+ <string>Path:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="1">
+ <widget class="Core::Utils::PathChooser" name="pathChooser" native="true"/>
+ </item>
+ <item row="5" column="1">
+ <widget class="QCheckBox" name="generateFormCheckBox">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>Core::Utils::PathChooser</class>
+ <extends>QWidget</extends>
+ <header location="global">pathchooser.h</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>Core::Utils::ClassNameValidatingLineEdit</class>
+ <extends>QLineEdit</extends>
+ <header>classnamevalidatinglineedit.h</header>
+ </customwidget>
+ <customwidget>
+ <class>Core::Utils::FileNameValidatingLineEdit</class>
+ <extends>QLineEdit</extends>
+ <header location="global">utils/filenamevalidatinglineedit.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/libs/utils/pathchooser.cpp b/src/libs/utils/pathchooser.cpp
new file mode 100644
index 0000000000..188aa3b126
--- /dev/null
+++ b/src/libs/utils/pathchooser.cpp
@@ -0,0 +1,185 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "pathchooser.h"
+#include "basevalidatinglineedit.h"
+
+#include <QtGui/QLineEdit>
+#include <QtGui/QHBoxLayout>
+#include <QtGui/QToolButton>
+#include <QtGui/QFileDialog>
+#include <QtGui/QDesktopServices>
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QDir>
+#include <QtCore/QSettings>
+#include <QtCore/QDebug>
+
+namespace Core {
+namespace Utils {
+
+// ------------------ PathValidatingLineEdit
+class PathValidatingLineEdit : public BaseValidatingLineEdit {
+public:
+ explicit PathValidatingLineEdit(QWidget *parent = 0);
+
+protected:
+ virtual bool validate(const QString &value, QString *errorMessage) const;
+};
+
+PathValidatingLineEdit::PathValidatingLineEdit(QWidget *parent) :
+ BaseValidatingLineEdit(parent)
+{
+}
+
+bool PathValidatingLineEdit::validate(const QString &value, QString *errorMessage) const
+{
+ return PathChooser::validatePath(value, errorMessage);
+}
+
+// ------------------ PathChooserPrivate
+struct PathChooserPrivate {
+ PathChooserPrivate();
+
+ PathValidatingLineEdit *m_lineEdit;
+};
+
+PathChooserPrivate::PathChooserPrivate() :
+ m_lineEdit(new PathValidatingLineEdit)
+{
+}
+
+PathChooser::PathChooser(QWidget *parent) :
+ QWidget(parent),
+ m_d(new PathChooserPrivate)
+{
+ QHBoxLayout *hLayout = new QHBoxLayout;
+ hLayout->setContentsMargins(0, 0, 0, 0);
+
+ connect(m_d->m_lineEdit, SIGNAL(validReturnPressed()), this, SIGNAL(returnPressed()));
+ connect(m_d->m_lineEdit, SIGNAL(textChanged(QString)), this, SIGNAL(changed()));
+ connect(m_d->m_lineEdit, SIGNAL(validChanged()), this, SIGNAL(validChanged()));
+
+ m_d->m_lineEdit->setMinimumWidth(300);
+ hLayout->addWidget(m_d->m_lineEdit);
+
+ QToolButton *browseButton = new QToolButton;
+ browseButton->setText(tr("..."));
+ connect(browseButton, SIGNAL(clicked()), this, SLOT(slotBrowse()));
+
+ hLayout->addWidget(browseButton);
+ setLayout(hLayout);
+ setFocusProxy(m_d->m_lineEdit);
+}
+
+PathChooser::~PathChooser()
+{
+ delete m_d;
+}
+
+QString PathChooser::path() const
+{
+ return m_d->m_lineEdit->text();
+}
+
+void PathChooser::setPath(const QString &path)
+{
+ const QString defaultPath = path.isEmpty() ? homePath() : path;
+ m_d->m_lineEdit->setText(QDir::toNativeSeparators(defaultPath));
+}
+
+void PathChooser::slotBrowse()
+{
+ QString predefined = path();
+ if (!predefined.isEmpty() && !QFileInfo(predefined).isDir())
+ predefined.clear();
+ // Prompt for a directory, delete trailing slashes unless it is "/", only
+ QString newPath = QFileDialog::getExistingDirectory(this, tr("Choose a path"), predefined);
+ if (!newPath .isEmpty()) {
+ if (newPath .size() > 1 && newPath .endsWith(QDir::separator()))
+ newPath .truncate(newPath .size() - 1);
+ setPath(newPath);
+ }
+}
+
+bool PathChooser::isValid() const
+{
+ return m_d->m_lineEdit->isValid();
+}
+
+QString PathChooser::errorMessage() const
+{
+ return m_d->m_lineEdit->errorMessage();
+}
+
+bool PathChooser::validatePath(const QString &path, QString *errorMessage)
+{
+ if (path.isEmpty()) {
+ if (errorMessage)
+ *errorMessage = tr("The path must not be empty.");
+ return false;
+ }
+ // Must be a directory?
+ const QFileInfo fi(path);
+ if (fi.isDir())
+ return true; // Happy!
+
+ if (!fi.exists()) {
+ if (errorMessage)
+ *errorMessage = tr("The path '%1' does not exist.").arg(path);
+ return false;
+ }
+ // Must be something weird
+ if (errorMessage)
+ *errorMessage = tr("The path '%1' is not a directory.").arg(path);
+ return false;
+}
+
+QString PathChooser::label()
+{
+ return tr("Path:");
+}
+
+QString PathChooser::homePath()
+{
+#ifdef Q_OS_WIN
+ // Return 'users/<name>/Documents' on Windows, since Windows explorer
+ // does not let people actually display the contents of their home
+ // directory. Alternatively, create a QtCreator-specific directory?
+ return QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
+#else
+ return QDir::homePath();
+#endif
+}
+
+}
+}
diff --git a/src/libs/utils/pathchooser.h b/src/libs/utils/pathchooser.h
new file mode 100644
index 0000000000..e09040c4c0
--- /dev/null
+++ b/src/libs/utils/pathchooser.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 PATHCHOOSER_H
+#define PATHCHOOSER_H
+
+#include "utils_global.h"
+
+#include <QtGui/QWidget>
+
+namespace Core {
+namespace Utils {
+
+struct PathChooserPrivate;
+
+/* A Control that let's the user choose a path, consisting of a QLineEdit and
+ * a "Browse" button. Has some validation logic for embedding into
+ * QWizardPage. */
+
+class QWORKBENCH_UTILS_EXPORT PathChooser : public QWidget
+{
+ Q_DISABLE_COPY(PathChooser)
+ Q_OBJECT
+ Q_PROPERTY(QString path READ path WRITE setPath DESIGNABLE true)
+
+public:
+ explicit PathChooser(QWidget *parent = 0);
+ virtual ~PathChooser();
+
+ bool isValid() const;
+ QString errorMessage() const;
+
+ QString path() const;
+
+ // Returns the suggested label title when used in a form layout
+ static QString label();
+
+ static bool validatePath(const QString &path, QString *errorMessage = 0);
+
+ // Return the home directory, which needs some fixing under Windows.
+ static QString homePath();
+
+signals:
+ void validChanged();
+ void changed();
+ void returnPressed();
+
+public slots:
+ void setPath(const QString &);
+
+private slots:
+ void slotBrowse();
+
+private:
+ PathChooserPrivate *m_d;
+};
+
+}
+}
+
+#endif // PATHCHOOSER_H
diff --git a/src/libs/utils/projectintropage.cpp b/src/libs/utils/projectintropage.cpp
new file mode 100644
index 0000000000..bc17333fb9
--- /dev/null
+++ b/src/libs/utils/projectintropage.cpp
@@ -0,0 +1,215 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "projectintropage.h"
+#include "filewizardpage.h"
+#include "ui_projectintropage.h"
+
+#include <QtGui/QMessageBox>
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+
+namespace Core {
+namespace Utils {
+
+struct ProjectIntroPagePrivate
+{
+ ProjectIntroPagePrivate();
+ Ui::ProjectIntroPage m_ui;
+ bool m_complete;
+ // Status label style sheets
+ const QString m_errorStyleSheet;
+ const QString m_warningStyleSheet;
+ const QString m_hintStyleSheet;
+};
+
+ProjectIntroPagePrivate:: ProjectIntroPagePrivate() :
+ m_complete(false),
+ m_errorStyleSheet(QLatin1String("background : red;")),
+ m_warningStyleSheet(QLatin1String("background : yellow;")),
+ m_hintStyleSheet()
+{
+}
+
+ProjectIntroPage::ProjectIntroPage(QWidget *parent) :
+ QWizardPage(parent),
+ m_d(new ProjectIntroPagePrivate)
+{
+ m_d->m_ui.setupUi(this);
+ hideStatusLabel();
+ m_d->m_ui.nameLineEdit->setInitialText(tr("<Enter_Name>"));
+ m_d->m_ui.nameLineEdit->setFocus(Qt::TabFocusReason);
+ connect(m_d->m_ui.pathChooser, SIGNAL(changed()), this, SLOT(slotChanged()));
+ connect(m_d->m_ui.nameLineEdit, SIGNAL(textChanged(QString)), this, SLOT(slotChanged()));
+ connect(m_d->m_ui.pathChooser, SIGNAL(returnPressed()), this, SLOT(slotActivated()));
+ connect(m_d->m_ui.nameLineEdit, SIGNAL(validReturnPressed()), this, SLOT(slotActivated()));
+}
+
+void ProjectIntroPage::insertControl(int row, QWidget *label, QWidget *control)
+{
+ m_d->m_ui.formLayout->insertRow(row, label, control);
+}
+
+ProjectIntroPage::~ProjectIntroPage()
+{
+ delete m_d;
+}
+
+QString ProjectIntroPage::name() const
+{
+ return m_d->m_ui.nameLineEdit->text();
+}
+
+QString ProjectIntroPage::path() const
+{
+ return m_d->m_ui.pathChooser->path();
+}
+
+void ProjectIntroPage::setPath(const QString &path)
+{
+ m_d->m_ui.pathChooser->setPath(path);
+}
+
+void ProjectIntroPage::setName(const QString &name)
+{
+ m_d->m_ui.nameLineEdit->setText(name);
+}
+
+QString ProjectIntroPage::description() const
+{
+ return m_d->m_ui.descriptionLabel->text();
+}
+
+void ProjectIntroPage::setDescription(const QString &description)
+{
+ m_d->m_ui.descriptionLabel->setText(description);
+}
+
+void ProjectIntroPage::changeEvent(QEvent *e)
+{
+ switch(e->type()) {
+ case QEvent::LanguageChange:
+ m_d->m_ui.retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+}
+
+bool ProjectIntroPage::isComplete() const
+{
+ return m_d->m_complete;
+}
+
+bool ProjectIntroPage::validate()
+{
+ // Validate and display status
+ if (!m_d->m_ui.pathChooser->isValid()) {
+ displayStatusMessage(Error, m_d->m_ui.pathChooser->errorMessage());
+ return false;
+ }
+
+ // Name valid? Ignore 'DisplayingInitialText' state.
+ bool nameValid = false;
+ switch (m_d->m_ui.nameLineEdit->state()) {
+ case BaseValidatingLineEdit::Invalid:
+ displayStatusMessage(Error, m_d->m_ui.nameLineEdit->errorMessage());
+ return false;
+ case BaseValidatingLineEdit::DisplayingInitialText:
+ break;
+ case BaseValidatingLineEdit::Valid:
+ nameValid = true;
+ break;
+ }
+
+ // Check existence of the directory
+ QString projectDir = path();
+ projectDir += QDir::separator();
+ projectDir += m_d->m_ui.nameLineEdit->text();
+ const QFileInfo projectDirFile(projectDir);
+ if (!projectDirFile.exists()) { // All happy
+ hideStatusLabel();
+ return nameValid;
+ }
+
+ if (projectDirFile.isDir()) {
+ displayStatusMessage(Warning, tr("The project already exists."));
+ return nameValid;;
+ }
+ // Not a directory, but something else, likely causing directory creation to fail
+ displayStatusMessage(Error, tr("A file with that name already exists."));
+ return false;
+}
+
+void ProjectIntroPage::slotChanged()
+{
+ const bool newComplete = validate();
+ if (newComplete != m_d->m_complete) {
+ m_d->m_complete = newComplete;
+ emit completeChanged();
+ }
+}
+
+void ProjectIntroPage::slotActivated()
+{
+ if (m_d->m_complete)
+ emit activated();
+}
+
+bool ProjectIntroPage::validateProjectDirectory(const QString &name, QString *errorMessage)
+{
+ return ProjectNameValidatingLineEdit::validateProjectName(name, errorMessage);
+}
+
+void ProjectIntroPage::displayStatusMessage(StatusLabelMode m, const QString &s)
+{
+ switch (m) {
+ case Error:
+ m_d->m_ui.stateLabel->setStyleSheet(m_d->m_errorStyleSheet);
+ break;
+ case Warning:
+ m_d->m_ui.stateLabel->setStyleSheet(m_d->m_warningStyleSheet);
+ break;
+ case Hint:
+ m_d->m_ui.stateLabel->setStyleSheet(m_d->m_hintStyleSheet);
+ break;
+ }
+ m_d->m_ui.stateLabel->setText(s);
+}
+
+void ProjectIntroPage::hideStatusLabel()
+{
+ displayStatusMessage(Hint, QString());
+}
+
+}
+}
diff --git a/src/libs/utils/projectintropage.h b/src/libs/utils/projectintropage.h
new file mode 100644
index 0000000000..56dcc25327
--- /dev/null
+++ b/src/libs/utils/projectintropage.h
@@ -0,0 +1,107 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 PROJECTINTROPAGE_H
+#define PROJECTINTROPAGE_H
+
+#include "utils_global.h"
+
+#include <QtGui/QWizardPage>
+
+namespace Core {
+namespace Utils {
+
+struct ProjectIntroPagePrivate;
+
+/* Standard wizard page for a single file letting the user choose name
+ * and path. Looks similar to FileWizardPage, but provides additional
+ * functionality:
+ * - Description label at the top for displaying introductory text
+ * - It does on the fly validation (connected to changed()) and displays
+ * warnings/errors in a status label at the bottom (the page is complete
+ * when fully validated, validatePage() is thus not implemented).
+ *
+ * Note: Careful when changing projectintropage.ui. It must have main
+ * geometry cleared and QLayout::SetMinimumSize constraint on the main
+ * layout, otherwise, QWizard will squeeze it due to its strange expanding
+ * hacks. */
+
+class QWORKBENCH_UTILS_EXPORT ProjectIntroPage : public QWizardPage {
+ Q_OBJECT
+ Q_DISABLE_COPY(ProjectIntroPage)
+ Q_PROPERTY(QString description READ description WRITE setPath DESIGNABLE true)
+ Q_PROPERTY(QString path READ path WRITE setPath DESIGNABLE true)
+ Q_PROPERTY(QString name READ name WRITE setName DESIGNABLE true)
+public:
+ explicit ProjectIntroPage(QWidget *parent = 0);
+ virtual ~ProjectIntroPage();
+
+ QString name() const;
+ QString path() const;
+ QString description() const;
+
+ // Insert an additional control into the form layout for the target.
+ void insertControl(int row, QWidget *label, QWidget *control);
+
+ virtual bool isComplete() const;
+
+ // Validate a project directory name entry field
+ static bool validateProjectDirectory(const QString &name, QString *errorMessage);
+
+signals:
+ void activated();
+
+public slots:
+ void setPath(const QString &path);
+ void setName(const QString &name);
+ void setDescription(const QString &description);
+
+private slots:
+ void slotChanged();
+ void slotActivated();
+
+protected:
+ virtual void changeEvent(QEvent *e);
+
+private:
+ enum StatusLabelMode { Error, Warning, Hint };
+
+ bool validate();
+ void displayStatusMessage(StatusLabelMode m, const QString &);
+ void hideStatusLabel();
+
+ ProjectIntroPagePrivate *m_d;
+};
+
+}
+}
+#endif // PROJECTINTROPAGE_H
diff --git a/src/libs/utils/projectintropage.ui b/src/libs/utils/projectintropage.ui
new file mode 100644
index 0000000000..f530b78044
--- /dev/null
+++ b/src/libs/utils/projectintropage.ui
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Core::Utils::ProjectIntroPage</class>
+ <widget class="QWizardPage" name="Core::Utils::ProjectIntroPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>208</width>
+ <height>143</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>WizardPage</string>
+ </property>
+ <property name="title">
+ <string>Introduction and project location</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetMinimumSize</enum>
+ </property>
+ <item>
+ <widget class="QLabel" name="descriptionLabel">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QFrame" name="frame">
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="nameLabel">
+ <property name="text">
+ <string>Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="Core::Utils::ProjectNameValidatingLineEdit" name="nameLineEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="pathLabel">
+ <property name="text">
+ <string>Path:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="Core::Utils::PathChooser" name="pathChooser" native="true"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QLabel" name="stateLabel">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>Core::Utils::PathChooser</class>
+ <extends>QWidget</extends>
+ <header>pathchooser.h</header>
+ <container>1</container>
+ </customwidget>
+ <customwidget>
+ <class>Core::Utils::ProjectNameValidatingLineEdit</class>
+ <extends>QLineEdit</extends>
+ <header>projectnamevalidatinglineedit.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/libs/utils/projectnamevalidatinglineedit.cpp b/src/libs/utils/projectnamevalidatinglineedit.cpp
new file mode 100644
index 0000000000..fb979d3934
--- /dev/null
+++ b/src/libs/utils/projectnamevalidatinglineedit.cpp
@@ -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 (qt-info@nokia.com)
+**
+**
+** 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 "projectnamevalidatinglineedit.h"
+#include "filenamevalidatinglineedit.h"
+
+namespace Core {
+namespace Utils {
+
+ProjectNameValidatingLineEdit::ProjectNameValidatingLineEdit(QWidget *parent) :
+ BaseValidatingLineEdit(parent)
+{
+}
+
+bool ProjectNameValidatingLineEdit::validateProjectName(const QString &name, QString *errorMessage /* = 0*/)
+{
+ // Validation is file name + checking for dots
+ if (!FileNameValidatingLineEdit::validateFileName(name, errorMessage))
+ return false;
+
+ // We don't want dots in the directory name for some legacy Windows
+ // reason. Since we are cross-platform, we generally disallow it.
+ if (name.contains(QLatin1Char('.'))) {
+ if (errorMessage)
+ *errorMessage = tr("The name must not contain the '.'-character.");
+ return false;
+ }
+ return true;
+}
+
+bool ProjectNameValidatingLineEdit::validate(const QString &value, QString *errorMessage) const
+{
+ return validateProjectName(value, errorMessage);
+}
+
+}
+}
diff --git a/src/libs/utils/projectnamevalidatinglineedit.h b/src/libs/utils/projectnamevalidatinglineedit.h
new file mode 100644
index 0000000000..c677cea141
--- /dev/null
+++ b/src/libs/utils/projectnamevalidatinglineedit.h
@@ -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 (qt-info@nokia.com)
+**
+**
+** 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 PROJECTNAMEVALIDATINGLINEEDIT_H
+#define PROJECTNAMEVALIDATINGLINEEDIT_H
+
+#include "basevalidatinglineedit.h"
+
+namespace Core {
+namespace Utils {
+
+class QWORKBENCH_UTILS_EXPORT ProjectNameValidatingLineEdit : public BaseValidatingLineEdit {
+ Q_OBJECT
+ Q_DISABLE_COPY(ProjectNameValidatingLineEdit)
+
+public:
+ explicit ProjectNameValidatingLineEdit(QWidget *parent = 0);
+
+ static bool validateProjectName(const QString &name, QString *errorMessage /* = 0*/);
+
+protected:
+ virtual bool validate(const QString &value, QString *errorMessage) const;
+};
+
+}
+}
+#endif // PROJECTNAMEVALIDATINGLINEEDIT_H
diff --git a/src/libs/utils/qtcolorbutton.cpp b/src/libs/utils/qtcolorbutton.cpp
new file mode 100644
index 0000000000..8b54bdda1d
--- /dev/null
+++ b/src/libs/utils/qtcolorbutton.cpp
@@ -0,0 +1,290 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "qtcolorbutton.h"
+#include <QtGui/QColorDialog>
+#include <QtGui/QPainter>
+#include <QtCore/QMimeData>
+#include <QtGui/QDragEnterEvent>
+#include <QtGui/QApplication>
+
+namespace Core {
+namespace Utils {
+
+class QtColorButtonPrivate
+{
+ QtColorButton *q_ptr;
+ Q_DECLARE_PUBLIC(QtColorButton)
+public:
+ QColor m_color;
+#ifndef QT_NO_DRAGANDDROP
+ QColor m_dragColor;
+ QPoint m_dragStart;
+ bool m_dragging;
+#endif
+ bool m_backgroundCheckered;
+ bool m_alphaAllowed;
+
+ void slotEditColor();
+ QColor shownColor() const;
+ QPixmap generatePixmap() const;
+};
+
+void QtColorButtonPrivate::slotEditColor()
+{
+ QColor newColor;
+ if (m_alphaAllowed) {
+ bool ok;
+ const QRgb rgba = QColorDialog::getRgba(m_color.rgba(), &ok, q_ptr);
+ if (!ok)
+ return;
+ newColor = QColor::fromRgba(rgba);
+ } else {
+ newColor = QColorDialog::getColor(m_color, q_ptr);
+ if (!newColor.isValid())
+ return;
+ }
+ if (newColor == q_ptr->color())
+ return;
+ q_ptr->setColor(newColor);
+ emit q_ptr->colorChanged(m_color);
+}
+
+QColor QtColorButtonPrivate::shownColor() const
+{
+#ifndef QT_NO_DRAGANDDROP
+ if (m_dragging)
+ return m_dragColor;
+#endif
+ return m_color;
+}
+
+QPixmap QtColorButtonPrivate::generatePixmap() const
+{
+ QPixmap pix(24, 24);
+
+ int pixSize = 20;
+ QBrush br(shownColor());
+
+ QPixmap pm(2 * pixSize, 2 * pixSize);
+ QPainter pmp(&pm);
+ pmp.fillRect(0, 0, pixSize, pixSize, Qt::lightGray);
+ pmp.fillRect(pixSize, pixSize, pixSize, pixSize, Qt::lightGray);
+ pmp.fillRect(0, pixSize, pixSize, pixSize, Qt::darkGray);
+ pmp.fillRect(pixSize, 0, pixSize, pixSize, Qt::darkGray);
+ pmp.fillRect(0, 0, 2 * pixSize, 2 * pixSize, shownColor());
+ br = QBrush(pm);
+
+ QPainter p(&pix);
+ int corr = 1;
+ QRect r = pix.rect().adjusted(corr, corr, -corr, -corr);
+ p.setBrushOrigin((r.width() % pixSize + pixSize) / 2 + corr, (r.height() % pixSize + pixSize) / 2 + corr);
+ p.fillRect(r, br);
+
+ p.fillRect(r.width() / 4 + corr, r.height() / 4 + corr,
+ r.width() / 2, r.height() / 2,
+ QColor(shownColor().rgb()));
+ p.drawRect(pix.rect().adjusted(0, 0, -1, -1));
+
+ return pix;
+}
+
+///////////////
+
+QtColorButton::QtColorButton(QWidget *parent)
+ : QToolButton(parent)
+{
+ d_ptr = new QtColorButtonPrivate;
+ d_ptr->q_ptr = this;
+ d_ptr->m_dragging = false;
+ d_ptr->m_backgroundCheckered = true;
+ d_ptr->m_alphaAllowed = true;
+
+ setAcceptDrops(true);
+
+ connect(this, SIGNAL(clicked()), this, SLOT(slotEditColor()));
+ setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred));
+}
+
+QtColorButton::~QtColorButton()
+{
+ delete d_ptr;
+}
+
+void QtColorButton::setColor(const QColor &color)
+{
+ if (d_ptr->m_color == color)
+ return;
+ d_ptr->m_color = color;
+ update();
+}
+
+QColor QtColorButton::color() const
+{
+ return d_ptr->m_color;
+}
+
+void QtColorButton::setBackgroundCheckered(bool checkered)
+{
+ if (d_ptr->m_backgroundCheckered == checkered)
+ return;
+ d_ptr->m_backgroundCheckered = checkered;
+ update();
+}
+
+bool QtColorButton::isBackgroundCheckered() const
+{
+ return d_ptr->m_backgroundCheckered;
+}
+
+void QtColorButton::setAlphaAllowed(bool allowed)
+{
+ d_ptr->m_alphaAllowed = allowed;
+}
+
+bool QtColorButton::isAlphaAllowed() const
+{
+ return d_ptr->m_alphaAllowed;
+}
+
+void QtColorButton::paintEvent(QPaintEvent *event)
+{
+ QToolButton::paintEvent(event);
+ if (!isEnabled())
+ return;
+
+ const int pixSize = 10;
+ QBrush br(d_ptr->shownColor());
+ if (d_ptr->m_backgroundCheckered) {
+ QPixmap pm(2 * pixSize, 2 * pixSize);
+ QPainter pmp(&pm);
+ pmp.fillRect(0, 0, pixSize, pixSize, Qt::white);
+ pmp.fillRect(pixSize, pixSize, pixSize, pixSize, Qt::white);
+ pmp.fillRect(0, pixSize, pixSize, pixSize, Qt::black);
+ pmp.fillRect(pixSize, 0, pixSize, pixSize, Qt::black);
+ pmp.fillRect(0, 0, 2 * pixSize, 2 * pixSize, d_ptr->shownColor());
+ br = QBrush(pm);
+ }
+
+ QPainter p(this);
+ const int corr = 5;
+ QRect r = rect().adjusted(corr, corr, -corr, -corr);
+ p.setBrushOrigin((r.width() % pixSize + pixSize) / 2 + corr, (r.height() % pixSize + pixSize) / 2 + corr);
+ p.fillRect(r, br);
+
+ //const int adjX = qRound(r.width() / 4.0);
+ //const int adjY = qRound(r.height() / 4.0);
+ //p.fillRect(r.adjusted(adjX, adjY, -adjX, -adjY),
+ // QColor(d_ptr->shownColor().rgb()));
+ /*
+ p.fillRect(r.adjusted(0, r.height() * 3 / 4, 0, 0),
+ QColor(d_ptr->shownColor().rgb()));
+ p.fillRect(r.adjusted(0, 0, 0, -r.height() * 3 / 4),
+ QColor(d_ptr->shownColor().rgb()));
+ */
+ /*
+ const QColor frameColor0(0, 0, 0, qRound(0.2 * (0xFF - d_ptr->shownColor().alpha())));
+ p.setPen(frameColor0);
+ p.drawRect(r.adjusted(adjX, adjY, -adjX - 1, -adjY - 1));
+ */
+
+ const QColor frameColor1(0, 0, 0, 26);
+ p.setPen(frameColor1);
+ p.drawRect(r.adjusted(1, 1, -2, -2));
+ const QColor frameColor2(0, 0, 0, 51);
+ p.setPen(frameColor2);
+ p.drawRect(r.adjusted(0, 0, -1, -1));
+}
+
+void QtColorButton::mousePressEvent(QMouseEvent *event)
+{
+#ifndef QT_NO_DRAGANDDROP
+ if (event->button() == Qt::LeftButton)
+ d_ptr->m_dragStart = event->pos();
+#endif
+ QToolButton::mousePressEvent(event);
+}
+
+void QtColorButton::mouseMoveEvent(QMouseEvent *event)
+{
+#ifndef QT_NO_DRAGANDDROP
+ if (event->buttons() & Qt::LeftButton &&
+ (d_ptr->m_dragStart - event->pos()).manhattanLength() > QApplication::startDragDistance()) {
+ QMimeData *mime = new QMimeData;
+ mime->setColorData(color());
+ QDrag *drg = new QDrag(this);
+ drg->setMimeData(mime);
+ drg->setPixmap(d_ptr->generatePixmap());
+ setDown(false);
+ event->accept();
+ drg->start();
+ return;
+ }
+#endif
+ QToolButton::mouseMoveEvent(event);
+}
+
+#ifndef QT_NO_DRAGANDDROP
+void QtColorButton::dragEnterEvent(QDragEnterEvent *event)
+{
+ const QMimeData *mime = event->mimeData();
+ if (!mime->hasColor())
+ return;
+
+ event->accept();
+ d_ptr->m_dragColor = qvariant_cast<QColor>(mime->colorData());
+ d_ptr->m_dragging = true;
+ update();
+}
+
+void QtColorButton::dragLeaveEvent(QDragLeaveEvent *event)
+{
+ event->accept();
+ d_ptr->m_dragging = false;
+ update();
+}
+
+void QtColorButton::dropEvent(QDropEvent *event)
+{
+ event->accept();
+ d_ptr->m_dragging = false;
+ if (d_ptr->m_dragColor == color())
+ return;
+ setColor(d_ptr->m_dragColor);
+ emit colorChanged(color());
+}
+#endif
+
+} // namespace Utils
+} // namespace Core
+
+#include "moc_qtcolorbutton.cpp"
diff --git a/src/libs/utils/qtcolorbutton.h b/src/libs/utils/qtcolorbutton.h
new file mode 100644
index 0000000000..07355c883e
--- /dev/null
+++ b/src/libs/utils/qtcolorbutton.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 QTCOLORBUTTON_H
+#define QTCOLORBUTTON_H
+
+#include "utils_global.h"
+
+#include <QtGui/QToolButton>
+
+namespace Core {
+namespace Utils {
+
+class QWORKBENCH_UTILS_EXPORT QtColorButton : public QToolButton
+{
+ Q_OBJECT
+ Q_PROPERTY(bool backgroundCheckered READ isBackgroundCheckered WRITE setBackgroundCheckered)
+ Q_PROPERTY(bool alphaAllowed READ isAlphaAllowed WRITE setAlphaAllowed)
+public:
+ QtColorButton(QWidget *parent = 0);
+ ~QtColorButton();
+
+ bool isBackgroundCheckered() const;
+ void setBackgroundCheckered(bool checkered);
+
+ bool isAlphaAllowed() const;
+ void setAlphaAllowed(bool allowed);
+
+ QColor color() const;
+
+public slots:
+ void setColor(const QColor &color);
+
+signals:
+ void colorChanged(const QColor &color);
+protected:
+ void paintEvent(QPaintEvent *event);
+ void mousePressEvent(QMouseEvent *event);
+ void mouseMoveEvent(QMouseEvent *event);
+#ifndef QT_NO_DRAGANDDROP
+ void dragEnterEvent(QDragEnterEvent *event);
+ void dragLeaveEvent(QDragLeaveEvent *event);
+ void dropEvent(QDropEvent *event);
+#endif
+private:
+ class QtColorButtonPrivate *d_ptr;
+ friend class QtColorButtonPrivate;
+ Q_DISABLE_COPY(QtColorButton)
+ Q_PRIVATE_SLOT(d_ptr, void slotEditColor())
+};
+
+} // namespace Utils
+} // namespace Core
+
+#endif // QTCOLORBUTTON_H
diff --git a/src/libs/utils/reloadpromptutils.cpp b/src/libs/utils/reloadpromptutils.cpp
new file mode 100644
index 0000000000..ca1d9e23de
--- /dev/null
+++ b/src/libs/utils/reloadpromptutils.cpp
@@ -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 (qt-info@nokia.com)
+**
+**
+** 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 "reloadpromptutils.h"
+#include <QtGui/QMessageBox>
+
+using namespace Core;
+using namespace Core::Utils;
+
+QWORKBENCH_UTILS_EXPORT Core::Utils::ReloadPromptAnswer
+ Core::Utils::reloadPrompt(const QString &fileName, QWidget *parent)
+{
+ return reloadPrompt(QObject::tr("File Changed"),
+ QObject::tr("The file %1 has changed outside Qt Creator. Do you want to reload it?").arg(fileName),
+ parent);
+}
+
+QWORKBENCH_UTILS_EXPORT Core::Utils::ReloadPromptAnswer
+ Core::Utils::reloadPrompt(const QString &title, const QString &prompt, QWidget *parent)
+{
+ switch (QMessageBox::question(parent, title, prompt, QMessageBox::Yes|QMessageBox::YesToAll|QMessageBox::No|QMessageBox::NoToAll,
+ QMessageBox::YesToAll)) {
+ case QMessageBox::Yes:
+ return ReloadCurrent;
+ case QMessageBox::YesToAll:
+ return ReloadAll;
+ case QMessageBox::No:
+ return ReloadSkipCurrent;
+ default:
+ break;
+ }
+ return ReloadNone;
+}
diff --git a/src/libs/utils/reloadpromptutils.h b/src/libs/utils/reloadpromptutils.h
new file mode 100644
index 0000000000..deaf4b920a
--- /dev/null
+++ b/src/libs/utils/reloadpromptutils.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 RELOADPROMPTUTILS_H
+#define RELOADPROMPTUTILS_H
+
+#include "utils_global.h"
+
+QT_BEGIN_NAMESPACE
+class QString;
+class QWidget;
+QT_END_NAMESPACE
+
+namespace Core {
+namespace Utils {
+
+enum ReloadPromptAnswer { ReloadCurrent, ReloadAll, ReloadSkipCurrent, ReloadNone };
+
+QWORKBENCH_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const QString &fileName, QWidget *parent);
+QWORKBENCH_UTILS_EXPORT ReloadPromptAnswer reloadPrompt(const QString &title, const QString &prompt, QWidget *parent);
+
+} // namespace Utils
+} // namespace Core
+
+#endif // RELOADPROMPTUTILS_H
diff --git a/src/libs/utils/settingsutils.cpp b/src/libs/utils/settingsutils.cpp
new file mode 100644
index 0000000000..ca8de01828
--- /dev/null
+++ b/src/libs/utils/settingsutils.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 (qt-info@nokia.com)
+**
+**
+** 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 "settingsutils.h"
+#include <QtCore/QString>
+
+namespace Core {
+namespace Utils {
+
+QWORKBENCH_UTILS_EXPORT QString settingsKey(const QString &category)
+{
+ QString rc(category);
+ const QChar underscore = QLatin1Char('_');
+ const int size = rc.size();
+ for (int i = 0; i < size;i++) {
+ const QChar c = rc.at(i);
+ if (!c.isLetterOrNumber() && c != underscore)
+ rc[i] = underscore;
+ }
+ return rc;
+}
+
+}
+}
diff --git a/src/libs/utils/settingsutils.h b/src/libs/utils/settingsutils.h
new file mode 100644
index 0000000000..734a2f02f9
--- /dev/null
+++ b/src/libs/utils/settingsutils.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 SETTINGSTUTILS_H
+#define SETTINGSTUTILS_H
+
+#include "utils_global.h"
+
+namespace Core {
+namespace Utils {
+
+// Create a usable settings key from a category,
+// for example Editor|C++ -> Editor_C__
+QWORKBENCH_UTILS_EXPORT QString settingsKey(const QString &category);
+
+} // namespace Utils
+} // namespace Core
+
+#endif // SETTINGSTUTILS_H
diff --git a/src/libs/utils/submiteditorwidget.cpp b/src/libs/utils/submiteditorwidget.cpp
new file mode 100644
index 0000000000..aeafcd828d
--- /dev/null
+++ b/src/libs/utils/submiteditorwidget.cpp
@@ -0,0 +1,305 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "submiteditorwidget.h"
+#include "ui_submiteditorwidget.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QPointer>
+
+enum { debug= 0 };
+
+namespace Core {
+namespace Utils {
+
+struct SubmitEditorWidgetPrivate {
+ SubmitEditorWidgetPrivate();
+
+ Ui::SubmitEditorWidget m_ui;
+ bool m_filesSelected;
+ bool m_filesChecked;
+};
+
+SubmitEditorWidgetPrivate::SubmitEditorWidgetPrivate() :
+ m_filesSelected(false),
+ m_filesChecked(false)
+{
+}
+
+SubmitEditorWidget::SubmitEditorWidget(QWidget *parent) :
+ QWidget(parent),
+ m_d(new SubmitEditorWidgetPrivate)
+{
+ m_d->m_ui.setupUi(this);
+ // File List
+ m_d->m_ui.fileList->setSelectionMode(QAbstractItemView::ExtendedSelection);
+ connect(m_d->m_ui.fileList, SIGNAL(itemActivated(QListWidgetItem*)), this, SLOT(triggerDiffSelected()));
+ connect(m_d->m_ui.fileList, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(fileItemChanged(QListWidgetItem*)));
+ connect(m_d->m_ui.fileList, SIGNAL(itemSelectionChanged()), this, SLOT(fileSelectionChanged()));
+
+ // Text
+ m_d->m_ui.description->setFont(QFont(QLatin1String("Courier")));
+
+ setFocusPolicy(Qt::StrongFocus);
+ setFocusProxy(m_d->m_ui.description);
+}
+
+SubmitEditorWidget::~SubmitEditorWidget()
+{
+ delete m_d;
+}
+
+void SubmitEditorWidget::registerActions(QAction *editorUndoAction, QAction *editorRedoAction,
+ QAction *submitAction, QAction *diffAction)
+{
+ if (editorUndoAction) {
+ editorUndoAction->setEnabled(m_d->m_ui.description->document()->isUndoAvailable());
+ connect(m_d->m_ui.description, SIGNAL(undoAvailable(bool)), editorUndoAction, SLOT(setEnabled(bool)));
+ connect(editorUndoAction, SIGNAL(triggered()), m_d->m_ui.description, SLOT(undo()));
+ }
+ if (editorRedoAction) {
+ editorRedoAction->setEnabled(m_d->m_ui.description->document()->isRedoAvailable());
+ connect(m_d->m_ui.description, SIGNAL(redoAvailable(bool)), editorRedoAction, SLOT(setEnabled(bool)));
+ connect(editorRedoAction, SIGNAL(triggered()), m_d->m_ui.description, SLOT(redo()));
+ }
+
+ if (submitAction) {
+ if (debug)
+ qDebug() << submitAction << m_d->m_ui.fileList->count() << "items" << m_d->m_filesChecked;
+ submitAction->setEnabled(m_d->m_filesChecked);
+ connect(this, SIGNAL(fileCheckStateChanged(bool)), submitAction, SLOT(setEnabled(bool)));
+ }
+ if (diffAction) {
+ if (debug)
+ qDebug() << diffAction << m_d->m_filesSelected;
+ diffAction->setEnabled(m_d->m_filesSelected);
+ connect(this, SIGNAL(fileSelectionChanged(bool)), diffAction, SLOT(setEnabled(bool)));
+ connect(diffAction, SIGNAL(triggered()), this, SLOT(triggerDiffSelected()));
+ }
+}
+
+void SubmitEditorWidget::unregisterActions(QAction *editorUndoAction, QAction *editorRedoAction,
+ QAction *submitAction, QAction *diffAction)
+{
+ if (editorUndoAction) {
+ disconnect(m_d->m_ui.description, SIGNAL(undoAvailableChanged(bool)), editorUndoAction, SLOT(setEnabled(bool)));
+ disconnect(editorUndoAction, SIGNAL(triggered()), m_d->m_ui.description, SLOT(undo()));
+ }
+ if (editorRedoAction) {
+ disconnect(m_d->m_ui.description, SIGNAL(redoAvailableChanged(bool)), editorRedoAction, SLOT(setEnabled(bool)));
+ disconnect(editorRedoAction, SIGNAL(triggered()), m_d->m_ui.description, SLOT(redo()));
+ }
+
+ if (submitAction)
+ disconnect(this, SIGNAL(fileCheckStateChanged(bool)), submitAction, SLOT(setEnabled(bool)));
+
+ if (diffAction) {
+ disconnect(this, SIGNAL(fileSelectionChanged(bool)), diffAction, SLOT(setEnabled(bool)));
+ disconnect(diffAction, SIGNAL(triggered()), this, SLOT(triggerDiffSelected()));
+ }
+}
+
+
+QString SubmitEditorWidget::trimmedDescriptionText() const
+{
+ // Make sure we have one terminating NL
+ QString text = descriptionText().trimmed();
+ text += QLatin1Char('\n');
+ return text;
+}
+
+QString SubmitEditorWidget::descriptionText() const
+{
+ return m_d->m_ui.description->toPlainText();
+}
+
+void SubmitEditorWidget::setDescriptionText(const QString &text)
+{
+ m_d->m_ui.description->setPlainText(text);
+}
+
+QStringList SubmitEditorWidget::fileList() const
+{
+ QStringList rc;
+ const int count = m_d->m_ui.fileList->count();
+ for (int i = 0; i < count; i++)
+ rc.push_back(m_d->m_ui.fileList->item(i)->text());
+ return rc;
+}
+
+void SubmitEditorWidget::addFilesUnblocked(const QStringList &list, bool checked, bool userCheckable)
+{
+ if (debug)
+ qDebug() << Q_FUNC_INFO << list << checked << userCheckable;
+ foreach (const QString &f, list) {
+ QListWidgetItem *item = new QListWidgetItem(f);
+ item->setCheckState(checked ? Qt::Checked : Qt::Unchecked);
+ if (!userCheckable)
+ item->setFlags(item->flags() & ~Qt::ItemIsUserCheckable);
+ m_d->m_ui.fileList->addItem(item);
+ }
+}
+
+void SubmitEditorWidget::addFiles(const QStringList &list, bool checked, bool userCheckable)
+{
+ if (list.empty())
+ return;
+
+ const bool blocked = m_d->m_ui.fileList->blockSignals(true);
+ addFilesUnblocked(list, checked, userCheckable);
+ m_d->m_ui.fileList->blockSignals(blocked);
+ // Did we gain any checked files..update action accordingly
+ if (!m_d->m_filesChecked && checked) {
+ m_d->m_filesChecked = true;
+ emit fileCheckStateChanged(m_d->m_filesChecked);
+ }
+}
+
+void SubmitEditorWidget::setFileList(const QStringList &list)
+{
+ // Trigger enabling of menu action
+ m_d->m_ui.fileList->clearSelection();
+
+ const bool blocked = m_d->m_ui.fileList->blockSignals(true);
+ m_d->m_ui.fileList->clear();
+ if (!list.empty()) {
+ addFilesUnblocked(list, true, true);
+ // Checked files added?
+ if (!m_d->m_filesChecked) {
+ m_d->m_filesChecked = true;
+ emit fileCheckStateChanged(m_d->m_filesChecked);
+ }
+ }
+ m_d->m_ui.fileList->blockSignals(blocked);
+}
+
+static bool containsCheckState(const QListWidget *lw, Qt::CheckState cs)
+{
+ const int count = lw->count();
+ for (int i = 0; i < count; i++)
+ if (lw->item(i)->checkState() == cs)
+ return true;
+ return false;
+}
+
+QStringList SubmitEditorWidget::selectedFiles() const
+{
+ QStringList rc;
+ const int count = m_d->m_ui.fileList->count();
+ for (int i = 0; i < count; i++) {
+ const QListWidgetItem *item = m_d->m_ui.fileList->item(i);
+ if (item->isSelected())
+ rc.push_back(item->text());
+ }
+ return rc;
+}
+
+QStringList SubmitEditorWidget::checkedFiles() const
+{
+ QStringList rc;
+ const int count = m_d->m_ui.fileList->count();
+ for (int i = 0; i < count; i++) {
+ const QListWidgetItem *item = m_d->m_ui.fileList->item(i);
+ if (item->checkState() == Qt::Checked)
+ rc.push_back(item->text());
+ }
+ return rc;
+}
+
+QPlainTextEdit *SubmitEditorWidget::descriptionEdit() const
+{
+ return m_d->m_ui.description;
+}
+
+void SubmitEditorWidget::triggerDiffSelected()
+{
+ const QStringList sel = selectedFiles();
+ if (!sel.empty())
+ emit diffSelected(sel);
+}
+
+void SubmitEditorWidget::fileItemChanged(QListWidgetItem *item)
+{
+ const Qt::CheckState st = item->checkState();
+ if (debug)
+ qDebug() << Q_FUNC_INFO << st << item->text() << m_d->m_filesChecked;
+ // Enable the actions according to check state
+ switch (st) {
+ case Qt::Unchecked: // Item was unchecked: Any checked items left?
+ if (m_d->m_filesChecked && !containsCheckState(m_d->m_ui.fileList, Qt::Checked)) {
+ m_d->m_filesChecked = false;
+ emit fileCheckStateChanged(m_d->m_filesChecked);
+ }
+ break;
+ case Qt::Checked:
+ // Item was Checked. First one?
+ if (!m_d->m_filesChecked) {
+ m_d->m_filesChecked = true;
+ emit fileCheckStateChanged(m_d->m_filesChecked);
+ }
+ break;
+ case Qt::PartiallyChecked: // Errm?
+ break;
+ }
+}
+
+void SubmitEditorWidget::fileSelectionChanged()
+{
+ const bool newFilesSelected = !m_d->m_ui.fileList->selectedItems().empty();
+ if (debug)
+ qDebug() << Q_FUNC_INFO << newFilesSelected;
+ if (m_d->m_filesSelected != newFilesSelected) {
+ m_d->m_filesSelected = newFilesSelected;
+ emit fileSelectionChanged(m_d->m_filesSelected);
+ if (debug)
+ qDebug() << Q_FUNC_INFO << m_d->m_filesSelected;
+ }
+}
+
+void SubmitEditorWidget::changeEvent(QEvent *e)
+{
+ switch(e->type()) {
+ case QEvent::LanguageChange:
+ m_d->m_ui.retranslateUi(this);
+ break;
+ default:
+ break;
+ }
+}
+
+void SubmitEditorWidget::insertTopWidget(QWidget *w)
+{
+ m_d->m_ui.vboxLayout->insertWidget(0, w);
+}
+
+} // namespace Utils
+} // namespace Core
diff --git a/src/libs/utils/submiteditorwidget.h b/src/libs/utils/submiteditorwidget.h
new file mode 100644
index 0000000000..3c40ccecba
--- /dev/null
+++ b/src/libs/utils/submiteditorwidget.h
@@ -0,0 +1,122 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 SUBMITEDITORWIDGET_H
+#define SUBMITEDITORWIDGET_H
+
+#include "utils_global.h"
+
+#include <QtGui/QWidget>
+
+QT_BEGIN_NAMESPACE
+class QPlainTextEdit;
+class QListWidgetItem;
+class QAction;
+QT_END_NAMESPACE
+
+namespace Core {
+namespace Utils {
+
+struct SubmitEditorWidgetPrivate;
+
+/* The submit editor presents the commit message in a text editor and an
+ * checkable list of modified files in a list window. The user can delete
+ * files from the list by pressing unchecking them or diff the selection
+ * by doubleclicking.
+ *
+ * Additionally, standard creator actions can be registered:
+ * Undo/redo will be set up to work with the description editor.
+ * Submit will be set up to be enabled according to checkstate.
+ * Diff will be set up to trigger diffSelected().
+ *
+ * Note that the actions are connected by signals; in the rare event that there
+ * are several instances of the SubmitEditorWidget belonging to the same
+ * context active, the actions must be registered/unregistered in the editor
+ * change event.
+ * Care should be taken to ensure the widget is deleted properly when the
+ * editor closes. */
+
+class QWORKBENCH_UTILS_EXPORT SubmitEditorWidget : public QWidget {
+ Q_OBJECT
+ Q_DISABLE_COPY(SubmitEditorWidget)
+ Q_PROPERTY(QString descriptionText READ descriptionText WRITE setDescriptionText DESIGNABLE true)
+ Q_PROPERTY(QStringList fileList READ fileList WRITE setFileList DESIGNABLE true)
+public:
+ explicit SubmitEditorWidget(QWidget *parent = 0);
+ virtual ~SubmitEditorWidget();
+
+ void registerActions(QAction *editorUndoAction, QAction *editorRedoAction,
+ QAction *submitAction = 0, QAction *diffAction = 0);
+ void unregisterActions(QAction *editorUndoAction, QAction *editorRedoAction,
+ QAction *submitAction = 0, QAction *diffAction = 0);
+
+ QString descriptionText() const;
+ void setDescriptionText(const QString &text);
+ // Should be used to normalize newlines.
+ QString trimmedDescriptionText() const;
+
+ // The raw file list
+ QStringList fileList() const;
+ void addFiles(const QStringList&, bool checked = true, bool userCheckable = true);
+ void setFileList(const QStringList&);
+
+ // Files to be included in submit
+ QStringList checkedFiles() const;
+
+ // Selected files for diff
+ QStringList selectedFiles() const;
+
+ QPlainTextEdit *descriptionEdit() const;
+
+signals:
+ void diffSelected(const QStringList &);
+ void fileSelectionChanged(bool someFileSelected);
+ void fileCheckStateChanged(bool someFileChecked);
+
+protected:
+ virtual void changeEvent(QEvent *e);
+ void insertTopWidget(QWidget *w);
+
+private slots:
+ void triggerDiffSelected();
+ void fileItemChanged(QListWidgetItem *);
+ void fileSelectionChanged();
+
+private:
+ void addFilesUnblocked(const QStringList &list, bool checked, bool userCheckable);
+
+ SubmitEditorWidgetPrivate *m_d;
+};
+
+}
+}
+#endif // SUBMITEDITORWIDGET_H
diff --git a/src/libs/utils/submiteditorwidget.ui b/src/libs/utils/submiteditorwidget.ui
new file mode 100644
index 0000000000..1a30e8b791
--- /dev/null
+++ b/src/libs/utils/submiteditorwidget.ui
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Core::Utils::SubmitEditorWidget</class>
+ <widget class="QWidget" name="Core::Utils::SubmitEditorWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>582</width>
+ <height>502</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Subversion Submit</string>
+ </property>
+ <layout class="QVBoxLayout">
+ <item>
+ <widget class="QGroupBox" name="descriptionBox">
+ <property name="title">
+ <string>Des&amp;cription</string>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ <layout class="QGridLayout">
+ <item row="0" column="0">
+ <widget class="QPlainTextEdit" name="description">
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>F&amp;iles</string>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ <layout class="QGridLayout">
+ <item row="0" column="0">
+ <widget class="QListWidget" name="fileList">
+ <property name="font">
+ <font/>
+ </property>
+ <property name="textElideMode">
+ <enum>Qt::ElideNone</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/libs/utils/synchronousprocess.cpp b/src/libs/utils/synchronousprocess.cpp
new file mode 100644
index 0000000000..71bcdffb6c
--- /dev/null
+++ b/src/libs/utils/synchronousprocess.cpp
@@ -0,0 +1,356 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 "synchronousprocess.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QTimer>
+#include <QtCore/QEventLoop>
+#include <QtCore/QTextCodec>
+
+#include <QtGui/QApplication>
+
+enum { debug = 0 };
+
+enum { defaultMaxHangTimerCount = 10 };
+
+namespace Core {
+namespace Utils {
+
+// ----------- SynchronousProcessResponse
+SynchronousProcessResponse::SynchronousProcessResponse() :
+ result(StartFailed),
+ exitCode(-1)
+{
+}
+
+void SynchronousProcessResponse::clear()
+{
+ result = StartFailed;
+ exitCode = -1;
+ stdOut.clear();
+ stdErr.clear();
+}
+
+QWORKBENCH_UTILS_EXPORT QDebug operator<<(QDebug str, const SynchronousProcessResponse& r)
+{
+ QDebug nsp = str.nospace();
+ nsp << "SynchronousProcessResponse: result=" << r.result << " ex=" << r.exitCode << '\n'
+ << r.stdOut.size() << " bytes stdout, stderr=" << r.stdErr << '\n';
+ return str;
+}
+
+// Data for one channel buffer (stderr/stdout)
+struct ChannelBuffer {
+ ChannelBuffer();
+ void clearForRun();
+ QByteArray linesRead();
+
+ QByteArray data;
+ bool firstData;
+ bool bufferedSignalsEnabled;
+ bool firstBuffer;
+ int bufferPos;
+};
+
+ChannelBuffer::ChannelBuffer() :
+ firstData(true),
+ bufferedSignalsEnabled(false),
+ firstBuffer(true),
+ bufferPos(0)
+{
+}
+
+void ChannelBuffer::clearForRun()
+{
+ firstData = true;
+ firstBuffer = true;
+ bufferPos = 0;
+}
+
+/* Check for complete lines read from the device and return them, moving the
+ * buffer position. This is based on the assumption that '\n' is the new line
+ * marker in any sane codec. */
+QByteArray ChannelBuffer::linesRead()
+{
+ // Any new lines?
+ const int lastLineIndex = data.lastIndexOf('\n');
+ if (lastLineIndex == -1 || lastLineIndex <= bufferPos)
+ return QByteArray();
+ const int nextBufferPos = lastLineIndex + 1;
+ const QByteArray lines = data.mid(bufferPos, nextBufferPos - bufferPos);
+ bufferPos = nextBufferPos;
+ return lines;
+}
+
+// ----------- SynchronousProcessPrivate
+struct SynchronousProcessPrivate {
+ SynchronousProcessPrivate();
+ void clearForRun();
+
+ QTextCodec *m_stdOutCodec;
+ QProcess m_process;
+ QTimer m_timer;
+ QEventLoop m_eventLoop;
+ SynchronousProcessResponse m_result;
+ int m_hangTimerCount;
+ int m_maxHangTimerCount;
+
+ ChannelBuffer m_stdOut;
+ ChannelBuffer m_stdErr;
+};
+
+SynchronousProcessPrivate::SynchronousProcessPrivate() :
+ m_stdOutCodec(0),
+ m_hangTimerCount(0),
+ m_maxHangTimerCount(defaultMaxHangTimerCount)
+{
+}
+
+void SynchronousProcessPrivate::clearForRun()
+{
+ m_hangTimerCount = 0;
+ m_stdOut.clearForRun();
+ m_stdErr.clearForRun();
+ m_result.clear();
+}
+
+// ----------- SynchronousProcess
+SynchronousProcess::SynchronousProcess() :
+ m_d(new SynchronousProcessPrivate)
+{
+ m_d->m_timer.setInterval(1000);
+ connect(&m_d->m_timer, SIGNAL(timeout()), this, SLOT(slotTimeout()));
+ connect(&m_d->m_process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(finished(int,QProcess::ExitStatus)));
+ connect(&m_d->m_process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(error(QProcess::ProcessError)));
+ connect(&m_d->m_process, SIGNAL(readyReadStandardOutput()),
+ this, SLOT(stdOutReady()));
+ connect(&m_d->m_process, SIGNAL(readyReadStandardError()),
+ this, SLOT(stdErrReady()));
+}
+
+SynchronousProcess::~SynchronousProcess()
+{
+ delete m_d;
+}
+
+void SynchronousProcess::setTimeout(int timeoutMS)
+{
+ m_d->m_maxHangTimerCount = qMax(2, timeoutMS / 1000);
+}
+
+int SynchronousProcess::timeout() const
+{
+ return 1000 * m_d->m_maxHangTimerCount;
+}
+
+void SynchronousProcess::setStdOutCodec(QTextCodec *c)
+{
+ m_d->m_stdOutCodec = c;
+}
+
+QTextCodec *SynchronousProcess::stdOutCodec() const
+{
+ return m_d->m_stdOutCodec;
+}
+
+bool SynchronousProcess::stdOutBufferedSignalsEnabled() const
+{
+ return m_d->m_stdOut.bufferedSignalsEnabled;
+}
+
+void SynchronousProcess::setStdOutBufferedSignalsEnabled(bool v)
+{
+ m_d->m_stdOut.bufferedSignalsEnabled = v;
+}
+
+bool SynchronousProcess::stdErrBufferedSignalsEnabled() const
+{
+ return m_d->m_stdErr.bufferedSignalsEnabled;
+}
+
+void SynchronousProcess::setStdErrBufferedSignalsEnabled(bool v)
+{
+ m_d->m_stdErr.bufferedSignalsEnabled = v;
+}
+
+QStringList SynchronousProcess::environment() const
+{
+ return m_d->m_process.environment();
+}
+
+void SynchronousProcess::setEnvironment(const QStringList &e)
+{
+ m_d->m_process.setEnvironment(e);
+}
+
+SynchronousProcessResponse SynchronousProcess::run(const QString &binary,
+ const QStringList &args)
+{
+ if (debug)
+ qDebug() << '>' << Q_FUNC_INFO << binary << args;
+
+ m_d->clearForRun();
+ m_d->m_timer.start();
+
+ QApplication::setOverrideCursor(Qt::WaitCursor);
+
+ m_d->m_process.start(binary, args, QIODevice::ReadOnly);
+ m_d->m_eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
+ if (m_d->m_result.result == SynchronousProcessResponse::Finished || m_d->m_result.result == SynchronousProcessResponse::FinishedError) {
+ processStdOut(false);
+ processStdErr(false);
+ }
+
+ m_d->m_result.stdOut = convertStdOut(m_d->m_stdOut.data);
+ m_d->m_result.stdErr = convertStdErr(m_d->m_stdErr.data);
+
+ m_d->m_timer.stop();
+ QApplication::restoreOverrideCursor();
+
+ if (debug)
+ qDebug() << '<' << Q_FUNC_INFO << binary << m_d->m_result;
+ return m_d->m_result;
+}
+
+void SynchronousProcess::slotTimeout()
+{
+ if (++m_d->m_hangTimerCount > m_d->m_maxHangTimerCount) {
+ m_d->m_process.kill();
+ m_d->m_result.result = SynchronousProcessResponse::Hang;
+ }
+
+ if (debug)
+ qDebug() << Q_FUNC_INFO << m_d->m_hangTimerCount;
+}
+
+void SynchronousProcess::finished(int exitCode, QProcess::ExitStatus e)
+{
+ if (debug)
+ qDebug() << Q_FUNC_INFO << exitCode << e;
+ m_d->m_hangTimerCount = 0;
+ switch (e) {
+ case QProcess::NormalExit:
+ m_d->m_result.result = exitCode ? SynchronousProcessResponse::FinishedError : SynchronousProcessResponse::Finished;
+ m_d->m_result.exitCode = exitCode;
+ break;
+ case QProcess::CrashExit:
+ m_d->m_result.result = SynchronousProcessResponse::TerminatedAbnormally;
+ m_d->m_result.exitCode = -1;
+ break;
+ }
+ m_d->m_eventLoop.quit();
+}
+
+void SynchronousProcess::error(QProcess::ProcessError e)
+{
+ m_d->m_hangTimerCount = 0;
+ if (debug)
+ qDebug() << Q_FUNC_INFO << e;
+ m_d->m_result.result = SynchronousProcessResponse::StartFailed;
+ m_d->m_eventLoop.quit();
+}
+
+void SynchronousProcess::stdOutReady()
+{
+ m_d->m_hangTimerCount = 0;
+ processStdOut(true);
+}
+
+void SynchronousProcess::stdErrReady()
+{
+ m_d->m_hangTimerCount = 0;
+ processStdErr(true);
+}
+
+QString SynchronousProcess::convertStdErr(const QByteArray &ba)
+{
+ return QString::fromLocal8Bit(ba).remove(QLatin1Char('\r'));
+}
+
+QString SynchronousProcess::convertStdOut(const QByteArray &ba) const
+{
+ QString stdOut = m_d->m_stdOutCodec ? m_d->m_stdOutCodec->toUnicode(ba) : QString::fromLocal8Bit(ba);
+ return stdOut.remove(QLatin1Char('\r'));
+}
+
+void SynchronousProcess::processStdOut(bool emitSignals)
+{
+ // Handle binary data
+ const QByteArray ba = m_d->m_process.readAllStandardOutput();
+ if (debug > 1)
+ qDebug() << Q_FUNC_INFO << emitSignals << ba;
+ if (!ba.isEmpty()) {
+ m_d->m_stdOut.data += ba;
+ if (emitSignals) {
+ // Emit binary signals
+ emit stdOut(ba, m_d->m_stdOut.firstData);
+ m_d->m_stdOut.firstData = false;
+ // Buffered. Emit complete lines?
+ if (m_d->m_stdOut.bufferedSignalsEnabled) {
+ const QByteArray lines = m_d->m_stdOut.linesRead();
+ if (!lines.isEmpty()) {
+ emit stdOutBuffered(convertStdOut(lines), m_d->m_stdOut.firstBuffer);
+ m_d->m_stdOut.firstBuffer = false;
+ }
+ }
+ }
+ }
+}
+
+void SynchronousProcess::processStdErr(bool emitSignals)
+{
+ // Handle binary data
+ const QByteArray ba = m_d->m_process.readAllStandardError();
+ if (debug > 1)
+ qDebug() << Q_FUNC_INFO << emitSignals << ba;
+ if (!ba.isEmpty()) {
+ m_d->m_stdErr.data += ba;
+ if (emitSignals) {
+ // Emit binary signals
+ emit stdErr(ba, m_d->m_stdErr.firstData);
+ m_d->m_stdErr.firstData = false;
+ if (m_d->m_stdErr.bufferedSignalsEnabled) {
+ // Buffered. Emit complete lines?
+ const QByteArray lines = m_d->m_stdErr.linesRead();
+ if (!lines.isEmpty()) {
+ emit stdErrBuffered(convertStdErr(lines), m_d->m_stdErr.firstBuffer);
+ m_d->m_stdErr.firstBuffer = false;
+ }
+ }
+ }
+ }
+}
+
+}
+}
diff --git a/src/libs/utils/synchronousprocess.h b/src/libs/utils/synchronousprocess.h
new file mode 100644
index 0000000000..9458655d6b
--- /dev/null
+++ b/src/libs/utils/synchronousprocess.h
@@ -0,0 +1,139 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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 SYNCHRONOUSPROCESS_H
+#define SYNCHRONOUSPROCESS_H
+
+#include <QtCore/QObject>
+#include <QtCore/QProcess>
+#include <QtCore/QStringList>
+
+#include "utils_global.h"
+
+QT_BEGIN_NAMESPACE
+class QTextCodec;
+class QDebug;
+class QByteArray;
+QT_END_NAMESPACE
+
+namespace Core {
+namespace Utils {
+
+struct SynchronousProcessPrivate;
+
+/* Result of SynchronousProcess execution */
+struct QWORKBENCH_UTILS_EXPORT SynchronousProcessResponse {
+ enum Result {
+ // Finished with return code 0
+ Finished,
+ // Finished with return code != 0
+ FinishedError,
+ // Process terminated abnormally (kill)
+ TerminatedAbnormally,
+ // Executable could not be started
+ StartFailed,
+ // Hang, no output after time out
+ Hang };
+
+ SynchronousProcessResponse();
+ void clear();
+
+ Result result;
+ int exitCode;
+ QString stdOut;
+ QString stdErr;
+};
+
+QWORKBENCH_UTILS_EXPORT QDebug operator<<(QDebug str, const SynchronousProcessResponse &);
+
+/* SynchronousProcess: Runs a synchronous process in its own event loop
+ * that blocks only user input events. Thus, it allows for the gui to
+ * repaint and append output to log windows.
+ *
+ * The stdOut(), stdErr() signals are emitted unbuffered as the process
+ * writes them.
+ *
+ * The stdOutBuffered(), stdErrBuffered() signals are emitted with complete
+ * lines based on the '\n' marker if they are enabled using
+ * stdOutBufferedSignalsEnabled()/setStdErrBufferedSignalsEnabled().
+ * They would typically be used for log windows. */
+
+class QWORKBENCH_UTILS_EXPORT SynchronousProcess : public QObject {
+ Q_OBJECT
+public:
+ SynchronousProcess();
+ virtual ~SynchronousProcess();
+
+ /* Timeout for hanging processes (no reaction on stderr/stdout)*/
+ void setTimeout(int timeoutMS);
+ int timeout() const;
+
+ void setStdOutCodec(QTextCodec *c);
+ QTextCodec *stdOutCodec() const;
+
+ bool stdOutBufferedSignalsEnabled() const;
+ void setStdOutBufferedSignalsEnabled(bool);
+
+ bool stdErrBufferedSignalsEnabled() const;
+ void setStdErrBufferedSignalsEnabled(bool);
+
+ QStringList environment() const;
+ void setEnvironment(const QStringList &);
+
+ SynchronousProcessResponse run(const QString &binary, const QStringList &args);
+
+signals:
+ void stdOut(const QByteArray &data, bool firstTime);
+ void stdErr(const QByteArray &data, bool firstTime);
+
+ void stdOutBuffered(const QString &data, bool firstTime);
+ void stdErrBuffered(const QString &data, bool firstTime);
+
+private slots:
+ void slotTimeout();
+ void finished(int exitCode, QProcess::ExitStatus e);
+ void error(QProcess::ProcessError);
+ void stdOutReady();
+ void stdErrReady();
+
+private:
+ void processStdOut(bool emitSignals);
+ void processStdErr(bool emitSignals);
+ static QString convertStdErr(const QByteArray &);
+ QString convertStdOut(const QByteArray &) const;
+
+ SynchronousProcessPrivate *m_d;
+};
+
+}
+}
+#endif
diff --git a/src/libs/utils/utils.pri b/src/libs/utils/utils.pri
new file mode 100644
index 0000000000..4e173f2cad
--- /dev/null
+++ b/src/libs/utils/utils.pri
@@ -0,0 +1 @@
+LIBS *= -l$$qtLibraryTarget(Utils)
diff --git a/src/libs/utils/utils.pro b/src/libs/utils/utils.pro
new file mode 100644
index 0000000000..d98ca1d889
--- /dev/null
+++ b/src/libs/utils/utils.pro
@@ -0,0 +1,53 @@
+TEMPLATE = lib
+TARGET = Utils
+
+DEFINES += QWORKBENCH_UTILS_LIBRARY
+
+include(../../qworkbenchlibrary.pri)
+
+SOURCES += \
+ reloadpromptutils.cpp \
+ settingsutils.cpp \
+ filesearch.cpp \
+ pathchooser.cpp \
+ filewizardpage.cpp \
+ filewizarddialog.cpp \
+ projectintropage.cpp \
+ basevalidatinglineedit.cpp \
+ filenamevalidatinglineedit.cpp \
+ projectnamevalidatinglineedit.cpp \
+ codegeneration.cpp \
+ newclasswidget.cpp \
+ classnamevalidatinglineedit.cpp \
+ linecolumnlabel.cpp \
+ fancylineedit.cpp \
+ qtcolorbutton.cpp \
+ submiteditorwidget.cpp \
+ synchronousprocess.cpp
+
+HEADERS += \
+ utils_global.h \
+ reloadpromptutils.h \
+ settingsutils.h \
+ filesearch.h \
+ listutils.h \
+ pathchooser.h \
+ filewizardpage.h \
+ filewizarddialog.h \
+ projectintropage.h \
+ basevalidatinglineedit.h \
+ filenamevalidatinglineedit.h \
+ projectnamevalidatinglineedit.h \
+ codegeneration.h \
+ newclasswidget.h \
+ classnamevalidatinglineedit.h \
+ linecolumnlabel.h \
+ fancylineedit.h \
+ qtcolorbutton.h \
+ submiteditorwidget.h \
+ synchronousprocess.h
+
+FORMS += filewizardpage.ui \
+ projectintropage.ui \
+ newclasswidget.ui \
+ submiteditorwidget.ui
diff --git a/src/libs/utils/utils_global.h b/src/libs/utils/utils_global.h
new file mode 100644
index 0000000000..3a91f77a2b
--- /dev/null
+++ b/src/libs/utils/utils_global.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** 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.
+**
+***************************************************************************/
+/****************************************************************************
+**
+** Copyright (C) 1992-$THISYEAR$ Trolltech AS. All rights reserved.
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $LICENSE$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef UTILS_GLOBAL_H
+#define UTILS_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(QWORKBENCH_UTILS_LIBRARY)
+# define QWORKBENCH_UTILS_EXPORT Q_DECL_EXPORT
+#else
+# define QWORKBENCH_UTILS_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // UTILS_GLOBAL_H