on xenial help sign in
launcher parity: close apps from quicklist
commit3848075527e267ac17b3190bea2bec7d926b2f2d authorLukáš Tinkl <lukas.tinkl@canonical.com> dateTue 9 Jun 2015, 20:37 (11 years ago) parent23baf1c
8 files changed+105−19
plugins/Unity/Launcher/launcheritem.cpp+10 plugins/Unity/Launcher/launcheritem.h+1 plugins/Unity/Launcher/launchermodel.cpp+29−14 plugins/Unity/Launcher/quicklistentry.cpp+6−2 plugins/Unity/Launcher/quicklistentry.h+3−1 plugins/Unity/Launcher/quicklistmodel.cpp+12−1 plugins/Unity/Launcher/quicklistmodel.h+3−1 tests/plugins/Unity/Launcher/launchermodeltest.cpp+41
plugins/Unity/Launcher/launcheritem.cpp+10
@@ -40,10 +40,15 @@ LauncherItem::LauncherItem(const QString &appId, const QString &name, const QStr
4040 nameAction.setActionId("launch_item");
4141 nameAction.setText(m_name);
4242 m_quickList->appendAction(nameAction);
43+
4344 QuickListEntry pinningAction;
4445 pinningAction.setActionId("pin_item");
4546 pinningAction.setText(gettext("Pin shortcut"));
4647 m_quickList->appendAction(pinningAction);
48+
49+ m_quitAction.setActionId("stop_item");
50+ m_quitAction.setIcon("application-exit");
51+ m_quitAction.setText(gettext("Quit"));
4752}
4853
4954QString LauncherItem::appId() const
@@ -110,6 +115,11 @@ void LauncherItem::setRunning(bool running)
110115{
111116 if (m_running != running) {
112117 m_running = running;
118+ if (m_running) { // add the quit action
119+ m_quickList->appendAction(m_quitAction);
120+ } else { // remove the quit action
121+ m_quickList->removeAction(m_quitAction);
122+ }
113123 Q_EMIT runningChanged(running);
114124 }
115125}
plugins/Unity/Launcher/launcheritem.h+1
@@ -70,6 +70,7 @@ private:
7070 bool m_countVisible;
7171 bool m_focused;
7272 QuickListModel *m_quickList;
73+ QuickListEntry m_quitAction;
7374
7475 friend class LauncherModel;
7576};
plugins/Unity/Launcher/launchermodel.cpp+29−14
@@ -82,9 +82,14 @@ QVariant LauncherModel::data(const QModelIndex &index, int role) const
8282 return item->progress();
8383 case RoleFocused:
8484 return item->focused();
85+ case RoleRunning:
86+ return item->running();
87+ default:
88+ qWarning() << Q_FUNC_INFO << "missing role, implement me";
89+ return QVariant();
8590 }
8691
87− return QVariant();
92+ return LauncherModelInterface::data(index, role);
8893}
8994
9095unity::shell::launcher::LauncherItemInterface *LauncherModel::get(int index) const
@@ -134,7 +139,7 @@ void LauncherModel::pin(const QString &appId, int index)
134139 if (index == -1 || index == currentIndex) {
135140 m_list.at(currentIndex)->setPinned(true);
136141 QModelIndex modelIndex = this->index(currentIndex);
137− Q_EMIT dataChanged(modelIndex, modelIndex, QVector<int>() << RolePinned);
142+ Q_EMIT dataChanged(modelIndex, modelIndex, {RolePinned});
138143 } else {
139144 move(currentIndex, index);
140145 // move() will store the list to the backend itself, so just exit at this point.
@@ -147,7 +152,7 @@ void LauncherModel::pin(const QString &appId, int index)
147152
148153 DesktopFileHandler desktopFile(appId);
149154 if (!desktopFile.isValid()) {
150− qWarning() << "Can't pin this application, there is no .destkop file available.";
155+ qWarning() << "Can't pin this application, there is no .desktop file available.";
151156 return;
152157 }
153158
@@ -172,7 +177,7 @@ void LauncherModel::requestRemove(const QString &appId)
172177
173178void LauncherModel::quickListActionInvoked(const QString &appId, int actionIndex)
174179{
175− int index = findApplication(appId);
180+ const int index = findApplication(appId);
176181 if (index < 0) {
177182 return;
178183 }
@@ -273,6 +278,7 @@ bool LauncherModel::onlyPinned() const
273278
274279void LauncherModel::setOnlyPinned(bool onlyPinned) {
275280 Q_UNUSED(onlyPinned);
281+ // FIXME implement showing only pinned apps
276282 qWarning() << "This launcher implementation does not support showing only pinned apps";
277283}
278284
@@ -299,7 +305,7 @@ void LauncherModel::unpin(const QString &appId)
299305 if (m_list.at(index)->pinned()) {
300306 m_list.at(index)->setPinned(false);
301307 QModelIndex modelIndex = this->index(index);
302− Q_EMIT dataChanged(modelIndex, modelIndex, QVector<int>() << RolePinned);
308+ Q_EMIT dataChanged(modelIndex, modelIndex, {RolePinned});
303309 }
304310 } else {
305311 beginRemoveRows(QModelIndex(), index, index);
@@ -325,7 +331,7 @@ void LauncherModel::progressChanged(const QString &appId, int progress)
325331 if (idx >= 0) {
326332 LauncherItem *item = m_list.at(idx);
327333 item->setProgress(progress);
328− Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleProgress);
334+ Q_EMIT dataChanged(index(idx), index(idx), {RoleProgress});
329335 }
330336}
331337
@@ -335,7 +341,7 @@ void LauncherModel::countChanged(const QString &appId, int count)
335341 if (idx >= 0) {
336342 LauncherItem *item = m_list.at(idx);
337343 item->setCount(count);
338− Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleCount);
344+ Q_EMIT dataChanged(index(idx), index(idx), {RoleCount});
339345 m_asAdapter->syncItems(m_list);
340346 }
341347}
@@ -346,7 +352,7 @@ void LauncherModel::countVisibleChanged(const QString &appId, int countVisible)
346352 if (idx >= 0) {
347353 LauncherItem *item = m_list.at(idx);
348354 item->setCountVisible(countVisible);
349− Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleCountVisible);
355+ Q_EMIT dataChanged(index(idx), index(idx), {RoleCountVisible});
350356
351357 // If countVisible goes to false, and the item is neither pinned nor recent we can drop it
352358 if (!countVisible && !item->pinned() && !item->recent()) {
@@ -388,7 +394,7 @@ void LauncherModel::refresh()
388394 item->setName(desktopFile.displayName());
389395 item->setIcon(desktopFile.icon());
390396 item->setPinned(item->pinned()); // update pinned text if needed
391− Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleName << RoleIcon);
397+ Q_EMIT dataChanged(index(idx), index(idx), {RoleName, RoleIcon});
392398 }
393399 }
394400
@@ -475,12 +481,13 @@ void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
475481 if (!item->recent()) {
476482 item->setRecent(true);
477483 m_asAdapter->syncItems(m_list);
478− Q_EMIT dataChanged(index(itemIndex), index(itemIndex), QVector<int>() << RoleRecent);
484+ Q_EMIT dataChanged(index(itemIndex), index(itemIndex), {RoleRecent});
479485 }
480− // Shall we paint some running/recent app highlight? If yes, do it here.
486+ // TODO Shall we paint some running/recent app highlight? If yes, do it here.
481487 } else {
482488 LauncherItem *item = new LauncherItem(app->appId(), app->name(), app->icon().toString(), this);
483489 item->setRecent(true);
490+ item->setRunning(true);
484491 item->setFocused(app->focused());
485492
486493 beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
@@ -502,7 +509,15 @@ void LauncherModel::applicationRemoved(const QModelIndex &parent, int row)
502509 }
503510 }
504511
505− if (appIndex > -1 && !m_list.at(appIndex)->pinned()) {
512+ if (appIndex < 0) {
513+ qWarning() << Q_FUNC_INFO << "appIndex not found";
514+ return;
515+ }
516+
517+ LauncherItem * item = m_list.at(appIndex);
518+ item->setRunning(false);
519+
520+ if (!item->pinned()) {
506521 beginRemoveRows(QModelIndex(), appIndex, appIndex);
507522 m_list.takeAt(appIndex)->deleteLater();
508523 endRemoveRows();
@@ -517,10 +532,10 @@ void LauncherModel::focusedAppIdChanged()
517532 LauncherItem *item = m_list.at(i);
518533 if (!item->focused() && item->appId() == appId) {
519534 item->setFocused(true);
520− Q_EMIT dataChanged(index(i), index(i), QVector<int>() << RoleFocused);
535+ Q_EMIT dataChanged(index(i), index(i), {RoleFocused});
521536 } else if (item->focused() && item->appId() != appId) {
522537 item->setFocused(false);
523− Q_EMIT dataChanged(index(i), index(i), QVector<int>() << RoleFocused);
538+ Q_EMIT dataChanged(index(i), index(i), {RoleFocused});
524539 }
525540 }
526541}
plugins/Unity/Launcher/quicklistentry.cpp+6−2
@@ -1,4 +1,4 @@
1−/* Copyright (C) 2013 Canonical, Ltd.
1+/* Copyright (C) 2013, 2015 Canonical, Ltd.
22 *
33 * Authors:
44 * Michael Zanetti <michael.zanetti@canonical.com>
@@ -20,7 +20,6 @@
2020
2121QuickListEntry::QuickListEntry()
2222{
23−
2423}
2524
2625QString QuickListEntry::actionId() const
@@ -57,3 +56,8 @@ bool QuickListEntry::clickable() const
5756{
5857 return !m_actionId.isEmpty();
5958}
59+
60+bool QuickListEntry::operator==(const QuickListEntry &other)
61+{
62+ return !other.actionId().isEmpty() && other.actionId() == m_actionId;
63+}
plugins/Unity/Launcher/quicklistentry.h+3−1
@@ -1,4 +1,4 @@
1−/* Copyright (C) 2013 Canonical, Ltd.
1+/* Copyright (C) 2013, 2015 Canonical, Ltd.
22 *
33 * Authors:
44 * Michael Zanetti <michael.zanetti@canonical.com>
@@ -37,6 +37,8 @@ public:
3737
3838 bool clickable() const;
3939
40+ bool operator==(const QuickListEntry & other);
41+
4042private:
4143 QString m_actionId;
4244 QString m_text;
plugins/Unity/Launcher/quicklistmodel.cpp+12−1
@@ -1,5 +1,5 @@
11/*
2− * Copyright 2013 Canonical Ltd.
2+ * Copyright 2013, 2015 Canonical Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU Lesser General Public License as published by
@@ -48,6 +48,17 @@ void QuickListModel::updateAction(const QuickListEntry &entry)
4848 }
4949}
5050
51+void QuickListModel::removeAction(const QuickListEntry &entry)
52+{
53+ const int start = m_list.indexOf(entry);
54+ if (start > -1) {
55+ beginRemoveRows(QModelIndex(), start, start);
56+ m_list.removeOne(entry);
57+ Q_EMIT dataChanged(index(start), index(start));
58+ endRemoveRows();
59+ }
60+}
61+
5162QuickListEntry QuickListModel::get(int index) const
5263{
5364 return m_list.at(index);
plugins/Unity/Launcher/quicklistmodel.h+3−1
@@ -1,5 +1,5 @@
11/*
2− * Copyright 2013 Canonical Ltd.
2+ * Copyright 201, 2015 Canonical Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU Lesser General Public License as published by
@@ -46,6 +46,8 @@ public:
4646 */
4747 void updateAction(const QuickListEntry &entry);
4848
49+ void removeAction(const QuickListEntry &entry);
50+
4951 QuickListEntry get(int index) const;
5052
5153 int rowCount(const QModelIndex &parent = QModelIndex()) const override;
tests/plugins/Unity/Launcher/launchermodeltest.cpp+41
@@ -66,6 +66,7 @@ class MockAppManager: public unity::shell::application::ApplicationManagerInterf
6666 Q_OBJECT
6767public:
6868 MockAppManager(QObject *parent = 0): ApplicationManagerInterface(parent) {}
69+ ~MockAppManager() {}
6970 int rowCount(const QModelIndex &) const override { return m_list.count(); }
7071 QVariant data(const QModelIndex &, int ) const override { return QVariant(); }
7172 QString focusedApplicationId() const override {
@@ -323,6 +324,46 @@ private Q_SLOTS:
323324 QCOMPARE(launcherModel->get(0)->appId(), QLatin1String("abs-icon"));
324325 }
325326
327+ void testQuitMenuItem() {
328+ // we have 2 apps running, both should have the Quit action in its quick list
329+ QCOMPARE(launcherModel->rowCount(), 2);
330+
331+ // stop the second one keeping it pinned so that it doesn't go away
332+ launcherModel->pin("no-icon");
333+ appManager->stopApplication("no-icon");
334+
335+ // find the first Quit item, should be there
336+ QuickListModel *model = qobject_cast<QuickListModel*>(launcherModel->get(0)->quickList());
337+ int quitActionIndex = -1;
338+ for (int i = 0; i < model->rowCount(); ++i) {
339+ if (model->get(i).actionId() == "stop_item") {
340+ quitActionIndex = i;
341+ break;
342+ }
343+ }
344+ QVERIFY(quitActionIndex >= 0);
345+
346+ // find the second Quit item, should NOT be there, the app is stopped
347+ QuickListModel *model2 = qobject_cast<QuickListModel*>(launcherModel->get(1)->quickList());
348+ int quitActionIndex2 = -1;
349+ for (int i = 0; i < model2->rowCount(); ++i) {
350+ if (model2->get(i).actionId() == "stop_item") {
351+ quitActionIndex2 = i;
352+ break;
353+ }
354+ }
355+ QVERIFY(quitActionIndex2 == -1);
356+
357+ // trigger the first quit item quicklist action
358+ launcherModel->quickListActionInvoked(launcherModel->get(0)->appId(), quitActionIndex);
359+ // first app should be gone...
360+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
361+ // ... the second app (now at index 0) should still be there, pinned and stopped
362+ QCOMPARE(launcherModel->get(0)->appId(), QStringLiteral("no-icon"));
363+ QCOMPARE(launcherModel->get(0)->pinned(), true);
364+ QCOMPARE(launcherModel->get(0)->running(), false);
365+ }
366+
326367 void testGetUrlForAppId() {
327368 QCOMPARE(launcherModel->getUrlForAppId(QString()), QString());
328369 QCOMPARE(launcherModel->getUrlForAppId(""), QString());