~ubuntu-branches/ubuntu/vivid/muon/vivid-proposed

« back to all changes in this revision

Viewing changes to installer/MainWindow.cpp

  • Committer: Package Import Robot
  • Author(s): Scarlett Clark
  • Date: 2015-03-24 07:36:31 UTC
  • mto: This revision was merged to the branch mainline in revision 86.
  • Revision ID: package-import@ubuntu.com-20150324073631-7nmay5episnfkdlt
Tags: upstream-5.2.2
ImportĀ upstreamĀ versionĀ 5.2.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/***************************************************************************
2
 
 *   Copyright Ā© 2010-2012 Jonathan Thomas <echidnaman@kubuntu.org>        *
3
 
 *                                                                         *
4
 
 *   This program is free software; you can redistribute it and/or         *
5
 
 *   modify it under the terms of the GNU General Public License as        *
6
 
 *   published by the Free Software Foundation; either version 2 of        *
7
 
 *   the License or (at your option) version 3 or any later version        *
8
 
 *   accepted by the membership of KDE e.V. (or its successor approved     *
9
 
 *   by the membership of KDE e.V.), which shall act as a proxy            *
10
 
 *   defined in Section 14 of version 3 of the license.                    *
11
 
 *                                                                         *
12
 
 *   This program is distributed in the hope that it will be useful,       *
13
 
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
14
 
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
15
 
 *   GNU General Public License for more details.                          *
16
 
 *                                                                         *
17
 
 *   You should have received a copy of the GNU General Public License     *
18
 
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
19
 
 ***************************************************************************/
20
 
 
21
 
#include "MainWindow.h"
22
 
 
23
 
// Qt includes
24
 
#include <QStandardItemModel>
25
 
#include <QtCore/QStringBuilder>
26
 
#include <QtCore/QTimer>
27
 
#include <QAbstractItemView>
28
 
#include <QSplitter>
29
 
#include <QtWidgets/QStackedWidget>
30
 
 
31
 
// KDE includes
32
 
#include <KActionCollection>
33
 
#include <KMessageBox>
34
 
#include <KMessageWidget>
35
 
#include <KPixmapSequence>
36
 
#include <KPixmapSequenceOverlayPainter>
37
 
#include <KService>
38
 
#include <KToolInvocation>
39
 
 
40
 
// QApt includes
41
 
#include <QApt/Backend>
42
 
 
43
 
//libmuonapt includes
44
 
#include <HistoryView/HistoryView.h>
45
 
#include "../libmuonapt/QAptActions.h"
46
 
 
47
 
// Libmuon includes
48
 
#include <Transaction/TransactionModel.h>
49
 
#include <resources/ResourcesModel.h>
50
 
 
51
 
// Own includes
52
 
#include "ApplicationLauncher.h"
53
 
#include "ResourceView/ResourceListView.h"
54
 
#include "AvailableView.h"
55
 
#include "ProgressView.h"
56
 
#include "ViewSwitcher.h"
57
 
#include "LaunchListModel.h"
58
 
#include "MuonInstallerSettings.h"
59
 
 
60
 
enum ViewModelRole {
61
 
    /// A role for storing ViewType
62
 
    ViewTypeRole = Qt::UserRole + 1,
63
 
    /// A role for storing origin filter data
64
 
    OriginFilterRole,
65
 
    /// A role for storing state filter data
66
 
    StateFilterRole
67
 
};
68
 
 
69
 
enum ViewType {
70
 
    /// An invalid value
71
 
    InvalidView = 0,
72
 
    /// A simple ApplicationView that is filterable by status or origin
73
 
    AppView,
74
 
    /// An ApplicationView that has a Categorical homepage
75
 
    CatView,
76
 
    /// A CategoryView showing subcategories
77
 
    SubCatView,
78
 
    /// A view for showing history
79
 
    History,
80
 
    /// A view for showing in-progress transactions
81
 
    Progress
82
 
};
83
 
 
84
 
