1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights. These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
32 **************************************************************************/
34 #include "pluginview.h"
35 #include "pluginview_p.h"
36 #include "pluginmanager.h"
37 #include "pluginspec.h"
38 #include "plugincollection.h"
39 #include "ui_pluginview.h"
41 #include <QtCore/QDir>
42 #include <QtGui/QHeaderView>
43 #include <QtGui/QTreeWidgetItem>
44 #include <QtGui/QPalette>
49 \class ExtensionSystem::PluginView
50 \brief Widget that shows a list of all plugins and their state.
52 This can be embedded e.g. in a dialog in the application that
53 uses the plugin manager.
54 The class also provides notifications for interactions with the list.
56 \sa ExtensionSystem::PluginDetailsView
57 \sa ExtensionSystem::PluginErrorView
61 \fn void PluginView::currentPluginChanged(ExtensionSystem::PluginSpec *spec)
62 The current selection in the plugin list has changed to the
63 plugin corresponding to \a spec.
67 \fn void PluginView::pluginActivated(ExtensionSystem::PluginSpec *spec)
68 The plugin list entry corresponding to \a spec has been activated,
69 e.g. by a double-click.
72 using namespace ExtensionSystem;
74 Q_DECLARE_METATYPE(ExtensionSystem::PluginSpec*)
75 Q_DECLARE_METATYPE(ExtensionSystem::PluginCollection*)
78 \fn PluginView::PluginView(PluginManager *manager, QWidget *parent)
79 Constructs a PluginView that gets the list of plugins from the
80 given plugin \a manager with a given \a parent widget.
82 PluginView::PluginView(PluginManager *manager, QWidget *parent)
84 m_ui(new Internal::Ui::PluginView),
85 p(new Internal::PluginViewPrivate),
86 m_allowCheckStateUpdate(true),
90 QHeaderView *header = m_ui->categoryWidget->header();
91 header->setResizeMode(0, QHeaderView::ResizeToContents);
92 header->setResizeMode(2, QHeaderView::ResizeToContents);
94 m_okIcon = QIcon(QLatin1String(":/extensionsystem/images/ok.png"));
95 m_errorIcon = QIcon(QLatin1String(":/extensionsystem/images/error.png"));
96 m_notLoadedIcon = QIcon(QLatin1String(":/extensionsystem/images/notloaded.png"));
98 m_ui->categoryWidget->setColumnWidth(C_LOAD, 40);
100 // cannot disable these
101 m_whitelist << QString("Core") << QString("Locator")
102 << QString("Find") << QString("TextEditor");
104 p->manager = manager;
105 connect(p->manager, SIGNAL(pluginsChanged()), this, SLOT(updateList()));
106 connect(m_ui->categoryWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
107 this, SLOT(selectPlugin(QTreeWidgetItem*)));
108 connect(m_ui->categoryWidget, SIGNAL(itemActivated(QTreeWidgetItem*,int)),
109 this, SLOT(activatePlugin(QTreeWidgetItem*)));
115 \fn PluginView::~PluginView()
118 PluginView::~PluginView()
125 \fn PluginSpec *PluginView::currentPlugin() const
126 Returns the current selection in the list of plugins.
128 PluginSpec *PluginView::currentPlugin() const
130 if (!m_ui->categoryWidget->currentItem())
132 if (!m_ui->categoryWidget->currentItem()->data(0, Qt::UserRole).isNull())
133 return m_ui->categoryWidget->currentItem()->data(0, Qt::UserRole).value<PluginSpec *>();
137 void PluginView::updateList()
139 connect(m_ui->categoryWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
140 this, SLOT(updatePluginSettings(QTreeWidgetItem*, int)));
142 PluginCollection *defaultCollection = 0;
143 foreach(PluginCollection *collection, p->manager->pluginCollections()) {
144 if (collection->name().isEmpty()) {
145 defaultCollection = collection;
148 // State, name, load, version, vendor.
149 QTreeWidgetItem *collectionItem = new QTreeWidgetItem(QStringList()
150 << collection->name()
151 << QString() // state
153 << QString() // version
154 << QString()); // vendor
155 m_items.append(collectionItem);
157 Qt::CheckState groupState = Qt::Unchecked;
158 int state = parsePluginSpecs(collectionItem, groupState, collection->plugins());
160 collectionItem->setIcon(0, iconForState(state));
161 collectionItem->setData(C_LOAD, Qt::CheckStateRole, QVariant(groupState));
162 collectionItem->setToolTip(C_LOAD, tr("Load on Startup"));
163 collectionItem->setData(0, Qt::UserRole, qVariantFromValue(collection));
166 // add all non-categorized plugins into utilities. could also be added as root items
167 // but that makes the tree ugly.
168 QTreeWidgetItem *defaultCollectionItem = new QTreeWidgetItem(QStringList()
169 << QString(tr("Utilities"))
175 m_items.append(defaultCollectionItem);
176 Qt::CheckState groupState = Qt::Unchecked;
177 int state = parsePluginSpecs(defaultCollectionItem, groupState, defaultCollection ? defaultCollection->plugins() : QList<PluginSpec *>());
179 defaultCollectionItem->setIcon(0, iconForState(state));
180 defaultCollectionItem->setData(C_LOAD, Qt::CheckStateRole, QVariant(groupState));
181 defaultCollectionItem->setToolTip(C_LOAD, tr("Load on Startup"));
182 defaultCollectionItem->setData(0, Qt::UserRole, qVariantFromValue(defaultCollection));
184 updatePluginDependencies();
186 m_ui->categoryWidget->clear();
187 if (!m_items.isEmpty()) {
188 m_ui->categoryWidget->addTopLevelItems(m_items);
189 m_ui->categoryWidget->expandAll();
192 m_ui->categoryWidget->sortItems(0, Qt::AscendingOrder);
193 if (m_ui->categoryWidget->topLevelItemCount())
194 m_ui->categoryWidget->setCurrentItem(m_ui->categoryWidget->topLevelItem(0));
197 int PluginView::parsePluginSpecs(QTreeWidgetItem *parentItem, Qt::CheckState &groupState, QList<PluginSpec*> plugins)
202 for (int i = 0; i < plugins.length(); ++i) {
203 PluginSpec *spec = plugins[i];
204 if (spec->hasError())
205 ret |= ParsedWithErrors;
207 QTreeWidgetItem *pluginItem = new QTreeWidgetItem(QStringList()
209 << QString() // load on startup
210 << QString::fromLatin1("%1 (%2)").arg(spec->version(), spec->compatVersion())
213 pluginItem->setToolTip(0, QDir::toNativeSeparators(spec->filePath()));
214 bool ok = !spec->hasError();
215 QIcon icon = ok ? m_okIcon : m_errorIcon;
216 if (ok && (spec->state() != PluginSpec::Running))
217 icon = m_notLoadedIcon;
219 pluginItem->setIcon(0, icon);
220 pluginItem->setData(0, Qt::UserRole, qVariantFromValue(spec));
222 Qt::CheckState state = Qt::Unchecked;
223 if (spec->isEnabled()) {
228 if (!m_whitelist.contains(spec->name())) {
229 pluginItem->setData(C_LOAD, Qt::CheckStateRole, state);
231 pluginItem->setData(C_LOAD, Qt::CheckStateRole, Qt::Checked);
232 pluginItem->setFlags(Qt::ItemIsSelectable);
235 pluginItem->setToolTip(C_LOAD, tr("Load on Startup"));
237 m_specToItem.insert(spec, pluginItem);
240 parentItem->addChild(pluginItem);
242 m_items.append(pluginItem);
246 if (loadCount == plugins.length()) {
247 groupState = Qt::Checked;
249 } else if (loadCount == 0) {
250 groupState = Qt::Unchecked;
253 groupState = Qt::PartiallyChecked;
254 ret = ret | ParsedPartial;
259 QIcon PluginView::iconForState(int state)
261 if (state & ParsedWithErrors)
264 if (state & ParsedNone || state & ParsedPartial)
265 return m_notLoadedIcon;
270 void PluginView::selectPlugin(QTreeWidgetItem *current)
273 emit currentPluginChanged(0);
274 else if (current->data(0, Qt::UserRole).canConvert<PluginSpec*>())
275 emit currentPluginChanged(current->data(0, Qt::UserRole).value<PluginSpec *>());
277 emit currentPluginChanged(0);
281 void PluginView::activatePlugin(QTreeWidgetItem *item)
283 if (item->data(0, Qt::UserRole).canConvert<PluginSpec*>()) {
284 emit pluginActivated(item->data(0, Qt::UserRole).value<PluginSpec *>());
286 emit pluginActivated(0);
289 void PluginView::updatePluginSettings(QTreeWidgetItem *item, int column)
291 if (!m_allowCheckStateUpdate)
294 m_allowCheckStateUpdate = false;
296 bool loadOnStartup = item->data(C_LOAD, Qt::CheckStateRole).toBool();
298 if (item->data(0, Qt::UserRole).canConvert<PluginSpec*>()) {
299 PluginSpec *spec = item->data(0, Qt::UserRole).value<PluginSpec *>();
301 if (column == C_LOAD) {
303 spec->setEnabled(loadOnStartup);
304 updatePluginDependencies();
306 if (item->parent()) {
307 PluginCollection *collection = item->parent()->data(0, Qt::UserRole).value<PluginCollection *>();
308 Qt::CheckState state = Qt::PartiallyChecked;
310 for (int i = 0; i < collection->plugins().length(); ++i) {
311 if (collection->plugins().at(i)->isEnabled())
314 if (loadCount == collection->plugins().length())
316 else if (loadCount == 0)
317 state = Qt::Unchecked;
319 item->parent()->setData(C_LOAD, Qt::CheckStateRole, state);
322 emit pluginSettingsChanged(spec);
326 PluginCollection *collection = item->data(0, Qt::UserRole).value<PluginCollection *>();
327 for (int i = 0; i < collection->plugins().length(); ++i) {
328 PluginSpec *spec = collection->plugins().at(i);
329 QTreeWidgetItem *child = m_specToItem.value(spec);
331 if (!m_whitelist.contains(spec->name())) {
332 spec->setEnabled(loadOnStartup);
333 Qt::CheckState state = (loadOnStartup ? Qt::Checked : Qt::Unchecked);
334 child->setData(C_LOAD, Qt::CheckStateRole, state);
336 child->setData(C_LOAD, Qt::CheckStateRole, Qt::Checked);
337 child->setFlags(Qt::ItemIsSelectable);
340 updatePluginDependencies();
341 emit pluginSettingsChanged(collection->plugins().first());
344 m_allowCheckStateUpdate = true;
347 void PluginView::updatePluginDependencies()
349 foreach (PluginSpec *spec, PluginManager::instance()->loadQueue()) {
350 bool disableIndirectly = false;
351 if (m_whitelist.contains(spec->name()))
354 QHashIterator<PluginDependency, PluginSpec *> it(spec->dependencySpecs());
355 while (it.hasNext()) {
357 if (it.key().type == PluginDependency::Optional)
359 PluginSpec *depSpec = it.value();
360 if (!depSpec->isEnabled() || depSpec->isDisabledIndirectly()) {
361 disableIndirectly = true;
365 QTreeWidgetItem *childItem = m_specToItem.value(spec);
366 childItem->setDisabled(disableIndirectly);
368 if (disableIndirectly == spec->isDisabledIndirectly())
370 spec->setDisabledIndirectly(disableIndirectly);
372 if (childItem->parent() && !childItem->parent()->isExpanded())
373 childItem->parent()->setExpanded(true);