Plugin manager for enabling/disabling plugins

Go to About Plugins and enable/disable plugins from there.

Reviewed-by: mae
This commit is contained in:
Lasse Holmstedt
2010-03-12 16:02:23 +01:00
parent f4487c4c67
commit 68c49a65e9
48 changed files with 639 additions and 77 deletions

View File

@@ -202,7 +202,6 @@ int main(int argc, char **argv)
QLatin1String("Nokia"), QLatin1String("QtCreator"));
locale = settings.value("General/OverrideLanguage", locale).toString();
const QString &creatorTrPath = QCoreApplication::applicationDirPath()
+ QLatin1String(SHARE_PATH "/translations");
if (translator.load(QLatin1String("qtcreator_") + locale, creatorTrPath)) {

View File

@@ -19,14 +19,16 @@ HEADERS += pluginerrorview.h \
pluginspec_p.h \
pluginview.h \
pluginview_p.h \
optionsparser.h
optionsparser.h \
plugincollection.h
SOURCES += pluginerrorview.cpp \
plugindetailsview.cpp \
iplugin.cpp \
pluginmanager.cpp \
pluginspec.cpp \
pluginview.cpp \
optionsparser.cpp
optionsparser.cpp \
plugincollection.cpp
FORMS += pluginview.ui \
pluginerrorview.ui \
plugindetailsview.ui

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

View File

@@ -128,8 +128,7 @@ bool OptionsParser::checkForNoLoadOption()
"The plugin '%1' does not exist.").arg(m_currentArg);
m_hasError = true;
} else {
m_pmPrivate->pluginSpecs.removeAll(spec);
delete spec;
m_pmPrivate->removePluginSpec(spec);
m_isDependencyRefreshNeeded = true;
}
}

View File

@@ -0,0 +1,37 @@
#include "plugincollection.h"
#include "pluginspec.h"
namespace ExtensionSystem {
PluginCollection::PluginCollection(const QString& name) :
m_name(name)
{
}
PluginCollection::~PluginCollection()
{
}
QString PluginCollection::name() const
{
return m_name;
}
void PluginCollection::addPlugin(PluginSpec *spec)
{
m_plugins.append(spec);
}
void PluginCollection::removePlugin(PluginSpec *spec)
{
m_plugins.removeOne(spec);
}
QList<PluginSpec *> PluginCollection::plugins() const
{
return m_plugins;
}
}

View File

@@ -0,0 +1,31 @@
#ifndef PLUGINCOLLECTION_H
#define PLUGINCOLLECTION_H
#include <QList>
#include <QString>
#include "extensionsystem_global.h"
namespace ExtensionSystem {
class PluginSpec;
class EXTENSIONSYSTEM_EXPORT PluginCollection
{
public:
explicit PluginCollection(const QString& name);
~PluginCollection();
QString name() const;
void addPlugin(PluginSpec *spec);
void removePlugin(PluginSpec *spec);
QList<PluginSpec *> plugins() const;
private:
QString m_name;
QList<PluginSpec *> m_plugins;
};
}
#endif // PLUGINCOLLECTION_H

View File

@@ -78,6 +78,10 @@ void PluginDetailsView::update(PluginSpec *spec)
m_ui->vendor->setText(spec->vendor());
const QString link = QString::fromLatin1("<a href=\"%1\">%1</a>").arg(spec->url());
m_ui->url->setText(link);
QString component = tr("None");
if (!spec->category().isEmpty())
component = spec->category();
m_ui->component->setText(component);
m_ui->location->setText(QDir::toNativeSeparators(spec->filePath()));
m_ui->description->setText(spec->description());
m_ui->copyright->setText(spec->copyright());

View File

@@ -66,7 +66,7 @@
<item row="3" column="1">
<widget class="QLabel" name="vendor"/>
</item>
<item row="4" column="0">
<item row="5" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Url:</string>
@@ -76,14 +76,14 @@
</property>
</widget>
</item>
<item row="4" column="1">
<item row="5" column="1">
<widget class="QLabel" name="url">
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item row="5" column="0">
<item row="6" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Location:</string>
@@ -93,14 +93,14 @@
</property>
</widget>
</item>
<item row="5" column="1">
<item row="6" column="1">
<widget class="QLabel" name="location">
<property name="wordWrap">
<bool>false</bool>
</property>
</widget>
</item>
<item row="6" column="0">
<item row="7" column="0">
<layout class="QVBoxLayout">
<item>
<widget class="QLabel" name="label_8">
@@ -127,7 +127,7 @@
</item>
</layout>
</item>
<item row="6" column="1">
<item row="7" column="1">
<widget class="QTextEdit" name="description">
<property name="tabChangesFocus">
<bool>true</bool>
@@ -137,7 +137,7 @@
</property>
</widget>
</item>
<item row="7" column="0">
<item row="8" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Copyright:</string>
@@ -147,10 +147,10 @@
</property>
</widget>
</item>
<item row="7" column="1">
<item row="8" column="1">
<widget class="QLabel" name="copyright"/>
</item>
<item row="8" column="0">
<item row="9" column="0">
<layout class="QVBoxLayout">
<item>
<widget class="QLabel" name="label_9">
@@ -177,7 +177,7 @@
</item>
</layout>
</item>
<item row="8" column="1">
<item row="9" column="1">
<widget class="QTextEdit" name="license">
<property name="tabChangesFocus">
<bool>true</bool>
@@ -187,7 +187,7 @@
</property>
</widget>
</item>
<item row="9" column="0">
<item row="10" column="0">
<layout class="QVBoxLayout">
<item>
<widget class="QLabel" name="label_10">
@@ -214,9 +214,26 @@
</item>
</layout>
</item>
<item row="9" column="1">
<item row="10" column="1">
<widget class="QListWidget" name="dependencies"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Group:</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="component">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>