MainWindow::MainWindow()
85
 
    : MuonMainWindow()
86
 
    , m_appBackend(nullptr)
87
 
    , m_launches(nullptr)
88
 
    , m_launcherMessage(nullptr)
89
 
    , m_appLauncher(nullptr)
90
 
    , m_progressItem(nullptr)
91
 
{
92
 
    initGUI();
93
 
 
94
 
    TransactionModel *transModel = TransactionModel::global();
95
 
    connect(transModel, SIGNAL(startingFirstTransaction()), SLOT(addProgressItem()));
96
 
    connect(transModel, SIGNAL(lastTransactionFinished()), SLOT(removeProgressItem()));
97
 
    m_launches = new LaunchListModel(this);
98
 
 
99
 
    ResourcesModel* resourcesModel = ResourcesModel::global();
100
 
    resourcesModel->integrateMainWindow(this);
101
 
    connect(resourcesModel, SIGNAL(backendsChanged()), SLOT(initObject()));
102
 
}
103
 
 
104
 
MainWindow::~MainWindow()
105
 
{
106
 
    MuonInstallerSettings::self()->writeConfig();
107
 
}
108
 
 
109
 
void MainWindow::initGUI()
110
 
{
111
 
    m_mainWidget = new QSplitter(this);
112
 
    m_mainWidget->setOrientation(Qt::Horizontal);
113
 
    connect(m_mainWidget, SIGNAL(splitterMoved(int,int)), this, SLOT(saveSplitterSizes()));
114
 
    setCentralWidget(m_mainWidget);
115
 
 
116
 
    // Set up the navigational sidebar on the right
117
 
    m_viewSwitcher = new ViewSwitcher(this);
118
 
    connect(m_viewSwitcher, SIGNAL(activated(QModelIndex)),
119
 
            this, SLOT(changeView(QModelIndex)));
120
 
    m_mainWidget->addWidget(m_viewSwitcher);
121
 
 
122
 
    // Set up the main pane
123
 
    KVBox *leftWidget = new KVBox(this);
124
 
    m_launcherMessage = new KMessageWidget(leftWidget);
125
 
    m_launcherMessage->hide();
126
 
    m_launcherMessage->setMessageType(KMessageWidget::Positive);
127
 
 
128
 
    m_viewStack = new QStackedWidget(leftWidget);
129
 
    m_viewStack->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
130
 
 
131
 
    // Busy widget
132
 
    m_busyWidget = new QWidget(m_viewStack);
133
 
    KPixmapSequenceOverlayPainter *busyWidget = new KPixmapSequenceOverlayPainter(m_busyWidget);
134
 
    busyWidget->setSequence(KPixmapSequence("process-working", KIconLoader::SizeSmallMedium));
135
 
    busyWidget->setWidget(m_busyWidget);
136
 
    busyWidget->start();
137
 
 
138
 
    m_viewStack->addWidget(m_busyWidget);
139
 
    m_viewStack->setCurrentWidget(m_busyWidget);
140
 
 
141
 
    m_mainWidget->addWidget(leftWidget);
142
 
    loadSplitterSizes();
143
 
 
144
 
    m_viewModel = new QStandardItemModel(this);
145
 
    m_viewSwitcher->setModel(m_viewModel);
146
 
 
147
 
    setupActions();
148
 
    setupGUI(StandardWindowOption(KXmlGuiWindow::Default & ~KXmlGuiWindow::StatusBar));
149
 
}
150
 
 
151
 
void MainWindow::initObject()
152
 
