pluginview.cpp 12.4 KB
Newer Older
1
/**************************************************************************
con's avatar
con committed
2
3
4
**
** This file is part of Qt Creator
**
hjk's avatar
hjk committed
5
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
con's avatar
con committed
6
**
7
** Contact: Nokia Corporation (qt-info@nokia.com)
con's avatar
con committed
8
**
9
** Commercial Usage
10
**
11
12
13
14
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
15
**
16
** GNU Lesser General Public License Usage
17
**
18
19
20
21
22
23
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  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.
24
**
25
** If you are unsure which license is appropriate for your use, please
hjk's avatar
hjk committed
26
** contact the sales department at http://qt.nokia.com/contact.
con's avatar
con committed
27
**
28
**************************************************************************/
hjk's avatar
hjk committed
29

con's avatar
con committed
30
31
32
33
#include "pluginview.h"
#include "pluginview_p.h"
#include "pluginmanager.h"
#include "pluginspec.h"
34
#include "plugincollection.h"
con's avatar
con committed
35
36
#include "ui_pluginview.h"

37
#include <QtCore/QDir>
con's avatar
con committed
38
39
#include <QtGui/QHeaderView>
#include <QtGui/QTreeWidgetItem>
40
41
#include <QtGui/QPalette>

con's avatar
con committed
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <QtDebug>

/*!
    \class ExtensionSystem::PluginView
    \brief Widget that shows a list of all plugins and their state.

    This can be embedded e.g. in a dialog in the application that
    uses the plugin manager.
    The class also provides notifications for interactions with the list.

    \sa ExtensionSystem::PluginDetailsView
    \sa ExtensionSystem::PluginErrorView
*/

/*!
    \fn void PluginView::currentPluginChanged(ExtensionSystem::PluginSpec *spec)
    The current selection in the plugin list has changed to the
    plugin corresponding to \a spec.
*/

/*!
    \fn void PluginView::pluginActivated(ExtensionSystem::PluginSpec *spec)
    The plugin list entry corresponding to \a spec has been activated,
    e.g. by a double-click.
*/

using namespace ExtensionSystem;

Q_DECLARE_METATYPE(ExtensionSystem::PluginSpec*);
71
Q_DECLARE_METATYPE(ExtensionSystem::PluginCollection*);
con's avatar
con committed
72
73
74
75
76
77
78

/*!
    \fn PluginView::PluginView(PluginManager *manager, QWidget *parent)
    Constructs a PluginView that gets the list of plugins from the
    given plugin \a manager with a given \a parent widget.
*/
PluginView::PluginView(PluginManager *manager, QWidget *parent)
79
    : QWidget(parent),
con's avatar
con committed
80
      m_ui(new Internal::Ui::PluginView),
81
82
83
      p(new Internal::PluginViewPrivate),
      m_allowCheckStateUpdate(true),
      C_LOAD(1)
con's avatar
con committed
84
85
{
    m_ui->setupUi(this);
86
    QHeaderView *header = m_ui->categoryWidget->header();
con's avatar
con committed
87
88
    header->setResizeMode(0, QHeaderView::ResizeToContents);
    header->setResizeMode(2, QHeaderView::ResizeToContents);
89
90
91
92
93

    m_okIcon = QIcon(QLatin1String(":/extensionsystem/images/ok.png"));
    m_errorIcon = QIcon(QLatin1String(":/extensionsystem/images/error.png"));
    m_notLoadedIcon = QIcon(QLatin1String(":/extensionsystem/images/notloaded.png"));

94
95
    m_ui->categoryWidget->setColumnWidth(C_LOAD, 40);

96
97
98
99
    // cannot disable these
    m_whitelist << QString("Core") << QString("Locator")
                << QString("Find") << QString("TextEditor");

con's avatar
con committed
100
101
    p->manager = manager;
    connect(p->manager, SIGNAL(pluginsChanged()), this, SLOT(updateList()));
102
    connect(m_ui->categoryWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
con's avatar
con committed
103
            this, SLOT(selectPlugin(QTreeWidgetItem*)));
104
    connect(m_ui->categoryWidget, SIGNAL(itemActivated(QTreeWidgetItem*,int)),
con's avatar
con committed
105
            this, SLOT(activatePlugin(QTreeWidgetItem*)));
106

con's avatar
con committed
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
    updateList();
}

/*!
    \fn PluginView::~PluginView()
    \internal
*/
PluginView::~PluginView()
{
    delete p;
    delete m_ui;
}

/*!
    \fn PluginSpec *PluginView::currentPlugin() const
    Returns the current selection in the list of plugins.
*/
PluginSpec *PluginView::currentPlugin() const
{
126
    if (!m_ui->categoryWidget->currentItem())
con's avatar
con committed
127
        return 0;
128
129
130
    if (!m_ui->categoryWidget->currentItem()->data(0, Qt::UserRole).isNull())
        return m_ui->categoryWidget->currentItem()->data(0, Qt::UserRole).value<PluginSpec *>();
    return 0;
con's avatar
con committed
131
132
133
134
}

void PluginView::updateList()
{
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
    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;
154
        int state = parsePluginSpecs(collectionItem, groupState, collection->plugins());
155

156
        collectionItem->setIcon(0, iconForState(state));
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
        collectionItem->setData(C_LOAD, Qt::CheckStateRole, QVariant(groupState));
        collectionItem->setToolTip(C_LOAD, tr("Load on Startup"));
        collectionItem->setData(0, Qt::UserRole, qVariantFromValue(collection));
    }

    // 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;
173
    int state = parsePluginSpecs(defaultCollectionItem, groupState, defaultCollection ? defaultCollection->plugins() : QList<PluginSpec *>());
