forked from qt-creator/qt-creator
Use TreeModel in plugin dialog
Change-Id: Ifc18e9779b9841a2f08c48dcd8dad36627d6e537 Reviewed-by: Eike Ziller <eike.ziller@theqtcompany.com>
This commit is contained in:
@@ -1301,10 +1301,6 @@ void PluginManagerPrivate::resolveDependencies()
|
|||||||
spec->d->resolveDependencies(pluginSpecs);
|
spec->d->resolveDependencies(pluginSpecs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset disabledIndirectly flag
|
|
||||||
foreach (PluginSpec *spec, loadQueue())
|
|
||||||
spec->d->disabledIndirectly = false;
|
|
||||||
|
|
||||||
foreach (PluginSpec *spec, loadQueue()) {
|
foreach (PluginSpec *spec, loadQueue()) {
|
||||||
spec->d->disableIndirectlyIfDependencyDisabled();
|
spec->d->disableIndirectlyIfDependencyDisabled();
|
||||||
}
|
}
|
||||||
@@ -1329,11 +1325,6 @@ PluginSpec *PluginManagerPrivate::pluginForOption(const QString &option, bool *r
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PluginManagerPrivate::disablePluginIndirectly(PluginSpec *spec)
|
|
||||||
{
|
|
||||||
spec->d->disabledIndirectly = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
PluginSpec *PluginManagerPrivate::pluginByName(const QString &name) const
|
PluginSpec *PluginManagerPrivate::pluginByName(const QString &name) const
|
||||||
{
|
{
|
||||||
foreach (PluginSpec *spec, pluginSpecs)
|
foreach (PluginSpec *spec, pluginSpecs)
|
||||||
|
|||||||
@@ -80,7 +80,6 @@ public:
|
|||||||
void setGlobalSettings(QSettings *settings);
|
void setGlobalSettings(QSettings *settings);
|
||||||
void readSettings();
|
void readSettings();
|
||||||
void writeSettings();
|
void writeSettings();
|
||||||
void disablePluginIndirectly(PluginSpec *spec);
|
|
||||||
|
|
||||||
class TestSpec {
|
class TestSpec {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -542,11 +542,6 @@ void PluginSpec::setDisabledByDefault(bool value)
|
|||||||
d->disabledByDefault = value;
|
d->disabledByDefault = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PluginSpec::setDisabledIndirectly(bool value)
|
|
||||||
{
|
|
||||||
d->disabledIndirectly = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PluginSpec::setForceEnabled(bool value)
|
void PluginSpec::setForceEnabled(bool value)
|
||||||
{
|
{
|
||||||
d->forceEnabled = value;
|
d->forceEnabled = value;
|
||||||
|
|||||||
@@ -113,7 +113,6 @@ public:
|
|||||||
|
|
||||||
void setEnabled(bool value);
|
void setEnabled(bool value);
|
||||||
void setDisabledByDefault(bool value);
|
void setDisabledByDefault(bool value);
|
||||||
void setDisabledIndirectly(bool value);
|
|
||||||
void setForceEnabled(bool value);
|
void setForceEnabled(bool value);
|
||||||
void setForceDisabled(bool value);
|
void setForceDisabled(bool value);
|
||||||
|
|
||||||
|
|||||||
@@ -32,14 +32,17 @@
|
|||||||
#include "pluginmanager.h"
|
#include "pluginmanager.h"
|
||||||
#include "pluginspec.h"
|
#include "pluginspec.h"
|
||||||
#include "plugincollection.h"
|
#include "plugincollection.h"
|
||||||
|
|
||||||
|
#include <utils/algorithm.h>
|
||||||
#include <utils/itemviews.h>
|
#include <utils/itemviews.h>
|
||||||
|
#include <utils/treemodel.h>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QGridLayout>
|
#include <QGridLayout>
|
||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
#include <QPalette>
|
#include <QSet>
|
||||||
#include <QTreeWidgetItem>
|
#include <QItemSelectionModel>
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\class ExtensionSystem::PluginView
|
\class ExtensionSystem::PluginView
|
||||||
@@ -66,56 +69,244 @@
|
|||||||
for example by a double-click.
|
for example by a double-click.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using namespace ExtensionSystem;
|
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(ExtensionSystem::PluginSpec*)
|
Q_DECLARE_METATYPE(ExtensionSystem::PluginSpec*)
|
||||||
Q_DECLARE_METATYPE(ExtensionSystem::PluginCollection*)
|
Q_DECLARE_METATYPE(ExtensionSystem::PluginCollection*)
|
||||||
|
|
||||||
|
using namespace Utils;
|
||||||
|
|
||||||
|
namespace ExtensionSystem {
|
||||||
|
|
||||||
|
enum Columns { NameColumn, LoadedColumn, VersionColumn, VendorColumn, };
|
||||||
|
|
||||||
|
enum IconIndex { OkIcon, ErrorIcon, NotLoadedIcon };
|
||||||
|
|
||||||
|
static const QIcon &icon(int num)
|
||||||
|
{
|
||||||
|
static QIcon icons[] = {
|
||||||
|
QIcon(QLatin1String(":/extensionsystem/images/ok.png")),
|
||||||
|
QIcon(QLatin1String(":/extensionsystem/images/error.png")),
|
||||||
|
QIcon(QLatin1String(":/extensionsystem/images/notloaded.png")),
|
||||||
|
};
|
||||||
|
return icons[num];
|
||||||
|
}
|
||||||
|
|
||||||
|
class PluginItem : public TreeItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PluginItem(PluginSpec *spec, PluginView *view)
|
||||||
|
: m_spec(spec), m_view(view)
|
||||||
|
{}
|
||||||
|
|
||||||
|
int columnCount() const { return 4; }
|
||||||
|
|
||||||
|
QVariant data(int column, int role) const
|
||||||
|
{
|
||||||
|
switch (column) {
|
||||||
|
case NameColumn:
|
||||||
|
if (role == Qt::DisplayRole)
|
||||||
|
return m_spec->name();
|
||||||
|
if (role == Qt::ToolTipRole)
|
||||||
|
return QDir::toNativeSeparators(m_spec->filePath());
|
||||||
|
if (role == Qt::DecorationRole) {
|
||||||
|
bool ok = !m_spec->hasError();
|
||||||
|
QIcon i = icon(ok ? OkIcon : ErrorIcon);
|
||||||
|
if (ok && m_spec->state() != PluginSpec::Running)
|
||||||
|
i = icon(NotLoadedIcon);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LoadedColumn:
|
||||||
|
if (!m_spec->isAvailableForHostPlatform()) {
|
||||||
|
if (role == Qt::CheckStateRole)
|
||||||
|
return Qt::Unchecked;
|
||||||
|
if (role == Qt::ToolTipRole)
|
||||||
|
return PluginView::tr("Plugin is not available on this platform.");
|
||||||
|
} else if (m_spec->isRequired()) {
|
||||||
|
if (role == Qt::CheckStateRole)
|
||||||
|
return Qt::Checked;
|
||||||
|
if (role == Qt::ToolTipRole)
|
||||||
|
return PluginView::tr("Plugin is required.");
|
||||||
|
} else {
|
||||||
|
if (role == Qt::CheckStateRole)
|
||||||
|
return m_spec->isEnabledInSettings() ? Qt::Checked : Qt::Unchecked;
|
||||||
|
if (role == Qt::ToolTipRole)
|
||||||
|
return PluginView::tr("Load on startup");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VersionColumn:
|
||||||
|
if (role == Qt::DisplayRole)
|
||||||
|
return QString::fromLatin1("%1 (%2)").arg(m_spec->version(), m_spec->compatVersion());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VendorColumn:
|
||||||
|
if (role == Qt::DisplayRole)
|
||||||
|
return m_spec->vendor();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setData(int column, const QVariant &data, int role)
|
||||||
|
{
|
||||||
|
if (column == LoadedColumn && role == Qt::CheckStateRole) {
|
||||||
|
m_spec->setEnabled(data.toBool());
|
||||||
|
update();
|
||||||
|
parent()->update();
|
||||||
|
emit m_view->pluginSettingsChanged(m_spec);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEnabled() const
|
||||||
|
{
|
||||||
|
if (m_spec->isRequired() || !m_spec->isAvailableForHostPlatform())
|
||||||
|
return false;
|
||||||
|
foreach (PluginSpec *spec, m_view->m_pluginDependencies.value(m_spec))
|
||||||
|
if (!spec->isEnabledInSettings())
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::ItemFlags flags(int column) const
|
||||||
|
{
|
||||||
|
Qt::ItemFlags ret = Qt::ItemIsSelectable;
|
||||||
|
|
||||||
|
if (isEnabled())
|
||||||
|
ret |= Qt::ItemIsEnabled;
|
||||||
|
|
||||||
|
if (column == LoadedColumn) {
|
||||||
|
if (m_spec->isAvailableForHostPlatform() && !m_spec->isRequired())
|
||||||
|
ret |= Qt::ItemIsEditable | Qt ::ItemIsUserCheckable;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
PluginSpec *m_spec; // Not owned.
|
||||||
|
PluginView *m_view; // Not owned.
|
||||||
|
};
|
||||||
|
|
||||||
|
class CollectionItem : public TreeItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CollectionItem(const QString &name, QList<PluginSpec *> plugins, PluginView *view)
|
||||||
|
: m_name(name), m_plugins(plugins), m_view(view)
|
||||||
|
{
|
||||||
|
foreach (PluginSpec *spec, plugins)
|
||||||
|
appendChild(new PluginItem(spec, view));
|
||||||
|
}
|
||||||
|
|
||||||
|
int columnCount() const { return 4; }
|
||||||
|
|
||||||
|
QVariant data(int column, int role) const
|
||||||
|
{
|
||||||
|
if (column == NameColumn) {
|
||||||
|
if (role == Qt::DisplayRole)
|
||||||
|
return m_name;
|
||||||
|
if (role == Qt::DecorationRole) {
|
||||||
|
foreach (PluginSpec *spec, m_plugins) {
|
||||||
|
if (spec->hasError())
|
||||||
|
return icon(ErrorIcon);
|
||||||
|
if (!spec->isEnabledInSettings())
|
||||||
|
return icon(NotLoadedIcon);
|
||||||
|
}
|
||||||
|
return icon(OkIcon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (column == LoadedColumn) {
|
||||||
|
if (role == Qt::ToolTipRole)
|
||||||
|
return PluginView::tr("Load on Startup");
|
||||||
|
if (role == Qt::CheckStateRole) {
|
||||||
|
int checkedCount = 0;
|
||||||
|
foreach (PluginSpec *spec, m_plugins) {
|
||||||
|
if (spec->isEnabledInSettings())
|
||||||
|
++checkedCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkedCount == 0)
|
||||||
|
return Qt::Unchecked;
|
||||||
|
if (checkedCount == m_plugins.length())
|
||||||
|
return Qt::Checked;
|
||||||
|
return Qt::PartiallyChecked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setData(int column, const QVariant &data, int role)
|
||||||
|
{
|
||||||
|
if (column == LoadedColumn && role == Qt::CheckStateRole) {
|
||||||
|
foreach (TreeItem *item, children())
|
||||||
|
static_cast<PluginItem *>(item)->setData(column, data, role);
|
||||||
|
update();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::ItemFlags flags(int column) const
|
||||||
|
{
|
||||||
|
Qt::ItemFlags ret = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
|
||||||
|
if (column == LoadedColumn)
|
||||||
|
ret |= Qt::ItemIsEditable | Qt::ItemIsUserCheckable;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
QString m_name;
|
||||||
|
QList<PluginSpec *> m_plugins;
|
||||||
|
PluginView *m_view; // Not owned.
|
||||||
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Constructs a PluginView that gets the list of plugins from the
|
Constructs a PluginView that gets the list of plugins from the
|
||||||
given plugin \a manager with a given \a parent widget.
|
given plugin \a manager with a given \a parent widget.
|
||||||
*/
|
*/
|
||||||
PluginView::PluginView(QWidget *parent)
|
PluginView::PluginView(QWidget *parent)
|
||||||
: QWidget(parent),
|
: QWidget(parent)
|
||||||
m_allowCheckStateUpdate(true),
|
|
||||||
C_LOAD(1)
|
|
||||||
{
|
{
|
||||||
m_categoryWidget = new Utils::TreeWidget(this);
|
m_categoryView = new TreeView(this);
|
||||||
m_categoryWidget->setAlternatingRowColors(true);
|
m_categoryView->setAlternatingRowColors(true);
|
||||||
m_categoryWidget->setIndentation(20);
|
m_categoryView->setIndentation(20);
|
||||||
m_categoryWidget->setUniformRowHeights(true);
|
m_categoryView->setUniformRowHeights(true);
|
||||||
m_categoryWidget->setSortingEnabled(true);
|
m_categoryView->setSortingEnabled(true);
|
||||||
m_categoryWidget->setColumnCount(4);
|
m_categoryView->setColumnWidth(LoadedColumn, 40);
|
||||||
m_categoryWidget->setColumnWidth(C_LOAD, 40);
|
m_categoryView->header()->setDefaultSectionSize(120);
|
||||||
m_categoryWidget->header()->setDefaultSectionSize(120);
|
m_categoryView->header()->setMinimumSectionSize(35);
|
||||||
m_categoryWidget->header()->setMinimumSectionSize(35);
|
m_categoryView->setActivationMode(Utils::DoubleClickActivation);
|
||||||
m_categoryWidget->setActivationMode(Utils::DoubleClickActivation);
|
m_categoryView->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||||
|
m_categoryView->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||||
|
|
||||||
QTreeWidgetItem *headerItem = m_categoryWidget->headerItem();
|
m_model = new TreeModel(this);
|
||||||
headerItem->setText(0, tr("Name"));
|
m_model->setRootItem(new TreeItem(QStringList()
|
||||||
headerItem->setText(1, tr("Load"));
|
<< tr("Name") << tr("Load") << tr("Version") << tr("Vendor")));
|
||||||
headerItem->setText(2, tr("Version"));
|
m_categoryView->setModel(m_model);
|
||||||
headerItem->setText(3, tr("Vendor"));
|
|
||||||
|
|
||||||
QGridLayout *gridLayout = new QGridLayout(this);
|
QGridLayout *gridLayout = new QGridLayout(this);
|
||||||
gridLayout->setContentsMargins(2, 2, 2, 2);
|
gridLayout->setContentsMargins(2, 2, 2, 2);
|
||||||
gridLayout->addWidget(m_categoryWidget, 1, 0, 1, 1);
|
gridLayout->addWidget(m_categoryView, 1, 0, 1, 1);
|
||||||
|
|
||||||
QHeaderView *header = m_categoryWidget->header();
|
QHeaderView *header = m_categoryView->header();
|
||||||
header->setSectionResizeMode(0, QHeaderView::ResizeToContents);
|
header->setSectionResizeMode(0, QHeaderView::ResizeToContents);
|
||||||
header->setSectionResizeMode(2, QHeaderView::ResizeToContents);
|
header->setSectionResizeMode(2, QHeaderView::ResizeToContents);
|
||||||
|
|
||||||
m_okIcon = QIcon(QLatin1String(":/extensionsystem/images/ok.png"));
|
connect(PluginManager::instance(), &PluginManager::pluginsChanged,
|
||||||
m_errorIcon = QIcon(QLatin1String(":/extensionsystem/images/error.png"));
|
this, &PluginView::updatePlugins);
|
||||||
m_notLoadedIcon = QIcon(QLatin1String(":/extensionsystem/images/notloaded.png"));
|
|
||||||
|
|
||||||
connect(PluginManager::instance(), SIGNAL(pluginsChanged()), this, SLOT(updateList()));
|
connect(m_categoryView, &QAbstractItemView::activated,
|
||||||
connect(m_categoryWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
|
[this](const QModelIndex &idx) { pluginActivated(pluginForIndex(idx)); });
|
||||||
this, SLOT(selectPlugin(QTreeWidgetItem*)));
|
|
||||||
connect(m_categoryWidget, SIGNAL(itemActivated(QTreeWidgetItem*,int)),
|
|
||||||
this, SLOT(activatePlugin(QTreeWidgetItem*)));
|
|
||||||
|
|
||||||
updateList();
|
connect(m_categoryView->selectionModel(), &QItemSelectionModel::currentChanged,
|
||||||
|
[this](const QModelIndex &idx) { currentPluginChanged(pluginForIndex(idx)); });
|
||||||
|
|
||||||
|
updatePlugins();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -130,253 +321,69 @@ PluginView::~PluginView()
|
|||||||
*/
|
*/
|
||||||
PluginSpec *PluginView::currentPlugin() const
|
PluginSpec *PluginView::currentPlugin() const
|
||||||
{
|
{
|
||||||
if (!m_categoryWidget->currentItem())
|
return pluginForIndex(m_categoryView->currentIndex());
|
||||||
return 0;
|
|
||||||
if (!m_categoryWidget->currentItem()->data(0, Qt::UserRole).isNull())
|
|
||||||
return m_categoryWidget->currentItem()->data(0, Qt::UserRole).value<PluginSpec *>();
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PluginView::updateList()
|
PluginSpec *PluginView::pluginForIndex(const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
connect(m_categoryWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
|
auto item = dynamic_cast<PluginItem *>(m_model->itemFromIndex(index));
|
||||||
this, SLOT(updatePluginSettings(QTreeWidgetItem*,int)));
|
return item ? item->m_spec: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void queryDependendPlugins(PluginSpec *spec, QSet<PluginSpec *> *dependencies)
|
||||||
|
{
|
||||||
|
QHashIterator<PluginDependency, PluginSpec *> it(spec->dependencySpecs());
|
||||||
|
while (it.hasNext()) {
|
||||||
|
it.next();
|
||||||
|
PluginSpec *dep = it.value();
|
||||||
|
if (!dependencies->contains(dep)) {
|
||||||
|
dependencies->insert(dep);
|
||||||
|
queryDependendPlugins(dep, dependencies);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PluginView::updatePlugins()
|
||||||
|
{
|
||||||
|
// Dependencies.
|
||||||
|
m_pluginDependencies.clear();
|
||||||
|
foreach (PluginSpec *spec, PluginManager::loadQueue()) {
|
||||||
|
QSet<PluginSpec *> deps;
|
||||||
|
queryDependendPlugins(spec, &deps);
|
||||||
|
m_pluginDependencies[spec] = deps;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Model.
|
||||||
|
m_model->removeItems();
|
||||||
|
|
||||||
PluginCollection *defaultCollection = 0;
|
PluginCollection *defaultCollection = 0;
|
||||||
|
QList<CollectionItem *> collections;
|
||||||
foreach (PluginCollection *collection, PluginManager::pluginCollections()) {
|
foreach (PluginCollection *collection, PluginManager::pluginCollections()) {
|
||||||
if (collection->name().isEmpty() || collection->plugins().isEmpty()) {
|
if (collection->name().isEmpty() || collection->plugins().isEmpty()) {
|
||||||
defaultCollection = collection;
|
defaultCollection = collection;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// State, name, load, version, vendor.
|
collections.append(new CollectionItem(collection->name(), collection->plugins(), this));
|
||||||
QTreeWidgetItem *collectionItem = new QTreeWidgetItem(QStringList()
|
|
||||||
<< collection->name()
|
|
||||||
<< QString() // state
|
|
||||||
<< QString() // load
|
|
||||||
<< QString() // version
|
|
||||||
<< QString()); // vendor
|
|
||||||
m_items.append(collectionItem);
|
|
||||||
|
|
||||||
Qt::CheckState groupState = Qt::Unchecked;
|
|
||||||
int state = parsePluginSpecs(collectionItem, groupState, collection->plugins());
|
|
||||||
|
|
||||||
collectionItem->setIcon(0, iconForState(state));
|
|
||||||
collectionItem->setData(C_LOAD, Qt::CheckStateRole, QVariant(groupState));
|
|
||||||
collectionItem->setToolTip(C_LOAD, tr("Load on Startup"));
|
|
||||||
collectionItem->setData(0, Qt::UserRole, qVariantFromValue(collection));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<PluginSpec *> plugins = defaultCollection ? defaultCollection->plugins() : QList<PluginSpec *>();
|
QList<PluginSpec *> plugins;
|
||||||
|
if (defaultCollection)
|
||||||
|
plugins = defaultCollection->plugins();
|
||||||
|
|
||||||
if (!plugins.isEmpty()) {
|
if (!plugins.isEmpty()) {
|
||||||
// add all non-categorized plugins into utilities. could also be added as root items
|
// add all non-categorized plugins into utilities. could also be added as root items
|
||||||
// but that makes the tree ugly.
|
// but that makes the tree ugly.
|
||||||
QTreeWidgetItem *defaultCollectionItem = new QTreeWidgetItem(QStringList()
|
collections.append(new CollectionItem(tr("Utilities"), plugins, this));
|
||||||
<< QString(tr("Utilities"))
|
|
||||||
<< QString()
|
|
||||||
<< QString()
|
|
||||||
<< QString()
|
|
||||||
<< QString());
|
|
||||||
|
|
||||||
m_items.append(defaultCollectionItem);
|
|
||||||
Qt::CheckState groupState = Qt::Unchecked;
|
|
||||||
int state = parsePluginSpecs(defaultCollectionItem, groupState, plugins);
|
|
||||||
|
|
||||||
defaultCollectionItem->setIcon(0, iconForState(state));
|
|
||||||
defaultCollectionItem->setData(C_LOAD, Qt::CheckStateRole, QVariant(groupState));
|
|
||||||
defaultCollectionItem->setToolTip(C_LOAD, tr("Load on Startup"));
|
|
||||||
defaultCollectionItem->setData(0, Qt::UserRole, qVariantFromValue(defaultCollection));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePluginDependencies();
|
Utils::sort(collections, [](CollectionItem *a, CollectionItem *b) -> bool
|
||||||
|
{ return a->m_name < b->m_name; });
|
||||||
|
|
||||||
m_categoryWidget->clear();
|
foreach (CollectionItem *collection, collections)
|
||||||
if (!m_items.isEmpty()) {
|
m_model->rootItem()->appendChild(collection);
|
||||||
m_categoryWidget->addTopLevelItems(m_items);
|
|
||||||
m_categoryWidget->expandAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_categoryWidget->sortItems(0, Qt::AscendingOrder);
|
m_model->layoutChanged();
|
||||||
if (m_categoryWidget->topLevelItemCount())
|
m_categoryView->expandAll();
|
||||||
m_categoryWidget->setCurrentItem(m_categoryWidget->topLevelItem(0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int PluginView::parsePluginSpecs(QTreeWidgetItem *parentItem, Qt::CheckState &groupState, QList<PluginSpec*> plugins)
|
} // namespace ExtensionSystem
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
int checkedCount = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < plugins.length(); ++i) {
|
|
||||||
PluginSpec *spec = plugins[i];
|
|
||||||
if (spec->hasError())
|
|
||||||
ret |= ParsedWithErrors;
|
|
||||||
|
|
||||||
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->isEnabledInSettings()) {
|
|
||||||
state = Qt::Checked;
|
|
||||||
++checkedCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!spec->isAvailableForHostPlatform()) {
|
|
||||||
pluginItem->setData(C_LOAD, Qt::CheckStateRole, Qt::Unchecked);
|
|
||||||
pluginItem->setFlags(Qt::ItemIsSelectable);
|
|
||||||
pluginItem->setToolTip(C_LOAD, tr("Plugin is not available on this platform."));
|
|
||||||
} else if (spec->isRequired()){
|
|
||||||
pluginItem->setData(C_LOAD, Qt::CheckStateRole, Qt::Checked);
|
|
||||||
pluginItem->setFlags(Qt::ItemIsSelectable);
|
|
||||||
pluginItem->setToolTip(C_LOAD, tr("Plugin is required."));
|
|
||||||
} else {
|
|
||||||
pluginItem->setData(C_LOAD, Qt::CheckStateRole, state);
|
|
||||||
pluginItem->setToolTip(C_LOAD, tr("Load on startup"));
|
|
||||||
}
|
|
||||||
|
|
||||||
m_specToItem.insert(spec, pluginItem);
|
|
||||||
|
|
||||||
if (parentItem)
|
|
||||||
parentItem->addChild(pluginItem);
|
|
||||||
else
|
|
||||||
m_items.append(pluginItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (checkedCount == 0) {
|
|
||||||
groupState = Qt::Unchecked;
|
|
||||||
ret |= ParsedNone;
|
|
||||||
} else if (checkedCount == plugins.length()) {
|
|
||||||
groupState = Qt::Checked;
|
|
||||||
ret |= ParsedAll;
|
|
||||||
} else {
|
|
||||||
groupState = Qt::PartiallyChecked;
|
|
||||||
ret = ret | ParsedPartial;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
QIcon PluginView::iconForState(int state)
|
|
||||||
{
|
|
||||||
if (state & ParsedWithErrors)
|
|
||||||
return m_errorIcon;
|
|
||||||
|
|
||||||
if (state & ParsedNone || state & ParsedPartial)
|
|
||||||
return m_notLoadedIcon;
|
|
||||||
|
|
||||||
return m_okIcon;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PluginView::selectPlugin(QTreeWidgetItem *current)
|
|
||||||
{
|
|
||||||
if (!current)
|
|
||||||
emit currentPluginChanged(0);
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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->setEnabled(loadOnStartup);
|
|
||||||
updatePluginDependencies();
|
|
||||||
|
|
||||||
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)->isEnabledInSettings())
|
|
||||||
++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 (spec->isAvailableForHostPlatform() && !spec->isRequired()) {
|
|
||||||
spec->setEnabled(loadOnStartup);
|
|
||||||
Qt::CheckState state = (loadOnStartup ? Qt::Checked : Qt::Unchecked);
|
|
||||||
child->setData(C_LOAD, Qt::CheckStateRole, state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
updatePluginDependencies();
|
|
||||||
if (!collection->plugins().isEmpty())
|
|
||||||
emit pluginSettingsChanged(collection->plugins().first());
|
|
||||||
}
|
|
||||||
|
|
||||||
m_allowCheckStateUpdate = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PluginView::updatePluginDependencies()
|
|
||||||
{
|
|
||||||
foreach (PluginSpec *spec, PluginManager::loadQueue()) {
|
|
||||||
bool disableIndirectly = false;
|
|
||||||
if (spec->isRequired())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
QHashIterator<PluginDependency, PluginSpec *> it(spec->dependencySpecs());
|
|
||||||
while (it.hasNext()) {
|
|
||||||
it.next();
|
|
||||||
if (it.key().type == PluginDependency::Optional)
|
|
||||||
continue;
|
|
||||||
PluginSpec *depSpec = it.value();
|
|
||||||
if (!depSpec->isEnabledInSettings() || depSpec->isDisabledIndirectly()) {
|
|
||||||
disableIndirectly = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
QTreeWidgetItem *childItem = m_specToItem.value(spec);
|
|
||||||
childItem->setDisabled(disableIndirectly || !spec->isAvailableForHostPlatform());
|
|
||||||
|
|
||||||
if (disableIndirectly == spec->isDisabledIndirectly())
|
|
||||||
continue;
|
|
||||||
spec->setDisabledIndirectly(disableIndirectly);
|
|
||||||
|
|
||||||
if (childItem->parent() && !childItem->parent()->isExpanded())
|
|
||||||
childItem->parent()->setExpanded(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -33,21 +33,22 @@
|
|||||||
|
|
||||||
#include "extensionsystem_global.h"
|
#include "extensionsystem_global.h"
|
||||||
|
|
||||||
#include <QHash>
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QIcon>
|
#include <QSet>
|
||||||
|
#include <QHash>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
namespace Utils {
|
||||||
class QTreeWidgetItem;
|
class TreeItem;
|
||||||
QT_END_NAMESPACE
|
class TreeModel;
|
||||||
|
class TreeView;
|
||||||
namespace Utils { class TreeWidget; }
|
} // namespace Utils
|
||||||
|
|
||||||
namespace ExtensionSystem {
|
namespace ExtensionSystem {
|
||||||
|
|
||||||
class PluginManager;
|
class PluginManager;
|
||||||
class PluginSpec;
|
class PluginSpec;
|
||||||
class PluginCollection;
|
class PluginItem;
|
||||||
|
class CollectionItem;
|
||||||
|
|
||||||
class EXTENSIONSYSTEM_EXPORT PluginView : public QWidget
|
class EXTENSIONSYSTEM_EXPORT PluginView : public QWidget
|
||||||
{
|
{
|
||||||
@@ -64,28 +65,16 @@ signals:
|
|||||||
void pluginActivated(ExtensionSystem::PluginSpec *spec);
|
void pluginActivated(ExtensionSystem::PluginSpec *spec);
|
||||||
void pluginSettingsChanged(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:
|
private:
|
||||||
enum ParsedState { ParsedNone = 1, ParsedPartial = 2, ParsedAll = 4, ParsedWithErrors = 8};
|
PluginSpec *pluginForIndex(const QModelIndex &index) const;
|
||||||
QIcon iconForState(int state);
|
void updatePlugins();
|
||||||
void updatePluginDependencies();
|
|
||||||
int parsePluginSpecs(QTreeWidgetItem *parentItem, Qt::CheckState &groupState, QList<PluginSpec*> plugins);
|
|
||||||
|
|
||||||
Utils::TreeWidget *m_categoryWidget;
|
Utils::TreeView *m_categoryView;
|
||||||
QList<QTreeWidgetItem*> m_items;
|
Utils::TreeModel *m_model;
|
||||||
QHash<PluginSpec*, QTreeWidgetItem*> m_specToItem;
|
|
||||||
|
|
||||||
QIcon m_okIcon;
|
friend class CollectionItem;
|
||||||
QIcon m_errorIcon;
|
friend class PluginItem;
|
||||||
QIcon m_notLoadedIcon;
|
QHash<PluginSpec *, QSet<PluginSpec *>> m_pluginDependencies;
|
||||||
bool m_allowCheckStateUpdate;
|
|
||||||
|
|
||||||
const int C_LOAD;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespae ExtensionSystem
|
} // namespae ExtensionSystem
|
||||||
|
|||||||
Reference in New Issue
Block a user