{
153
 
    ResourcesModel *resourcesModel = ResourcesModel::global();
154
 
 
155
 
    QVector<AbstractResourcesBackend*> backends = resourcesModel->backends();
156
 
    for (AbstractResourcesBackend *backend : backends) {
157
 
        if(!m_appBackend &&
158
 
            backend->metaObject()->className()==QLatin1String("ApplicationBackend"))
159
 
        {
160
 
            m_appBackend = backend;
161
 
            connect(m_appBackend, SIGNAL(fetchingChanged()), SLOT(aptFetchingChanged()));
162
 
            connect(m_appBackend, SIGNAL(sourcesEditorFinished()), SLOT(sourcesEditorFinished()));
163
 
            populateViews();
164
 
        }
165
 
    }
166
 
    connect(resourcesModel, SIGNAL(allInitialized()), SLOT(populateViews()));
167
 
}
168
 
 
169
 
void MainWindow::aptFetchingChanged()
170
 
{
171
 
    if(m_appBackend && !m_appBackend->isFetching())
172
 
        showLauncherMessage();
173
 
}
174
 
 
175
 
void MainWindow::loadSplitterSizes()
176
 
{
177
 
    QList<int> sizes = MuonInstallerSettings::self()->splitterSizes();
178
 
 
179
 
    if (sizes.isEmpty()) {
180
 
        sizes << 115 << (this->width() - 115);
181
 
    }
182
 
    m_mainWidget->setSizes(sizes);
183
 
}
184
 
 
185
 
void MainWindow::saveSplitterSizes()
186
 
{
187
 
    MuonInstallerSettings::self()->setSplitterSizes(m_mainWidget->sizes());
188
 
    MuonInstallerSettings::self()->writeConfig();
189
 
}
190
 
 
191
 
void MainWindow::clearViews()
192
 
{
193
 
    setCanExit(false); // APT is reloading at this point
194
 
    foreach (QWidget *widget, m_viewHash) {
195
 
        delete widget;
196
 
    }
197
 
    m_viewHash.clear();
198
 
    m_viewModel->clear();
199
 
}
200
 
 
201
 
QStandardItem* MainWindow::createOriginItem(const QString& originName)
202
 
{
203
 
//     TODO: when origins are abstracted out this should go too
204
 
    QApt::Backend* backend = qobject_cast<QApt::Backend*>(m_appBackend->property("backend").value<QObject*>());
205
 
    QString originLabel = backend->originLabel(originName);
206
 
    if(originLabel.isEmpty())
207
 
        originLabel = originName;
208
 
 
209
 
    // We must spread the word of Origin. Hallowed are the Ori! ;P
210
 
    QStandardItem *viewItem = new QStandardItem;
211
 
    viewItem->setEditable(false);
212
 
    viewItem->setText(originLabel);
213
 
    viewItem->setData(originName, OriginFilterRole);
214
 
    viewItem->setData(AppView, ViewTypeRole);
215
 
 
216
 
    if (originName == "Ubuntu") {
217
 
        viewItem->setText(i18nc("@item:inlistbox", "Provided by Kubuntu"));
218
 
        viewItem->setIcon(QIcon::fromTheme("ubuntu-logo"));
219
 
    }
220
 
 
221
 
    if (originName == "Debian") {
222
 
        viewItem->setText(i18nc("@item:inlistbox", "Provided by Debian"));
223
 
        viewItem->setIcon(QIcon::fromTheme("emblem-debian"));
224
 
    }
225
 
 
226
 
    if (originName == "Canonical") {
227
 
        viewItem->setText(i18nc("@item:inlistbox The name of the repository provided by Canonical, Ltd. ",
228
 
                                "Canonical Partners"));
229
 
        viewItem->setIcon(QIcon::fromTheme("partner"));
230
 
    }
231
 
 
232
 
    if (originName.startsWith(QLatin1String("LP-PPA"))) {
233
 
        viewItem->setIcon(QIcon::fromTheme("user-identity"));
234
 
 
235
 
        if (originName == QLatin1String("LP-PPA-app-review-board")) {
236
 
            viewItem->setText(i18nc("@item:inlistbox An independent software source",
237
 
                                    "Independent"));
238
 
            viewItem->setIcon(QIcon::fromTheme("system-users"));
239
 
        } else
240
 
            viewItem->setIcon(QIcon::fromTheme("user-identity"));
241
 
    }
242
 
    return viewItem;
243
 
}
244
 
 
245
 
