Merge lp:~lukas-kde/unity8/closeAppsFromQuicklist into lp:unity8
- closeAppsFromQuicklist
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Michael Zanetti | ||||
Approved revision: | 1826 | ||||
Merged at revision: | 1889 | ||||
Proposed branch: | lp:~lukas-kde/unity8/closeAppsFromQuicklist | ||||
Merge into: | lp:unity8 | ||||
Prerequisite: | lp:~macslow/unity8/use-set-progress-api | ||||
Diff against target: |
788 lines (+198/-71) 17 files modified
plugins/Greeter/Unity/Launcher/launchermodelas.cpp (+13/-14) plugins/Unity/Launcher/asadapter.cpp (+3/-2) plugins/Unity/Launcher/asadapter.h (+1/-4) plugins/Unity/Launcher/gsettings.cpp (+1/-1) plugins/Unity/Launcher/launcheritem.cpp (+10/-0) plugins/Unity/Launcher/launcheritem.h (+1/-0) plugins/Unity/Launcher/launchermodel.cpp (+45/-24) 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) qml/Launcher/LauncherPanel.qml (+22/-13) tests/mocks/Unity/Launcher/MockLauncherItem.cpp (+3/-0) tests/mocks/Unity/Launcher/MockLauncherItem.h (+1/-0) tests/mocks/Unity/Launcher/MockLauncherModel.cpp (+4/-1) tests/plugins/Unity/Launcher/launchermodeltest.cpp (+41/-0) tests/qmltests/Launcher/tst_Launcher.qml (+29/-7) |
||||
To merge this branch: | bzr merge lp:~lukas-kde/unity8/closeAppsFromQuicklist | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michael Zanetti (community) | Approve | ||
Daniel d'Andrada | Pending | ||
PS Jenkins bot | continuous-integration | Pending | |
Albert Astals Cid | tags clean & merges fine | Pending | |
Review via email: mp+265669@code.launchpad.net |
This proposal supersedes a proposal from 2015-06-18.
Commit message
launcher parity: close apps from quicklist
Description of the change
launcher parity: close apps from quicklist
- adds a Quit item to the launcher quicklist
- partially reverts the visual appearance to the old design of popup menus
- invokes the popup menu also on the right mouse click
* Are there any related MPs required for this MP to build/function as expected? Please list.
No
* Did you perform an exploratory manual test run of your code change and any related functionality?
Yes
* Did you make sure that your branch does not contain spurious tags?
Yes
* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
N/A
* If you changed the UI, has there been a design review?
No (however, there is a revert to the old design)
* Did you have a look at the warnings when running tests? Can they be reduced?
Yes
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
I see you have lp:~lukas-kde/unity8/highdpi-mousetouchadaptor in this branch. Either remove those changes or make lp:~lukas-kde/unity8/highdpi-mousetouchadaptor a prerequisite.
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
In qml/Launcher/
"""
- __foregroundColor: "black"
+ __foregroundColor: Theme.palette.
"""
"Theme" is deprecated. Please use the context variable "theme" instead. We have tons of warnings on this already. See https:/
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
I would like to see a qml test launches an app and then closes it using this "quit" quick list menu entry.
I should also be able to manually test this feature or try it out (eg, via "make tryShell"), without having to flash a device for that.
Lukáš Tinkl (lukas-kde) wrote : Posted in a previous version of this proposal | # |
> I would like to see a qml test launches an app and then closes it using this
> "quit" quick list menu entry.
There is already a test for this, albeit not a QML one: launchermodelte
> I should also be able to manually test this feature or try it out (eg, via
> "make tryShell"), without having to flash a device for that.
Right, I'll see what I can do with that but I'd prefer doing that in a separate MP; it goes a bit beyond the scope of this review, none of the current quick list actions are testable from QML yet (Pin/Unpin etc).
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1811
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal | # |
Some inline comments.
Lukáš Tinkl (lukas-kde) wrote : Posted in a previous version of this proposal | # |
> Some inline comments.
Should be fixed by r. 1812
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1813
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal | # |
Hmm... testing it, the quicklist visuals seem to be the expected ones any more. Sorry if I gave bad advice on reverting the complete commit. We should only revert the positioning to what it was before, but not the coloring. Also the arrow points to the wrong direction. It should point from the menu box towards the clicked launcher item, not the other way round.
Lukáš Tinkl (lukas-kde) wrote : Posted in a previous version of this proposal | # |
Ack, will fix
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal | # |
http://
Font is white on white, also I'm missing the close entry.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1814
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1815
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1823
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : Posted in a previous version of this proposal | # |
Text conflict in qml/Launcher/
1 conflicts encountered.
Albert Astals Cid (aacid) : Posted in a previous version of this proposal | # |
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1824
http://
Executed test runs:
FAILURE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal | # |
Looks ok and works, except the dbusinterface changes are not needed. Please drop them.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1825
http://
Executed test runs:
FAILURE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal | # |
* Did you perform an exploratory manual test run of the code change and any related functionality?
yes
* Did CI run pass? If not, please explain why.
as much as it can, yes
* Did you make sure that the branch does not contain spurious tags?
yes
Michael Zanetti (mzanetti) wrote : | # |
re-approving as per superseded MP.
Jenkins won't work on this any more as it now depends on a unity-api change...
- 1827. By Lukáš Tinkl
-
re-merge again on top of use-set-
progress- api to fix failing QML tests
Preview Diff
1 | === modified file 'plugins/Greeter/Unity/Launcher/launchermodelas.cpp' | |||
2 | --- plugins/Greeter/Unity/Launcher/launchermodelas.cpp 2015-07-29 12:33:59 +0000 | |||
3 | +++ plugins/Greeter/Unity/Launcher/launchermodelas.cpp 2015-07-29 12:33:59 +0000 | |||
4 | @@ -67,6 +67,8 @@ | |||
5 | 67 | return item->progress(); | 67 | return item->progress(); |
6 | 68 | case RoleFocused: | 68 | case RoleFocused: |
7 | 69 | return item->focused(); | 69 | return item->focused(); |
8 | 70 | case RoleRunning: | ||
9 | 71 | return item->running(); | ||
10 | 70 | } | 72 | } |
11 | 71 | 73 | ||
12 | 72 | return QVariant(); | 74 | return QVariant(); |
13 | @@ -217,14 +219,10 @@ | |||
14 | 217 | item->setCount(cachedMap.value("count").toInt()); | 219 | item->setCount(cachedMap.value("count").toInt()); |
15 | 218 | item->setCountVisible(cachedMap.value("countVisible").toBool()); | 220 | item->setCountVisible(cachedMap.value("countVisible").toBool()); |
16 | 219 | item->setProgress(cachedMap.value("progress").toInt()); | 221 | item->setProgress(cachedMap.value("progress").toInt()); |
17 | 222 | item->setRunning(cachedMap.value("running").toBool()); | ||
18 | 223 | |||
19 | 220 | int idx = m_list.indexOf(item); | 224 | int idx = m_list.indexOf(item); |
27 | 221 | Q_EMIT dataChanged(index(idx), | 225 | Q_EMIT dataChanged(index(idx), index(idx), {RoleName, RoleIcon, RoleCount, RoleCountVisible, RoleRunning, RoleProgress}); |
21 | 222 | index(idx), | ||
22 | 223 | {RoleName, | ||
23 | 224 | RoleIcon, | ||
24 | 225 | RoleCount, | ||
25 | 226 | RoleCountVisible, | ||
26 | 227 | RoleProgress}); | ||
28 | 228 | } | 226 | } |
29 | 229 | break; | 227 | break; |
30 | 230 | } | 228 | } |
31 | @@ -262,16 +260,17 @@ | |||
32 | 262 | } | 260 | } |
33 | 263 | 261 | ||
34 | 264 | if (itemIndex == -1) { | 262 | if (itemIndex == -1) { |
36 | 265 | QVariantMap chachedMap = entry.toMap(); | 263 | QVariantMap cachedMap = entry.toMap(); |
37 | 266 | // Need to add it. Just add it into the addedIndex to keep same ordering as the list in AS. | 264 | // Need to add it. Just add it into the addedIndex to keep same ordering as the list in AS. |
41 | 267 | LauncherItem *item = new LauncherItem(chachedMap.value("id").toString(), | 265 | LauncherItem *item = new LauncherItem(cachedMap.value("id").toString(), |
42 | 268 | chachedMap.value("name").toString(), | 266 | cachedMap.value("name").toString(), |
43 | 269 | chachedMap.value("icon").toString(), | 267 | cachedMap.value("icon").toString(), |
44 | 270 | this); | 268 | this); |
45 | 271 | item->setPinned(true); | 269 | item->setPinned(true); |
49 | 272 | item->setCount(chachedMap.value("count").toInt()); | 270 | item->setCount(cachedMap.value("count").toInt()); |
50 | 273 | item->setCountVisible(chachedMap.value("countVisible").toBool()); | 271 | item->setCountVisible(cachedMap.value("countVisible").toBool()); |
51 | 274 | item->setProgress(chachedMap.value("progress").toInt()); | 272 | item->setProgress(cachedMap.value("progress").toInt()); |
52 | 273 | item->setRunning(cachedMap.value("running").toBool()); | ||
53 | 275 | beginInsertRows(QModelIndex(), newPosition, newPosition); | 274 | beginInsertRows(QModelIndex(), newPosition, newPosition); |
54 | 276 | m_list.insert(newPosition, item); | 275 | m_list.insert(newPosition, item); |
55 | 277 | endInsertRows(); | 276 | endInsertRows(); |
56 | 278 | 277 | ||
57 | === modified file 'plugins/Unity/Launcher/asadapter.cpp' | |||
58 | --- plugins/Unity/Launcher/asadapter.cpp 2015-07-29 12:33:59 +0000 | |||
59 | +++ plugins/Unity/Launcher/asadapter.cpp 2015-07-29 12:33:59 +0000 | |||
60 | @@ -34,12 +34,12 @@ | |||
61 | 34 | m_accounts->deleteLater(); | 34 | m_accounts->deleteLater(); |
62 | 35 | } | 35 | } |
63 | 36 | 36 | ||
65 | 37 | void ASAdapter::syncItems(QList<LauncherItem *> m_list) | 37 | void ASAdapter::syncItems(const QList<LauncherItem*> &list) |
66 | 38 | { | 38 | { |
67 | 39 | if (m_accounts && !m_user.isEmpty()) { | 39 | if (m_accounts && !m_user.isEmpty()) { |
68 | 40 | QList<QVariantMap> items; | 40 | QList<QVariantMap> items; |
69 | 41 | 41 | ||
71 | 42 | Q_FOREACH(LauncherItem *item, m_list) { | 42 | Q_FOREACH(LauncherItem *item, list) { |
72 | 43 | items << itemToVariant(item); | 43 | items << itemToVariant(item); |
73 | 44 | } | 44 | } |
74 | 45 | 45 | ||
75 | @@ -56,6 +56,7 @@ | |||
76 | 56 | details.insert("count", item->count()); | 56 | details.insert("count", item->count()); |
77 | 57 | details.insert("countVisible", item->countVisible()); | 57 | details.insert("countVisible", item->countVisible()); |
78 | 58 | details.insert("pinned", item->pinned()); | 58 | details.insert("pinned", item->pinned()); |
79 | 59 | details.insert("running", item->running()); | ||
80 | 59 | details.insert("progress", item->progress()); | 60 | details.insert("progress", item->progress()); |
81 | 60 | return details; | 61 | return details; |
82 | 61 | } | 62 | } |
83 | 62 | 63 | ||
84 | === modified file 'plugins/Unity/Launcher/asadapter.h' | |||
85 | --- plugins/Unity/Launcher/asadapter.h 2015-02-11 14:13:26 +0000 | |||
86 | +++ plugins/Unity/Launcher/asadapter.h 2015-07-29 12:33:59 +0000 | |||
87 | @@ -21,7 +21,6 @@ | |||
88 | 21 | 21 | ||
89 | 22 | class LauncherItem; | 22 | class LauncherItem; |
90 | 23 | class AccountsServiceDBusAdaptor; | 23 | class AccountsServiceDBusAdaptor; |
91 | 24 | class QDBusInterface; | ||
92 | 25 | 24 | ||
93 | 26 | class ASAdapter | 25 | class ASAdapter |
94 | 27 | { | 26 | { |
95 | @@ -29,7 +28,7 @@ | |||
96 | 29 | ASAdapter(); | 28 | ASAdapter(); |
97 | 30 | ~ASAdapter(); | 29 | ~ASAdapter(); |
98 | 31 | 30 | ||
100 | 32 | void syncItems(QList<LauncherItem*> m_list); | 31 | void syncItems(const QList<LauncherItem*> &list); |
101 | 33 | 32 | ||
102 | 34 | private: | 33 | private: |
103 | 35 | QVariantMap itemToVariant(LauncherItem *item) const; | 34 | QVariantMap itemToVariant(LauncherItem *item) const; |
104 | @@ -38,8 +37,6 @@ | |||
105 | 38 | AccountsServiceDBusAdaptor *m_accounts; | 37 | AccountsServiceDBusAdaptor *m_accounts; |
106 | 39 | QString m_user; | 38 | QString m_user; |
107 | 40 | 39 | ||
108 | 41 | QDBusInterface *m_userInterface; | ||
109 | 42 | |||
110 | 43 | friend class LauncherModelTest; | 40 | friend class LauncherModelTest; |
111 | 44 | }; | 41 | }; |
112 | 45 | 42 | ||
113 | 46 | 43 | ||
114 | === modified file 'plugins/Unity/Launcher/gsettings.cpp' | |||
115 | --- plugins/Unity/Launcher/gsettings.cpp 2015-03-04 08:54:12 +0000 | |||
116 | +++ plugins/Unity/Launcher/gsettings.cpp 2015-07-29 12:33:59 +0000 | |||
117 | @@ -68,7 +68,7 @@ | |||
118 | 68 | void GSettings::onSettingsChanged(const QString &key) | 68 | void GSettings::onSettingsChanged(const QString &key) |
119 | 69 | { | 69 | { |
120 | 70 | if (key == "items") { | 70 | if (key == "items") { |
122 | 71 | QStringList cachedItems = m_gSettings->get("items").toStringList(); | 71 | const QStringList cachedItems = m_gSettings->get("items").toStringList(); |
123 | 72 | if (m_cachedItems != cachedItems) { | 72 | if (m_cachedItems != cachedItems) { |
124 | 73 | m_cachedItems = cachedItems; | 73 | m_cachedItems = cachedItems; |
125 | 74 | Q_EMIT changed(); | 74 | Q_EMIT changed(); |
126 | 75 | 75 | ||
127 | === modified file 'plugins/Unity/Launcher/launcheritem.cpp' | |||
128 | --- plugins/Unity/Launcher/launcheritem.cpp 2015-07-29 12:33:59 +0000 | |||
129 | +++ plugins/Unity/Launcher/launcheritem.cpp 2015-07-29 12:33:59 +0000 | |||
130 | @@ -41,10 +41,15 @@ | |||
131 | 41 | nameAction.setActionId("launch_item"); | 41 | nameAction.setActionId("launch_item"); |
132 | 42 | nameAction.setText(m_name); | 42 | nameAction.setText(m_name); |
133 | 43 | m_quickList->appendAction(nameAction); | 43 | m_quickList->appendAction(nameAction); |
134 | 44 | |||
135 | 44 | QuickListEntry pinningAction; | 45 | QuickListEntry pinningAction; |
136 | 45 | pinningAction.setActionId("pin_item"); | 46 | pinningAction.setActionId("pin_item"); |
137 | 46 | pinningAction.setText(gettext("Pin shortcut")); | 47 | pinningAction.setText(gettext("Pin shortcut")); |
138 | 47 | m_quickList->appendAction(pinningAction); | 48 | m_quickList->appendAction(pinningAction); |
139 | 49 | |||
140 | 50 | m_quitAction.setActionId("stop_item"); | ||
141 | 51 | m_quitAction.setIcon("application-exit"); | ||
142 | 52 | m_quitAction.setText(gettext("Quit")); | ||
143 | 48 | } | 53 | } |
144 | 49 | 54 | ||
145 | 50 | QString LauncherItem::appId() const | 55 | QString LauncherItem::appId() const |
146 | @@ -111,6 +116,11 @@ | |||
147 | 111 | { | 116 | { |
148 | 112 | if (m_running != running) { | 117 | if (m_running != running) { |
149 | 113 | m_running = running; | 118 | m_running = running; |
150 | 119 | if (m_running) { // add the quit action | ||
151 | 120 | m_quickList->appendAction(m_quitAction); | ||
152 | 121 | } else { // remove the quit action | ||
153 | 122 | m_quickList->removeAction(m_quitAction); | ||
154 | 123 | } | ||
155 | 114 | Q_EMIT runningChanged(running); | 124 | Q_EMIT runningChanged(running); |
156 | 115 | } | 125 | } |
157 | 116 | } | 126 | } |
158 | 117 | 127 | ||
159 | === modified file 'plugins/Unity/Launcher/launcheritem.h' | |||
160 | --- plugins/Unity/Launcher/launcheritem.h 2015-07-29 12:33:59 +0000 | |||
161 | +++ plugins/Unity/Launcher/launcheritem.h 2015-07-29 12:33:59 +0000 | |||
162 | @@ -73,6 +73,7 @@ | |||
163 | 73 | bool m_focused; | 73 | bool m_focused; |
164 | 74 | bool m_alerting; | 74 | bool m_alerting; |
165 | 75 | QuickListModel *m_quickList; | 75 | QuickListModel *m_quickList; |
166 | 76 | QuickListEntry m_quitAction; | ||
167 | 76 | 77 | ||
168 | 77 | friend class LauncherModel; | 78 | friend class LauncherModel; |
169 | 78 | }; | 79 | }; |
170 | 79 | 80 | ||
171 | === modified file 'plugins/Unity/Launcher/launchermodel.cpp' | |||
172 | --- plugins/Unity/Launcher/launchermodel.cpp 2015-07-29 12:33:59 +0000 | |||
173 | +++ plugins/Unity/Launcher/launchermodel.cpp 2015-07-29 12:33:59 +0000 | |||
174 | @@ -36,7 +36,7 @@ | |||
175 | 36 | m_settings(new GSettings(this)), | 36 | m_settings(new GSettings(this)), |
176 | 37 | m_dbusIface(new DBusInterface(this)), | 37 | m_dbusIface(new DBusInterface(this)), |
177 | 38 | m_asAdapter(new ASAdapter()), | 38 | m_asAdapter(new ASAdapter()), |
179 | 39 | m_appManager(0) | 39 | m_appManager(nullptr) |
180 | 40 | { | 40 | { |
181 | 41 | connect(m_dbusIface, &DBusInterface::countChanged, this, &LauncherModel::countChanged); | 41 | connect(m_dbusIface, &DBusInterface::countChanged, this, &LauncherModel::countChanged); |
182 | 42 | connect(m_dbusIface, &DBusInterface::countVisibleChanged, this, &LauncherModel::countVisibleChanged); | 42 | connect(m_dbusIface, &DBusInterface::countVisibleChanged, this, &LauncherModel::countVisibleChanged); |
183 | @@ -86,6 +86,11 @@ | |||
184 | 86 | return item->focused(); | 86 | return item->focused(); |
185 | 87 | case RoleAlerting: | 87 | case RoleAlerting: |
186 | 88 | return item->alerting(); | 88 | return item->alerting(); |
187 | 89 | case RoleRunning: | ||
188 | 90 | return item->running(); | ||
189 | 91 | default: | ||
190 | 92 | qWarning() << Q_FUNC_INFO << "missing role, implement me"; | ||
191 | 93 | return QVariant(); | ||
192 | 89 | } | 94 | } |
193 | 90 | 95 | ||
194 | 91 | return QVariant(); | 96 | return QVariant(); |
195 | @@ -150,7 +155,7 @@ | |||
196 | 150 | if (index == -1 || index == currentIndex) { | 155 | if (index == -1 || index == currentIndex) { |
197 | 151 | m_list.at(currentIndex)->setPinned(true); | 156 | m_list.at(currentIndex)->setPinned(true); |
198 | 152 | QModelIndex modelIndex = this->index(currentIndex); | 157 | QModelIndex modelIndex = this->index(currentIndex); |
200 | 153 | Q_EMIT dataChanged(modelIndex, modelIndex, QVector<int>() << RolePinned); | 158 | Q_EMIT dataChanged(modelIndex, modelIndex, {RolePinned}); |
201 | 154 | } else { | 159 | } else { |
202 | 155 | move(currentIndex, index); | 160 | move(currentIndex, index); |
203 | 156 | // move() will store the list to the backend itself, so just exit at this point. | 161 | // move() will store the list to the backend itself, so just exit at this point. |
204 | @@ -163,7 +168,7 @@ | |||
205 | 163 | 168 | ||
206 | 164 | DesktopFileHandler desktopFile(appId); | 169 | DesktopFileHandler desktopFile(appId); |
207 | 165 | if (!desktopFile.isValid()) { | 170 | if (!desktopFile.isValid()) { |
209 | 166 | qWarning() << "Can't pin this application, there is no .destkop file available."; | 171 | qWarning() << "Can't pin this application, there is no .desktop file available."; |
210 | 167 | return; | 172 | return; |
211 | 168 | } | 173 | } |
212 | 169 | 174 | ||
213 | @@ -188,7 +193,7 @@ | |||
214 | 188 | 193 | ||
215 | 189 | void LauncherModel::quickListActionInvoked(const QString &appId, int actionIndex) | 194 | void LauncherModel::quickListActionInvoked(const QString &appId, int actionIndex) |
216 | 190 | { | 195 | { |
218 | 191 | int index = findApplication(appId); | 196 | const int index = findApplication(appId); |
219 | 192 | if (index < 0) { | 197 | if (index < 0) { |
220 | 193 | return; | 198 | return; |
221 | 194 | } | 199 | } |
222 | @@ -196,7 +201,7 @@ | |||
223 | 196 | LauncherItem *item = m_list.at(index); | 201 | LauncherItem *item = m_list.at(index); |
224 | 197 | QuickListModel *model = qobject_cast<QuickListModel*>(item->quickList()); | 202 | QuickListModel *model = qobject_cast<QuickListModel*>(item->quickList()); |
225 | 198 | if (model) { | 203 | if (model) { |
227 | 199 | QString actionId = model->get(actionIndex).actionId(); | 204 | const QString actionId = model->get(actionIndex).actionId(); |
228 | 200 | 205 | ||
229 | 201 | // Check if this is one of the launcher actions we handle ourselves | 206 | // Check if this is one of the launcher actions we handle ourselves |
230 | 202 | if (actionId == "pin_item") { | 207 | if (actionId == "pin_item") { |
231 | @@ -207,7 +212,10 @@ | |||
232 | 207 | } | 212 | } |
233 | 208 | } else if (actionId == "launch_item") { | 213 | } else if (actionId == "launch_item") { |
234 | 209 | QDesktopServices::openUrl(getUrlForAppId(appId)); | 214 | QDesktopServices::openUrl(getUrlForAppId(appId)); |
236 | 210 | 215 | } else if (actionId == "stop_item") { // Quit | |
237 | 216 | if (m_appManager) { | ||
238 | 217 | m_appManager->stopApplication(appId); | ||
239 | 218 | } | ||
240 | 211 | // Nope, we don't know this action, let the backend forward it to the application | 219 | // Nope, we don't know this action, let the backend forward it to the application |
241 | 212 | } else { | 220 | } else { |
242 | 213 | // TODO: forward quicklist action to app, possibly via m_dbusIface | 221 | // TODO: forward quicklist action to app, possibly via m_dbusIface |
243 | @@ -305,7 +313,7 @@ | |||
244 | 305 | 313 | ||
245 | 306 | void LauncherModel::unpin(const QString &appId) | 314 | void LauncherModel::unpin(const QString &appId) |
246 | 307 | { | 315 | { |
248 | 308 | int index = findApplication(appId); | 316 | const int index = findApplication(appId); |
249 | 309 | if (index < 0) { | 317 | if (index < 0) { |
250 | 310 | return; | 318 | return; |
251 | 311 | } | 319 | } |
252 | @@ -314,7 +322,7 @@ | |||
253 | 314 | if (m_list.at(index)->pinned()) { | 322 | if (m_list.at(index)->pinned()) { |
254 | 315 | m_list.at(index)->setPinned(false); | 323 | m_list.at(index)->setPinned(false); |
255 | 316 | QModelIndex modelIndex = this->index(index); | 324 | QModelIndex modelIndex = this->index(index); |
257 | 317 | Q_EMIT dataChanged(modelIndex, modelIndex, QVector<int>() << RolePinned); | 325 | Q_EMIT dataChanged(modelIndex, modelIndex, {RolePinned}); |
258 | 318 | } | 326 | } |
259 | 319 | } else { | 327 | } else { |
260 | 320 | beginRemoveRows(QModelIndex(), index, index); | 328 | beginRemoveRows(QModelIndex(), index, index); |
261 | @@ -336,25 +344,25 @@ | |||
262 | 336 | 344 | ||
263 | 337 | void LauncherModel::progressChanged(const QString &appId, int progress) | 345 | void LauncherModel::progressChanged(const QString &appId, int progress) |
264 | 338 | { | 346 | { |
266 | 339 | int idx = findApplication(appId); | 347 | const int idx = findApplication(appId); |
267 | 340 | if (idx >= 0) { | 348 | if (idx >= 0) { |
268 | 341 | LauncherItem *item = m_list.at(idx); | 349 | LauncherItem *item = m_list.at(idx); |
269 | 342 | item->setProgress(progress); | 350 | item->setProgress(progress); |
271 | 343 | Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleProgress); | 351 | Q_EMIT dataChanged(index(idx), index(idx), {RoleProgress}); |
272 | 344 | } | 352 | } |
273 | 345 | } | 353 | } |
274 | 346 | 354 | ||
275 | 347 | void LauncherModel::countChanged(const QString &appId, int count) | 355 | void LauncherModel::countChanged(const QString &appId, int count) |
276 | 348 | { | 356 | { |
278 | 349 | int idx = findApplication(appId); | 357 | const int idx = findApplication(appId); |
279 | 350 | if (idx >= 0) { | 358 | if (idx >= 0) { |
280 | 351 | LauncherItem *item = m_list.at(idx); | 359 | LauncherItem *item = m_list.at(idx); |
281 | 352 | item->setCount(count); | 360 | item->setCount(count); |
282 | 353 | if (item->countVisible()) { | 361 | if (item->countVisible()) { |
283 | 354 | setAlerting(item->appId(), true); | 362 | setAlerting(item->appId(), true); |
284 | 355 | } | 363 | } |
285 | 356 | Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleCount); | ||
286 | 357 | m_asAdapter->syncItems(m_list); | 364 | m_asAdapter->syncItems(m_list); |
287 | 365 | Q_EMIT dataChanged(index(idx), index(idx), {RoleCount}); | ||
288 | 358 | } | 366 | } |
289 | 359 | } | 367 | } |
290 | 360 | 368 | ||
291 | @@ -367,7 +375,7 @@ | |||
292 | 367 | if (countVisible) { | 375 | if (countVisible) { |
293 | 368 | setAlerting(item->appId(), true); | 376 | setAlerting(item->appId(), true); |
294 | 369 | } | 377 | } |
296 | 370 | Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleCountVisible); | 378 | Q_EMIT dataChanged(index(idx), index(idx), {RoleCountVisible}); |
297 | 371 | 379 | ||
298 | 372 | // If countVisible goes to false, and the item is neither pinned nor recent we can drop it | 380 | // If countVisible goes to false, and the item is neither pinned nor recent we can drop it |
299 | 373 | if (!countVisible && !item->pinned() && !item->recent()) { | 381 | if (!countVisible && !item->pinned() && !item->recent()) { |
300 | @@ -408,7 +416,8 @@ | |||
301 | 408 | item->setName(desktopFile.displayName()); | 416 | item->setName(desktopFile.displayName()); |
302 | 409 | item->setIcon(desktopFile.icon()); | 417 | item->setIcon(desktopFile.icon()); |
303 | 410 | item->setPinned(item->pinned()); // update pinned text if needed | 418 | item->setPinned(item->pinned()); // update pinned text if needed |
305 | 411 | Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleName << RoleIcon); | 419 | item->setRunning(item->running()); |
306 | 420 | Q_EMIT dataChanged(index(idx), index(idx), {RoleName, RoleIcon, RoleRunning}); | ||
307 | 412 | } | 421 | } |
308 | 413 | } | 422 | } |
309 | 414 | 423 | ||
310 | @@ -426,7 +435,7 @@ | |||
311 | 426 | 435 | ||
312 | 427 | // Now walk through settings and see if we need to add something | 436 | // Now walk through settings and see if we need to add something |
313 | 428 | for (int settingsIndex = 0; settingsIndex < m_settings->storedApplications().count(); ++settingsIndex) { | 437 | for (int settingsIndex = 0; settingsIndex < m_settings->storedApplications().count(); ++settingsIndex) { |
315 | 429 | QString entry = m_settings->storedApplications().at(settingsIndex); | 438 | const QString entry = m_settings->storedApplications().at(settingsIndex); |
316 | 430 | int itemIndex = -1; | 439 | int itemIndex = -1; |
317 | 431 | for (int i = 0; i < m_list.count(); ++i) { | 440 | for (int i = 0; i < m_list.count(); ++i) { |
318 | 432 | if (m_list.at(i)->appId() == entry) { | 441 | if (m_list.at(i)->appId() == entry) { |
319 | @@ -499,25 +508,27 @@ | |||
320 | 499 | return; | 508 | return; |
321 | 500 | } | 509 | } |
322 | 501 | 510 | ||
324 | 502 | int itemIndex = findApplication(app->appId()); | 511 | const int itemIndex = findApplication(app->appId()); |
325 | 503 | if (itemIndex != -1) { | 512 | if (itemIndex != -1) { |
326 | 504 | LauncherItem *item = m_list.at(itemIndex); | 513 | LauncherItem *item = m_list.at(itemIndex); |
327 | 505 | if (!item->recent()) { | 514 | if (!item->recent()) { |
328 | 506 | item->setRecent(true); | 515 | item->setRecent(true); |
331 | 507 | m_asAdapter->syncItems(m_list); | 516 | Q_EMIT dataChanged(index(itemIndex), index(itemIndex), {RoleRecent}); |
330 | 508 | Q_EMIT dataChanged(index(itemIndex), index(itemIndex), QVector<int>() << RoleRecent); | ||
332 | 509 | } | 517 | } |
334 | 510 | // Shall we paint some running/recent app highlight? If yes, do it here. | 518 | item->setRunning(true); |
335 | 519 | // TODO Shall we paint some running/recent app highlight? If yes, do it here. | ||
336 | 511 | } else { | 520 | } else { |
337 | 512 | LauncherItem *item = new LauncherItem(app->appId(), app->name(), app->icon().toString(), this); | 521 | LauncherItem *item = new LauncherItem(app->appId(), app->name(), app->icon().toString(), this); |
338 | 513 | item->setRecent(true); | 522 | item->setRecent(true); |
339 | 523 | item->setRunning(true); | ||
340 | 514 | item->setFocused(app->focused()); | 524 | item->setFocused(app->focused()); |
341 | 515 | 525 | ||
342 | 516 | beginInsertRows(QModelIndex(), m_list.count(), m_list.count()); | 526 | beginInsertRows(QModelIndex(), m_list.count(), m_list.count()); |
343 | 517 | m_list.append(item); | 527 | m_list.append(item); |
344 | 518 | endInsertRows(); | 528 | endInsertRows(); |
345 | 519 | m_asAdapter->syncItems(m_list); | ||
346 | 520 | } | 529 | } |
347 | 530 | m_asAdapter->syncItems(m_list); | ||
348 | 531 | Q_EMIT dataChanged(index(itemIndex), index(itemIndex), {RoleRunning}); | ||
349 | 521 | } | 532 | } |
350 | 522 | 533 | ||
351 | 523 | void LauncherModel::applicationRemoved(const QModelIndex &parent, int row) | 534 | void LauncherModel::applicationRemoved(const QModelIndex &parent, int row) |
352 | @@ -532,25 +543,35 @@ | |||
353 | 532 | } | 543 | } |
354 | 533 | } | 544 | } |
355 | 534 | 545 | ||
357 | 535 | if (appIndex > -1 && !m_list.at(appIndex)->pinned()) { | 546 | if (appIndex < 0) { |
358 | 547 | qWarning() << Q_FUNC_INFO << "appIndex not found"; | ||
359 | 548 | return; | ||
360 | 549 | } | ||
361 | 550 | |||
362 | 551 | LauncherItem * item = m_list.at(appIndex); | ||
363 | 552 | item->setRunning(false); | ||
364 | 553 | |||
365 | 554 | if (!item->pinned()) { | ||
366 | 536 | beginRemoveRows(QModelIndex(), appIndex, appIndex); | 555 | beginRemoveRows(QModelIndex(), appIndex, appIndex); |
367 | 537 | m_list.takeAt(appIndex)->deleteLater(); | 556 | m_list.takeAt(appIndex)->deleteLater(); |
368 | 538 | endRemoveRows(); | 557 | endRemoveRows(); |
369 | 539 | m_asAdapter->syncItems(m_list); | 558 | m_asAdapter->syncItems(m_list); |
370 | 559 | Q_EMIT dataChanged(index(appIndex), index(appIndex), {RolePinned}); | ||
371 | 540 | } | 560 | } |
372 | 561 | Q_EMIT dataChanged(index(appIndex), index(appIndex), {RoleRunning}); | ||
373 | 541 | } | 562 | } |
374 | 542 | 563 | ||
375 | 543 | void LauncherModel::focusedAppIdChanged() | 564 | void LauncherModel::focusedAppIdChanged() |
376 | 544 | { | 565 | { |
378 | 545 | QString appId = m_appManager->focusedApplicationId(); | 566 | const QString appId = m_appManager->focusedApplicationId(); |
379 | 546 | for (int i = 0; i < m_list.count(); ++i) { | 567 | for (int i = 0; i < m_list.count(); ++i) { |
380 | 547 | LauncherItem *item = m_list.at(i); | 568 | LauncherItem *item = m_list.at(i); |
381 | 548 | if (!item->focused() && item->appId() == appId) { | 569 | if (!item->focused() && item->appId() == appId) { |
382 | 549 | item->setFocused(true); | 570 | item->setFocused(true); |
384 | 550 | Q_EMIT dataChanged(index(i), index(i), QVector<int>() << RoleFocused); | 571 | Q_EMIT dataChanged(index(i), index(i), {RoleFocused}); |
385 | 551 | } else if (item->focused() && item->appId() != appId) { | 572 | } else if (item->focused() && item->appId() != appId) { |
386 | 552 | item->setFocused(false); | 573 | item->setFocused(false); |
388 | 553 | Q_EMIT dataChanged(index(i), index(i), QVector<int>() << RoleFocused); | 574 | Q_EMIT dataChanged(index(i), index(i), {RoleFocused}); |
389 | 554 | } | 575 | } |
390 | 555 | } | 576 | } |
391 | 556 | } | 577 | } |
392 | 557 | 578 | ||
393 | === modified file 'plugins/Unity/Launcher/quicklistentry.cpp' | |||
394 | --- plugins/Unity/Launcher/quicklistentry.cpp 2014-08-26 11:34:22 +0000 | |||
395 | +++ plugins/Unity/Launcher/quicklistentry.cpp 2015-07-29 12:33:59 +0000 | |||
396 | @@ -1,4 +1,4 @@ | |||
398 | 1 | /* Copyright (C) 2013 Canonical, Ltd. | 1 | /* Copyright (C) 2013, 2015 Canonical, Ltd. |
399 | 2 | * | 2 | * |
400 | 3 | * Authors: | 3 | * Authors: |
401 | 4 | * Michael Zanetti <michael.zanetti@canonical.com> | 4 | * Michael Zanetti <michael.zanetti@canonical.com> |
402 | @@ -20,7 +20,6 @@ | |||
403 | 20 | 20 | ||
404 | 21 | QuickListEntry::QuickListEntry() | 21 | QuickListEntry::QuickListEntry() |
405 | 22 | { | 22 | { |
406 | 23 | |||
407 | 24 | } | 23 | } |
408 | 25 | 24 | ||
409 | 26 | QString QuickListEntry::actionId() const | 25 | QString QuickListEntry::actionId() const |
410 | @@ -57,3 +56,8 @@ | |||
411 | 57 | { | 56 | { |
412 | 58 | return !m_actionId.isEmpty(); | 57 | return !m_actionId.isEmpty(); |
413 | 59 | } | 58 | } |
414 | 59 | |||
415 | 60 | bool QuickListEntry::operator==(const QuickListEntry &other) | ||
416 | 61 | { | ||
417 | 62 | return !other.actionId().isEmpty() && other.actionId() == m_actionId; | ||
418 | 63 | } | ||
419 | 60 | 64 | ||
420 | === modified file 'plugins/Unity/Launcher/quicklistentry.h' | |||
421 | --- plugins/Unity/Launcher/quicklistentry.h 2014-08-26 11:34:22 +0000 | |||
422 | +++ plugins/Unity/Launcher/quicklistentry.h 2015-07-29 12:33:59 +0000 | |||
423 | @@ -1,4 +1,4 @@ | |||
425 | 1 | /* Copyright (C) 2013 Canonical, Ltd. | 1 | /* Copyright (C) 2013, 2015 Canonical, Ltd. |
426 | 2 | * | 2 | * |
427 | 3 | * Authors: | 3 | * Authors: |
428 | 4 | * Michael Zanetti <michael.zanetti@canonical.com> | 4 | * Michael Zanetti <michael.zanetti@canonical.com> |
429 | @@ -37,6 +37,8 @@ | |||
430 | 37 | 37 | ||
431 | 38 | bool clickable() const; | 38 | bool clickable() const; |
432 | 39 | 39 | ||
433 | 40 | bool operator==(const QuickListEntry & other); | ||
434 | 41 | |||
435 | 40 | private: | 42 | private: |
436 | 41 | QString m_actionId; | 43 | QString m_actionId; |
437 | 42 | QString m_text; | 44 | QString m_text; |
438 | 43 | 45 | ||
439 | === modified file 'plugins/Unity/Launcher/quicklistmodel.cpp' | |||
440 | --- plugins/Unity/Launcher/quicklistmodel.cpp 2013-10-02 11:00:53 +0000 | |||
441 | +++ plugins/Unity/Launcher/quicklistmodel.cpp 2015-07-29 12:33:59 +0000 | |||
442 | @@ -1,5 +1,5 @@ | |||
443 | 1 | /* | 1 | /* |
445 | 2 | * Copyright 2013 Canonical Ltd. | 2 | * Copyright 2013, 2015 Canonical Ltd. |
446 | 3 | * | 3 | * |
447 | 4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
448 | 5 | * it under the terms of the GNU Lesser General Public License as published by | 5 | * it under the terms of the GNU Lesser General Public License as published by |
449 | @@ -48,6 +48,17 @@ | |||
450 | 48 | } | 48 | } |
451 | 49 | } | 49 | } |
452 | 50 | 50 | ||
453 | 51 | void QuickListModel::removeAction(const QuickListEntry &entry) | ||
454 | 52 | { | ||
455 | 53 | const int start = m_list.indexOf(entry); | ||
456 | 54 | if (start > -1) { | ||
457 | 55 | beginRemoveRows(QModelIndex(), start, start); | ||
458 | 56 | m_list.removeOne(entry); | ||
459 | 57 | Q_EMIT dataChanged(index(start), index(start)); | ||
460 | 58 | endRemoveRows(); | ||
461 | 59 | } | ||
462 | 60 | } | ||
463 | 61 | |||
464 | 51 | QuickListEntry QuickListModel::get(int index) const | 62 | QuickListEntry QuickListModel::get(int index) const |
465 | 52 | { | 63 | { |
466 | 53 | return m_list.at(index); | 64 | return m_list.at(index); |
467 | 54 | 65 | ||
468 | === modified file 'plugins/Unity/Launcher/quicklistmodel.h' | |||
469 | --- plugins/Unity/Launcher/quicklistmodel.h 2015-04-30 09:31:51 +0000 | |||
470 | +++ plugins/Unity/Launcher/quicklistmodel.h 2015-07-29 12:33:59 +0000 | |||
471 | @@ -1,5 +1,5 @@ | |||
472 | 1 | /* | 1 | /* |
474 | 2 | * Copyright 2013 Canonical Ltd. | 2 | * Copyright 201, 2015 Canonical Ltd. |
475 | 3 | * | 3 | * |
476 | 4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
477 | 5 | * it under the terms of the GNU Lesser General Public License as published by | 5 | * it under the terms of the GNU Lesser General Public License as published by |
478 | @@ -46,6 +46,8 @@ | |||
479 | 46 | */ | 46 | */ |
480 | 47 | void updateAction(const QuickListEntry &entry); | 47 | void updateAction(const QuickListEntry &entry); |
481 | 48 | 48 | ||
482 | 49 | void removeAction(const QuickListEntry &entry); | ||
483 | 50 | |||
484 | 49 | QuickListEntry get(int index) const; | 51 | QuickListEntry get(int index) const; |
485 | 50 | 52 | ||
486 | 51 | int rowCount(const QModelIndex &parent = QModelIndex()) const override; | 53 | int rowCount(const QModelIndex &parent = QModelIndex()) const override; |
487 | 52 | 54 | ||
488 | === modified file 'qml/Launcher/LauncherPanel.qml' | |||
489 | --- qml/Launcher/LauncherPanel.qml 2015-07-29 12:33:59 +0000 | |||
490 | +++ qml/Launcher/LauncherPanel.qml 2015-07-29 12:33:59 +0000 | |||
491 | @@ -15,7 +15,7 @@ | |||
492 | 15 | */ | 15 | */ |
493 | 16 | 16 | ||
494 | 17 | import QtQuick 2.3 | 17 | import QtQuick 2.3 |
496 | 18 | import Ubuntu.Components 1.1 | 18 | import Ubuntu.Components 1.2 |
497 | 19 | import Ubuntu.Components.ListItems 1.0 as ListItems | 19 | import Ubuntu.Components.ListItems 1.0 as ListItems |
498 | 20 | import Unity.Launcher 0.1 | 20 | import Unity.Launcher 0.1 |
499 | 21 | import Ubuntu.Components.Popups 0.1 | 21 | import Ubuntu.Components.Popups 0.1 |
500 | @@ -358,6 +358,7 @@ | |||
501 | 358 | MouseArea { | 358 | MouseArea { |
502 | 359 | id: dndArea | 359 | id: dndArea |
503 | 360 | objectName: "dndArea" | 360 | objectName: "dndArea" |
504 | 361 | acceptedButtons: Qt.LeftButton | Qt.RightButton | ||
505 | 361 | anchors { | 362 | anchors { |
506 | 362 | fill: parent | 363 | fill: parent |
507 | 363 | topMargin: launcherListView.topMargin | 364 | topMargin: launcherListView.topMargin |
508 | @@ -369,7 +370,7 @@ | |||
509 | 369 | property int draggedIndex: -1 | 370 | property int draggedIndex: -1 |
510 | 370 | property var selectedItem | 371 | property var selectedItem |
511 | 371 | property bool preDragging: false | 372 | property bool preDragging: false |
513 | 372 | property bool dragging: selectedItem !== undefined && selectedItem !== null && selectedItem.dragging | 373 | property bool dragging: !!selectedItem && selectedItem.dragging |
514 | 373 | property bool postDragging: false | 374 | property bool postDragging: false |
515 | 374 | property int startX | 375 | property int startX |
516 | 375 | property int startY | 376 | property int startY |
517 | @@ -387,6 +388,15 @@ | |||
518 | 387 | return; | 388 | return; |
519 | 388 | } | 389 | } |
520 | 389 | 390 | ||
521 | 391 | if (mouse.button & Qt.RightButton) { // context menu | ||
522 | 392 | // Opening QuickList | ||
523 | 393 | quickList.item = clickedItem; | ||
524 | 394 | quickList.model = launcherListView.model.get(index).quickList; | ||
525 | 395 | quickList.appId = launcherListView.model.get(index).appId; | ||
526 | 396 | quickList.state = "open"; | ||
527 | 397 | return | ||
528 | 398 | } | ||
529 | 399 | |||
530 | 390 | // First/last item do the scrolling at more than 12 degrees | 400 | // First/last item do the scrolling at more than 12 degrees |
531 | 391 | if (index == 0 || index == launcherListView.count - 1) { | 401 | if (index == 0 || index == launcherListView.count - 1) { |
532 | 392 | if (clickedItem.angle > 12) { | 402 | if (clickedItem.angle > 12) { |
533 | @@ -580,7 +590,7 @@ | |||
534 | 580 | id: quickListShape | 590 | id: quickListShape |
535 | 581 | objectName: "quickListShape" | 591 | objectName: "quickListShape" |
536 | 582 | anchors.fill: quickList | 592 | anchors.fill: quickList |
538 | 583 | opacity: quickList.state === "open" ? 0.96 : 0 | 593 | opacity: quickList.state === "open" ? 0.8 : 0 |
539 | 584 | visible: opacity > 0 | 594 | visible: opacity > 0 |
540 | 585 | rotation: root.rotation | 595 | rotation: root.rotation |
541 | 586 | 596 | ||
542 | @@ -592,15 +602,15 @@ | |||
543 | 592 | 602 | ||
544 | 593 | Image { | 603 | Image { |
545 | 594 | anchors { | 604 | anchors { |
548 | 595 | left: parent.left | 605 | right: parent.left |
549 | 596 | leftMargin: quickList.item !== undefined ? (quickList.item.width - units.gu(1)) / 2 - width / 2 : 0 | 606 | rightMargin: -units.dp(4) |
550 | 597 | verticalCenter: parent.verticalCenter | 607 | verticalCenter: parent.verticalCenter |
552 | 598 | verticalCenterOffset: (parent.height / 2 + units.dp(3)) * (quickList.offset > 0 ? 1 : -1) * (root.inverted ? 1 : -1) | 608 | verticalCenterOffset: -quickList.offset * (root.inverted ? -1 : 1) |
553 | 599 | } | 609 | } |
554 | 600 | height: units.gu(1) | 610 | height: units.gu(1) |
555 | 601 | width: units.gu(2) | 611 | width: units.gu(2) |
556 | 602 | source: "graphics/quicklist_tooltip.png" | 612 | source: "graphics/quicklist_tooltip.png" |
558 | 603 | rotation: (quickList.offset > 0 ? 0 : 180) + (root.inverted ? 0 : 180) | 613 | rotation: 90 |
559 | 604 | } | 614 | } |
560 | 605 | 615 | ||
561 | 606 | InverseMouseArea { | 616 | InverseMouseArea { |
562 | @@ -623,11 +633,11 @@ | |||
563 | 623 | height: quickListColumn.height | 633 | height: quickListColumn.height |
564 | 624 | visible: quickListShape.visible | 634 | visible: quickListShape.visible |
565 | 625 | anchors { | 635 | anchors { |
568 | 626 | left: root.inverted ? undefined : parent.left | 636 | left: root.inverted ? undefined : parent.right |
569 | 627 | right: root.inverted ? parent.right : undefined | 637 | right: root.inverted ? parent.left : undefined |
570 | 628 | margins: units.gu(1) | 638 | margins: units.gu(1) |
571 | 629 | } | 639 | } |
573 | 630 | y: itemCenter + offset | 640 | y: itemCenter - (height / 2) + offset |
574 | 631 | rotation: root.rotation | 641 | rotation: root.rotation |
575 | 632 | 642 | ||
576 | 633 | property var model | 643 | property var model |
577 | @@ -636,9 +646,8 @@ | |||
578 | 636 | 646 | ||
579 | 637 | // internal | 647 | // internal |
580 | 638 | property int itemCenter: item ? root.mapFromItem(quickList.item).y + (item.height / 2) : units.gu(1) | 648 | property int itemCenter: item ? root.mapFromItem(quickList.item).y + (item.height / 2) : units.gu(1) |
584 | 639 | property int offset: item !== undefined ? (itemCenter + (item.height/2) + height + units.gu(1) > parent.height ? | 649 | property int offset: itemCenter + (height/2) + units.gu(1) > parent.height ? -itemCenter - (height/2) - units.gu(1) + parent.height : |
585 | 640 | -(item.height/2) - height - units.gu(.5) : | 650 | itemCenter - (height/2) < units.gu(1) ? (height/2) - itemCenter + units.gu(1) : 0 |
583 | 641 | (item.height/2) + units.gu(.5)) : 0 | ||
586 | 642 | 651 | ||
587 | 643 | Column { | 652 | Column { |
588 | 644 | id: quickListColumn | 653 | id: quickListColumn |
589 | 645 | 654 | ||
590 | === modified file 'tests/mocks/Unity/Launcher/MockLauncherItem.cpp' | |||
591 | --- tests/mocks/Unity/Launcher/MockLauncherItem.cpp 2015-07-29 12:33:59 +0000 | |||
592 | +++ tests/mocks/Unity/Launcher/MockLauncherItem.cpp 2015-07-29 12:33:59 +0000 | |||
593 | @@ -40,7 +40,10 @@ | |||
594 | 40 | m_alerting(false), | 40 | m_alerting(false), |
595 | 41 | m_quickList(new MockQuickListModel(this)) | 41 | m_quickList(new MockQuickListModel(this)) |
596 | 42 | { | 42 | { |
597 | 43 | } | ||
598 | 43 | 44 | ||
599 | 45 | MockLauncherItem::~MockLauncherItem() | ||
600 | 46 | { | ||
601 | 44 | } | 47 | } |
602 | 45 | 48 | ||
603 | 46 | QString MockLauncherItem::appId() const | 49 | QString MockLauncherItem::appId() const |
604 | 47 | 50 | ||
605 | === modified file 'tests/mocks/Unity/Launcher/MockLauncherItem.h' | |||
606 | --- tests/mocks/Unity/Launcher/MockLauncherItem.h 2015-07-29 12:33:59 +0000 | |||
607 | +++ tests/mocks/Unity/Launcher/MockLauncherItem.h 2015-07-29 12:33:59 +0000 | |||
608 | @@ -31,6 +31,7 @@ | |||
609 | 31 | Q_OBJECT | 31 | Q_OBJECT |
610 | 32 | public: | 32 | public: |
611 | 33 | MockLauncherItem(const QString &appId, const QString& desktopFile, const QString& name, const QString& icon, QObject* parent = 0); | 33 | MockLauncherItem(const QString &appId, const QString& desktopFile, const QString& name, const QString& icon, QObject* parent = 0); |
612 | 34 | ~MockLauncherItem(); | ||
613 | 34 | 35 | ||
614 | 35 | QString appId() const override; | 36 | QString appId() const override; |
615 | 36 | QString desktopFile() const; | 37 | QString desktopFile() const; |
616 | 37 | 38 | ||
617 | === modified file 'tests/mocks/Unity/Launcher/MockLauncherModel.cpp' | |||
618 | --- tests/mocks/Unity/Launcher/MockLauncherModel.cpp 2015-07-29 12:33:59 +0000 | |||
619 | +++ tests/mocks/Unity/Launcher/MockLauncherModel.cpp 2015-07-29 12:33:59 +0000 | |||
620 | @@ -44,6 +44,7 @@ | |||
621 | 44 | item = new MockLauncherItem("webbrowser-app", "/usr/share/applications/webbrowser-app.desktop", "Browser", "browser", this); | 44 | item = new MockLauncherItem("webbrowser-app", "/usr/share/applications/webbrowser-app.desktop", "Browser", "browser", this); |
622 | 45 | item->setCount(1); | 45 | item->setCount(1); |
623 | 46 | item->setCountVisible(true); | 46 | item->setCountVisible(true); |
624 | 47 | item->setRunning(true); | ||
625 | 47 | item->setAlerting(false); | 48 | item->setAlerting(false); |
626 | 48 | m_list.append(item); | 49 | m_list.append(item); |
627 | 49 | item = new MockLauncherItem("twitter-webapp", "/usr/share/applications/twitter-webapp.desktop", "Twitter", "twitter", this); | 50 | item = new MockLauncherItem("twitter-webapp", "/usr/share/applications/twitter-webapp.desktop", "Twitter", "twitter", this); |
628 | @@ -194,7 +195,9 @@ | |||
629 | 194 | int index = findApp(appId); | 195 | int index = findApp(appId); |
630 | 195 | if (index >= 0) { | 196 | if (index >= 0) { |
631 | 196 | beginRemoveRows(QModelIndex(), index, 0); | 197 | beginRemoveRows(QModelIndex(), index, 0); |
633 | 197 | m_list.takeAt(index)->deleteLater(); | 198 | MockLauncherItem * item = m_list.takeAt(index); |
634 | 199 | item->setRunning(false); | ||
635 | 200 | item->deleteLater(); | ||
636 | 198 | endRemoveRows(); | 201 | endRemoveRows(); |
637 | 199 | } | 202 | } |
638 | 200 | } | 203 | } |
639 | 201 | 204 | ||
640 | === modified file 'tests/plugins/Unity/Launcher/launchermodeltest.cpp' | |||
641 | --- tests/plugins/Unity/Launcher/launchermodeltest.cpp 2015-07-29 12:33:59 +0000 | |||
642 | +++ tests/plugins/Unity/Launcher/launchermodeltest.cpp 2015-07-29 12:33:59 +0000 | |||
643 | @@ -68,6 +68,7 @@ | |||
644 | 68 | Q_OBJECT | 68 | Q_OBJECT |
645 | 69 | public: | 69 | public: |
646 | 70 | MockAppManager(QObject *parent = 0): ApplicationManagerInterface(parent) {} | 70 | MockAppManager(QObject *parent = 0): ApplicationManagerInterface(parent) {} |
647 | 71 | ~MockAppManager() {} | ||
648 | 71 | int rowCount(const QModelIndex &) const override { return m_list.count(); } | 72 | int rowCount(const QModelIndex &) const override { return m_list.count(); } |
649 | 72 | QVariant data(const QModelIndex &, int ) const override { return QVariant(); } | 73 | QVariant data(const QModelIndex &, int ) const override { return QVariant(); } |
650 | 73 | QString focusedApplicationId() const override { | 74 | QString focusedApplicationId() const override { |
651 | @@ -325,6 +326,46 @@ | |||
652 | 325 | QCOMPARE(launcherModel->get(0)->appId(), QLatin1String("abs-icon")); | 326 | QCOMPARE(launcherModel->get(0)->appId(), QLatin1String("abs-icon")); |
653 | 326 | } | 327 | } |
654 | 327 | 328 | ||
655 | 329 | void testQuitMenuItem() { | ||
656 | 330 | // we have 2 apps running, both should have the Quit action in its quick list | ||
657 | 331 | QCOMPARE(launcherModel->rowCount(), 2); | ||
658 | 332 | |||
659 | 333 | // stop the second one keeping it pinned so that it doesn't go away | ||
660 | 334 | launcherModel->pin("no-icon"); | ||
661 | 335 | appManager->stopApplication("no-icon"); | ||
662 | 336 | |||
663 | 337 | // find the first Quit item, should be there | ||
664 | 338 | QuickListModel *model = qobject_cast<QuickListModel*>(launcherModel->get(0)->quickList()); | ||
665 | 339 | int quitActionIndex = -1; | ||
666 | 340 | for (int i = 0; i < model->rowCount(); ++i) { | ||
667 | 341 | if (model->get(i).actionId() == "stop_item") { | ||
668 | 342 | quitActionIndex = i; | ||
669 | 343 | break; | ||
670 | 344 | } | ||
671 | 345 | } | ||
672 | 346 | QVERIFY(quitActionIndex >= 0); | ||
673 | 347 | |||
674 | 348 | // find the second Quit item, should NOT be there, the app is stopped | ||
675 | 349 | QuickListModel *model2 = qobject_cast<QuickListModel*>(launcherModel->get(1)->quickList()); | ||
676 | 350 | int quitActionIndex2 = -1; | ||
677 | 351 | for (int i = 0; i < model2->rowCount(); ++i) { | ||
678 | 352 | if (model2->get(i).actionId() == "stop_item") { | ||
679 | 353 | quitActionIndex2 = i; | ||
680 | 354 | break; | ||
681 | 355 | } | ||
682 | 356 | } | ||
683 | 357 | QVERIFY(quitActionIndex2 == -1); | ||
684 | 358 | |||
685 | 359 | // trigger the first quit item quicklist action | ||
686 | 360 | launcherModel->quickListActionInvoked(launcherModel->get(0)->appId(), quitActionIndex); | ||
687 | 361 | // first app should be gone... | ||
688 | 362 | QCOMPARE(launcherModel->rowCount(QModelIndex()), 1); | ||
689 | 363 | // ... the second app (now at index 0) should still be there, pinned and stopped | ||
690 | 364 | QCOMPARE(launcherModel->get(0)->appId(), QStringLiteral("no-icon")); | ||
691 | 365 | QCOMPARE(launcherModel->get(0)->pinned(), true); | ||
692 | 366 | QCOMPARE(launcherModel->get(0)->running(), false); | ||
693 | 367 | } | ||
694 | 368 | |||
695 | 328 | void testGetUrlForAppId() { | 369 | void testGetUrlForAppId() { |
696 | 329 | QCOMPARE(launcherModel->getUrlForAppId(QString()), QString()); | 370 | QCOMPARE(launcherModel->getUrlForAppId(QString()), QString()); |
697 | 330 | QCOMPARE(launcherModel->getUrlForAppId(""), QString()); | 371 | QCOMPARE(launcherModel->getUrlForAppId(""), QString()); |
698 | 331 | 372 | ||
699 | === modified file 'tests/qmltests/Launcher/tst_Launcher.qml' | |||
700 | --- tests/qmltests/Launcher/tst_Launcher.qml 2015-07-29 12:33:59 +0000 | |||
701 | +++ tests/qmltests/Launcher/tst_Launcher.qml 2015-07-29 12:33:59 +0000 | |||
702 | @@ -197,7 +197,7 @@ | |||
703 | 197 | startX+units.gu(8), startY); | 197 | startX+units.gu(8), startY); |
704 | 198 | 198 | ||
705 | 199 | var panel = findChild(launcher, "launcherPanel"); | 199 | var panel = findChild(launcher, "launcherPanel"); |
707 | 200 | verify(panel != undefined); | 200 | verify(!!panel); |
708 | 201 | 201 | ||
709 | 202 | // wait until it gets fully extended | 202 | // wait until it gets fully extended |
710 | 203 | tryCompare(panel, "x", 0); | 203 | tryCompare(panel, "x", 0); |
711 | @@ -208,7 +208,7 @@ | |||
712 | 208 | mouseMove(root, 1, root.height / 2); | 208 | mouseMove(root, 1, root.height / 2); |
713 | 209 | 209 | ||
714 | 210 | var panel = findChild(launcher, "launcherPanel"); | 210 | var panel = findChild(launcher, "launcherPanel"); |
716 | 211 | verify(panel != undefined); | 211 | verify(!!panel); |
717 | 212 | 212 | ||
718 | 213 | // wait until it gets fully extended | 213 | // wait until it gets fully extended |
719 | 214 | tryCompare(panel, "x", 0); | 214 | tryCompare(panel, "x", 0); |
720 | @@ -248,7 +248,7 @@ | |||
721 | 248 | waitUntilLauncherDisappears(); | 248 | waitUntilLauncherDisappears(); |
722 | 249 | 249 | ||
723 | 250 | var panel = findChild(launcher, "launcherPanel") | 250 | var panel = findChild(launcher, "launcherPanel") |
725 | 251 | verify(panel != undefined) | 251 | verify(!!panel) |
726 | 252 | 252 | ||
727 | 253 | // it starts out hidden just left of the left launcher edge | 253 | // it starts out hidden just left of the left launcher edge |
728 | 254 | compare(panel.x, -panel.width) | 254 | compare(panel.x, -panel.width) |
729 | @@ -286,7 +286,7 @@ | |||
730 | 286 | 286 | ||
731 | 287 | var appIcon = findChild(launcher, "launcherDelegate0"); | 287 | var appIcon = findChild(launcher, "launcherDelegate0"); |
732 | 288 | 288 | ||
734 | 289 | verify(appIcon != undefined); | 289 | verify(!!appIcon); |
735 | 290 | 290 | ||
736 | 291 | if (data.mouse) { | 291 | if (data.mouse) { |
737 | 292 | mouseClick(appIcon); | 292 | mouseClick(appIcon); |
738 | @@ -309,7 +309,7 @@ | |||
739 | 309 | dragLauncherIntoView() | 309 | dragLauncherIntoView() |
740 | 310 | 310 | ||
741 | 311 | var dashIcon = findChild(launcher, "dashItem") | 311 | var dashIcon = findChild(launcher, "dashItem") |
743 | 312 | verify(dashIcon != undefined) | 312 | verify(!!dashIcon) |
744 | 313 | 313 | ||
745 | 314 | mouseClick(dashIcon) | 314 | mouseClick(dashIcon) |
746 | 315 | 315 | ||
747 | @@ -599,7 +599,7 @@ | |||
748 | 599 | 599 | ||
749 | 600 | // Doing longpress | 600 | // Doing longpress |
750 | 601 | mousePress(draggedItem); | 601 | mousePress(draggedItem); |
752 | 602 | tryCompare(quickListShape, "opacity", 0.96); | 602 | tryCompare(quickListShape, "opacity", 0.8); |
753 | 603 | mouseRelease(draggedItem); | 603 | mouseRelease(draggedItem); |
754 | 604 | 604 | ||
755 | 605 | verify(quickList.y >= units.gu(1)); | 605 | verify(quickList.y >= units.gu(1)); |
756 | @@ -684,9 +684,31 @@ | |||
757 | 684 | tryCompare(quickList, "state", ""); | 684 | tryCompare(quickList, "state", ""); |
758 | 685 | } | 685 | } |
759 | 686 | 686 | ||
760 | 687 | function test_quickListMenuOnRMB() { | ||
761 | 688 | dragLauncherIntoView(); | ||
762 | 689 | var clickedItem = findChild(launcher, "launcherDelegate5") | ||
763 | 690 | var quickList = findChild(launcher, "quickList") | ||
764 | 691 | var quickListShape = findChild(launcher, "quickListShape") | ||
765 | 692 | var dndArea = findChild(launcher, "dndArea"); | ||
766 | 693 | |||
767 | 694 | // Initial state | ||
768 | 695 | tryCompare(quickListShape, "visible", false) | ||
769 | 696 | |||
770 | 697 | // Doing RMB click | ||
771 | 698 | mouseClick(clickedItem, clickedItem.width / 2, clickedItem.height / 2, Qt.RightButton) | ||
772 | 699 | tryCompare(quickListShape, "visible", true) | ||
773 | 700 | verify(quickList, "state", "open") | ||
774 | 701 | verify(dndArea, "dragging", false) | ||
775 | 702 | |||
776 | 703 | // Click somewhere in the empty space to dismiss the quicklist | ||
777 | 704 | mouseClick(launcher, launcher.width - units.gu(1), units.gu(1)); | ||
778 | 705 | tryCompare(quickListShape, "visible", false); | ||
779 | 706 | verify(quickList, "state", "") | ||
780 | 707 | } | ||
781 | 708 | |||
782 | 687 | function test_revealByHover() { | 709 | function test_revealByHover() { |
783 | 688 | var panel = findChild(launcher, "launcherPanel"); | 710 | var panel = findChild(launcher, "launcherPanel"); |
785 | 689 | verify(panel != undefined); | 711 | verify(!!panel); |
786 | 690 | 712 | ||
787 | 691 | revealByHover(); | 713 | revealByHover(); |
788 | 692 | tryCompare(launcher, "state", "visibleTemporary"); | 714 | tryCompare(launcher, "state", "visibleTemporary"); |
PASSED: Continuous integration, rev:1810 jenkins. qa.ubuntu. com/job/ unity8- ci/5803/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- wily-touch/ 94 jenkins. qa.ubuntu. com/job/ unity8- wily-amd64- ci/81 jenkins. qa.ubuntu. com/job/ unity8- wily-i386- ci/81 jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- runner- wily-mako/ 72 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- wily-armhf/ 94 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- wily-armhf/ 94/artifact/ work/output/ *zip*/output. zip s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 21099
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/unity8- ci/5803/ rebuild
http://