View File

@@ -33,6 +33,7 @@
#include "pluginspec_p.h"
#include "optionsparser.h"
#include "iplugin.h"
#include "plugincollection.h"
#include <QtCore/QMetaProperty>
#include <QtCore/QDir>
@@ -40,11 +41,14 @@
#include <QtCore/QWriteLocker>
#include <QtCore/QTime>
#include <QtCore/QDateTime>
#include <QtCore/QSettings>
#include <QtDebug>
#ifdef WITH_TESTS
#include <QTest>
#endif
static const char * const C_IGNORED_PLUGINS = "Plugins/Ignored";
typedef QList<ExtensionSystem::PluginSpec *> PluginSpecSet;
enum { debugLeaks = 0 };
@@ -297,6 +301,16 @@ void PluginManager::setFileExtension(const QString &extension)
d->extension = extension;
}
void PluginManager::loadSettings()
{
d->loadSettings();
}
void PluginManager::writeSettings()
{
d->writeSettings();
}
/*!
\fn QStringList PluginManager::arguments() const
The arguments left over after parsing (Neither startup nor plugin
@@ -322,6 +336,11 @@ QList<PluginSpec *> PluginManager::plugins() const
return d->pluginSpecs;
}
QHash<QString, PluginCollection *> PluginManager::pluginCollections() const
{
return d->pluginCategories;
}
/*!
\fn QString PluginManager::serializedArguments() const
@@ -593,11 +612,35 @@ PluginManagerPrivate::~PluginManagerPrivate()
{
stopAll();
qDeleteAll(pluginSpecs);
qDeleteAll(pluginCategories);
if (!allObjects.isEmpty()) {
qDebug() << "There are" << allObjects.size() << "objects left in the plugin manager pool: " << allObjects;
}
}
void PluginManagerPrivate::writeSettings()
{
QSettings settings(QSettings::IniFormat, QSettings::UserScope,
QLatin1String("Nokia"), QLatin1String("QtCreator"));
QStringList notLoadedPlugins;
foreach(PluginSpec *spec, pluginSpecs) {
if (!spec->loadOnStartup())
notLoadedPlugins.append(spec->name());
}
settings.setValue(QLatin1String(C_IGNORED_PLUGINS), notLoadedPlugins);
}
void PluginManagerPrivate::loadSettings()
{
const QSettings settings(QSettings::IniFormat, QSettings::UserScope,
QLatin1String("Nokia"), QLatin1String("QtCreator"));
notLoadedPlugins = settings.value(QLatin1String(C_IGNORED_PLUGINS)).toStringList();
}
void PluginManagerPrivate::stopAll()
{
QList<PluginSpec *> queue = loadQueue();
@@ -719,9 +762,11 @@ bool PluginManagerPrivate::loadQueue(PluginSpec *spec, QList<PluginSpec *> &queu
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 += PluginManager::tr("Cannot load plugin because dependencies are not resolved");
if (!spec->d->ignoreOnStartup && spec->d->loadOnStartup) {
spec->d->hasError = true;
spec->d->errorString += "\n";
spec->d->errorString += PluginManager::tr("Cannot load plugin because dependencies are not resolved");
}
return false;
}
// add dependencies
@@ -745,8 +790,9 @@ bool PluginManagerPrivate::loadQueue(PluginSpec *spec, QList<PluginSpec *> &queu
*/
void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destState)
{
if (spec->hasError())
if (spec->hasError() || spec->ignoreOnStartup())
return;
switch (destState) {
case PluginSpec::Running:
profilingReport(">initializeExtensions", spec);
@@ -796,6 +842,7 @@ void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destSt
void PluginManagerPrivate::setPluginPaths(const QStringList &paths)
{
pluginPaths = paths;
loadSettings();
readPluginPaths();
}
@@ -805,8 +852,10 @@ void PluginManagerPrivate::setPluginPaths(const QStringList &paths)
*/
void PluginManagerPrivate::readPluginPaths()
{
qDeleteAll(pluginCategories);
qDeleteAll(pluginSpecs);
pluginSpecs.clear();
pluginCategories.clear();
QStringList specFiles;
QStringList searchPaths = pluginPaths;
@@ -820,9 +869,25 @@ void PluginManagerPrivate::readPluginPaths()
foreach (const QFileInfo &subdir, dirs)
searchPaths << subdir.absoluteFilePath();
}
defaultCollection = new PluginCollection(QString());
pluginCategories.insert("", defaultCollection);
foreach (const QString &specFile, specFiles) {
PluginSpec *spec = new PluginSpec;
spec->d->read(specFile);
PluginCollection *collection = 0;
// find correct plugin collection or create a new one
if (pluginCategories.contains(spec->category()))
collection = pluginCategories.value(spec->category());
else {
collection = new PluginCollection(spec->category());
pluginCategories.insert(spec->category(), collection);
}
if (notLoadedPlugins.contains(spec->name()))
spec->setLoadOnStartup(false);
collection->addPlugin(spec);
pluginSpecs.append(spec);
}
resolveDependencies();
@@ -862,6 +927,21 @@ PluginSpec *PluginManagerPrivate::pluginForOption(const QString &option, bool *r
return 0;
}
void PluginManagerPrivate::removePluginSpec(PluginSpec *spec)
{
pluginSpecs.removeAll(spec);
if (pluginCategories.contains(spec->category()))
pluginCategories.value(spec->category())->removePlugin(spec);
foreach(PluginSpec *dep, spec->dependencySpecs()) {
dep->removeDependentPlugin(spec);
}
delete spec;
spec = 0;
}
PluginSpec *PluginManagerPrivate::pluginByName(const QString &name) const
{
foreach (PluginSpec *spec, pluginSpecs)

View File

@@ -42,7 +42,7 @@ class QTextStream;
QT_END_NAMESPACE
namespace ExtensionSystem {
class PluginCollection;
namespace Internal {
class PluginManagerPrivate;
}
@@ -95,9 +95,14 @@ public:
QStringList pluginPaths() const;
void setPluginPaths(const QStringList &paths);
QList<PluginSpec *> plugins() const;
QHash<QString, PluginCollection *> pluginCollections() const;
void setFileExtension(const QString &extension);
QString fileExtension() const;
// Settings
void loadSettings();
void writeSettings();
// command line arguments
QStringList arguments() const;
bool parseOptions(const QStringList &args,

View File

@@ -45,6 +45,7 @@ QT_END_NAMESPACE
namespace ExtensionSystem {
class PluginManager;
class PluginCollection;
namespace Internal {
@@ -68,12 +69,17 @@ public:
void resolveDependencies();
void initProfiling();
void profilingReport(const char *what, const PluginSpec *spec = 0);
void loadSettings();
void writeSettings();
void removePluginSpec(PluginSpec *spec);
QHash<QString, PluginCollection *> pluginCategories;
QList<PluginSpec *> pluginSpecs;
QList<PluginSpec *> testSpecs;
QStringList pluginPaths;
QString extension;
QList<QObject *> allObjects; // ### make this a QList<QPointer<QObject> > > ?
QStringList notLoadedPlugins;
QStringList arguments;
QScopedPointer<QTime> m_profileTimer;
@@ -87,6 +93,7 @@ public:
static PluginSpec *createSpec();
static PluginSpecPrivate *privateSpec(PluginSpec *spec);
private:
PluginCollection *defaultCollection;
PluginManager *q;
void readPluginPaths();

View File

@@ -226,6 +226,30 @@ QString PluginSpec::url() const
return d->url;
}
/*!
\fn QString PluginSpec::category() const
The category that the plugin belongs to. Categories are groups of plugins which allow for keeping them together in the UI.
Returns an empty string if the plugin does not belong to a category.
*/
QString PluginSpec::category() const
{
return d->category;
}
/*!
\fn bool PluginSpec::loadOnStartup() const
True if the plugin is loaded at startup. True by default - the user can change it from the Plugin settings.
*/
bool PluginSpec::loadOnStartup() const
{
return d->loadOnStartup;
}
bool PluginSpec::ignoreOnStartup() const
{
return d->ignoreOnStartup;
}
/*!
\fn QList<PluginDependency> PluginSpec::dependencies() const
The plugin dependencies. This is valid after the PluginSpec::Read state is reached.
@@ -358,6 +382,33 @@ QList<PluginSpec *> PluginSpec::dependencySpecs() const
return d->dependencySpecs;
}
/*!
\fn QList<PluginSpec *> PluginSpec::providesSpecs() const
Returns the list of plugins that depend on this one.
\sa PluginSpec::dependencySpecs()
*/
QList<PluginSpec *> PluginSpec::providesSpecs() const
{
return d->providesSpecs;
}
/*!
\fn void PluginSpec::addDependentPlugin(PluginSpec *dependent)
Adds a dependent the list of plugins that depend on this one.
\sa PluginSpec::providesSpecs()
*/
void PluginSpec::addDependentPlugin(PluginSpec *dependent)
{
d->providesSpecs.append(dependent);
}
void PluginSpec::removeDependentPlugin(PluginSpec *dependent)
{
d->providesSpecs.removeOne(dependent);
}
//==========PluginSpecPrivate==================
namespace {
@@ -370,6 +421,7 @@ namespace {
const char * const LICENSE = "license";
const char * const DESCRIPTION = "description";
const char * const URL = "url";
const char * const CATEGORY = "category";
const char * const DEPENDENCYLIST = "dependencyList";
const char * const DEPENDENCY = "dependency";
const char * const DEPENDENCY_NAME = "name";
@@ -384,7 +436,10 @@ namespace {
\internal
*/
PluginSpecPrivate::PluginSpecPrivate(PluginSpec *spec)
: plugin(0),
:
loadOnStartup(true),
ignoreOnStartup(false),
plugin(0),
state(PluginSpec::Invalid),
hasError(false),
q(spec)
@@ -405,6 +460,7 @@ bool PluginSpecPrivate::read(const QString &fileName)
= license
= description
= url
= category
= location
= "";
state = PluginSpec::Invalid;
@@ -440,6 +496,16 @@ bool PluginSpecPrivate::read(const QString &fileName)
return true;
}
void PluginSpec::setLoadOnStartup(bool value)
{
d->loadOnStartup = value;
}
void PluginSpec::setIgnoreOnStartup(bool value)
{
d->ignoreOnStartup = value;
}
/*!
\fn bool PluginSpecPrivate::reportError(const QString &err)
\internal
@@ -523,6 +589,8 @@ void PluginSpecPrivate::readPluginSpec(QXmlStreamReader &reader)
description = reader.readElementText().trimmed();
else if (element == URL)
url = reader.readElementText().trimmed();
else if (element == CATEGORY)
category = reader.readElementText().trimmed();
else if (element == DEPENDENCYLIST)
readDependencies(reader);
else if (element == ARGUMENTLIST)
@@ -725,9 +793,15 @@ bool PluginSpecPrivate::resolveDependencies(const QList<PluginSpec *> &specs)
QList<PluginSpec *> resolvedDependencies;
foreach (const PluginDependency &dependency, dependencies) {
PluginSpec *found = 0;
foreach (PluginSpec *spec, specs) {
if (spec->provides(dependency.name, dependency.version)) {
found = spec;
if (!spec->loadOnStartup() || spec->ignoreOnStartup())
ignoreOnStartup = true;
spec->addDependentPlugin(q);
break;
}
}
@@ -743,8 +817,12 @@ bool PluginSpecPrivate::resolveDependencies(const QList<PluginSpec *> &specs)
}
if (hasError)
return false;
dependencySpecs = resolvedDependencies;
state = PluginSpec::Resolved;
if (loadOnStartup && !ignoreOnStartup)
state = PluginSpec::Resolved;
return true;
}

View File

@@ -78,6 +78,10 @@ public:
QString license() const;
QString description() const;
QString url() const;
QString category() const;
bool loadOnStartup() const;
// true if loading was not done due to user unselecting this plugin or its dependencies
bool ignoreOnStartup() const;
QList<PluginDependency> dependencies() const;
typedef QList<PluginArgumentDescription> PluginArgumentDescriptions;
@@ -87,6 +91,9 @@ public:
QString location() const;
QString filePath() const;
void setLoadOnStartup(bool value);
void setIgnoreOnStartup(bool value);
QStringList arguments() const;
void setArguments(const QStringList &arguments);
void addArgument(const QString &argument);
@@ -96,6 +103,13 @@ public:
// dependency specs, valid after 'Resolved' state is reached
QList<PluginSpec *> dependencySpecs() const;
// list of plugins that depend on this - e.g. this plugins provides for them
QList<PluginSpec *> providesSpecs() const;
// add/remove from providesSpecs
void addDependentPlugin(PluginSpec *dependent);
void removeDependentPlugin(PluginSpec *dependent);
// linked plugin instance, valid after 'Loaded' state is reached
IPlugin *plugin() const;

View File

@@ -67,12 +67,16 @@ public:
QString license;
QString description;
QString url;
QString category;
QList<PluginDependency> dependencies;
bool loadOnStartup;
bool ignoreOnStartup;
QString location;
QString filePath;
QStringList arguments;
QList<PluginSpec *> providesSpecs;
QList<PluginSpec *> dependencySpecs;
PluginSpec::PluginArgumentDescriptions argumentDescriptions;
IPlugin *plugin;

View File

@@ -31,11 +31,14 @@
#include "pluginview_p.h"
#include "pluginmanager.h"
#include "pluginspec.h"
#include "plugincollection.h"
#include "ui_pluginview.h"
#include <QtCore/QDir>
#include <QtGui/QHeaderView>
#include <QtGui/QTreeWidgetItem>
#include <QtGui/QPalette>
#include <QtDebug>
/*!
@@ -65,6 +68,7 @@
using namespace ExtensionSystem;
Q_DECLARE_METATYPE(ExtensionSystem::PluginSpec*);
Q_DECLARE_METATYPE(ExtensionSystem::PluginCollection*);
/*!
\fn PluginView::PluginView(PluginManager *manager, QWidget *parent)
@@ -74,20 +78,30 @@ Q_DECLARE_METATYPE(ExtensionSystem::PluginSpec*);
PluginView::PluginView(PluginManager *manager, QWidget *parent)
: QWidget(parent),
m_ui(new Internal::Ui::PluginView),
p(new Internal::PluginViewPrivate)
p(new Internal::PluginViewPrivate),
m_allowCheckStateUpdate(true),
C_LOAD(1)
{
m_ui->setupUi(this);
QHeaderView *header = m_ui->pluginWidget->header();
QHeaderView *header = m_ui->categoryWidget->header();
header->setResizeMode(0, QHeaderView::ResizeToContents);
header->setResizeMode(1, QHeaderView::ResizeToContents);
header->setResizeMode(2, QHeaderView::ResizeToContents);
m_ui->pluginWidget->sortItems(1, Qt::AscendingOrder);
m_okIcon = QIcon(QLatin1String(":/extensionsystem/images/ok.png"));
m_errorIcon = QIcon(QLatin1String(":/extensionsystem/images/error.png"));
m_notLoadedIcon = QIcon(QLatin1String(":/extensionsystem/images/notloaded.png"));
// cannot disable these
m_whitelist << QString("Core") << QString("Locator")
<< QString("Find") << QString("TextEditor");
p->manager = manager;
connect(p->manager, SIGNAL(pluginsChanged()), this, SLOT(updateList()));
connect(m_ui->pluginWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
connect(m_ui->categoryWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
this, SLOT(selectPlugin(QTreeWidgetItem*)));
connect(m_ui->pluginWidget, SIGNAL(itemActivated(QTreeWidgetItem*,int)),
connect(m_ui->categoryWidget, SIGNAL(itemActivated(QTreeWidgetItem*,int)),
this, SLOT(activatePlugin(QTreeWidgetItem*)));
updateList();
}
@@ -107,51 +121,230 @@ PluginView::~PluginView()
*/
PluginSpec *PluginView::currentPlugin() const
{
if (!m_ui->pluginWidget->currentItem())
if (!m_ui->categoryWidget->currentItem())
return 0;
return m_ui->pluginWidget->currentItem()->data(0, Qt::UserRole).value<PluginSpec *>();
if (!m_ui->categoryWidget->currentItem()->data(0, Qt::UserRole).isNull())
return m_ui->categoryWidget->currentItem()->data(0, Qt::UserRole).value<PluginSpec *>();
return 0;
}
void PluginView::updateList()
{
const QIcon okIcon(QLatin1String(":/extensionsystem/images/ok.png"));
const QIcon errorIcon(QLatin1String(":/extensionsystem/images/error.png"));
QList<QTreeWidgetItem *> items;
QTreeWidgetItem *currentItem = 0;
PluginSpec *currPlugin = currentPlugin();
foreach (PluginSpec *spec, p->manager->plugins()) {
QTreeWidgetItem *item = new QTreeWidgetItem(QStringList()
<< QString()
<< spec->name()
<< QString::fromLatin1("%1 (%2)").arg(spec->version(), spec->compatVersion())
<< spec->vendor()
<< QDir::toNativeSeparators(spec->filePath()));
item->setToolTip(4, QDir::toNativeSeparators(spec->filePath()));
item->setIcon(0, spec->hasError() ? errorIcon : okIcon);
item->setData(0, Qt::UserRole, qVariantFromValue(spec));
items.append(item);
if (currPlugin == spec)
currentItem = item;
connect(m_ui->categoryWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
this, SLOT(updatePluginSettings(QTreeWidgetItem*, int)));
PluginCollection *defaultCollection = 0;
foreach(PluginCollection *collection, p->manager->pluginCollections()) {
if (collection->name().isEmpty()) {
defaultCollection = collection;
continue;
}
// State, name, load, version, vendor.
QTreeWidgetItem *collectionItem = new QTreeWidgetItem(QStringList()
<< collection->name()
<< QString() // state
<< QString() // load
<< QString() // version
<< QString()); // vendor
m_items.append(collectionItem);
Qt::CheckState groupState = Qt::Unchecked;
bool hasErrors = parsePluginSpecs(collectionItem, groupState, collection->plugins());
collectionItem->setIcon(0, hasErrors ? m_errorIcon : m_okIcon);
collectionItem->setData(C_LOAD, Qt::CheckStateRole, QVariant(groupState));
collectionItem->setToolTip(C_LOAD, tr("Load on Startup"));
collectionItem->setData(0, Qt::UserRole, qVariantFromValue(collection));
}
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());
// add all non-categorized plugins into utilities. could also be added as root items
// but that makes the tree ugly.
QTreeWidgetItem *defaultCollectionItem = new QTreeWidgetItem(QStringList()
<< QString(tr("Utilities"))
<< QString()
<< QString()
<< QString()
<< QString());
m_items.append(defaultCollectionItem);
Qt::CheckState groupState = Qt::Unchecked;
bool hasErrors = parsePluginSpecs(defaultCollectionItem, groupState, defaultCollection->plugins());
defaultCollectionItem->setIcon(0, hasErrors ? m_errorIcon : m_okIcon);
defaultCollectionItem->setData(C_LOAD, Qt::CheckStateRole, QVariant(groupState));
defaultCollectionItem->setToolTip(C_LOAD, tr("Load on Startup"));
defaultCollectionItem->setData(0, Qt::UserRole, qVariantFromValue(defaultCollection));
foreach (PluginSpec *spec, m_specToItem.keys())
toggleRelatedPlugins(spec, spec->loadOnStartup() && !spec->ignoreOnStartup());
m_ui->categoryWidget->clear();
if (!m_items.isEmpty()) {
m_ui->categoryWidget->addTopLevelItems(m_items);
m_ui->categoryWidget->expandAll();
}
m_ui->categoryWidget->sortItems(0, Qt::AscendingOrder);
if (m_ui->categoryWidget->topLevelItemCount())
m_ui->categoryWidget->setCurrentItem(m_ui->categoryWidget->topLevelItem(0));
}
bool PluginView::parsePluginSpecs(QTreeWidgetItem *parentItem, Qt::CheckState &groupState, QList<PluginSpec*> plugins)
{
bool hasErrors = false;
int loadCount = 0;
for (int i = 0; i < plugins.length(); ++i) {
PluginSpec *spec = plugins[i];
if (spec->hasError())
hasErrors = true;
QTreeWidgetItem *pluginItem = new QTreeWidgetItem(QStringList()
<< spec->name()
<< QString() // load on startup
<< QString::fromLatin1("%1 (%2)").arg(spec->version(), spec->compatVersion())
<< spec->vendor());
pluginItem->setToolTip(0, QDir::toNativeSeparators(spec->filePath()));
bool ok = !spec->hasError();
QIcon &icon = ok ? m_okIcon : m_errorIcon;
if (ok && (spec->state() != PluginSpec::Running))
icon = m_notLoadedIcon;
pluginItem->setIcon(0, icon);
pluginItem->setData(0, Qt::UserRole, qVariantFromValue(spec));
Qt::CheckState state = Qt::Unchecked;
if (spec->loadOnStartup()) {
state = Qt::Checked;
//if (!spec->ignoreOnStartup())
++loadCount;
} else
hasErrors = true;
if (!m_whitelist.contains(spec->name()))
pluginItem->setData(C_LOAD, Qt::CheckStateRole, state);
else {
QColor disabledColor = palette().color(QPalette::Disabled,QPalette::WindowText).lighter(120);
pluginItem->setData(C_LOAD, Qt::CheckStateRole, Qt::Checked);
pluginItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
pluginItem->setSizeHint(C_LOAD, QSize(1,1));
pluginItem->setForeground(C_LOAD, QBrush(disabledColor)); // QBrush(Qt::white, Qt::NoBrush));
//pluginItem->setBackground(C_LOAD, QBrush(Qt::white, Qt::NoBrush));
}
pluginItem->setToolTip(C_LOAD, tr("Load on Startup"));
m_specToItem.insert(spec, pluginItem);
if (parentItem)
parentItem->addChild(pluginItem);
else
m_items.append(pluginItem);
}
if (loadCount == plugins.length())
groupState = Qt::Checked;
else if (loadCount == 0)
groupState = Qt::Unchecked;
else
groupState = Qt::PartiallyChecked;
return hasErrors;
}
void PluginView::selectPlugin(QTreeWidgetItem *current)
{
if (!current)
emit currentPluginChanged(0);
else
else if (current->data(0, Qt::UserRole).canConvert<PluginSpec*>())
emit currentPluginChanged(current->data(0, Qt::UserRole).value<PluginSpec *>());
else
emit currentPluginChanged(0);
}
void PluginView::activatePlugin(QTreeWidgetItem *item)
{
emit pluginActivated(item->data(0, Qt::UserRole).value<PluginSpec *>());
if (item->data(0, Qt::UserRole).canConvert<PluginSpec*>()) {
emit pluginActivated(item->data(0, Qt::UserRole).value<PluginSpec *>());
} else
emit pluginActivated(0);
}
void PluginView::updatePluginSettings(QTreeWidgetItem *item, int column)
{
if (!m_allowCheckStateUpdate)
return;
m_allowCheckStateUpdate = false;
bool loadOnStartup = item->data(C_LOAD, Qt::CheckStateRole).toBool();
if (item->data(0, Qt::UserRole).canConvert<PluginSpec*>()) {
PluginSpec *spec = item->data(0, Qt::UserRole).value<PluginSpec *>();
if (column == C_LOAD) {
spec->setLoadOnStartup(loadOnStartup);
toggleRelatedPlugins(spec, loadOnStartup);
if (item->parent()) {
PluginCollection *collection = item->parent()->data(0, Qt::UserRole).value<PluginCollection *>();
Qt::CheckState state = Qt::PartiallyChecked;
int loadCount = 0;
for (int i = 0; i < collection->plugins().length(); ++i) {
if (collection->plugins().at(i)->loadOnStartup())
++loadCount;
}
if (loadCount == collection->plugins().length())
state = Qt::Checked;
else if (loadCount == 0)
state = Qt::Unchecked;
item->parent()->setData(C_LOAD, Qt::CheckStateRole, state);
}
emit pluginSettingsChanged(spec);
}
} else {
PluginCollection *collection = item->data(0, Qt::UserRole).value<PluginCollection *>();
for (int i = 0; i < collection->plugins().length(); ++i) {
PluginSpec *spec = collection->plugins().at(i);
QTreeWidgetItem *child = m_specToItem.value(spec);
if (!m_whitelist.contains(spec->name())) {
spec->setLoadOnStartup(loadOnStartup);
Qt::CheckState state = (loadOnStartup ? Qt::Checked : Qt::Unchecked);
child->setData(C_LOAD, Qt::CheckStateRole, state);
toggleRelatedPlugins(spec, loadOnStartup);
} else {
child->setData(C_LOAD, Qt::CheckStateRole, Qt::Checked);
child->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
}
}
emit pluginSettingsChanged(collection->plugins().first());
}
m_allowCheckStateUpdate = true;
}
void PluginView::toggleRelatedPlugins(PluginSpec *modifiedPlugin, bool isPluginEnabled)
{
for(int i = 0; i < modifiedPlugin->providesSpecs().length(); ++i) {
PluginSpec *spec = modifiedPlugin->providesSpecs().at(i);
QTreeWidgetItem *childItem = m_specToItem.value(spec);
if (childItem->isDisabled() != !isPluginEnabled) {
childItem->setDisabled(!isPluginEnabled);
if (childItem->parent() && !childItem->parent()->isExpanded())
childItem->parent()->setExpanded(true);
toggleRelatedPlugins(spec, isPluginEnabled);
}
}
}

View File

@@ -32,7 +32,9 @@
#include "extensionsystem_global.h"
#include <QtCore/QHash>
#include <QtGui/QWidget>
#include <QtGui/QIcon>
QT_BEGIN_NAMESPACE
class QTreeWidgetItem;
@@ -42,6 +44,7 @@ namespace ExtensionSystem {
class PluginManager;
class PluginSpec;
class PluginCollection;
namespace Internal {
class PluginViewPrivate;
@@ -63,15 +66,30 @@ public:
signals:
void currentPluginChanged(ExtensionSystem::PluginSpec *spec);
void pluginActivated(ExtensionSystem::PluginSpec *spec);
void pluginSettingsChanged(ExtensionSystem::PluginSpec *spec);
private slots:
void updatePluginSettings(QTreeWidgetItem *item, int column);
void updateList();
void selectPlugin(QTreeWidgetItem *current);
void activatePlugin(QTreeWidgetItem *item);
private:
void toggleRelatedPlugins(PluginSpec *spec, bool isPluginEnabled = true);
bool parsePluginSpecs(QTreeWidgetItem *parentItem, Qt::CheckState &groupState, QList<PluginSpec*> plugins);
Internal::Ui::PluginView *m_ui;
Internal::PluginViewPrivate *p;
QList<QTreeWidgetItem*> m_items;
QHash<PluginSpec*, QTreeWidgetItem*> m_specToItem;
QStringList m_whitelist;
QIcon m_okIcon;
QIcon m_errorIcon;
QIcon m_notLoadedIcon;
bool m_allowCheckStateUpdate;
const int C_LOAD;
};
} // namespae ExtensionSystem

View File

@@ -1,6 +1,7 @@
<RCC>
<qresource prefix="/extensionsystem" >
<qresource prefix="/extensionsystem">
<file>images/ok.png</file>
<file>images/error.png</file>
<file>images/notloaded.png</file>
</qresource>
</RCC>

View File

@@ -14,37 +14,55 @@
<property name="margin">
<number>2</number>
</property>
<item row="0" column="0">
<widget class="QTreeWidget" name="pluginWidget">
<item row="1" column="0">
<widget class="QTreeWidget" name="categoryWidget">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="indentation">
<number>0</number>
<number>20</number>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<property name="itemsExpandable">
<property name="uniformRowHeights">
<bool>false</bool>
</property>
<property name="itemsExpandable">
<bool>true</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<property name="columnCount">
<number>5</number>
<number>4</number>
</property>
<attribute name="headerDefaultSectionSize">
<number>120</number>
</attribute>
<attribute name="headerHighlightSections">
<bool>false</bool>
</attribute>
<attribute name="headerMinimumSectionSize">
<number>35</number>
</attribute>
<attribute name="headerDefaultSectionSize">
<number>120</number>
</attribute>
<attribute name="headerMinimumSectionSize">
<number>35</number>
</attribute>
<attribute name="headerHighlightSections">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string>State</string>
<string>Name</string>
</property>
</column>
<column>
<property name="text">
<string>Name</string>
<string>Load</string>
</property>
</column>
<column>
@@ -57,11 +75,6 @@
<string>Vendor</string>
</property>
</column>
<column>
<property name="text">
<string>Location</string>
</property>
</column>
</widget>
</item>
</layout>

View File

@@ -10,6 +10,7 @@ GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
</license>
<category>Qt Creator</category>
<description>Binary editor component.</description>
<url>http://qt.nokia.com</url>
<dependencyList>

View File

@@ -10,6 +10,7 @@ GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
</license>
<category>Qt Creator</category>
<description>Bookmarks in text editors.</description>
<url>http://qt.nokia.com</url>
<dependencyList>

View File

@@ -10,6 +10,7 @@ GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
</license>
<category>Build Systems</category>
<description>CMake support</description>
<url>http://qt.nokia.com</url>
<dependencyList>

View File

@@ -10,6 +10,7 @@ GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
</license>
<category>Qt Creator</category>
<description>The core plugin for the Qt IDE.</description>
<url>http://qt.nokia.com</url>
<argumentList>

View File

@@ -40,10 +40,13 @@
#include <QtGui/QDialog>
#include <QtGui/QDialogButtonBox>
#include <QtGui/QPushButton>
#include <QtGui/QLabel>
#include <QtDebug>
using namespace Core::Internal;
bool PluginDialog::m_isRestartRequired = false;
PluginDialog::PluginDialog(QWidget *parent)
: QDialog(parent),
m_view(new ExtensionSystem::PluginView(ExtensionSystem::PluginManager::instance(), this))
@@ -59,14 +62,21 @@ PluginDialog::PluginDialog(QWidget *parent)
m_closeButton->setEnabled(true);
m_closeButton->setDefault(true);
m_restartRequired = new QLabel(tr("Restart required."), this);
if (!m_isRestartRequired)
m_restartRequired->setVisible(false);
QHBoxLayout *hl = new QHBoxLayout;
hl->addWidget(m_detailsButton);
hl->addWidget(m_errorDetailsButton);
hl->addSpacing(10);
hl->addWidget(m_restartRequired);
hl->addStretch(5);
hl->addWidget(m_closeButton);
vl->addLayout(hl);
resize(650, 400);
setWindowTitle(tr("Installed Plugins"));
@@ -74,18 +84,35 @@ PluginDialog::PluginDialog(QWidget *parent)
this, SLOT(updateButtons()));
connect(m_view, SIGNAL(pluginActivated(ExtensionSystem::PluginSpec*)),
this, SLOT(openDetails(ExtensionSystem::PluginSpec*)));
connect(m_view, SIGNAL(pluginSettingsChanged(ExtensionSystem::PluginSpec*)),
this, SLOT(updateRestartRequired()));
connect(m_detailsButton, SIGNAL(clicked()), this, SLOT(openDetails()));
connect(m_errorDetailsButton, SIGNAL(clicked()), this, SLOT(openErrorDetails()));
connect(m_closeButton, SIGNAL(clicked()), this, SLOT(accept()));
connect(m_closeButton, SIGNAL(clicked()), this, SLOT(closeDialog()));
updateButtons();
}
void PluginDialog::closeDialog()
{
ExtensionSystem::PluginManager::instance()->writeSettings();
accept();
}
void PluginDialog::updateRestartRequired()
{
// just display the notice all the time after once changing something
m_isRestartRequired = true;
m_restartRequired->setVisible(true);
}
void PluginDialog::updateButtons()
{
ExtensionSystem::PluginSpec *selectedSpec = m_view->currentPlugin();
if (selectedSpec) {
m_detailsButton->setEnabled(true);
m_errorDetailsButton->setEnabled(selectedSpec->hasError());
m_errorDetailsButton->setEnabled(selectedSpec->hasError()
|| selectedSpec->ignoreOnStartup()
|| !selectedSpec->loadOnStartup());
} else {
m_detailsButton->setEnabled(false);
m_errorDetailsButton->setEnabled(false);

View File

@@ -34,6 +34,7 @@
QT_BEGIN_NAMESPACE
class QPushButton;
class QLabel;
QT_END_NAMESPACE
namespace ExtensionSystem {
@@ -52,10 +53,12 @@ public:
explicit PluginDialog(QWidget *parent);
private slots:
void updateRestartRequired();
void updateButtons();
void openDetails();
void openDetails(ExtensionSystem::PluginSpec *spec);
void openErrorDetails();
void closeDialog();
private:
ExtensionSystem::PluginView *m_view;
@@ -63,6 +66,8 @@ private:
QPushButton *m_detailsButton;
QPushButton *m_errorDetailsButton;
QPushButton *m_closeButton;
QLabel *m_restartRequired;
static bool m_isRestartRequired;
};
} // namespace Internal

View File

@@ -10,6 +10,7 @@ GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
</license>
<category>C++</category>
<description>C/C++ editor component.</description>
<url>http://qt.nokia.com</url>
<dependencyList>

View File

@@ -10,6 +10,7 @@ GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
</license>
<category>C++</category>
<description>Tools for analyzing C/C++ code.</description>
<url>http://qt.nokia.com</url>
<dependencyList>

View File

@@ -10,6 +10,7 @@ GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
</license>
<category>Version Control</category>
<description>CVS integration.</description>
<url>http://qt.nokia.com</url>
<dependencyList>

View File

@@ -10,6 +10,7 @@ GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
</license>
<category>Qt Creator</category>
<description>Debugger integration.</description>
<url>http://qt.nokia.com</url>
<dependencyList>

View File

@@ -10,6 +10,7 @@ GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
</license>
<category>Qt Creator</category>
<description>Qt Designer integration.</description>
<url>http://qt.nokia.com</url>
<dependencyList>

View File

@@ -10,6 +10,7 @@ GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
</license>
<category>Qt Creator</category>
<description>Provides the find widget and the hooks for find implementations.</description>
<url>http://qt.nokia.com</url>
<dependencyList>

View File

@@ -10,6 +10,7 @@ GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
</license>
<category>Build Systems</category>
<description>Generic support</description>
<url>http://qt.nokia.com</url>
<dependencyList>

View File

@@ -10,6 +10,7 @@ GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
</license>
<category>Version Control</category>
<description>Git integration.</description>
<url>http://qt.nokia.com</url>
<dependencyList>

View File

@@ -10,6 +10,7 @@ GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
</license>
<category>Qt Creator</category>
<description>Help system.</description>
<url>http://qt.nokia.com</url>
<dependencyList>

View File

@@ -10,6 +10,7 @@ GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
</license>
<category>Qt Creator</category>
<description>Provides the Locator widget and the hooks for Locator filter implementations.</description>
<url>http://qt.nokia.com</url>
<dependencyList>

View File

@@ -10,6 +10,7 @@ GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
</license>
<category>Version Control</category>
<description>Mercurial integration.</description>
<url>http://qt.nokia.com</url>
<dependencyList>

View File

@@ -10,6 +10,7 @@ GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
</license>
<category>Version Control</category>
<description>Perforce integration.</description>
<url>http://qt.nokia.com</url>
<dependencyList>

View File

@@ -10,6 +10,7 @@ GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
</license>
<category>Qt Creator</category>
<description>ProjectExplorer framework that can be extended with different kind of project types.</description>
<url>http://qt.nokia.com</url>
<dependencyList>

View File

@@ -16,6 +16,7 @@ General Public License version 2.1 as published by the Free Software
Foundation. Please review the following information to
ensure the GNU Lesser General Public License version 2.1 requirements
will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.</license>
<category>QML</category>
<description>Editor for QML.</description>
<url>http://qt.nokia.com</url>
<dependencyList>

View File

@@ -80,6 +80,7 @@ BauhausPlugin::BauhausPlugin() :
m_closeAllEditorsAction(new QAction(this)),
m_closeOtherEditorsAction(new QAction(this))
{
// Exceptions should never ever assert: they are handled in a number of
// places where it is actually VALID AND EXPECTED BEHAVIOUR to get an
// exception.

View File

@@ -16,6 +16,7 @@ General Public License version 2.1 as published by the Free Software
Foundation. Please review the following information to
ensure the GNU Lesser General Public License version 2.1 requirements
will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.</license>
<category>QML</category>
<description>Qml support</description>
<url>http://qt.nokia.com</url>
<dependencyList>

View File

@@ -10,6 +10,7 @@ GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
</license>
<category>QML</category>
<description>Editor for QML and JavaScript.</description>
<url>http://qt.nokia.com</url>
<dependencyList>

View File

@@ -10,6 +10,7 @@ GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
</license>
<category>QML</category>
<description>Qml support</description>
<url>http://qt.nokia.com</url>
<dependencyList>

View File

@@ -10,6 +10,7 @@ GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
</license>
<category>Build Systems</category>
<description>Provides project type for Qt 4 pro files and tools.</description>
<url>http://qt.nokia.com</url>
<dependencyList>

View File

@@ -10,6 +10,7 @@ GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
</license>
<category>Qt Creator</category>
<description>Editor for qrc files.</description>
<url>http://qt.nokia.com</url>
<dependencyList>

View File

@@ -10,6 +10,7 @@ GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
</license>
<category>Version Control</category>
<description>Subversion integration.</description>
<url>http://qt.nokia.com</url>
<dependencyList>

View File

@@ -10,6 +10,7 @@ GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
</license>
<category>Qt Creator</category>
<description>Text editor framework and the implementation of the basic text editor.</description>
<url>http://qt.nokia.com</url>
<dependencyList>

View File

@@ -10,6 +10,7 @@ GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
</license>
<category>Version Control</category>
<description>Version Control System Base Plugin</description>
<url>http://qt.nokia.com</url>
<dependencyList>

View File

@@ -10,6 +10,7 @@ GNU Lesser General Public License Usage
Alternatively, this plugin may be used under the terms of the GNU Lesser General Public License version 2.1 as published by the Free Software Foundation. Please review the following information to ensure the GNU Lesser General Public License version 2.1 requirements will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
</license>
<category>Qt Creator</category>
<description>Default Welcome Screen Plugin</description>
<url>http://qt.nokia.com</url>
<dependencyList>