OSDN Git Service

bb631ec28d50cf1dde798952b3ab611e0ef94a02
[qt-creator-jp/qt-creator-jp.git] / src / libs / extensionsystem / pluginview.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
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
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
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.
24 **
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.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
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"
40
41 #include <QtCore/QDir>
42 #include <QtGui/QHeaderView>
43 #include <QtGui/QTreeWidgetItem>
44 #include <QtGui/QPalette>
45
46 #include <QtDebug>
47
48 /*!
49     \class ExtensionSystem::PluginView
50     \brief Widget that shows a list of all plugins and their state.
51
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.
55
56     \sa ExtensionSystem::PluginDetailsView
57     \sa ExtensionSystem::PluginErrorView
58 */
59
60 /*!
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.
64 */
65
66 /*!
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.
70 */
71
72 using namespace ExtensionSystem;
73
74 Q_DECLARE_METATYPE(ExtensionSystem::PluginSpec*)
75 Q_DECLARE_METATYPE(ExtensionSystem::PluginCollection*)
76
77 /*!
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.
81 */
82 PluginView::PluginView(PluginManager *manager, QWidget *parent)
83     : QWidget(parent),
84       m_ui(new Internal::Ui::PluginView),
85       p(new Internal::PluginViewPrivate),
86       m_allowCheckStateUpdate(true),
87       C_LOAD(1)
88 {
89     m_ui->setupUi(this);
90     QHeaderView *header = m_ui->categoryWidget->header();
91     header->setResizeMode(0, QHeaderView::ResizeToContents);
92     header->setResizeMode(2, QHeaderView::ResizeToContents);
93
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"));
97
98     m_ui->categoryWidget->setColumnWidth(C_LOAD, 40);
99
100     // cannot disable these
101     m_whitelist << QString("Core") << QString("Locator")
102                 << QString("Find") << QString("TextEditor");
103
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*)));
110
111     updateList();
112 }
113
114 /*!
115     \fn PluginView::~PluginView()
116     \internal
117 */
118 PluginView::~PluginView()
119 {
120     delete p;
121     delete m_ui;
122 }
123
124 /*!
125     \fn PluginSpec *PluginView::currentPlugin() const
126     Returns the current selection in the list of plugins.
127 */
128 PluginSpec *PluginView::currentPlugin() const
129 {
130     if (!m_ui->categoryWidget->currentItem())
131         return 0;
132     if (!m_ui->categoryWidget->currentItem()->data(0, Qt::UserRole).isNull())
133         return m_ui->categoryWidget->currentItem()->data(0, Qt::UserRole).value<PluginSpec *>();
134     return 0;
135 }
136
137 void PluginView::updateList()
138 {
139     connect(m_ui->categoryWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
140             this, SLOT(updatePluginSettings(QTreeWidgetItem*, int)));
141
142     PluginCollection *defaultCollection = 0;
143     foreach(PluginCollection *collection, p->manager->pluginCollections()) {
144         if (collection->name().isEmpty()) {
145             defaultCollection = collection;
146             continue;
147         }
148         // State, name, load, version, vendor.
149         QTreeWidgetItem *collectionItem = new QTreeWidgetItem(QStringList()
150             << collection->name()
151             << QString()    // state
152             << QString()    // load
153             << QString()    // version
154             << QString());  // vendor
155         m_items.append(collectionItem);
156
157         Qt::CheckState groupState = Qt::Unchecked;
158         int state = parsePluginSpecs(collectionItem, groupState, collection->plugins());
159
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));
164     }
165
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"))
170         << QString()
171         << QString()
172         << QString()
173         << QString());
174
175     m_items.append(defaultCollectionItem);
176     Qt::CheckState groupState = Qt::Unchecked;
177     int state = parsePluginSpecs(defaultCollectionItem, groupState, defaultCollection ? defaultCollection->plugins() : QList<PluginSpec *>());
178
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));
183
184     updatePluginDependencies();
185
186     m_ui->categoryWidget->clear();
187     if (!m_items.isEmpty()) {
188         m_ui->categoryWidget->addTopLevelItems(m_items);
189         m_ui->categoryWidget->expandAll();
190     }
191
192     m_ui->categoryWidget->sortItems(0, Qt::AscendingOrder);
193     if (m_ui->categoryWidget->topLevelItemCount())
194         m_ui->categoryWidget->setCurrentItem(m_ui->categoryWidget->topLevelItem(0));
195 }
196
197 int PluginView::parsePluginSpecs(QTreeWidgetItem *parentItem, Qt::CheckState &groupState, QList<PluginSpec*> plugins)
198 {
199     int ret = 0;
200     int loadCount = 0;
201
202     for (int i = 0; i < plugins.length(); ++i) {
203         PluginSpec *spec = plugins[i];
204         if (spec->hasError())
205             ret |= ParsedWithErrors;
206
207         QTreeWidgetItem *pluginItem = new QTreeWidgetItem(QStringList()
208             << spec->name()
209             << QString()    // load on startup
210             << QString::fromLatin1("%1 (%2)").arg(spec->version(), spec->compatVersion())
211             << spec->vendor());
212
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;
218
219         pluginItem->setIcon(0, icon);
220         pluginItem->setData(0, Qt::UserRole, qVariantFromValue(spec));
221
222         Qt::CheckState state = Qt::Unchecked;
223         if (spec->isEnabled()) {
224             state = Qt::Checked;
225             ++loadCount;
226         }
227
228         if (!m_whitelist.contains(spec->name())) {
229             pluginItem->setData(C_LOAD, Qt::CheckStateRole, state);
230         } else {
231             pluginItem->setData(C_LOAD, Qt::CheckStateRole, Qt::Checked);
232             pluginItem->setFlags(Qt::ItemIsSelectable);
233         }
234
235         pluginItem->setToolTip(C_LOAD, tr("Load on Startup"));
236
237         m_specToItem.insert(spec, pluginItem);
238
239         if (parentItem)
240             parentItem->addChild(pluginItem);
241         else
242             m_items.append(pluginItem);
243
244     }
245
246     if (loadCount == plugins.length()) {
247         groupState = Qt::Checked;
248         ret |= ParsedAll;
249     } else if (loadCount == 0) {
250         groupState = Qt::Unchecked;
251         ret |= ParsedNone;
252     } else {
253         groupState = Qt::PartiallyChecked;
254         ret = ret | ParsedPartial;
255     }
256     return ret;
257 }
258
259 QIcon PluginView::iconForState(int state)
260 {
261     if (state & ParsedWithErrors)
262         return m_errorIcon;
263
264     if (state & ParsedNone || state & ParsedPartial)
265         return m_notLoadedIcon;
266
267     return m_okIcon;
268 }
269
270 void PluginView::selectPlugin(QTreeWidgetItem *current)
271 {
272     if (!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 *>());
276     else
277         emit currentPluginChanged(0);
278
279 }
280
281 void PluginView::activatePlugin(QTreeWidgetItem *item)
282 {
283     if (item->data(0, Qt::UserRole).canConvert<PluginSpec*>()) {
284         emit pluginActivated(item->data(0, Qt::UserRole).value<PluginSpec *>());
285     } else
286         emit pluginActivated(0);
287 }
288
289 void PluginView::updatePluginSettings(QTreeWidgetItem *item, int column)
290 {
291     if (!m_allowCheckStateUpdate)
292         return;
293
294     m_allowCheckStateUpdate = false;
295
296     bool loadOnStartup = item->data(C_LOAD, Qt::CheckStateRole).toBool();
297
298     if (item->data(0, Qt::UserRole).canConvert<PluginSpec*>()) {
299         PluginSpec *spec = item->data(0, Qt::UserRole).value<PluginSpec *>();
300
301         if (column == C_LOAD) {
302
303             spec->setEnabled(loadOnStartup);
304             updatePluginDependencies();
305
306             if (item->parent()) {
307                 PluginCollection *collection = item->parent()->data(0, Qt::UserRole).value<PluginCollection *>();
308                 Qt::CheckState state = Qt::PartiallyChecked;
309                 int loadCount = 0;
310                 for (int i = 0; i < collection->plugins().length(); ++i) {
311                     if (collection->plugins().at(i)->isEnabled())
312                         ++loadCount;
313                 }
314                 if (loadCount == collection->plugins().length())
315                     state = Qt::Checked;
316                 else if (loadCount == 0)
317                     state = Qt::Unchecked;
318
319                 item->parent()->setData(C_LOAD, Qt::CheckStateRole, state);
320             }
321
322             emit pluginSettingsChanged(spec);
323         }
324
325     } else {
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);
330
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);
335             } else {
336                 child->setData(C_LOAD, Qt::CheckStateRole, Qt::Checked);
337                 child->setFlags(Qt::ItemIsSelectable);
338             }
339         }
340         updatePluginDependencies();
341         emit pluginSettingsChanged(collection->plugins().first());
342     }
343
344     m_allowCheckStateUpdate = true;
345 }
346
347 void PluginView::updatePluginDependencies()
348 {
349     foreach (PluginSpec *spec, PluginManager::instance()->loadQueue()) {
350         bool disableIndirectly = false;
351         if (m_whitelist.contains(spec->name()))
352             continue;
353
354         QHashIterator<PluginDependency, PluginSpec *> it(spec->dependencySpecs());
355         while (it.hasNext()) {
356             it.next();
357             if (it.key().type == PluginDependency::Optional)
358                 continue;
359             PluginSpec *depSpec = it.value();
360             if (!depSpec->isEnabled() || depSpec->isDisabledIndirectly()) {
361                 disableIndirectly = true;
362                 break;
363             }
364         }
365         QTreeWidgetItem *childItem = m_specToItem.value(spec);
366         childItem->setDisabled(disableIndirectly);
367
368         if (disableIndirectly == spec->isDisabledIndirectly())
369             continue;
370         spec->setDisabledIndirectly(disableIndirectly);
371
372         if (childItem->parent() && !childItem->parent()->isExpanded())
373             childItem->parent()->setExpanded(true);
374     }
375 }