bool repositoryNameLessThan(const QString& a, const QString& b)
246
 
{
247
 
    static QStringList prioritary(QStringList() << "Debian" << "Ubuntu" << "Canonical" << "LP-PPA-app-review-board");
248
 
    int idxA = prioritary.indexOf(a), idxB = prioritary.indexOf(b);
249
 
    if(idxA == idxB)
250
 
        return a<b;
251
 
    else if((idxB == -1) ^ (idxA == -1))
252
 
        return idxB == -1;
253
 
    else
254
 
        return idxA<idxB;
255
 
}
256
 
 
257
 
QPair<QStringList, QStringList> fetchOrigins()
258
 
{
259
 
    QSet<QString> originSet, instOriginSet;
260
 
    
261
 
    ResourcesModel *resourcesModel = ResourcesModel::global();
262
 
    for(int i=0; i<resourcesModel->rowCount(); i++) {
263
 
        AbstractResource* app = resourcesModel->resourceAt(i);
264
 
        if (app->backend()->isFetching())
265
 
            continue;
266
 
        if (app->isInstalled())
267
 
            instOriginSet << app->origin();
268
 
        else
269
 
            originSet << app->origin();
270
 
    }
271
 
 
272
 
    originSet.remove(QString());
273
 
    instOriginSet.remove(QString());
274
 
    originSet += instOriginSet;
275
 
    
276
 
    QStringList originList=originSet.toList(), instOriginList=instOriginSet.toList();
277
 
    qSort(originList.begin(), originList.end(), repositoryNameLessThan);
278
 
    qSort(instOriginList.begin(), instOriginList.end(), repositoryNameLessThan);
279
 
    return qMakePair(originList, instOriginList);
280
 
}
281
 
 
282
 
void MainWindow::populateViews()
283
 
{
284
 
    m_viewModel->clear();
285
 
    QStandardItem *availableItem = new QStandardItem;
286
 
    availableItem->setEditable(false);
287
 
    availableItem->setIcon(QIcon::fromTheme("applications-other").pixmap(32,32));
288
 
    availableItem->setText(i18nc("@item:inlistbox Parent item for available software", "Get Software"));
289
 
    availableItem->setData(CatView, ViewTypeRole);
290
 
 
291
 
    QStandardItem *installedItem = new QStandardItem;
292
 
    installedItem->setEditable(false);
293
 
    installedItem->setIcon(QIcon::fromTheme("computer"));
294
 
    installedItem->setText(i18nc("@item:inlistbox Parent item for installed software", "Installed Software"));
295
 
    installedItem->setData(AppView, ViewTypeRole);
296
 
    installedItem->setData(AbstractResource::State::Installed, StateFilterRole);
297
 
    
298
 
    QPair< QStringList, QStringList > origins = fetchOrigins();
299
 
    QStringList originNames = origins.first;
300
 
    foreach(const QString &originName, originNames) {
301
 
        availableItem->appendRow(createOriginItem(originName));
302
 
    }
303
 
 
304
 
    QStringList instOriginNames = origins.second;
305
 
    foreach(const QString & originName, instOriginNames) {
306
 
        QStandardItem* viewItem = createOriginItem(originName);
307
 
 
308
 
        viewItem->setData(AbstractResource::State::Installed, StateFilterRole);
309
 
        installedItem->appendRow(viewItem);
310
 
    }
311
 
 
312
 
    QStandardItem *historyItem = new QStandardItem;
313
 
    historyItem->setEditable(false);
314
 
    historyItem->setIcon(QIcon::fromTheme("view-history").pixmap(32,32));
315
 
    historyItem->setText(i18nc("@item:inlistbox Item for showing the history view", "History"));
316
 
    historyItem->setData(History, ViewTypeRole);
317
 
 
318
 
    m_viewModel->appendRow(availableItem);
319
 
    m_viewModel->appendRow(installedItem);
320
 
    m_viewModel->appendRow(historyItem);
321
 
    selectFirstRow(m_viewSwitcher);
322
 
 
323
 
    emit viewsPopulated();
324
 
}
325
 
 
326
 