174

175
    defaultCollectionItem->setIcon(0, iconForState(state));
176
177
178
179
    defaultCollectionItem->setData(C_LOAD, Qt::CheckStateRole, QVariant(groupState));
    defaultCollectionItem->setToolTip(C_LOAD, tr("Load on Startup"));
    defaultCollectionItem->setData(0, Qt::UserRole, qVariantFromValue(defaultCollection));

180
    updatePluginDependencies();
181
182
183
184
185
186
187
188
189
190
191
192

    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));
}

193
int PluginView::parsePluginSpecs(QTreeWidgetItem *parentItem, Qt::CheckState &groupState, QList<PluginSpec*> plugins)
194
{
195
    int ret = 0;
196
    int loadCount = 0;
197

198
199
200
    for (int i = 0; i < plugins.length(); ++i) {
        PluginSpec *spec = plugins[i];
        if (spec->hasError())
201
            ret |= ParsedWithErrors;
202
203

        QTreeWidgetItem *pluginItem = new QTreeWidgetItem(QStringList()
con's avatar
con committed
204
            << spec->name()
205
            << QString()    // load on startup
206
            << QString::fromLatin1("%1 (%2)").arg(spec->version(), spec->compatVersion())
207
208
209
210
            << spec->vendor());

        pluginItem->setToolTip(0, QDir::toNativeSeparators(spec->filePath()));
        bool ok = !spec->hasError();
211
        QIcon icon = ok ? m_okIcon : m_errorIcon;
212
213
214
215
216
217
218
        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;
con's avatar
con committed
219
        if (spec->isEnabled()) {
220
            state = Qt::Checked;
221
222
            ++loadCount;
        }
223

224
        if (!m_whitelist.contains(spec->name())) {
225
            pluginItem->setData(C_LOAD, Qt::CheckStateRole, state);
226
        } else {
227
            pluginItem->setData(C_LOAD, Qt::CheckStateRole, Qt::Checked);
228
            pluginItem->setFlags(Qt::ItemIsSelectable);
229
        }
230

231
232
233
234
235
236
237
238
239
        pluginItem->setToolTip(C_LOAD, tr("Load on Startup"));

        m_specToItem.insert(spec, pluginItem);

        if (parentItem)
            parentItem->addChild(pluginItem);
        else
            m_items.append(pluginItem);

con's avatar
con committed
240
    }
241

242
    if (loadCount == plugins.length()) {
243
        groupState = Qt::Checked;
244
245
        ret |= ParsedAll;
    } else if (loadCount == 0) {
246
        groupState = Qt::Unchecked;
247
248
        ret |= ParsedNone;
    } else {
249
        groupState = Qt::PartiallyChecked;
250
251
252
253
254
255
256
257
258
259
260
261
        ret = ret | ParsedPartial;
    }
    return ret;
}

QIcon PluginView::iconForState(int state)
{
    if (state & ParsedWithErrors)
        return m_errorIcon;

    if (state & ParsedNone || state & ParsedPartial)
        return m_notLoadedIcon;
262

263
    return m_okIcon;
con's avatar
con committed
264
265
266
267
268
269
}

void PluginView::selectPlugin(QTreeWidgetItem *current)
{
    if (!current)
        emit currentPluginChanged(0);
270
    else if (current->data(0, Qt::UserRole).canConvert<PluginSpec*>())
con's avatar
con committed
271
        emit currentPluginChanged(current->data(0, Qt::UserRole).value<PluginSpec *>());
272
273
274
    else
        emit currentPluginChanged(0);

con's avatar
con committed
275
276
277
278
}

void PluginView::activatePlugin(QTreeWidgetItem *item)
{
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
    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) {

con's avatar
con committed
299
            spec->setEnabled(loadOnStartup);
300
            updatePluginDependencies();
301
302
303
304
305
306

            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) {
con's avatar
con committed
307
                    if (collection->plugins().at(i)->isEnabled())
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
                        ++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())) {
con's avatar
con committed
328
                spec->setEnabled(loadOnStartup);
329
330
331
332
                Qt::CheckState state = (loadOnStartup ? Qt::Checked : Qt::Unchecked);
                child->setData(C_LOAD, Qt::CheckStateRole, state);
            } else {
                child->setData(C_LOAD, Qt::CheckStateRole, Qt::Checked);
333
                child->setFlags(Qt::ItemIsSelectable);
334
335
            }
        }
336
        updatePluginDependencies();
337
338
339
340
341
342
        emit pluginSettingsChanged(collection->plugins().first());
    }

    m_allowCheckStateUpdate = true;
}

343
void PluginView::updatePluginDependencies()
344
{
345
346
    foreach (PluginSpec *spec, PluginManager::instance()->loadQueue()) {
        bool disableIndirectly = false;
347
348
349
        if (m_whitelist.contains(spec->name()))
            continue;

350
351
352
353
354
355
        foreach(const PluginSpec *depSpec, spec->dependencySpecs()) {
            if (!depSpec->isEnabled() || depSpec->isDisabledIndirectly()) {
                disableIndirectly = true;
                break;
            }
        }
356
        QTreeWidgetItem *childItem = m_specToItem.value(spec);
357
        childItem->setDisabled(disableIndirectly);
358

359
360
361
        if (disableIndirectly == spec->isDisabledIndirectly())
            continue;
        spec->setDisabledIndirectly(disableIndirectly);
362

363
364
        if (childItem->parent() && !childItem->parent()->isExpanded())
            childItem->parent()->setExpanded(true);
365
    }
con's avatar
con committed
366
}