void MainWindow::changeView(const QModelIndex &index)
327
 
{
328
 
    QWidget *view = m_viewHash.value(index);
329
 
 
330
 
    // Create new widget if not already created
331
 
    if (!view) {
332
 
        switch (index.data(ViewTypeRole).toInt()) {
333
 
        case AppView: {
334
 
            QString originFilter = index.data(OriginFilterRole).toString();
335
 
            AbstractResource::State stateFilter = (AbstractResource::State)index.data(StateFilterRole).toInt();
336
 
 
337
 
            view = new ResourceListView(this, index);
338
 
            ResourceListView *appView = static_cast<ResourceListView *>(view);
339
 
            appView->setStateFilter(stateFilter);
340
 
            appView->setOriginFilter(originFilter);
341
 
            appView->setCanShowTechnical(true);
342
 
 
343
 
            if (originFilter != QLatin1String("Ubuntu") && originFilter != QLatin1String("Debian"))
344
 
                appView->setShouldShowTechnical(true);
345
 
        }
346
 
            break;
347
 
        case CatView:
348
 
            view = new AvailableView(this);
349
 
            break;
350
 
        case History:
351
 
            view = new HistoryView(this);
352
 
            break;
353
 
        case Progress:
354
 
            view = new ProgressView(this);
355
 
        case InvalidView:
356
 
        default:
357
 
            break;
358
 
        }
359
 
 
360
 
        m_viewStack->addWidget(view);
361
 
    }
362
 
 
363
 
    m_viewStack->addWidget(view);
364
 
    m_viewStack->setCurrentWidget(view);
365
 
    m_viewStack->removeWidget(m_busyWidget);
366
 
 
367
 
    delete m_busyWidget;
368
 
    m_busyWidget = nullptr;
369
 
 
370
 
    m_viewHash[index] = view;
371
 
}
372
 
 
373
 
void MainWindow::selectFirstRow(const QAbstractItemView *itemView)
374
 
{
375
 
    QModelIndex firstRow = itemView->model()->index(0, 0);
376
 
    itemView->selectionModel()->select(firstRow, QItemSelectionModel::Select);
377
 
    changeView(firstRow);
378
 
}
379
 
 
380
 
void MainWindow::sourcesEditorFinished()
381
 
{
382
 
    clearViews();
383
 
    populateViews();
384
 
    find(effectiveWinId())->setEnabled(true);
385
 
}
386
 
 
387
 
void MainWindow::showLauncherMessage()
388
 
{
389
 
    clearMessageActions();
390
 
 
391
 
    if (m_launches->rowCount()==1) {
392
 
        QModelIndex index = m_launches->index(0, 0);
393
 
        QString name = index.data().toString();
394
 
        m_launcherMessage->setText(i18nc("@info", "%1 was successfully installed.", name));
395
 
 
396
 
        QIcon launchIcon = index.data(Qt::DecorationRole).value<QIcon>();
397
 
        QAction *launchAction = new QAction(launchIcon, i18nc("@action", "Start"), this);
398
 
        connect(launchAction, SIGNAL(activated()), this, SLOT(launchSingleApp()));
399
 
 
400
 
        m_launcherMessage->addAction(launchAction);
401
 
        m_launcherMessage->animatedShow();
402
 
    } else if (m_launches->rowCount() > 1) {
403
 
        m_launcherMessage->setText(i18nc("@info", "Applications successfully installed."));
404
 
        QAction *launchAction = new QAction(i18nc("@action", "Run New Applications..."), this);
405
 
        connect(launchAction, SIGNAL(activated()), this, SLOT(showAppLauncher()));
406
 
        m_launcherMessage->addAction(launchAction);
407
 
        m_launcherMessage->animatedShow();
408
 
    }
409
 
}
410
 
 
411
 
void MainWindow::launchSingleApp()
412
 
{
413
 
    m_launches->invokeApplication(0);
414
 
    m_launcherMessage->animatedHide();
415
 
    m_launcherMessage->removeAction(m_launcherMessage->actions().first());
416
 
}
417
 
 
418
 
void MainWindow::showAppLauncher()
419
 
{
420
 
    if (!m_appLauncher && !m_launches->rowCount()==0) {
421
 
        m_appLauncher = new ApplicationLauncher(m_launches);
422
 
        connect(m_appLauncher, SIGNAL(destroyed(QObject*)),
423
 
                this, SLOT(onAppLauncherClosed()));
424
 
        connect(m_appLauncher, SIGNAL(finished(int)),
425
 
                this, SLOT(onAppLauncherClosed()));
426
 
        m_appLauncher->setWindowTitle(i18nc("@title:window", "Installation Complete"));
427
 
        m_appLauncher->show();
428
 
    }
429
 
    m_launcherMessage->animatedHide();
430
 
}
431
 
 
432
 
void MainWindow::onAppLauncherClosed()
433
 
{
434
 
    m_appLauncher = 0;
435
 
}
436
 
 
437
 
void MainWindow::clearMessageActions()
438
 
{
439
 
    foreach (QAction *action, m_launcherMessage->actions()) {
440
 
        m_launcherMessage->removeAction(action);
441
 
    }
442
 
}
443
 
 
444
 
void MainWindow::addProgressItem()
445
 
{
446
 
    QStandardItem *parentItem = m_viewModel->invisibleRootItem();
447
 
 
448
 
    if (m_progressItem)
449
 
        return;
450
 
 
451
 
    m_progressItem = new QStandardItem;
452
 
    m_progressItem->setEditable(false);
453
 
    m_progressItem->setIcon(QIcon::fromTheme("download").pixmap(32,32));
454
 
    m_progressItem->setText(i18nc("@item:inlistbox Item for showing the progress view", "In Progress"));
455
 
    m_progressItem->setData(Progress, ViewTypeRole);
456
 
    parentItem->appendRow(m_progressItem);
457
 
 
458
 
    m_viewHash[m_progressItem->index()] = 0;
459
 
}
460
 
 
461
 
void MainWindow::removeProgressItem()
462
 
{
463
 
    if (!m_progressItem)
464
 
        return;
465
 
 
466
 
    QObject *progressView = m_viewHash.take(m_progressItem->index());
467
 
    if (progressView)
468
 
        progressView->deleteLater();
469
 
 
470
 
    m_viewModel->removeRow(m_progressItem->row());
471
 
    m_progressItem = nullptr;
472
 
}
473
 
 
474
 
void MainWindow::openApplication(const QString &app)
475
 
{
476
 
    setEnabled(false);
477
 
    m_appToBeOpened = app;
478
 
    triggerOpenApplication();
479
 
    if(!m_appToBeOpened.isEmpty())
480
 
        connect(this, SIGNAL(viewsPopulated()), SLOT(triggerOpenApplication()));
481
 
}
482
 
 
483
 
void MainWindow::triggerOpenApplication()
484
 
{
485
 
    if (!ResourcesModel::global())
486
 
        return;
487
 
 
488
 
    AbstractResource* app = ResourcesModel::global()->resourceByPackageName(m_appToBeOpened);
489
 
    if(app) {
490
 
        AvailableView *view = qobject_cast<AvailableView *>(m_viewStack->currentWidget());
491
 
        view->setResource(app);
492
 
 
493
 
        m_appToBeOpened.clear();
494
 
        disconnect(this, SIGNAL(viewsPopulated()), this, SLOT(triggerOpenApplication()));
495
 
        setEnabled(true);
496
 
    }
497
 
}