on xenial help sign in
Merge from wallpaper branch
commit1000459d4d581f61d4820d618b672afce914e57d authorMichael Terry <michael.terry@canonical.com> dateThu 5 Sep 2013, 14:22 (13 years ago) parente6dbf007417ab0
120 files changed+1804−1350
Components/EdgeDemo.qml+2−1 Components/EdgeDemoOverlay.qml+5 Dash/DashBar.qml+2−3 Greeter/Infographics.qml+1−2 Greeter/graphics/infographic_circle.png Greeter/graphics/infographic_circle_back.png Launcher/LauncherDelegate.qml+20−9 Launcher/LauncherPanel.qml+9−2 Launcher/graphics/focused_app_arrow@30.png Panel/Indicators/DefaultIndicatorWidget.qml+1−1 Panel/Indicators/DefaultIndicatorWidget2.qml+43−16 Panel/Indicators/NetworkIndicatorWidget.qml+1−1 Shell.qml+10−1 build+9 debian/changelog+71 debian/control+1 main.cpp+3−2 plugins/AccountsService/AccountsBindings.cpp−116 plugins/AccountsService/AccountsBindings.h−72 plugins/AccountsService/AccountsService.cpp+77−80 plugins/AccountsService/AccountsService.h+38−15 plugins/AccountsService/AccountsServiceDBusAdaptor.cpp+126 plugins/AccountsService/AccountsServiceDBusAdaptor.h+54 plugins/AccountsService/CMakeLists.txt+1−1 plugins/AccountsService/plugin.cpp+3−3 plugins/Unity/CMakeLists.txt+1 plugins/Unity/Indicators/qml/MenuItemFactory.qml+1−16 plugins/Unity/Indicators/rootactionstate.cpp+44−14 plugins/Unity/Indicators/rootactionstate.h+9−6 plugins/Unity/Launcher/CMakeLists.txt+5−1 plugins/Unity/Launcher/backend/launcherbackend.cpp+188−100 plugins/Unity/Launcher/backend/launcherbackend.h+12−14 plugins/Unity/Launcher/launcheritem.cpp+14 plugins/Unity/Launcher/launcheritem.h+4 plugins/Unity/Launcher/launchermodel.cpp+59 plugins/Unity/Launcher/launchermodel.h+1 plugins/Unity/categories.cpp−3 plugins/Unity/categories.h+1−2 plugins/Unity/checkoptionfilter.cpp+3−1 plugins/Unity/filter.h+3−2 plugins/Unity/genericoptionsmodel.cpp+20−3 plugins/Unity/genericoptionsmodel.h+4−2 plugins/Unity/multirangefilter.cpp+3−1 plugins/Unity/radiooptionfilter.cpp+3−1 plugins/Unity/ratingoptionsmodel.cpp+3−3 plugins/Unity/ratingoptionsmodel.h+1−1 plugins/Unity/ratingsfilter.cpp+2−1 plugins/Unity/showallfilteroption.cpp+60 plugins/Unity/showallfilteroption.h+51 plugins/Unity/unityoptionsmodel.cpp+5−4 plugins/Unity/unityoptionsmodel.h+2−1 po/ar.po+2−29 po/az.po+2−8 po/bg.po+2−11 po/ca.po+2−29 po/de.po+2−29 po/el.po+2−8 po/en_AU.po+2−29 po/en_GB.po+2−29 po/eo.po+2−2 po/es.po+24−49 po/fi.po+2−29 po/fo.po+2−8 po/fr.po+2−5 po/gl.po+2−29 po/he.po+2−8 po/hr.po+2−8 po/hu.po+2−17 po/hy.po+2−29 po/id.po+2−2 po/it.po+2−8 po/ja.po+2−2 po/kn.po+2−8 po/ko.po+2−23 po/ky.po+2−8 po/lv.po+2−8 po/my.po+2−8 po/nb.po+2−17 po/nl.po+2−8 po/pl.po+2−29 po/pt_BR.po+2−8 po/ro.po+2−8 po/ru.po+2−29 po/si.po+2−2 po/sl.po+2−23 po/sr.po+2−8 po/sv.po+2−2 po/te.po+2−5 po/tr.po+2−29 po/ug.po+2−29 po/uk.po+2−29 po/zh_CN.po+2−29 po/zh_TW.po+2−29 tests/mocks/AccountsService/AccountsBindings.cpp → tests/mocks/AccountsService/AccountsService.cpp+15−8 tests/mocks/AccountsService/AccountsBindings.h → tests/mocks/AccountsService/AccountsService.h+12−7 tests/mocks/AccountsService/CMakeLists.txt+1−1 tests/mocks/AccountsService/plugin.cpp+3−3 tests/mocks/LightDM/demo/GreeterPrivate.cpp+4−2 tests/mocks/Unity/CMakeLists.txt+2 tests/mocks/Unity/Launcher/MockLauncherItem.cpp+16 tests/mocks/Unity/Launcher/MockLauncherItem.h+4 tests/mocks/Unity/Launcher/MockLauncherModel.cpp+9 tests/mocks/Unity/Launcher/MockLauncherModel.h+1 tests/mocks/Unity/fake_applications_scope.cpp+68 tests/mocks/Unity/fake_applications_scope.h+33 tests/mocks/Unity/fake_categories.cpp+84−12 tests/mocks/Unity/fake_categories.h+7−3 tests/mocks/Unity/fake_preview.cpp+66 tests/mocks/Unity/fake_preview.h+62 tests/mocks/Unity/fake_scope.cpp+33−9 tests/mocks/Unity/fake_scope.h+15−1 tests/mocks/Unity/fake_scopes.cpp+4−1 tests/plugins/AccountsService/CMakeLists.txt+1−1 tests/plugins/AccountsService/client.cpp+11−11 tests/plugins/Unity/Launcher/CMakeLists.txt+41−4 tests/plugins/Unity/Launcher/launcherbackendtest.cpp+14−48 tests/plugins/Unity/Launcher/launchermodeltest.cpp+146 tests/plugins/Unity/filtersbindingstest.cpp+61−30 tests/plugins/Unity/filtersbindingstest.h+1−1 tests/qmltests/Launcher/tst_Launcher.qml+8
Components/EdgeDemo.qml+2−1
@@ -218,8 +218,9 @@ Item {
218218 d.finalEdgeDemo = d.overlay.createObject(demo.underlay, {
219219 "edge": "none",
220220 "title": i18n.tr("Well done"),
221− "text": i18n.tr("You have now mastered the edge gestures and can start using the phone"),
221+ "text": i18n.tr("You have now mastered the edge gestures and can start using the phone<br><br>Tap anywhere to start"),
222222 "anchors.fill": demo.dash,
223+ "showSkip": false,
223224 });
224225 }
225226 if (d.finalEdgeDemo) {
Components/EdgeDemoOverlay.qml+5
@@ -43,6 +43,11 @@ Showable {
4343 */
4444 property alias skipText: skipLabel.text
4545
46+ /*
47+ * This is the visible status of the skip button.
48+ */
49+ property alias showSkip: skipLabel.visible
50+
4651 /*
4752 * Whether this demo is running currently.
4853 */
Dash/DashBar.qml+2−3
@@ -83,9 +83,8 @@ Item {
8383 }
8484
8585 delegate:
86− Item {
87− signal clicked()
88−
86+ // FIXME: Use Panel's integrated trigger() once that works again.
87+ MouseArea {
8988 width: itemSize
9089 height: dashBar.height
9190 anchors.top: parent.top
Greeter/Infographics.qml+1−2
@@ -293,9 +293,8 @@ Item {
293293 objectName: "backgroundCircle"
294294
295295 anchors.fill: parent
296− opacity: 0.9
297296
298− source: "graphics/infographic_circle.png"
297+ source: "graphics/infographic_circle_back.png"
299298 }
300299
301300 Timer {
Greeter/graphics/infographic_circle.pngdeleted

Binary file not shown.

Greeter/graphics/infographic_circle_back.pngnew file

Binary file not shown.

Launcher/LauncherDelegate.qml+20−9
@@ -24,6 +24,7 @@ Item {
2424 property int count: -1
2525 property int progress: -1
2626 property bool highlighted: false
27+ property bool itemFocused: false
2728 property real maxAngle: 0
2829 property bool inverted: false
2930
@@ -43,17 +44,18 @@ Item {
4344 onCountChanged: shaderEffectSource.scheduleUpdate();
4445 onProgressChanged: shaderEffectSource.scheduleUpdate();
4546 onHighlightedChanged: shaderEffectSource.scheduleUpdate();
47+ onItemFocusedChanged: shaderEffectSource.scheduleUpdate();
4648
4749 Item {
4850 id: iconItem
49− width: parent.itemWidth
50− height: parent.itemHeight
51+ width: parent.itemWidth + units.gu(1)
52+ height: parent.itemHeight + units.gu(1)
5153 anchors.centerIn: parent
5254
5355 UbuntuShape {
5456 id: iconShape
5557 anchors.fill: parent
56− anchors.margins: units.gu(0.5)
58+ anchors.margins: units.gu(1)
5759 radius: "medium"
5860
5961 image: Image {
@@ -78,7 +80,7 @@ Item {
7880 anchors {
7981 right: parent.right
8082 top: parent.top
81− margins: -units.dp(1)
83+ margins: units.dp(3)
8284 }
8385 width: Math.min(root.itemWidth, Math.max(units.gu(3), countLabel.implicitWidth + units.gu(2.5)))
8486 height: units.gu(3)
@@ -105,9 +107,9 @@ Item {
105107 left: iconItem.left
106108 right: iconItem.right
107109 bottom: iconItem.bottom
108− leftMargin: units.gu(0.5)
109− rightMargin: units.gu(0.5)
110− bottomMargin: units.gu(0.5)
110+ leftMargin: units.gu(1)
111+ rightMargin: units.gu(1)
112+ bottomMargin: units.gu(1)
111113 }
112114 height: units.gu(1.5)
113115 visible: root.progress > -1
@@ -136,14 +138,23 @@ Item {
136138 }
137139 }
138140 }
141+ Image {
142+ objectName: "focusedHighlight"
143+ anchors {
144+ right: parent.right
145+ verticalCenter: parent.verticalCenter
146+ }
147+ visible: root.itemFocused
148+ source: "graphics/focused_app_arrow.png"
149+ }
139150 }
140151
141152 ShaderEffect {
142153 id: transformEffect
143154 anchors.centerIn: parent
144155 anchors.verticalCenterOffset: root.offset
145− width: parent.itemWidth
146− height: parent.itemHeight
156+ width: iconItem.width
157+ height: iconItem.height
147158 property real itemOpacity: root.itemOpacity
148159 property real brightness: Math.max(-1, root.brightness)
149160 property real angle: root.angle
Launcher/LauncherPanel.qml+9−2
@@ -50,8 +50,6 @@ Item {
5050 id: mainColumn
5151 anchors {
5252 fill: parent
53− leftMargin: units.gu(0.5)
54− rightMargin: units.gu(0.5)
5553 }
5654
5755 MouseArea {
@@ -94,6 +92,8 @@ Item {
9492 fill: parent
9593 topMargin: -extensionSize + units.gu(0.5)
9694 bottomMargin: -extensionSize + units.gu(1)
95+ leftMargin: units.gu(0.5)
96+ rightMargin: units.gu(0.5)
9797 }
9898 topMargin: extensionSize
9999 bottomMargin: extensionSize
@@ -156,6 +156,7 @@ Item {
156156 iconName: model.icon
157157 count: model.count
158158 progress: model.progress
159+ itemFocused: model.focused
159160 inverted: root.inverted
160161 z: -Math.abs(offset)
161162 maxAngle: 55
@@ -512,6 +513,12 @@ Item {
512513 objectName: "quickListEntry" + index
513514 text: (model.clickable ? "" : "<b>") + model.label + (model.clickable ? "" : "</b>")
514515 highlightWhenPressed: model.clickable
516+
517+ // FIXME: This is a workaround for the theme not being context sensitive. I.e. the
518+ // ListItems don't know that they are sitting in a themed Popover where the color
519+ // needs to be inverted.
520+ __foregroundColor: Theme.palette.selected.backgroundText
521+
515522 onClicked: {
516523 if (!model.clickable) {
517524 return;
Launcher/graphics/focused_app_arrow@30.pngnew file

Binary file not shown.

Panel/Indicators/DefaultIndicatorWidget.qml+1−1
@@ -24,7 +24,7 @@ import Unity.IndicatorsLegacy 0.1 as Indicators
2424Indicators.IndicatorWidget {
2525 id: indicatorWidget
2626
27− width: itemRow.width + units.gu(1)
27+ width: itemRow.width + units.gu(0.5)
2828
2929 property alias label: itemLabel.text
3030 property alias iconSource: itemImage.source
Panel/Indicators/DefaultIndicatorWidget2.qml+43−16
@@ -24,10 +24,11 @@ import Unity.Indicators 0.1 as Indicators
2424Indicators.IndicatorWidget {
2525 id: indicatorWidget
2626
27− width: itemRow.width + units.gu(1)
27+ width: itemRow.width + units.gu(0.5)
2828
29− property alias label: itemLabel.text
30− property alias iconSource: itemImage.source
29+ property alias leftLabel: itemLeftLabel.text
30+ property alias rightLabel: itemRightLabel.text
31+ property var icons: undefined
3132
3233 Row {
3334 id: itemRow
@@ -39,19 +40,43 @@ Indicators.IndicatorWidget {
3940 }
4041 spacing: units.gu(0.5)
4142
42− // FIXME : Should us Ubuntu.Icon . results in low res images
43− Image {
44− id: itemImage
45− objectName: "itemImage"
46− visible: source != ""
47− height: indicatorWidget.iconSize
48− width: indicatorWidget.iconSize
43+ Label {
44+ id: itemLeftLabel
45+ objectName: "leftLabel"
46+ color: Theme.palette.selected.backgroundText
47+ opacity: 0.8
48+ font.family: "Ubuntu"
49+ fontSize: "medium"
4950 anchors.verticalCenter: parent.verticalCenter
51+ visible: text != ""
52+ }
53+
54+ Row {
55+ width: childrenRect.width
56+ anchors {
57+ top: parent.top
58+ bottom: parent.bottom
59+ }
60+ spacing: units.gu(0.5)
61+
62+ Repeater {
63+ model: indicatorWidget.icons
64+
65+ Image {
66+ id: itemImage
67+ objectName: "itemImage"
68+ visible: source != ""
69+ source: modelData
70+ height: indicatorWidget.iconSize
71+ width: indicatorWidget.iconSize
72+ anchors.verticalCenter: parent.verticalCenter
73+ }
74+ }
5075 }
5176
5277 Label {
53− id: itemLabel
54− objectName: "itemLabel"
78+ id: itemRightLabel
79+ objectName: "rightLabel"
5580 color: Theme.palette.selected.backgroundText
5681 opacity: 0.8
5782 font.family: "Ubuntu"
@@ -63,14 +88,16 @@ Indicators.IndicatorWidget {
6388
6489 onActionStateChanged: {
6590 if (actionState == undefined) {
66− label = "";
67− iconSource = "";
91+ leftLabel = "";
92+ rightLabel = "";
93+ icons = undefined;
6894 enabled = false;
6995 return;
7096 }
7197
72− label = actionState.label;
73− iconSource = actionState.icon;
98+ leftLabel = actionState.leftLabel ? actionState.leftLabel : "";
99+ rightLabel = actionState.rightLabel ? actionState.rightLabel : "";
100+ icons = actionState.icons;
74101 enabled = actionState.visible;
75102 }
76103}
Panel/Indicators/NetworkIndicatorWidget.qml+1−1
@@ -24,7 +24,7 @@ import Unity.IndicatorsLegacy 0.1 as Indicators
2424Indicators.IndicatorWidget {
2525 id: indicatorWidget
2626
27− width: networkIcon.width + units.gu(1)
27+ width: networkIcon.width + units.gu(0.5)
2828
2929 property int signalStrength: 0
3030 property int connectionState: Indicators.NetworkConnection.Initial
Shell.qml+10−1
@@ -96,6 +96,15 @@ FocusScope {
9696 greeter.hide();
9797 shell.activateApplication(desktopFile);
9898 }
99+
100+ onMainStageFocusedApplicationChanged: {
101+ var app = applicationManager.mainStageFocusedApplication
102+ if (app != null) {
103+ LauncherModel.applicationFocused(app.desktopFile);
104+ } else {
105+ LauncherModel.applicationFocused("");
106+ }
107+ }
99108 }
100109
101110 function activateApplication(desktopFile, argument) {
@@ -470,7 +479,7 @@ FocusScope {
470479 onSelected: {
471480 // Update launcher items for new user
472481 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
473− AccountsService.setUser(user);
482+ AccountsService.user = user;
474483 LauncherModel.setUser(user);
475484 }
476485
build+9
@@ -57,6 +57,15 @@ mk_build_deps() {
5757 [ ! -f unity8-build-deps*deb -o $CODE_DIR/debian/control -nt unity8-build-deps*deb ] && mk-build-deps --install --root-cmd sudo $CODE_DIR/debian/control
5858}
5959
60+if [ -f "/usr/bin/ccache" ] ; then
61+ if [ "x$CC" = "x" ]; then
62+ export CC='ccache gcc'
63+ fi
64+ if [ "x$CXX" = "x" ] ; then
65+ export CXX='ccache g++'
66+ fi
67+fi
68+
6069if [ -f "/usr/bin/ninja" ] ; then
6170 GENERATOR="-G Ninja"
6271 # Ninja does not need -j, it parallelizes automatically.
debian/changelog+71
@@ -1,3 +1,74 @@
1+unity8 (7.81.3+13.10.20130905.2-0ubuntu1) saucy; urgency=low
2+
3+ [ Michael Zanetti ]
4+ * Integrate Launcher with AppManager.
5+
6+ [ Nick Dedekind ]
7+ * Removed FIXME from slider int->double conversion.
8+
9+ [ Ubuntu daily release ]
10+ * Automatic snapshot from revision 291
11+
12+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 05 Sep 2013 10:48:02 +0000
13+
14+unity8 (7.81.3+13.10.20130904.1-0ubuntu1) saucy; urgency=low
15+
16+ [ Nicolas d'Offay ]
17+ * Switched infographic background at design's request.
18+
19+ [ Ubuntu daily release ]
20+ * Automatic snapshot from revision 287
21+
22+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 04 Sep 2013 07:34:57 +0000
23+
24+unity8 (7.81.3+13.10.20130904-0ubuntu1) saucy; urgency=low
25+
26+ [ mhall119 ]
27+ * Add a little bit of text to the last step of the tour telling the
28+ user how to end it and get to their phone.
29+
30+ [ Jussi Pakkanen ]
31+ * Use CCache if it is installed.
32+
33+ [ Nick Dedekind ]
34+ * Multiple icon/label support for indicators.
35+
36+ [ Albert Astals ]
37+ * Remove unneeded role.
38+
39+ [ Lars Uebernickel ]
40+ * Fall back to "ubuntu-mobile" icon theme if $UBUNTU_ICON_THEME is
41+ unset.
42+
43+ [ Michael Zanetti ]
44+ * Use MouseAreas in DashBar to enable clicking again.
45+ * load launcher default config from existing dconf key.
46+
47+ [ Ubuntu daily release ]
48+ * Automatic snapshot from revision 285
49+
50+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 04 Sep 2013 03:02:57 +0000
51+
52+unity8 (7.81.3+13.10.20130903.1-0ubuntu1) saucy; urgency=low
53+
54+ [ Michael Zanetti ]
55+ * workaround quicklist text color.
56+
57+ [ Ubuntu daily release ]
58+ * Automatic snapshot from revision 277
59+
60+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 03 Sep 2013 06:09:36 +0000
61+
62+unity8 (7.81.3+13.10.20130830-0ubuntu1) saucy; urgency=low
63+
64+ [ Pawel Stolowski ]
65+ * Implement a virtual 'All' filter option.
66+
67+ [ Ubuntu daily release ]
68+ * Automatic snapshot from revision 275
69+
70+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Fri, 30 Aug 2013 12:44:40 +0000
71+
172unity8 (7.81.3+13.10.20130829.2-0ubuntu1) saucy; urgency=low
273
374 [ Michael Terry ]
debian/control+1
@@ -9,6 +9,7 @@ Build-Depends: cmake,
99 libgl1-mesa-dev[!armhf] | libgl-dev[!armhf],
1010 libgl1-mesa-dri,
1111 libgles2-mesa-dev[armhf],
12+ libgsettings-qt-dev,
1213 libhud-client2-dev,
1314 libjson-perl,
1415 libnih-dbus-dev,
main.cpp+3−2
@@ -65,9 +65,10 @@ void appendImportPaths(QQmlEngine *engine, const QStringList &paths)
6565
6666void resolveIconTheme() {
6767 const char *ubuntuIconTheme = getenv("UBUNTU_ICON_THEME");
68− if (ubuntuIconTheme != NULL) {
69− QIcon::setThemeName(ubuntuIconTheme);
68+ if (ubuntuIconTheme == NULL) {
69+ ubuntuIconTheme = "ubuntu-mobile";
7070 }
71+ QIcon::setThemeName(ubuntuIconTheme);
7172}
7273} // namespace {
7374
plugins/AccountsService/AccountsBindings.cppdeleted−116
@@ -1,116 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Author: Michael Terry <michael.terry@canonical.com>
17− */
18−
19−#include "AccountsBindings.h"
20−#include "AccountsService.h"
21−
22−#include <QStringList>
23−
24−AccountsBindings::AccountsBindings(QObject* parent)
25− : QObject(parent),
26− m_service(new AccountsService(this)),
27− m_user(qgetenv("USER"))
28−{
29− connect(m_service, SIGNAL(propertiesChanged(const QString &, const QString &, const QStringList &)),
30− this, SLOT(propertiesChanged(const QString &, const QString &, const QStringList &)));
31− connect(m_service, SIGNAL(maybeChanged(const QString &)),
32− this, SLOT(maybeChanged(const QString &)));
33−}
34−
35−void AccountsBindings::setUser(const QString &user)
36−{
37− m_user = user;
38− updateDemoEdges();
39− updateBackgroundFile();
40− updateStatsWelcomeScreen();
41−}
42−
43−bool AccountsBindings::getDemoEdges()
44−{
45− return m_demoEdges;
46−}
47−
48−void AccountsBindings::setDemoEdges(bool demoEdges)
49−{
50− m_demoEdges = demoEdges;
51− m_service->setUserProperty(m_user, "com.canonical.unity.AccountsService", "demo-edges", demoEdges);
52−}
53−
54−QString AccountsBindings::getBackgroundFile()
55−{
56− return m_backgroundFile;
57−}
58−
59−bool AccountsBindings::getStatsWelcomeScreen()
60−{
61− return m_statsWelcomeScreen;
62−}
63−
64−void AccountsBindings::updateDemoEdges()
65−{
66− auto demoEdges = m_service->getUserProperty(m_user, "com.canonical.unity.AccountsService", "demo-edges").toBool();
67− if (m_demoEdges != demoEdges) {
68− m_demoEdges = demoEdges;
69− Q_EMIT demoEdgesChanged();
70− }
71−}
72−
73−void AccountsBindings::updateBackgroundFile()
74−{
75− auto backgroundFile = m_service->getUserProperty(m_user, "org.freedesktop.Accounts.User", "BackgroundFile").toString();
76− if (m_backgroundFile != backgroundFile) {
77− m_backgroundFile = backgroundFile;
78− Q_EMIT backgroundFileChanged();
79− }
80−}
81−
82−void AccountsBindings::updateStatsWelcomeScreen()
83−{
84− auto statsWelcomeScreen = m_service->getUserProperty(m_user, "com.ubuntu.touch.AccountsService.SecurityPrivacy", "StatsWelcomeScreen").toBool();
85− if (m_statsWelcomeScreen != statsWelcomeScreen) {
86− m_statsWelcomeScreen = statsWelcomeScreen;
87− Q_EMIT statsWelcomeScreenChanged();
88− }
89−}
90−
91−void AccountsBindings::propertiesChanged(const QString &user, const QString &interface, const QStringList &changed)
92−{
93− if (m_user != user) {
94− return;
95− }
96−
97− if (interface == "com.canonical.unity.AccountsService") {
98− if (changed.contains("demo-edges")) {
99− updateDemoEdges();
100− }
101− } else if (interface == "com.ubuntu.touch.AccountsService.SecurityPrivacy") {
102− if (changed.contains("StatsWelcomeScreen")) {
103− updateStatsWelcomeScreen();
104− }
105− }
106−}
107−
108−void AccountsBindings::maybeChanged(const QString &user)
109−{
110− if (m_user != user) {
111− return;
112− }
113−
114− // Standard properties might have changed
115− updateBackgroundFile();
116−}
plugins/AccountsService/AccountsBindings.hdeleted−72
@@ -1,72 +0,0 @@
1−/*
2− * Copyright (C) 2012,2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Authors: Michael Terry <michael.terry@canonical.com>
17− */
18−
19−#ifndef UNITY_ACCOUNTSBINDINGS_H
20−#define UNITY_ACCOUNTSBINDINGS_H
21−
22−#include <QObject>
23−#include <QString>
24−
25−class AccountsService;
26−
27−class AccountsBindings: public QObject
28−{
29− Q_OBJECT
30− Q_PROPERTY (bool demoEdges
31− READ getDemoEdges
32− WRITE setDemoEdges
33− NOTIFY demoEdgesChanged)
34− Q_PROPERTY (QString backgroundFile
35− READ getBackgroundFile
36− NOTIFY backgroundFileChanged)
37− Q_PROPERTY (bool statsWelcomeScreen
38− READ getStatsWelcomeScreen
39− NOTIFY statsWelcomeScreenChanged)
40−
41−public:
42− explicit AccountsBindings(QObject *parent = 0);
43−
44− Q_INVOKABLE void setUser(const QString &user);
45−
46− bool getDemoEdges();
47− void setDemoEdges(bool demoEdges);
48− QString getBackgroundFile();
49− bool getStatsWelcomeScreen();
50−
51−Q_SIGNALS:
52− void demoEdgesChanged();
53− void backgroundFileChanged();
54− void statsWelcomeScreenChanged();
55−
56−private Q_SLOTS:
57− void propertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
58− void maybeChanged(const QString &user);
59−
60−private:
61− void updateDemoEdges();
62− void updateBackgroundFile();
63− void updateStatsWelcomeScreen();
64−
65− AccountsService *m_service;
66− QString m_user;
67− bool m_demoEdges;
68− QString m_backgroundFile;
69− bool m_statsWelcomeScreen;
70−};
71−
72−#endif
plugins/AccountsService/AccountsService.cpp+77−80
@@ -17,110 +17,107 @@
1717 */
1818
1919#include "AccountsService.h"
20−#include <QDBusConnection>
21−#include <QDBusConnectionInterface>
22−#include <QDBusMessage>
23−#include <QDBusVariant>
20+#include "AccountsServiceDBusAdaptor.h"
21+
22+#include <QStringList>
2423
2524AccountsService::AccountsService(QObject* parent)
2625 : QObject(parent),
27− accounts_manager(NULL),
28− users()
26+ m_service(new AccountsServiceDBusAdaptor(this)),
27+ m_user(qgetenv("USER"))
2928{
30− auto connection = QDBusConnection::SM_BUSNAME();
31− auto interface = connection.interface();
32− interface->startService("org.freedesktop.Accounts");
33− accounts_manager = new QDBusInterface("org.freedesktop.Accounts",
34− "/org/freedesktop/Accounts",
35− "org.freedesktop.Accounts",
36− connection, this);
29+ connect(m_service, SIGNAL(propertiesChanged(const QString &, const QString &, const QStringList &)),
30+ this, SLOT(propertiesChanged(const QString &, const QString &, const QStringList &)));
31+ connect(m_service, SIGNAL(maybeChanged(const QString &)),
32+ this, SLOT(maybeChanged(const QString &)));
3733}
3834
39−QVariant AccountsService::getUserProperty(const QString &user, const QString &interface, const QString &property)
35+QString AccountsService::getUser()
4036{
41− auto iface = getUserInterface(user);
42− if (iface != nullptr && iface->isValid()) {
43− auto answer = iface->call("Get", interface, property);
44− if (answer.type() == QDBusMessage::ReplyMessage) {
45− return answer.arguments()[0].value<QDBusVariant>().variant();
46− }
47− }
48− return QVariant();
37+ return m_user;
4938}
5039
51−void AccountsService::setUserProperty(const QString &user, const QString &interface, const QString &property, const QVariant &value)
40+void AccountsService::setUser(const QString &user)
5241{
53− auto iface = getUserInterface(user);
54− if (iface != nullptr && iface->isValid()) {
55− // The value needs to be carefully wrapped
56− iface->call("Set", interface, property, QVariant::fromValue(QDBusVariant(value)));
57− }
42+ m_user = user;
43+ Q_EMIT userChanged();
44+
45+ updateDemoEdges();
46+ updateBackgroundFile();
47+ updateStatsWelcomeScreen();
48+}
49+
50+bool AccountsService::getDemoEdges()
51+{
52+ return m_demoEdges;
5853}
5954
60−void AccountsService::propertiesChangedSlot(const QString &interface, const QVariantMap &changed, const QStringList &invalid)
55+void AccountsService::setDemoEdges(bool demoEdges)
6156{
62− // Merge changed and invalidated together
63− QStringList combined;
64− combined << invalid;
65− combined << changed.keys();
66− combined.removeDuplicates();
57+ m_demoEdges = demoEdges;
58+ m_service->setUserProperty(m_user, "com.canonical.unity.AccountsService", "demo-edges", demoEdges);
59+}
6760
68− Q_EMIT propertiesChanged(getUserForPath(message().path()), interface, combined);
61+QString AccountsService::getBackgroundFile()
62+{
63+ return m_backgroundFile;
6964}
7065
71−void AccountsService::maybeChangedSlot()
66+bool AccountsService::getStatsWelcomeScreen()
7267{
73− Q_EMIT maybeChanged(getUserForPath(message().path()));
68+ return m_statsWelcomeScreen;
7469}
7570
76−QString AccountsService::getUserForPath(const QString &path)
71+void AccountsService::updateDemoEdges()
7772{
78− QMap<QString, QDBusInterface *>::const_iterator i;
79− for (i = users.constBegin(); i != users.constEnd(); ++i) {
80− if (i.value()->path() == path) {
81− return i.key();
82− }
73+ auto demoEdges = m_service->getUserProperty(m_user, "com.canonical.unity.AccountsService", "demo-edges").toBool();
74+ if (m_demoEdges != demoEdges) {
75+ m_demoEdges = demoEdges;
76+ Q_EMIT demoEdgesChanged();
8377 }
84− return QString();
8578}
8679
87−QDBusInterface *AccountsService::getUserInterface(const QString &user)
80+void AccountsService::updateBackgroundFile()
8881{
89− auto iface = users.value(user);
90− if (iface == nullptr && accounts_manager->isValid()) {
91− auto answer = accounts_manager->call("FindUserByName", user);
92− if (answer.type() == QDBusMessage::ReplyMessage) {
93− auto path = answer.arguments()[0].value<QDBusObjectPath>().path();
94−
95− iface = new QDBusInterface("org.freedesktop.Accounts",
96− path,
97− "org.freedesktop.DBus.Properties",
98− accounts_manager->connection(), this);
99−
100− // With its own pre-defined properties, AccountsService is oddly
101− // close-lipped. It won't send out proper DBus.Properties notices,
102− // but it does have one catch-all Changed() signal. So let's
103− // listen to that.
104− iface->connection().connect(
105− iface->service(),
106− path,
107− "org.freedesktop.Accounts.User",
108− "Changed",
109− this,
110− SLOT(maybeChangedSlot()));
111−
112− // But custom properties do send out the right notifications, so
113− // let's still listen there.
114− iface->connection().connect(
115− iface->service(),
116− path,
117− "org.freedesktop.DBus.Properties",
118− "PropertiesChanged",
119− this,
120− SLOT(propertiesChangedSlot(QString, QVariantMap, QStringList)));
121−
122− users.insert(user, iface);
82+ auto backgroundFile = m_service->getUserProperty(m_user, "org.freedesktop.Accounts.User", "BackgroundFile").toString();
83+ if (m_backgroundFile != backgroundFile) {
84+ m_backgroundFile = backgroundFile;
85+ Q_EMIT backgroundFileChanged();
86+ }
87+}
88+
89+void AccountsService::updateStatsWelcomeScreen()
90+{
91+ auto statsWelcomeScreen = m_service->getUserProperty(m_user, "com.ubuntu.touch.AccountsService.SecurityPrivacy", "StatsWelcomeScreen").toBool();
92+ if (m_statsWelcomeScreen != statsWelcomeScreen) {
93+ m_statsWelcomeScreen = statsWelcomeScreen;
94+ Q_EMIT statsWelcomeScreenChanged();
95+ }
96+}
97+
98+void AccountsService::propertiesChanged(const QString &user, const QString &interface, const QStringList &changed)
99+{
100+ if (m_user != user) {
101+ return;
102+ }
103+
104+ if (interface == "com.canonical.unity.AccountsService") {
105+ if (changed.contains("demo-edges")) {
106+ updateDemoEdges();
123107 }
108+ } else if (interface == "com.ubuntu.touch.AccountsService.SecurityPrivacy") {
109+ if (changed.contains("StatsWelcomeScreen")) {
110+ updateStatsWelcomeScreen();
111+ }
112+ }
113+}
114+
115+void AccountsService::maybeChanged(const QString &user)
116+{
117+ if (m_user != user) {
118+ return;
124119 }
125− return iface;
120+
121+ // Standard properties might have changed
122+ updateBackgroundFile();
126123}
plugins/AccountsService/AccountsService.h+38−15
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2012,2013 Canonical, Ltd.
2+ * Copyright (C) 2013 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -19,36 +19,59 @@
1919#ifndef UNITY_ACCOUNTSSERVICE_H
2020#define UNITY_ACCOUNTSSERVICE_H
2121
22−#include <QDBusContext>
23−#include <QDBusInterface>
24−#include <QMap>
2522#include <QObject>
2623#include <QString>
2724
28−class AccountsService: public QObject, public QDBusContext
25+class AccountsServiceDBusAdaptor;
26+
27+class AccountsService: public QObject
2928{
3029 Q_OBJECT
30+ Q_PROPERTY (QString user
31+ READ getUser
32+ WRITE setUser
33+ NOTIFY userChanged)
34+ Q_PROPERTY (bool demoEdges
35+ READ getDemoEdges
36+ WRITE setDemoEdges
37+ NOTIFY demoEdgesChanged)
38+ Q_PROPERTY (QString backgroundFile
39+ READ getBackgroundFile
40+ NOTIFY backgroundFileChanged)
41+ Q_PROPERTY (bool statsWelcomeScreen
42+ READ getStatsWelcomeScreen
43+ NOTIFY statsWelcomeScreenChanged)
3144
3245public:
3346 explicit AccountsService(QObject *parent = 0);
3447
35− Q_INVOKABLE QVariant getUserProperty(const QString &user, const QString &interface, const QString &property);
36− Q_INVOKABLE void setUserProperty(const QString &user, const QString &interface, const QString &property, const QVariant &value);
48+ QString getUser();
49+ void setUser(const QString &user);
50+ bool getDemoEdges();
51+ void setDemoEdges(bool demoEdges);
52+ QString getBackgroundFile();
53+ bool getStatsWelcomeScreen();
3754
3855Q_SIGNALS:
39− void propertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
40− void maybeChanged(const QString &user); // Standard properties might have changed
56+ void userChanged();
57+ void demoEdgesChanged();
58+ void backgroundFileChanged();
59+ void statsWelcomeScreenChanged();
4160
4261private Q_SLOTS:
43− void propertiesChangedSlot(const QString &interface, const QVariantMap &changed, const QStringList &invalid);
44− void maybeChangedSlot();
62+ void propertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
63+ void maybeChanged(const QString &user);
4564
4665private:
47− QDBusInterface *getUserInterface(const QString &user);
48− QString getUserForPath(const QString &path);
66+ void updateDemoEdges();
67+ void updateBackgroundFile();
68+ void updateStatsWelcomeScreen();
4969
50− QDBusInterface *accounts_manager;
51− QMap<QString, QDBusInterface *> users;
70+ AccountsServiceDBusAdaptor *m_service;
71+ QString m_user;
72+ bool m_demoEdges;
73+ QString m_backgroundFile;
74+ bool m_statsWelcomeScreen;
5275};
5376
5477#endif
plugins/AccountsService/AccountsServiceDBusAdaptor.cppnew file+126
@@ -0,0 +1,126 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Author: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#include "AccountsServiceDBusAdaptor.h"
20+#include <QDBusConnection>
21+#include <QDBusConnectionInterface>
22+#include <QDBusMessage>
23+#include <QDBusVariant>
24+
25+AccountsServiceDBusAdaptor::AccountsServiceDBusAdaptor(QObject* parent)
26+ : QObject(parent),
27+ accounts_manager(NULL),
28+ users()
29+{
30+ auto connection = QDBusConnection::SM_BUSNAME();
31+ auto interface = connection.interface();
32+ interface->startService("org.freedesktop.Accounts");
33+ accounts_manager = new QDBusInterface("org.freedesktop.Accounts",
34+ "/org/freedesktop/Accounts",
35+ "org.freedesktop.Accounts",
36+ connection, this);
37+}
38+
39+QVariant AccountsServiceDBusAdaptor::getUserProperty(const QString &user, const QString &interface, const QString &property)
40+{
41+ auto iface = getUserInterface(user);
42+ if (iface != nullptr && iface->isValid()) {
43+ auto answer = iface->call("Get", interface, property);
44+ if (answer.type() == QDBusMessage::ReplyMessage) {
45+ return answer.arguments()[0].value<QDBusVariant>().variant();
46+ }
47+ }
48+ return QVariant();
49+}
50+
51+void AccountsServiceDBusAdaptor::setUserProperty(const QString &user, const QString &interface, const QString &property, const QVariant &value)
52+{
53+ auto iface = getUserInterface(user);
54+ if (iface != nullptr && iface->isValid()) {
55+ // The value needs to be carefully wrapped
56+ iface->call("Set", interface, property, QVariant::fromValue(QDBusVariant(value)));
57+ }
58+}
59+
60+void AccountsServiceDBusAdaptor::propertiesChangedSlot(const QString &interface, const QVariantMap &changed, const QStringList &invalid)
61+{
62+ // Merge changed and invalidated together
63+ QStringList combined;
64+ combined << invalid;
65+ combined << changed.keys();
66+ combined.removeDuplicates();
67+
68+ Q_EMIT propertiesChanged(getUserForPath(message().path()), interface, combined);
69+}
70+
71+void AccountsServiceDBusAdaptor::maybeChangedSlot()
72+{
73+ Q_EMIT maybeChanged(getUserForPath(message().path()));
74+}
75+
76+QString AccountsServiceDBusAdaptor::getUserForPath(const QString &path)
77+{
78+ QMap<QString, QDBusInterface *>::const_iterator i;
79+ for (i = users.constBegin(); i != users.constEnd(); ++i) {
80+ if (i.value()->path() == path) {
81+ return i.key();
82+ }
83+ }
84+ return QString();
85+}
86+
87+QDBusInterface *AccountsServiceDBusAdaptor::getUserInterface(const QString &user)
88+{
89+ auto iface = users.value(user);
90+ if (iface == nullptr && accounts_manager->isValid()) {
91+ auto answer = accounts_manager->call("FindUserByName", user);
92+ if (answer.type() == QDBusMessage::ReplyMessage) {
93+ auto path = answer.arguments()[0].value<QDBusObjectPath>().path();
94+
95+ iface = new QDBusInterface("org.freedesktop.Accounts",
96+ path,
97+ "org.freedesktop.DBus.Properties",
98+ accounts_manager->connection(), this);
99+
100+ // With its own pre-defined properties, AccountsService is oddly
101+ // close-lipped. It won't send out proper DBus.Properties notices,
102+ // but it does have one catch-all Changed() signal. So let's
103+ // listen to that.
104+ iface->connection().connect(
105+ iface->service(),
106+ path,
107+ "org.freedesktop.Accounts.User",
108+ "Changed",
109+ this,
110+ SLOT(maybeChangedSlot()));
111+
112+ // But custom properties do send out the right notifications, so
113+ // let's still listen there.
114+ iface->connection().connect(
115+ iface->service(),
116+ path,
117+ "org.freedesktop.DBus.Properties",
118+ "PropertiesChanged",
119+ this,
120+ SLOT(propertiesChangedSlot(QString, QVariantMap, QStringList)));
121+
122+ users.insert(user, iface);
123+ }
124+ }
125+ return iface;
126+}
plugins/AccountsService/AccountsServiceDBusAdaptor.hnew file+54
@@ -0,0 +1,54 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#ifndef UNITY_ACCOUNTSSERVICEDBUSADAPTOR_H
20+#define UNITY_ACCOUNTSSERVICEDBUSADAPTOR_H
21+
22+#include <QDBusContext>
23+#include <QDBusInterface>
24+#include <QMap>
25+#include <QObject>
26+#include <QString>
27+
28+class AccountsServiceDBusAdaptor: public QObject, public QDBusContext
29+{
30+ Q_OBJECT
31+
32+public:
33+ explicit AccountsServiceDBusAdaptor(QObject *parent = 0);
34+
35+ Q_INVOKABLE QVariant getUserProperty(const QString &user, const QString &interface, const QString &property);
36+ Q_INVOKABLE void setUserProperty(const QString &user, const QString &interface, const QString &property, const QVariant &value);
37+
38+Q_SIGNALS:
39+ void propertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
40+ void maybeChanged(const QString &user); // Standard properties might have changed
41+
42+private Q_SLOTS:
43+ void propertiesChangedSlot(const QString &interface, const QVariantMap &changed, const QStringList &invalid);
44+ void maybeChangedSlot();
45+
46+private:
47+ QDBusInterface *getUserInterface(const QString &user);
48+ QString getUserForPath(const QString &path);
49+
50+ QDBusInterface *accounts_manager;
51+ QMap<QString, QDBusInterface *> users;
52+};
53+
54+#endif
plugins/AccountsService/CMakeLists.txt+1−1
@@ -3,8 +3,8 @@ include(Plugins)
33add_definitions(-DSM_BUSNAME=systemBus)
44
55add_library(AccountsService-qml MODULE
6− AccountsBindings.cpp
76 AccountsService.cpp
7+ AccountsServiceDBusAdaptor.cpp
88 plugin.cpp
99 )
1010
plugins/AccountsService/plugin.cpp+3−3
@@ -17,7 +17,7 @@
1717 */
1818
1919#include "plugin.h"
20−#include "AccountsBindings.h"
20+#include "AccountsService.h"
2121
2222#include <QDBusMetaType>
2323#include <QtQml>
@@ -26,12 +26,12 @@ static QObject *service_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
2626{
2727 Q_UNUSED(engine)
2828 Q_UNUSED(scriptEngine)
29− return new AccountsBindings();
29+ return new AccountsService();
3030}
3131
3232void AccountsServicePlugin::registerTypes(const char *uri)
3333{
3434 Q_ASSERT(uri == QLatin1String("AccountsService"));
3535 qDBusRegisterMetaType<QList<QVariantMap>>();
36− qmlRegisterSingletonType<AccountsBindings>(uri, 0, 1, "AccountsService", service_provider);
36+ qmlRegisterSingletonType<AccountsService>(uri, 0, 1, "AccountsService", service_provider);
3737}
plugins/Unity/CMakeLists.txt+1
@@ -43,6 +43,7 @@ set(QMLPLUGIN_SRC
4343 preview.cpp
4444 previewaction.cpp
4545 previewinfohint.cpp
46+ showallfilteroption.cpp
4647 signalslist.cpp
4748 socialpreview.cpp
4849 socialpreviewcomment.cpp
plugins/Unity/Indicators/qml/MenuItemFactory.qml+1−16
@@ -73,23 +73,8 @@ Item {
7373 'max-icon': 'icon'});
7474 }
7575
76− // FIXME: The interval should be [0.0 - 1.0]. Unfortunately, when
77− // reaching the boundaries (0.0 or 1.0), the value is converted
78− // to an integer when automatically wrapped in a variant when
79− // passed to QStateAction::updateState(…). The server chokes on
80− // those values, complaining that they’re not of the right type…
8176 onChangeState: {
82− if (value == Math.round(value)) {
83− if (value >= maximumValue) {
84− model.changeState(modelIndex, maximumValue - 0.000001);
85− } else if (value <= minimumValue) {
86− model.changeState(modelIndex, minimumValue + 0.000001);
87− } else {
88− model.changeState(modelIndex, value * 1.000001);
89− }
90− } else {
91− model.changeState(modelIndex, value);
92− }
77+ model.changeState(modelIndex, value);
9378 }
9479 }
9580 }
plugins/Unity/Indicators/rootactionstate.cpp+44−14
@@ -108,25 +108,32 @@ bool RootActionState::isValid() const
108108 return m_menu && m_menu->rowCount() > 0;
109109}
110110
111−QString RootActionState::label() const
111+QString RootActionState::leftLabel() const
112112{
113113 if (!isValid()) return QString();
114114
115− return m_cachedState.value("label", QVariant::fromValue(QString())).toString();
115+ return m_cachedState.value("pre-label", QVariant::fromValue(QString())).toString();
116116}
117117
118−QString RootActionState::icon() const
118+QString RootActionState::rightLabel() const
119119{
120120 if (!isValid()) return QString();
121121
122− return m_cachedState.value("icon", QVariant::fromValue(QString())).toString();
122+ return m_cachedState.value("label", QVariant::fromValue(QString())).toString();
123+}
124+
125+QStringList RootActionState::icons() const
126+{
127+ if (!isValid()) return QStringList();
128+
129+ return m_cachedState.value("icons", QVariant::fromValue(QStringList())).toStringList();
123130}
124131
125132QString RootActionState::accessibleName() const
126133{
127134 if (!isValid()) return QString();
128135
129− return m_cachedState.value("accessible-name", QVariant::fromValue(QString())).toString();
136+ return m_cachedState.value("accessible-desc", QVariant::fromValue(QString())).toString();
130137}
131138
132139bool RootActionState::isVisible() const
@@ -198,16 +205,39 @@ QVariant RootActionState::toQVariant(GVariant* state) const
198205 while (g_variant_iter_loop (&iter, "{sv}", &key, &vvalue))
199206 {
200207 QString str = QString::fromUtf8(key);
201− if (str == "icon") {
208+ if (str == "icon" && !qmap.contains("icons")) {
209+ QStringList icons;
210+
202211 // FIXME - should be sending a url.
203− GIcon *icon = g_icon_deserialize (vvalue);
204− if (icon) {
205− qmap.insert(str, iconUri(icon));
206− g_object_unref (icon);
212+ GIcon *gicon = g_icon_deserialize (vvalue);
213+ if (gicon) {
214+ icons << iconUri(gicon);
215+ g_object_unref (gicon);
207216 }
208− else {
209− qmap.insert(str, QVariant(""));
217+ qmap.insert("icons", icons);
218+
219+ } else if (str == "icons") {
220+
221+ QStringList icons;
222+
223+ if (g_variant_type_is_array(g_variant_get_type(vvalue))) {
224+
225+
226+ for (int i = 0, iMax = g_variant_n_children(vvalue); i < iMax; i++) {
227+ GVariant *child = g_variant_get_child_value(vvalue, i);
228+
229+ // FIXME - should be sending a url.
230+ GIcon *gicon = g_icon_deserialize (child);
231+ if (gicon) {
232+ icons << iconUri(gicon);
233+ g_object_unref (gicon);
234+ }
235+ g_variant_unref(child);
236+ }
210237 }
238+ // will overwrite icon.
239+ qmap.insert("icons", icons);
240+
211241 } else {
212242 qmap.insert(str, ActionStateParser::toQVariant(vvalue));
213243 }
@@ -230,12 +260,12 @@ QVariant RootActionState::toQVariant(GVariant* state) const
230260 &visible);
231261
232262 qmap["label"] = label ? QString::fromUtf8(label) : "";
233− qmap["accessible-name"] = accessible_name ? QString::fromUtf8(accessible_name) : "";
263+ qmap["accessible-desc"] = accessible_name ? QString::fromUtf8(accessible_name) : "";
234264 qmap["visible"] = visible;
235265
236266 gicon = g_icon_new_for_string (icon, NULL);
237267 if (gicon) {
238− qmap["icon"] = iconUri(gicon);
268+ qmap["icons"] = QStringList() << iconUri(gicon);
239269 g_object_unref (gicon);
240270 }
241271
plugins/Unity/Indicators/rootactionstate.h+9−6
@@ -32,8 +32,9 @@ class UNITYINDICATORS_EXPORT RootActionState : public ActionStateParser
3232 Q_PROPERTY(UnityMenuModel* menu READ menu WRITE setMenu NOTIFY menuChanged)
3333
3434 Q_PROPERTY(bool valid READ isValid NOTIFY validChanged)
35− Q_PROPERTY(QString label READ label NOTIFY labelChanged)
36− Q_PROPERTY(QString icon READ icon NOTIFY iconChanged)
35+ Q_PROPERTY(QString leftLabel READ leftLabel NOTIFY leftLabelChanged)
36+ Q_PROPERTY(QString rightLabel READ rightLabel NOTIFY rightLabelChanged)
37+ Q_PROPERTY(QStringList icons READ icons NOTIFY iconsChanged)
3738 Q_PROPERTY(QString accessibleName READ accessibleName NOTIFY accessibleNameChanged)
3839 Q_PROPERTY(bool visible READ isVisible NOTIFY visibleChanged)
3940public:
@@ -47,8 +48,9 @@ public:
4748 void setIndex(int index);
4849
4950 bool isValid() const;
50− QString label() const;
51− QString icon() const;
51+ QString leftLabel() const;
52+ QString rightLabel() const;
53+ QStringList icons() const;
5254 QString accessibleName() const;
5355 bool isVisible() const;
5456
@@ -62,8 +64,9 @@ Q_SIGNALS:
6264 void indexChanged();
6365
6466 void validChanged();
65− void labelChanged();
66− void iconChanged();
67+ void leftLabelChanged();
68+ void rightLabelChanged();
69+ void iconsChanged();
6770 void accessibleNameChanged();
6871 void visibleChanged();
6972
plugins/Unity/Launcher/CMakeLists.txt+5−1
@@ -1,11 +1,13 @@
11include(FindPkgConfig)
22pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=2)
3+pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
34
45add_definitions(-DSM_BUSNAME=systemBus)
56
67include_directories(
78 ${CMAKE_CURRENT_SOURCE_DIR}
89 ${CMAKE_SOURCE_DIR}/plugins/AccountsService
10+ ${GSETTINGS_QT_INCLUDE_DIRS}
911)
1012
1113set(QMLLAUNCHERPLUGIN_SRC
@@ -15,7 +17,7 @@ set(QMLLAUNCHERPLUGIN_SRC
1517 quicklistmodel.cpp
1618 common/quicklistentry.cpp
1719 backend/launcherbackend.cpp
18− ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsService.cpp
20+ ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
1921 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
2022 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
2123 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
@@ -25,6 +27,8 @@ add_library(UnityLauncher-qml MODULE
2527 ${QMLLAUNCHERPLUGIN_SRC}
2628 )
2729
30+target_link_libraries(UnityLauncher-qml ${GSETTINGS_QT_LDFLAGS})
31+
2832qt5_use_modules(UnityLauncher-qml DBus Qml)
2933
3034# export the qmldir and qmltypes files
plugins/Unity/Launcher/backend/launcherbackend.cpp+188−100
@@ -18,109 +18,149 @@
1818 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1919 */
2020
21−#include "AccountsService.h"
21+#include "AccountsServiceDBusAdaptor.h"
2222#include "launcherbackend.h"
2323
2424#include <QDir>
2525#include <QDBusArgument>
2626#include <QFileInfo>
27+#include <QGSettings>
28+#include <QDebug>
29+
30+class LauncherBackendItem
31+{
32+public:
33+ LauncherBackendItem(): pinned(false) {}
34+
35+ QString desktopFile;
36+ QString displayName;
37+ QString icon;
38+ bool pinned;
39+};
2740
2841LauncherBackend::LauncherBackend(bool useStorage, QObject *parent):
2942 QObject(parent),
3043 m_accounts(nullptr)
3144{
3245 if (useStorage) {
33− m_accounts = new AccountsService(this);
46+ m_accounts = new AccountsServiceDBusAdaptor(this);
3447 }
35− setUser(qgetenv("USER"));
48+ m_user = qgetenv("USER");
49+ syncFromAccounts();
3650}
3751
3852LauncherBackend::~LauncherBackend()
3953{
40− clearItems();
41−}
54+ m_storedApps.clear();
4255
43−void LauncherBackend::clearItems()
44−{
45− for (LauncherBackendItem &app: m_storedApps) {
46− delete app.settings;
56+ Q_FOREACH(LauncherBackendItem *item, m_itemCache) {
57+ delete item;
4758 }
48− m_storedApps.clear();
59+ m_itemCache.clear();
4960}
5061
5162QStringList LauncherBackend::storedApplications() const
5263{
53− auto files = QStringList();
54− for (const LauncherBackendItem &app: m_storedApps) {
55− files << app.settings->fileName();
56− }
57− return files;
64+ return m_storedApps;
5865}
5966
6067void LauncherBackend::setStoredApplications(const QStringList &appIds)
6168{
62− // Record all existing pinned apps, so we can notice them in new list
63− auto pinnedItems = QStringList();
64− for (LauncherBackendItem &app: m_storedApps) {
65− if (app.pinned) {
66− pinnedItems.append(app.settings->fileName());
69+ if (appIds.count() < m_storedApps.count()) {
70+ Q_FOREACH(const QString &appId, m_storedApps) {
71+ if (!appIds.contains(appId)) {
72+ delete m_itemCache.take(appId);
73+ }
6774 }
6875 }
69−
70− clearItems();
71−
72− for (const QString &appId: appIds) {
73− loadApp(makeAppDetails(appId, pinnedItems.contains(desktopFile(appId))));
76+ m_storedApps = appIds;
77+ Q_FOREACH(const QString &appId, appIds) {
78+ if (!m_itemCache.contains(appId)) {
79+ QString df = findDesktopFile(appId);
80+ if (!df.isEmpty()) {
81+ LauncherBackendItem *item = parseDesktopFile(df);
82+ m_itemCache.insert(appId, item);
83+ } else {
84+ // Cannot find any data for that app... ignoring it.
85+ qWarning() << "cannot find desktop file for" << appId << ". discarding app.";
86+ m_storedApps.removeAll(appId);
87+ }
88+ }
7489 }
75−
7690 syncToAccounts();
7791}
7892
7993QString LauncherBackend::desktopFile(const QString &appId) const
8094{
81− QFileInfo fileInfo(QDir("/usr/share/applications"), appId);
82− return fileInfo.absoluteFilePath();
95+ LauncherBackendItem *item = m_itemCache.value(appId);
96+ if (item) {
97+ return item->desktopFile;
98+ }
99+
100+ return findDesktopFile(appId);
83101}
84102
85103QString LauncherBackend::displayName(const QString &appId) const
86104{
87− auto desktopFile = parseDesktopFile(appId);
88− auto displayName = desktopFile->value("Desktop Entry/Name").toString();
89− delete desktopFile;
90− return displayName;
105+ LauncherBackendItem *item = m_itemCache.value(appId);
106+ if (item) {
107+ return item->displayName;
108+ }
109+
110+ QString df = findDesktopFile(appId);
111+ if (!df.isEmpty()) {
112+ LauncherBackendItem *item = parseDesktopFile(df);
113+ m_itemCache.insert(appId, item);
114+ return item->displayName;
115+ }
116+
117+ return QString();
91118}
92119
93120QString LauncherBackend::icon(const QString &appId) const
94121{
95− auto desktopFile = parseDesktopFile(appId);
96− auto iconName = desktopFile->value("Desktop Entry/Icon").toString();
97− delete desktopFile;
98−
99− if (!iconName.isEmpty()) {
100− QFileInfo iconFileInfo(iconName);
101− if (iconFileInfo.isRelative()) {
102− iconName = "image://gicon/" + iconName;
122+ QString iconName;
123+ LauncherBackendItem *item = m_itemCache.value(appId);
124+ if (item) {
125+ iconName = item->icon;
126+ } else {
127+ QString df = findDesktopFile(appId);
128+ if (!df.isEmpty()) {
129+ LauncherBackendItem *item = parseDesktopFile(df);
130+ m_itemCache.insert(appId, item);
131+ iconName = item->icon;
103132 }
104133 }
105134
106− return iconName;
135+ QFileInfo info(iconName);
136+ if (info.exists()) {
137+ return info.absoluteFilePath();
138+ }
139+ return "image://theme/" + iconName;
107140}
108141
109142bool LauncherBackend::isPinned(const QString &appId) const
110143{
111− auto index = findItem(appId);
112− if (index < 0) {
113− return false;
114− } else {
115− return m_storedApps[index].pinned;
144+ LauncherBackendItem *item = m_itemCache.value(appId);
145+ if (item) {
146+ return item->pinned;
116147 }
148+ return false;
117149}
118150
119151void LauncherBackend::setPinned(const QString &appId, bool pinned)
120152{
121− auto index = findItem(appId);
122− if (index >= 0 && !m_storedApps[index].pinned) {
123− m_storedApps[index].pinned = pinned;
153+ if (!m_storedApps.contains(appId)) {
154+ return;
155+ }
156+
157+ LauncherBackendItem *item = m_itemCache.value(appId);
158+ if (!item) {
159+ item = new LauncherBackendItem();
160+ m_itemCache.insert(appId, item);
161+ }
162+ if (item->pinned != pinned) {
163+ item->pinned = pinned;
124164 syncToAccounts();
125165 }
126166}
@@ -153,8 +193,10 @@ int LauncherBackend::count(const QString &appId) const
153193
154194void LauncherBackend::setUser(const QString &username)
155195{
156− m_user = username;
157− syncFromAccounts();
196+ if (qgetenv("USER") == "lightdm" && m_user != username) {
197+ m_user = username;
198+ syncFromAccounts();
199+ }
158200}
159201
160202void LauncherBackend::triggerQuickListAction(const QString &appId, const QString &quickListId)
@@ -169,75 +211,132 @@ void LauncherBackend::syncFromAccounts()
169211 QList<QVariantMap> apps;
170212 bool defaults = true;
171213
172− clearItems();
214+ m_storedApps.clear();
173215
174− if (m_user != "" && m_accounts != nullptr) {
175− auto variant = m_accounts->getUserProperty(m_user, "com.canonical.unity.AccountsService", "launcher-items");
216+ if (m_accounts && !m_user.isEmpty()) {
217+ QVariant variant = m_accounts->getUserProperty(m_user, "com.canonical.unity.AccountsService", "launcher-items");
176218 apps = qdbus_cast<QList<QVariantMap>>(variant.value<QDBusArgument>());
177219 defaults = isDefaultsItem(apps);
178220 }
179221
180− // TODO: load default pinned ones from default config, instead of hardcoding here...
181− if (defaults) {
182− apps <<
183− makeAppDetails("dialer-app.desktop", true) <<
184− makeAppDetails("messaging-app.desktop", true) <<
185− makeAppDetails("address-book-app.desktop", true) <<
186− makeAppDetails("camera-app.desktop", true) <<
187− makeAppDetails("gallery-app.desktop", true) <<
188− makeAppDetails("facebook-webapp.desktop", true) <<
189− makeAppDetails("webbrowser-app.desktop", true) <<
190− makeAppDetails("twitter-webapp.desktop", true) <<
191− makeAppDetails("gmail-webapp.desktop", true) <<
192− makeAppDetails("ubuntu-weather-app.desktop", true) <<
193− makeAppDetails("notes-app.desktop", true) <<
194− makeAppDetails("calendar-app.desktop", true);
195− }
196−
197− for (const QVariant &app: apps) {
198− loadApp(app.toMap());
222+ if (m_accounts && defaults) { // Checking accounts as it'll be null when !useStorage
223+ QGSettings gSettings("com.canonical.Unity.Launcher", "/com/canonical/unity/launcher/");
224+ Q_FOREACH(const QString &entry, gSettings.get("favorites").toStringList()) {
225+ if (entry.startsWith("application://")) {
226+ QString appId = entry;
227+ // Transform "application://foobar.desktop" to "foobar"
228+ appId.remove("application://");
229+ if (appId.endsWith(".desktop")) {
230+ appId.chop(8);
231+ }
232+ QString df = findDesktopFile(appId);
233+
234+ if (!df.isEmpty()) {
235+ m_storedApps << appId;
236+
237+ if (!m_itemCache.contains(appId)) {
238+ m_itemCache.insert(appId, parseDesktopFile(df));
239+ }
240+ m_itemCache.value(appId)->pinned = true;
241+ }
242+ }
243+ }
244+ } else {
245+ for (const QVariant &app: apps) {
246+ loadFromVariant(app.toMap());
247+ }
199248 }
200249}
201250
202251void LauncherBackend::syncToAccounts()
203252{
204− if (m_user != "" && m_accounts != nullptr) {
253+ if (m_accounts && !m_user.isEmpty()) {
205254 QList<QVariantMap> items;
206255
207− for (LauncherBackendItem &app: m_storedApps) {
208− items << makeAppDetails(app.settings->fileName(), app.pinned);
256+ Q_FOREACH(const QString &appId, m_storedApps) {
257+ items << itemToVariant(appId);
209258 }
210259
211260 m_accounts->setUserProperty(m_user, "com.canonical.unity.AccountsService", "launcher-items", QVariant::fromValue(items));
212261 }
213262}
214263
215−QSettings *LauncherBackend::parseDesktopFile(const QString &appId) const
264+QString LauncherBackend::findDesktopFile(const QString &appId) const
216265{
217− auto fullAppId = desktopFile(appId);
218− return new QSettings(fullAppId, QSettings::IniFormat);
266+ int dashPos = -1;
267+ QString helper = appId;
268+
269+ QStringList searchDirs;
270+ searchDirs << QDir::homePath() + "/.local/share/applications";
271+ searchDirs << "/usr/share/applications";
272+
273+#ifdef LAUNCHER_TESTING
274+ searchDirs << "";
275+#endif
276+
277+ do {
278+ if (dashPos != -1) {
279+ helper = helper.replace(dashPos, 1, '/');
280+ }
281+
282+ Q_FOREACH(const QString &searchDir, searchDirs) {
283+ QFileInfo fileInfo(QDir(searchDir), helper + ".desktop");
284+ if (fileInfo.exists()) {
285+ return fileInfo.absoluteFilePath();
286+ }
287+ }
288+
289+ dashPos = helper.indexOf("-");
290+ } while (dashPos != -1);
291+
292+ return QString();
219293}
220294
221−void LauncherBackend::loadApp(const QVariantMap &details)
295+LauncherBackendItem* LauncherBackend::parseDesktopFile(const QString &desktopFile) const
222296{
223− auto appId = details.value("id").toString();
224− auto isPinned = details.value("is-pinned").toBool();
297+ QSettings settings(desktopFile, QSettings::IniFormat);
225298
226− if (appId.isEmpty()) {
299+
300+ LauncherBackendItem* item = new LauncherBackendItem();
301+ item->desktopFile = desktopFile;
302+ item->displayName = settings.value("Desktop Entry/Name").toString();
303+ item->icon = settings.value("Desktop Entry/Icon").toString();
304+ item->pinned = false;
305+ return item;
306+}
307+
308+void LauncherBackend::loadFromVariant(const QVariantMap &details)
309+{
310+ if (!details.contains("id")) {
227311 return;
228312 }
313+ QString appId = details.value("id").toString();
314+
315+ LauncherBackendItem *item = m_itemCache.value(appId);
316+ if (item) {
317+ delete item;
318+ }
319+
320+ item = new LauncherBackendItem();
229321
230− LauncherBackendItem item;
231− item.settings = parseDesktopFile(appId);
232− item.pinned = isPinned;
233− m_storedApps.append(item);
322+ item->desktopFile = details.value("desktopFile").toString();
323+ item->displayName = details.value("name").toString();
324+ item->icon = details.value("icon").toString();
325+ item->pinned = details.value("is-pinned").toBool();
326+
327+ m_itemCache.insert(appId, item);
328+ m_storedApps.append(appId);
234329}
235330
236−QVariantMap LauncherBackend::makeAppDetails(const QString &appId, bool pinned) const
331+QVariantMap LauncherBackend::itemToVariant(const QString &appId) const
237332{
333+ LauncherBackendItem *item = m_itemCache.value(appId);
238334 QVariantMap details;
239335 details.insert("id", appId);
240− details.insert("is-pinned", pinned);
336+ details.insert("name", item->displayName);
337+ details.insert("icon", item->icon);
338+ details.insert("desktopFile", item->desktopFile);
339+ details.insert("is-pinned", item->pinned);
241340 return details;
242341}
243342
@@ -248,14 +347,3 @@ bool LauncherBackend::isDefaultsItem(const QList<QVariantMap> &apps) const
248347 // list of one item with the 'defaults' field set to true.
249348 return (apps.size() == 1 && apps[0].value("defaults").toBool());
250349}
251−
252−int LauncherBackend::findItem(const QString &appId) const
253−{
254− auto fullAppId = desktopFile(appId);
255− for (int i = 0; i < m_storedApps.size(); ++i) {
256− if (m_storedApps[i].settings->fileName() == fullAppId) {
257− return i;
258− }
259− }
260− return -1;
261−}
plugins/Unity/Launcher/backend/launcherbackend.h+12−14
@@ -25,12 +25,14 @@
2525#include <QSettings>
2626#include <QStringList>
2727
28−class AccountsService;
28+class AccountsServiceDBusAdaptor;
2929
3030/**
3131 * @brief An interface that provides all the data needed by the launcher.
3232 */
3333
34+class LauncherBackendItem;
35+
3436class LauncherBackend : public QObject
3537{
3638 Q_OBJECT
@@ -141,24 +143,20 @@ Q_SIGNALS:
141143 void countChanged(const QString &appId, int count);
142144
143145private:
144− QSettings *parseDesktopFile(const QString &appId) const;
145− QVariantMap makeAppDetails(const QString &appId, bool pinned) const;
146− void loadApp(const QVariantMap &details);
147− int findItem(const QString &appId) const;
146+ QString findDesktopFile(const QString &appId) const;
147+ LauncherBackendItem* parseDesktopFile(const QString &desktopFile) const;
148+
149+ QVariantMap itemToVariant(const QString &appId) const;
150+ void loadFromVariant(const QVariantMap &details);
151+
148152 bool isDefaultsItem(const QList<QVariantMap> &apps) const;
149153 void syncFromAccounts();
150154 void syncToAccounts();
151− void clearItems();
152155
153− class LauncherBackendItem
154− {
155− public:
156− QSettings *settings;
157− bool pinned;
158− };
156+ QList<QString> m_storedApps;
157+ mutable QHash<QString, LauncherBackendItem*> m_itemCache;
159158
160− QList<LauncherBackendItem> m_storedApps;
161− AccountsService *m_accounts;
159+ AccountsServiceDBusAdaptor *m_accounts;
162160 QString m_user;
163161};
164162
plugins/Unity/Launcher/launcheritem.cpp+14
@@ -31,6 +31,7 @@ LauncherItem::LauncherItem(const QString &appId, const QString &desktopFile, con
3131 m_recent(false),
3232 m_progress(-1),
3333 m_count(0),
34+ m_focused(false),
3435 m_quickList(new QuickListModel(this))
3536{
3637 QuickListEntry nameAction;
@@ -131,6 +132,19 @@ void LauncherItem::setCount(int count)
131132 }
132133}
133134
135+bool LauncherItem::focused() const
136+{
137+ return m_focused;
138+}
139+
140+void LauncherItem::setFocused(bool focused)
141+{
142+ if (m_focused != focused) {
143+ m_focused = focused;
144+ Q_EMIT focusedChanged(focused);
145+ }
146+}
147+
134148unity::shell::launcher::QuickListModelInterface *LauncherItem::quickList() const
135149{
136150 return m_quickList;
plugins/Unity/Launcher/launcheritem.h+4
@@ -54,6 +54,9 @@ public:
5454 int count() const;
5555 void setCount(int count);
5656
57+ bool focused() const;
58+ void setFocused(bool focused);
59+
5760 unity::shell::launcher::QuickListModelInterface *quickList() const;
5861
5962Q_SIGNALS:
@@ -70,6 +73,7 @@ private:
7073 bool m_recent;
7174 int m_progress;
7275 int m_count;
76+ bool m_focused;
7377 QuickListModel *m_quickList;
7478};
7579
plugins/Unity/Launcher/launchermodel.cpp+59
@@ -74,6 +74,8 @@ QVariant LauncherModel::data(const QModelIndex &index, int role) const
7474 return item->count();
7575 case RoleProgress:
7676 return item->progress();
77+ case RoleFocused:
78+ return item->focused();
7779 }
7880
7981 return QVariant();
@@ -191,6 +193,63 @@ void LauncherModel::setUser(const QString &username)
191193 m_backend->setUser(username);
192194}
193195
196+void LauncherModel::applicationFocused(const QString &appId)
197+{
198+ // Unfocus all apps
199+ for(int i = 0; i < m_list.count(); ++i) {
200+ LauncherItem *item = m_list.at(i);
201+ if (item->focused()) {
202+ item->setFocused(false);
203+ Q_EMIT dataChanged(this->index(i), this->index(i), QVector<int>() << RoleFocused);
204+ }
205+ }
206+
207+ if (appId.isEmpty()) {
208+ return;
209+ }
210+
211+ // FIXME: drop this once we get real appIds from the AppManager
212+ QString helper = appId.split('/').last();
213+ if (helper.endsWith(".desktop")) {
214+ helper.chop(8);
215+ }
216+
217+ int index = findApplication(helper);
218+ if (index >= 0) {
219+ m_list.at(index)->setFocused(true);
220+ Q_EMIT dataChanged(this->index(index), this->index(index), QVector<int>() << RoleFocused);
221+ } else {
222+ // Add app to recent apps
223+ QString desktopFile = m_backend->desktopFile(helper);
224+ QString appName = m_backend->displayName(helper);
225+ QString icon = m_backend->icon(helper);
226+
227+ LauncherItem *item = new LauncherItem(helper, desktopFile, appName, icon);
228+ item->setRecent(true);
229+ item->setFocused(true);
230+ beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
231+ m_list.append(item);
232+ endInsertRows();
233+
234+ // Clean up old recent apps
235+ QList<int> recentAppIndices;
236+ for (int i = 0; i < m_list.count(); ++i) {
237+ if (m_list.at(i)->recent()) {
238+ recentAppIndices << i;
239+ }
240+ }
241+ int run = 0;
242+ while (recentAppIndices.count() > 5) {
243+ beginRemoveRows(QModelIndex(), recentAppIndices.first() - run, recentAppIndices.first() - run);
244+ m_list.takeAt(recentAppIndices.first() - run)->deleteLater();
245+ endRemoveRows();
246+ recentAppIndices.takeFirst();
247+ ++run;
248+ }
249+ storeAppList();
250+ }
251+}
252+
194253void LauncherModel::storeAppList()
195254{
196255 QStringList appIds;
plugins/Unity/Launcher/launchermodel.h+1
@@ -49,6 +49,7 @@ public:
4949 Q_INVOKABLE void requestRemove(const QString &appId);
5050 Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex);
5151 Q_INVOKABLE void setUser(const QString &username);
52+ Q_INVOKABLE void applicationFocused(const QString &appId);
5253
5354private:
5455 void storeAppList();
plugins/Unity/categories.cpp−3
@@ -43,7 +43,6 @@ Categories::Categories(QObject* parent)
4343 m_roles[Categories::RoleHints] = "hints";
4444 m_roles[Categories::RoleResults] = "results";
4545 m_roles[Categories::RoleCount] = "count";
46− m_roles[Categories::RoleCategoryIndex] = "categoryIndex";
4746
4847 // TODO This should not be needed but accumulatting the count changes
4948 // makes the visualization more stable and also makes crashes on fast
@@ -222,8 +221,6 @@ Categories::data(const QModelIndex& index, int role) const
222221 return QVariant::fromValue(m_overriddenCategories[id]->rowCount());
223222 }
224223 return QVariant::fromValue(getResults(index.row())->rowCount());
225− case RoleCategoryIndex:
226− return QVariant::fromValue(index.row());
227224 default:
228225 return QVariant();
229226 }
plugins/Unity/categories.h+1−2
@@ -50,8 +50,7 @@ public:
5050 RoleProgressSource,
5151 RoleHints,
5252 RoleResults,
53− RoleCount,
54− RoleCategoryIndex
53+ RoleCount
5554 };
5655
5756 Q_INVOKABLE void overrideResults(const QString& categoryId, QAbstractItemModel* model);
plugins/Unity/checkoptionfilter.cpp+3−1
@@ -52,9 +52,11 @@ void CheckOptionFilter::onOptionsChanged(unity::dash::CheckOptionFilter::CheckOp
5252
5353 m_options = new UnityOptionsModel(this, options,
5454 m_unityCheckOptionFilter->option_added,
55− m_unityCheckOptionFilter->option_removed);
55+ m_unityCheckOptionFilter->option_removed,
56+ m_unityCheckOptionFilter->show_all_button);
5657
5758 connect(m_options, SIGNAL(activeChanged(AbstractFilterOption *)), m_options, SLOT(ensureTheOnlyActive(AbstractFilterOption *)));
59+ connect(m_options, SIGNAL(showAllActivated()), this, SLOT(clear()));
5860
5961 /* Property change signals */
6062 m_signals << m_unityCheckOptionFilter->options.changed.connect(sigc::mem_fun(this, &CheckOptionFilter::onOptionsChanged));
plugins/Unity/filter.h+3−2
@@ -56,11 +56,12 @@ public:
5656 bool filtering() const;
5757 virtual GenericOptionsModel* options() const = 0;
5858
59− Q_INVOKABLE void clear();
60−
6159 static Filter* newFromUnityFilter(unity::dash::Filter::Ptr unityFilter);
6260 bool hasUnityFilter(unity::dash::Filter::Ptr unityFilter) const;
6361
62+public Q_SLOTS:
63+ void clear();
64+
6465Q_SIGNALS:
6566 void optionsChanged();
6667
plugins/Unity/genericoptionsmodel.cpp+20−3
@@ -22,10 +22,18 @@
2222
2323// local
2424#include "abstractfilteroption.h"
25+#include "showallfilteroption.h"
2526
26−GenericOptionsModel::GenericOptionsModel(QObject *parent)
27+GenericOptionsModel::GenericOptionsModel(bool showAllOption, QObject *parent)
2728 : QAbstractListModel(parent)
2829{
30+ if (showAllOption)
31+ {
32+ auto showAll = new ShowAllFilterOption(this);
33+ connect(showAll, SIGNAL(activeChanged(bool)), this, SLOT(onOptionChanged()));
34+ connect(showAll, SIGNAL(activeChanged(bool)), this, SLOT(onShowAllClicked(bool)));
35+ addOption(showAll);
36+ }
2937}
3038
3139GenericOptionsModel::~GenericOptionsModel()
@@ -73,7 +81,7 @@ QVariant GenericOptionsModel::data(const QModelIndex& index, int role) const
7381
7482int GenericOptionsModel::rowCount(const QModelIndex& /* parent */) const
7583{
76− return m_options.size ();
84+ return m_options.size();
7785}
7886
7987void GenericOptionsModel::setActive(int idx, bool value)
@@ -117,7 +125,10 @@ void GenericOptionsModel::ensureTheOnlyActive(AbstractFilterOption *activeOption
117125
118126void GenericOptionsModel::addOption(AbstractFilterOption *option, int index)
119127{
120− m_options.insert(index, option);
128+ if (index >= 0)
129+ m_options.insert(index, option);
130+ else
131+ m_options.append(option);
121132
122133 connect(option, SIGNAL(idChanged(const QString &)), this, SLOT(onOptionChanged()));
123134 connect(option, SIGNAL(nameChanged(const QString &)), this, SLOT(onOptionChanged()));
@@ -168,3 +179,9 @@ void GenericOptionsModel::onActiveChanged()
168179 Q_EMIT activeChanged(option);
169180 }
170181}
182+
183+void GenericOptionsModel::onShowAllClicked(bool active)
184+{
185+ if (active)
186+ Q_EMIT showAllActivated();
187+}
plugins/Unity/genericoptionsmodel.h+4−2
@@ -35,7 +35,7 @@ class Q_DECL_EXPORT GenericOptionsModel : public QAbstractListModel
3535 Q_ENUMS(Roles)
3636
3737public:
38− GenericOptionsModel(QObject *parent = nullptr);
38+ GenericOptionsModel(bool showAllOption = false, QObject *parent = nullptr);
3939 ~GenericOptionsModel();
4040
4141 enum Roles {
@@ -59,13 +59,15 @@ public Q_SLOTS:
5959
6060Q_SIGNALS:
6161 void activeChanged(AbstractFilterOption *option);
62+ void showAllActivated();
6263
6364protected Q_SLOTS:
6465 void onOptionChanged();
6566 void onActiveChanged();
67+ void onShowAllClicked(bool active);
6668
6769protected:
68− void addOption(AbstractFilterOption *option, int index);
70+ void addOption(AbstractFilterOption *option, int index = -1);
6971 void removeOption(int index);
7072 int indexOf(const QString &option_id);
7173
plugins/Unity/multirangefilter.cpp+3−1
@@ -52,9 +52,11 @@ void MultiRangeFilter::onOptionsChanged(unity::dash::MultiRangeFilter::Options o
5252
5353 m_options = new UnityOptionsModel(this, options,
5454 m_unityMultiRangeFilter->option_added,
55− m_unityMultiRangeFilter->option_removed);
55+ m_unityMultiRangeFilter->option_removed,
56+ m_unityMultiRangeFilter->show_all_button);
5657
5758 connect(m_options, SIGNAL(activeChanged(AbstractFilterOption *)), m_options, SLOT(ensureTheOnlyActive(AbstractFilterOption *)));
59+ connect(m_options, SIGNAL(showAllActivated()), this, SLOT(clear()));
5860
5961 /* Property change signals */
6062 m_signals << m_unityMultiRangeFilter->options.changed.connect(sigc::mem_fun(this, &MultiRangeFilter::onOptionsChanged));
plugins/Unity/radiooptionfilter.cpp+3−1
@@ -51,7 +51,9 @@ void RadioOptionFilter::onOptionsChanged(unity::dash::RadioOptionFilter::RadioOp
5151 }
5252 m_options = new UnityOptionsModel(this, m_unityRadioOptionFilter->options,
5353 m_unityRadioOptionFilter->option_added,
54− m_unityRadioOptionFilter->option_removed);
54+ m_unityRadioOptionFilter->option_removed,
55+ m_unityRadioOptionFilter->show_all_button);
56+ connect(m_options, SIGNAL(showAllActivated()), this, SLOT(clear()));
5557
5658 m_signals << m_unityRadioOptionFilter->options.changed.connect(sigc::mem_fun(this, &RadioOptionFilter::onOptionsChanged));
5759
plugins/Unity/ratingoptionsmodel.cpp+3−3
@@ -23,11 +23,11 @@
2323// local
2424#include "ratingfilteroption.h"
2525
26−RatingOptionsModel::RatingOptionsModel(QObject *parent) :
27− GenericOptionsModel(parent)
26+RatingOptionsModel::RatingOptionsModel(bool showAllOption, QObject *parent) :
27+ GenericOptionsModel(showAllOption, parent)
2828{
2929 for (int i=1; i<=5; i++) {
3030 auto opt = new RatingFilterOption(QString::number(i), i*0.2f, this);
31− addOption(opt, i-1);
31+ addOption(opt);
3232 }
3333}
plugins/Unity/ratingoptionsmodel.h+1−1
@@ -27,7 +27,7 @@ class RatingOptionsModel : public GenericOptionsModel
2727 Q_OBJECT
2828
2929public:
30− RatingOptionsModel(QObject *parent);
30+ RatingOptionsModel(bool showAllOption, QObject *parent);
3131};
3232
3333#endif // RATINGOPTIONSMODEL_H
plugins/Unity/ratingsfilter.cpp+2−1
@@ -53,9 +53,10 @@ void RatingsFilter::setUnityFilter(unity::dash::Filter::Ptr filter)
5353
5454 delete m_options;
5555
56− m_options = new RatingOptionsModel(this);
56+ m_options = new RatingOptionsModel(m_unityRatingsFilter->show_all_button, this);
5757 connect(m_options, SIGNAL(activeChanged(AbstractFilterOption *)), m_options, SLOT(ensureTheOnlyActive(AbstractFilterOption *)));
5858 connect(m_options, SIGNAL(activeChanged(AbstractFilterOption *)), this, SLOT(onActiveChanged(AbstractFilterOption *)));
59+ connect(m_options, SIGNAL(showAllActivated()), this, SLOT(clear()));
5960
6061 Q_EMIT optionsChanged();
6162}
plugins/Unity/showallfilteroption.cppnew file+60
@@ -0,0 +1,60 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+// self
21+#include "showallfilteroption.h"
22+
23+#include <libintl.h>
24+
25+unsigned int ShowAllFilterOption::m_showAllCount = 0;
26+
27+ShowAllFilterOption::ShowAllFilterOption(QObject *parent) :
28+ AbstractFilterOption(parent),
29+ m_active(false)
30+{
31+ m_id = QString("show_all::%1").arg(m_showAllCount++);
32+}
33+
34+QString ShowAllFilterOption::id() const
35+{
36+ return m_id;
37+}
38+
39+QString ShowAllFilterOption::name() const
40+{
41+ return QString::fromUtf8(dgettext("unity", "All"));
42+}
43+
44+QString ShowAllFilterOption::iconHint() const
45+{
46+ return QString::Null();
47+}
48+
49+bool ShowAllFilterOption::active() const
50+{
51+ return m_active;
52+}
53+
54+void ShowAllFilterOption::setActive(bool active)
55+{
56+ if (active != m_active) {
57+ m_active = active;
58+ Q_EMIT activeChanged(m_active);
59+ }
60+}
plugins/Unity/showallfilteroption.hnew file+51
@@ -0,0 +1,51 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+#ifndef SHOWALLFILTEROPTION_H
21+#define SHOWALLFILTEROPTION_H
22+
23+// local
24+#include "abstractfilteroption.h"
25+
26+class Q_DECL_EXPORT ShowAllFilterOption : public AbstractFilterOption
27+{
28+ Q_OBJECT
29+
30+public:
31+ explicit ShowAllFilterOption(QObject *parent = nullptr);
32+
33+ /* getters */
34+ QString id() const override;
35+ QString name() const override;
36+ QString iconHint() const override;
37+ bool active() const override;
38+
39+ /* setters */
40+ void setActive(bool active) override;
41+
42+private:
43+ bool m_active;
44+ QString m_id;
45+
46+ static unsigned int m_showAllCount;
47+};
48+
49+Q_DECLARE_METATYPE(ShowAllFilterOption*)
50+
51+#endif // SHOWALLFILTEROPTION_H
plugins/Unity/unityoptionsmodel.cpp+5−4
@@ -26,8 +26,9 @@
2626UnityOptionsModel::UnityOptionsModel(QObject *parent,
2727 const std::vector<unity::dash::FilterOption::Ptr> options,
2828 sigc::signal<void, unity::dash::FilterOption::Ptr> optionAdded,
29− sigc::signal<void, unity::dash::FilterOption::Ptr> optionRemoved) :
30− GenericOptionsModel(parent)
29+ sigc::signal<void, unity::dash::FilterOption::Ptr> optionRemoved,
30+ bool showAllOption) :
31+ GenericOptionsModel(showAllOption, parent)
3132{
3233 setOptions(options, optionAdded, optionRemoved);
3334}
@@ -38,7 +39,7 @@ void UnityOptionsModel::setOptions(const std::vector<unity::dash::FilterOption::
3839{
3940 for (unsigned int i=0; i<options.size(); i++)
4041 {
41− addOption(new FilterOption(options[i], this), i);
42+ addOption(new FilterOption(options[i], this));
4243 }
4344 optionAdded.connect(sigc::mem_fun(this, &UnityOptionsModel::onOptionAdded));
4445 optionRemoved.connect(sigc::mem_fun(this, &UnityOptionsModel::onOptionRemoved));
@@ -50,7 +51,7 @@ void UnityOptionsModel::onOptionAdded(unity::dash::FilterOption::Ptr option)
5051 if (index >= 0)
5152 {
5253 beginInsertRows(QModelIndex(), index, index);
53− addOption(new FilterOption(option, this), index);
54+ addOption(new FilterOption(option, this));
5455 endInsertRows();
5556 }
5657}
plugins/Unity/unityoptionsmodel.h+2−1
@@ -35,7 +35,8 @@ public:
3535 UnityOptionsModel(QObject *parent,
3636 const std::vector<unity::dash::FilterOption::Ptr> options,
3737 sigc::signal<void, unity::dash::FilterOption::Ptr> optionAdded,
38− sigc::signal<void, unity::dash::FilterOption::Ptr> optionRemoved);
38+ sigc::signal<void, unity::dash::FilterOption::Ptr> optionRemoved,
39+ bool showAllOption);
3940
4041private:
4142 void setOptions(const std::vector<unity::dash::FilterOption::Ptr> options,
po/ar.po+2−29
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n % 100 >= "
1818"3 && n % 100 <= 10 ? 3 : n % 100 >= 11 && n % 100 <= 99 ? 4 : 5;\n"
19−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
19+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
20+"X-Generator: Launchpad (build 16750)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
@@ -254,30 +254,3 @@ msgstr "عذراً، لا يوجد ما يطابق بحثك."
254254#, qt-format
255255msgid "Please enter %1"
256256msgstr ""
257−
258−#~ msgid "Running apps"
259−#~ msgstr "البرامج المُشغّلة"
260−
261−#~ msgid "Frequently used"
262−#~ msgstr "مُستخدمة بكثرة"
263−
264−#~ msgid "Installed"
265−#~ msgstr "مُثبّتة"
266−
267−#~ msgid "Available for download"
268−#~ msgstr "متوفرة للتنزيل"
269−
270−#~ msgid "Apps"
271−#~ msgstr "تطبيقات"
272−
273−#~ msgid "Frequent Apps"
274−#~ msgstr "تطبيقات مألوفة"
275−
276−#~ msgid "Recent Music"
277−#~ msgstr "آخر الصوتيات المشغلة"
278−
279−#~ msgid "Videos Popular Online"
280−#~ msgstr "فيديوهات رائجة على الإنترنت"
281−
282−#~ msgid "Home"
283−#~ msgstr "الرئيسية"
po/az.po+2−8
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "Bağışlayın, amma axtarışınıza heç bir nəticə uyğun gəlmir."
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "Tətbiqlər"
259−
260−#~ msgid "Home"
261−#~ msgstr "Ev"
po/bg.po+2−11
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Type: text/plain; charset=UTF-8\n"
1717"Content-Transfer-Encoding: 8bit\n"
1818"Plural-Forms: nplurals=2; plural=n != 1;\n"
19−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
19+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
20+"X-Generator: Launchpad (build 16750)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
@@ -254,12 +254,3 @@ msgstr "Съжаляваме, няма нищо, което да отговар
254254#, qt-format
255255msgid "Please enter %1"
256256msgstr ""
257−
258−#~ msgid "Installed"
259−#~ msgstr "Инсталирани"
260−
261−#~ msgid "Apps"
262−#~ msgstr "Приложения"
263−
264−#~ msgid "Home"
265−#~ msgstr "Начало"
po/ca.po+2−29
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,30 +253,3 @@ msgstr "No hi ha res que coincideixi amb la cerca"
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Running apps"
258−#~ msgstr "Aplications actives"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "Les més freqüents"
262−
263−#~ msgid "Installed"
264−#~ msgstr "Instal·lades"
265−
266−#~ msgid "Available for download"
267−#~ msgstr "Disponibles per baixar"
268−
269−#~ msgid "Apps"
270−#~ msgstr "Aplicacions"
271−
272−#~ msgid "Frequent Apps"
273−#~ msgstr "Aplicacions freqüents"
274−
275−#~ msgid "Recent Music"
276−#~ msgstr "Música recent"
277−
278−#~ msgid "Videos Popular Online"
279−#~ msgstr "Vídeos populars en línia"
280−
281−#~ msgid "Home"
282−#~ msgstr "Inici"
po/de.po+2−29
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,30 +253,3 @@ msgstr "Entschuldigung, es wurden keine Treffer erzielt."
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Running apps"
258−#~ msgstr "Aktive Anwendungen"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "Häufig verwendet"
262−
263−#~ msgid "Installed"
264−#~ msgstr "Installiert"
265−
266−#~ msgid "Available for download"
267−#~ msgstr "Zum Herunterladen verfügbar"
268−
269−#~ msgid "Apps"
270−#~ msgstr "Anwendungen"
271−
272−#~ msgid "Frequent Apps"
273−#~ msgstr "Häufig genutzte Anwendungen"
274−
275−#~ msgid "Recent Music"
276−#~ msgstr "Zuletzt gehörte Musik"
277−
278−#~ msgid "Videos Popular Online"
279−#~ msgstr "Beliebte Online-Videos"
280−
281−#~ msgid "Home"
282−#~ msgstr "Start"
po/el.po+2−8
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "Λυπούμαστε, δεν υπάρχει τίποτα που να τ
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "Εφαρμογές"
259−
260−#~ msgid "Home"
261−#~ msgstr "Αρχή"
po/en_AU.po+2−29
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,30 +253,3 @@ msgstr "Sorry, there is nothing that matches your search."
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Running apps"
258−#~ msgstr "Running apps"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "Frequently used"
262−
263−#~ msgid "Installed"
264−#~ msgstr "Installed"
265−
266−#~ msgid "Available for download"
267−#~ msgstr "Available for download"
268−
269−#~ msgid "Apps"
270−#~ msgstr "Apps"
271−
272−#~ msgid "Frequent Apps"
273−#~ msgstr "Frequent Apps"
274−
275−#~ msgid "Recent Music"
276−#~ msgstr "Recent Music"
277−
278−#~ msgid "Videos Popular Online"
279−#~ msgstr "Videos Popular Online"
280−
281−#~ msgid "Home"
282−#~ msgstr "Home"
po/en_GB.po+2−29
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,30 +253,3 @@ msgstr "Sorry, there is nothing that matches your search."
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr "Please enter %1"
256−
257−#~ msgid "Running apps"
258−#~ msgstr "Running apps"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "Frequently used"
262−
263−#~ msgid "Installed"
264−#~ msgstr "Installed"
265−
266−#~ msgid "Available for download"
267−#~ msgstr "Available for download"
268−
269−#~ msgid "Apps"
270−#~ msgstr "Apps"
271−
272−#~ msgid "Frequent Apps"
273−#~ msgstr "Frequent Apps"
274−
275−#~ msgid "Recent Music"
276−#~ msgstr "Recent Music"
277−
278−#~ msgid "Videos Popular Online"
279−#~ msgstr "Videos Popular Online"
280−
281−#~ msgid "Home"
282−#~ msgstr "Home"
po/eo.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/es.po+24−49
@@ -8,15 +8,15 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-07-08 07:25+0000\n"
11+"PO-Revision-Date: 2013-09-04 22:12+0000\n"
1212"Last-Translator: Adolfo Jayme Barrientos <fitoschido@gmail.com>\n"
1313"Language-Team: Spanish <es@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-09-05 05:35+0000\n"
19+"X-Generator: Launchpad (build 16758)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -88,47 +88,49 @@ msgstr "YouTube"
8888
8989#: Components/EdgeDemoOverlay.qml:145
9090msgid "Skip intro"
91−msgstr ""
91+msgstr "Omitir la introducción"
9292
9393#: Components/EdgeDemo.qml:98
9494msgid "Right edge"
95−msgstr ""
95+msgstr "Borde derecho"
9696
9797#: Components/EdgeDemo.qml:99
9898msgid "Try swiping from the right edge to unlock the phone"
99−msgstr ""
99+msgstr "Deslice el dedo desde el borde derecho para desbloquear el teléfono"
100100
101101#: Components/EdgeDemo.qml:135
102102msgid "Top edge"
103−msgstr ""
103+msgstr "Borde superior"
104104
105105#: Components/EdgeDemo.qml:136
106106msgid "Try swiping from the top edge to access the indicators"
107−msgstr ""
107+msgstr "Deslice el dedo desde el borde superior para acceder a los menús"
108108
109109#: Components/EdgeDemo.qml:161
110110msgid "Close"
111−msgstr ""
111+msgstr "Cerrar"
112112
113113#: Components/EdgeDemo.qml:162
114114msgid "Swipe up again to close the settings screen"
115−msgstr ""
115+msgstr "Deslice hacia arriba para cerrar la pantalla de configuración"
116116
117117#: Components/EdgeDemo.qml:189
118118msgid "Left edge"
119−msgstr ""
119+msgstr "Borde izquierdo"
120120
121121#: Components/EdgeDemo.qml:190
122122msgid "Swipe from the left to reveal the launcher for quick access to apps"
123123msgstr ""
124+"Deslice el dedo desde la izquierda para mostrar el lanzador y acceder "
125+"rápidamente a las aplicaciones"
124126
125127#: Components/EdgeDemo.qml:217
126128msgid "Well done"
127−msgstr ""
129+msgstr "Bien hecho"
128130
129131#: Components/EdgeDemo.qml:218
130132msgid "You have now mastered the edge gestures and can start using the phone"
131−msgstr ""
133+msgstr "Ahora domina el uso de gestos de los bordes. Puede usar el teléfono"
132134
133135#: Components/PageHeader.qml:298
134136msgid "Recent searches"
@@ -138,35 +140,35 @@ msgstr "Búsquedas recientes"
138140#: Dash/Apps/AppInfo.qml:73
139141#, qt-format
140142msgid "(%1)"
141−msgstr ""
143+msgstr "(%1)"
142144
143145#. TRANSLATORS: Number of persons who wrote reviews for this app
144146#: Dash/Apps/AppInfo.qml:85
145147#, qt-format
146148msgid "%1 review"
147149msgid_plural "%1 reviews"
148−msgstr[0] ""
149−msgstr[1] ""
150+msgstr[0] "%1 reseña"
151+msgstr[1] "%1 reseñas"
150152
151153#: Dash/Apps/AppPreview.qml:175
152154msgid "Rate this"
153−msgstr ""
155+msgstr "Valorar esto"
154156
155157#: Dash/Apps/AppReviews.qml:72
156158msgid "Add a review"
157−msgstr ""
159+msgstr "Añadir una reseña"
158160
159161#: Dash/Apps/AppReviews.qml:84
160162msgid "Review"
161−msgstr ""
163+msgstr "Reseñar"
162164
163165#: Dash/Apps/AppReviews.qml:118
164166msgid "Send"
165−msgstr ""
167+msgstr "Enviar"
166168
167169#: Dash/Apps/AppReviews.qml:136
168170msgid "Comments:"
169−msgstr ""
171+msgstr "Comentarios:"
170172
171173#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
172174msgid "Featured"
@@ -210,7 +212,7 @@ msgstr "Autor:"
210212
211213#: Greeter/Lockscreen.qml:134
212214msgid "Emergency Call"
213−msgstr ""
215+msgstr "Llamada de emergencia"
214216
215217#: Greeter/PassphraseLockscreen.qml:59
216218#, qt-format
@@ -253,30 +255,3 @@ msgstr "No hay nada que coincida con su búsqueda."
253255#, qt-format
254256msgid "Please enter %1"
255257msgstr "Introduzca %1"
256−
257−#~ msgid "Running apps"
258−#~ msgstr "Aplicaciones en ejecución"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "Usadas frecuentemente"
262−
263−#~ msgid "Installed"
264−#~ msgstr "Instaladas"
265−
266−#~ msgid "Available for download"
267−#~ msgstr "Disponibles para descargar"
268−
269−#~ msgid "Apps"
270−#~ msgstr "Aplicaciones"
271−
272−#~ msgid "Frequent Apps"
273−#~ msgstr "Aplicaciones frecuentes"
274−
275−#~ msgid "Recent Music"
276−#~ msgstr "Música reciente"
277−
278−#~ msgid "Videos Popular Online"
279−#~ msgstr "Vídeos populares en línea"
280−
281−#~ msgid "Home"
282−#~ msgstr "Inicio"
po/fi.po+2−29
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,30 +253,3 @@ msgstr "Hakuun täsmääviä tuloksia ei löydy."
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr "Kirjoita %1"
256−
257−#~ msgid "Running apps"
258−#~ msgstr "Käynnissä olevat sovellukset"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "Usein käytetyt"
262−
263−#~ msgid "Installed"
264−#~ msgstr "Asennetut"
265−
266−#~ msgid "Available for download"
267−#~ msgstr "Ladattavissa"
268−
269−#~ msgid "Apps"
270−#~ msgstr "Sovellukset"
271−
272−#~ msgid "Frequent Apps"
273−#~ msgstr "Yleisimmät sovellukset"
274−
275−#~ msgid "Recent Music"
276−#~ msgstr "Viimeisin musiikki"
277−
278−#~ msgid "Videos Popular Online"
279−#~ msgstr "Suositut verkkovideot"
280−
281−#~ msgid "Home"
282−#~ msgstr "Kotinäyttö"
po/fo.po+2−8
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "Tíanverri er tað einki sum hóskar til tína leiting."
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "Nýtsluskipanir"
259−
260−#~ msgid "Home"
261−#~ msgstr "Heim"
po/fr.po+2−5
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n > 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,6 +253,3 @@ msgstr ""
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "Applications"
po/gl.po+2−29
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,30 +253,3 @@ msgstr "Sentímolo, non hai nada que coincida con esta busca."
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Running apps"
258−#~ msgstr "Aplicativos en execución"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "Usadas frecuentemente"
262−
263−#~ msgid "Installed"
264−#~ msgstr "Instalado"
265−
266−#~ msgid "Available for download"
267−#~ msgstr "Dispoñíbel para descargar"
268−
269−#~ msgid "Apps"
270−#~ msgstr "Aplicativos"
271−
272−#~ msgid "Frequent Apps"
273−#~ msgstr "Aplicativos frecuentes"
274−
275−#~ msgid "Recent Music"
276−#~ msgstr "Música recente"
277−
278−#~ msgid "Videos Popular Online"
279−#~ msgstr "Vídeos populares en liña"
280−
281−#~ msgid "Home"
282−#~ msgstr "Cartafol persoal"
po/he.po+2−8
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "שום דבר אינו תואם לחיפוש שלך, עמך הסליחה
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "יישומים"
259−
260−#~ msgid "Home"
261−#~ msgstr "בית"
po/hr.po+2−8
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
1818"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
19+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
20+"X-Generator: Launchpad (build 16750)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
@@ -254,9 +254,3 @@ msgstr "Nažalost, ne postoji ništa što odgovara vašoj pretrazi."
254254#, qt-format
255255msgid "Please enter %1"
256256msgstr ""
257−
258−#~ msgid "Apps"
259−#~ msgstr "Aplikacije"
260−
261−#~ msgid "Home"
262−#~ msgstr "Početna"
po/hu.po+2−17
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,18 +253,3 @@ msgstr "Elnézést, nincs találat a keresésre."
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Running apps"
258−#~ msgstr "Futó alkalmazások"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "Gyakran használt"
262−
263−#~ msgid "Installed"
264−#~ msgstr "Telepített"
265−
266−#~ msgid "Apps"
267−#~ msgstr "Alkalmazások"
268−
269−#~ msgid "Home"
270−#~ msgstr "Kezdőoldal"
po/hy.po+2−29
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,30 +253,3 @@ msgstr "Կներերք, բայց Ձեր հարցումով ոչինչ չկար"
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Running apps"
258−#~ msgstr "Բացած ծրագրեր"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "Վերջին բացածները"
262−
263−#~ msgid "Installed"
264−#~ msgstr "Տեղադրված"
265−
266−#~ msgid "Available for download"
267−#~ msgstr "Հասանելի ծրագրեր"
268−
269−#~ msgid "Apps"
270−#~ msgstr "Ծրագրեր"
271−
272−#~ msgid "Frequent Apps"
273−#~ msgstr "Հաճախակի ծրագրերը"
274−
275−#~ msgid "Recent Music"
276−#~ msgstr "Վերջին երգերը"
277−
278−#~ msgid "Videos Popular Online"
279−#~ msgstr "Հայտնի օնլայն վիդեոներ"
280−
281−#~ msgid "Home"
282−#~ msgstr "Տուն"
po/id.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/it.po+2−8
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "Nessun risultato corrispondente alla ricerca."
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "Applicazioni"
259−
260−#~ msgid "Home"
261−#~ msgstr "Home"
po/ja.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/kn.po+2−8
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "ಕ್ಷಮಿಸಿ ನಿಮ್ಮ ಶೋಧನೆಗೆ ಸರಿಯ
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "ಅಪ್ಲಿಕೇಶನ್‌ಗಳು"
259−
260−#~ msgid "Home"
261−#~ msgstr "ಮನೆ (Home)"
po/ko.po+2−23
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,24 +253,3 @@ msgstr ""
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Running apps"
258−#~ msgstr "돌아가고 있는 앱"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "자주 쓰는 것들"
262−
263−#~ msgid "Installed"
264−#~ msgstr "깔림"
265−
266−#~ msgid "Available for download"
267−#~ msgstr "내려받을 수 있음"
268−
269−#~ msgid "Apps"
270−#~ msgstr "앱"
271−
272−#~ msgid "Frequent Apps"
273−#~ msgstr "자주 쓰는 앱"
274−
275−#~ msgid "Recent Music"
276−#~ msgstr "요즈음 찾는 음악"
po/ky.po+2−8
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "Тилекке каршы, сиздин издөөңүзгө эч нер
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "Тиркемелер"
259−
260−#~ msgid "Home"
261−#~ msgstr "Үй папкасы"
po/lv.po+2−8
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "Diemžēl nekas neatbilst jūsu meklētajam."
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "Lietotnes"
259−
260−#~ msgid "Home"
261−#~ msgstr "Mājas"
po/my.po+2−8
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "ဆောရီး၊ သင်၏ရှာဖွေမူနှင့
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "Apps"
259−
260−#~ msgid "Home"
261−#~ msgstr "ပင်မ"
po/nb.po+2−17
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,18 +253,3 @@ msgstr "Søket ga ingen treff."
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Frequently used"
258−#~ msgstr "Ofte brukt"
259−
260−#~ msgid "Installed"
261−#~ msgstr "Installert"
262−
263−#~ msgid "Available for download"
264−#~ msgstr "Tilgjengelig for nedlasting"
265−
266−#~ msgid "Apps"
267−#~ msgstr "Programmer"
268−
269−#~ msgid "Home"
270−#~ msgstr "Hjem"
po/nl.po+2−8
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "Er is helaas niets dat met uw zoekopdracht overeenkomt."
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "Apps"
259−
260−#~ msgid "Home"
261−#~ msgstr "Hoofdvenster"
po/pl.po+2−29
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
1818"|| n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
19+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
20+"X-Generator: Launchpad (build 16750)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
@@ -254,30 +254,3 @@ msgstr "Nie znaleziono pasujących wyników."
254254#, qt-format
255255msgid "Please enter %1"
256256msgstr "Wprowadź %1"
257−
258−#~ msgid "Running apps"
259−#~ msgstr "Uruchomione aplikacje"
260−
261−#~ msgid "Frequently used"
262−#~ msgstr "Najczęściej używane"
263−
264−#~ msgid "Installed"
265−#~ msgstr "Zainstalowane"
266−
267−#~ msgid "Available for download"
268−#~ msgstr "Dostępne do pobrania"
269−
270−#~ msgid "Apps"
271−#~ msgstr "Aplikacje"
272−
273−#~ msgid "Frequent Apps"
274−#~ msgstr "Często używane aplikacje"
275−
276−#~ msgid "Recent Music"
277−#~ msgstr "Najnowsza muzyka"
278−
279−#~ msgid "Videos Popular Online"
280−#~ msgstr "Wideo popularne online"
281−
282−#~ msgid "Home"
283−#~ msgstr "Dom"
po/pt_BR.po+2−8
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n > 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "Desculpe, não há nada que corresponda à sua pesquisa."
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "Aplicativos"
259−
260−#~ msgid "Home"
261−#~ msgstr "Início"
po/ro.po+2−8
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=(n == 1 ? 0: (((n % 100 > 19) || ((n % 100 "
1818"== 0) && (n != 0))) ? 2: 1));\n"
19−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
19+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
20+"X-Generator: Launchpad (build 16750)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
@@ -255,9 +255,3 @@ msgstr ""
255255#, qt-format
256256msgid "Please enter %1"
257257msgstr ""
258−
259−#~ msgid "Apps"
260−#~ msgstr "Aplicații"
261−
262−#~ msgid "Home"
263−#~ msgstr "Acasă"
po/ru.po+2−29
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
1818"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
19+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
20+"X-Generator: Launchpad (build 16750)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
@@ -254,30 +254,3 @@ msgstr "Извините, поиск не дал результатов."
254254#, qt-format
255255msgid "Please enter %1"
256256msgstr "Пожалуйста, введите %1"
257−
258−#~ msgid "Running apps"
259−#~ msgstr "Запущенные приложения"
260−
261−#~ msgid "Frequently used"
262−#~ msgstr "Часто используемые"
263−
264−#~ msgid "Installed"
265−#~ msgstr "Установленные"
266−
267−#~ msgid "Available for download"
268−#~ msgstr "Доступно для загрузки"
269−
270−#~ msgid "Apps"
271−#~ msgstr "Приложения"
272−
273−#~ msgid "Frequent Apps"
274−#~ msgstr "Часто используемые приложения"
275−
276−#~ msgid "Recent Music"
277−#~ msgstr "Недавно прослушанная музыка"
278−
279−#~ msgid "Videos Popular Online"
280−#~ msgstr "Популярные видео из сети"
281−
282−#~ msgid "Home"
283−#~ msgstr "Главная"
po/si.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/sl.po+2−23
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || "
1818"n%100==4 ? 3 : 0);\n"
19−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
19+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
20+"X-Generator: Launchpad (build 16750)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
@@ -254,24 +254,3 @@ msgstr "Nič se ne ujema z vašim iskalnim nizom."
254254#, qt-format
255255msgid "Please enter %1"
256256msgstr ""
257−
258−#~ msgid "Frequently used"
259−#~ msgstr "Pogosto uporabljano"
260−
261−#~ msgid "Installed"
262−#~ msgstr "Nameščeno"
263−
264−#~ msgid "Available for download"
265−#~ msgstr "Na voljo za prejem"
266−
267−#~ msgid "Apps"
268−#~ msgstr "Programi"
269−
270−#~ msgid "Recent Music"
271−#~ msgstr "Nedavna glasba"
272−
273−#~ msgid "Home"
274−#~ msgstr "Domov"
275−
276−#~ msgid "Frequent Apps"
277−#~ msgstr "Pogosto uporabljani programi"
po/sr.po+2−8
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
1818"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
19+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
20+"X-Generator: Launchpad (build 16750)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
@@ -254,9 +254,3 @@ msgstr "Нажалост, претрага није наишла на икакв
254254#, qt-format
255255msgid "Please enter %1"
256256msgstr ""
257−
258−#~ msgid "Apps"
259−#~ msgstr "Програми"
260−
261−#~ msgid "Home"
262−#~ msgstr "Почетна"
po/sv.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/te.po+2−5
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,6 +253,3 @@ msgstr ""
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Home"
258−#~ msgstr "నివాసం"
po/tr.po+2−29
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,30 +253,3 @@ msgstr "Üzgünüz, aramanızla eşleşen hiçbir şey yok."
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Running apps"
258−#~ msgstr "Çalışan uygulamalar"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "Sıkça kullanılanlar"
262−
263−#~ msgid "Installed"
264−#~ msgstr "Yüklenenler"
265−
266−#~ msgid "Available for download"
267−#~ msgstr "İndirilebilir durumda"
268−
269−#~ msgid "Apps"
270−#~ msgstr "Uygulamalar"
271−
272−#~ msgid "Frequent Apps"
273−#~ msgstr "Sıkça Kullanılan Uygulamalar"
274−
275−#~ msgid "Recent Music"
276−#~ msgstr "En Son Müzik"
277−
278−#~ msgid "Videos Popular Online"
279−#~ msgstr "Çevrimiçi Yaygın Videolar"
280−
281−#~ msgid "Home"
282−#~ msgstr "Ana Sayfa"
po/ug.po+2−29
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,30 +253,3 @@ msgstr "كەچۈرۈڭ، ئىزدىگىنىڭىزگە ماس نەتىجە تېپ
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Running apps"
258−#~ msgstr "ئىجرا بولۇۋاتقان ئەپلەر"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "كوپ ئىشلىتىلگەنلىرى"
262−
263−#~ msgid "Installed"
264−#~ msgstr "ئورنىتىلغانلىرى"
265−
266−#~ msgid "Available for download"
267−#~ msgstr "چۈشۈرگىلى بولىدىغانلىرى"
268−
269−#~ msgid "Apps"
270−#~ msgstr "ئەپلەر"
271−
272−#~ msgid "Frequent Apps"
273−#~ msgstr "دائىم ئىشلىتىلىدىغان ئەپلەر"
274−
275−#~ msgid "Recent Music"
276−#~ msgstr "يېقىندا ئاڭلىغان مۇزىكىلار"
277−
278−#~ msgid "Videos Popular Online"
279−#~ msgstr "توردىكى ئالقىشقا ئېرىشكەن سىنلار"
280−
281−#~ msgid "Home"
282−#~ msgstr "ماكان"
po/uk.po+2−29
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
1818"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
19+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
20+"X-Generator: Launchpad (build 16750)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
@@ -254,30 +254,3 @@ msgstr "Вибачте, для вказаних вами ключових слі
254254#, qt-format
255255msgid "Please enter %1"
256256msgstr "Будь ласка, введіть %1"
257−
258−#~ msgid "Running apps"
259−#~ msgstr "Запущені програми"
260−
261−#~ msgid "Frequently used"
262−#~ msgstr "Найчастіше використовувані"
263−
264−#~ msgid "Installed"
265−#~ msgstr "Встановлені"
266−
267−#~ msgid "Available for download"
268−#~ msgstr "Доступно до завантаження"
269−
270−#~ msgid "Apps"
271−#~ msgstr "Програми"
272−
273−#~ msgid "Frequent Apps"
274−#~ msgstr "Часто використовувані програми"
275−
276−#~ msgid "Recent Music"
277−#~ msgstr "Нещодавно прослухана музика"
278−
279−#~ msgid "Videos Popular Online"
280−#~ msgstr "Популярні в мережі відео"
281−
282−#~ msgid "Home"
283−#~ msgstr "Домівка"
po/zh_CN.po+2−29
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,30 +253,3 @@ msgstr "对不起,没有找到您想要的结果。"
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Running apps"
258−#~ msgstr "正在运行的应用程序"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "常用"
262−
263−#~ msgid "Installed"
264−#~ msgstr "已安装"
265−
266−#~ msgid "Available for download"
267−#~ msgstr "可供下载"
268−
269−#~ msgid "Apps"
270−#~ msgstr "应用程序"
271−
272−#~ msgid "Frequent Apps"
273−#~ msgstr "常用软件"
274−
275−#~ msgid "Recent Music"
276−#~ msgstr "近期听过的音乐"
277−
278−#~ msgid "Videos Popular Online"
279−#~ msgstr "热门在线视频"
280−
281−#~ msgid "Home"
282−#~ msgstr "主页"
po/zh_TW.po+2−29
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Generator: Launchpad (build 16750)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -253,30 +253,3 @@ msgstr "很抱歉,找不到符合您想搜尋的結果。"
253253#, qt-format
254254msgid "Please enter %1"
255255msgstr ""
256−
257−#~ msgid "Running apps"
258−#~ msgstr "執行中的程式"
259−
260−#~ msgid "Frequently used"
261−#~ msgstr "最常使用"
262−
263−#~ msgid "Installed"
264−#~ msgstr "已安裝"
265−
266−#~ msgid "Available for download"
267−#~ msgstr "可供下載"
268−
269−#~ msgid "Apps"
270−#~ msgstr "程式"
271−
272−#~ msgid "Frequent Apps"
273−#~ msgstr "常用的程式"
274−
275−#~ msgid "Recent Music"
276−#~ msgstr "最近聽過的音樂"
277−
278−#~ msgid "Videos Popular Online"
279−#~ msgstr "線上熱門的影片"
280−
281−#~ msgid "Home"
282−#~ msgstr "家屋"
tests/mocks/AccountsService/AccountsBindings.cpp → tests/mocks/AccountsService/AccountsService.cpprenamed+15−8
@@ -16,38 +16,45 @@
1616 * Author: Michael Terry <michael.terry@canonical.com>
1717 */
1818
19−#include "AccountsBindings.h"
19+#include "AccountsService.h"
2020
21−AccountsBindings::AccountsBindings(QObject* parent)
21+AccountsService::AccountsService(QObject* parent)
2222 : QObject(parent),
2323 m_statsWelcomeScreen(true)
2424{
2525}
2626
27−void AccountsBindings::setUser(const QString &)
27+QString AccountsService::getUser()
2828{
29+ return "testuser";
2930}
3031
31−bool AccountsBindings::getDemoEdges()
32+void AccountsService::setUser(const QString &user)
33+{
34+ Q_UNUSED(user)
35+}
36+
37+bool AccountsService::getDemoEdges()
3238{
3339 return false;
3440}
3541
36−void AccountsBindings::setDemoEdges(bool)
42+void AccountsService::setDemoEdges(bool demoEdges)
3743{
44+ Q_UNUSED(demoEdges)
3845}
3946
40−QString AccountsBindings::getBackgroundFile()
47+QString AccountsService::getBackgroundFile()
4148{
4249 return TOP_SRCDIR "/graphics/phone_background.jpg";
4350}
4451
45−bool AccountsBindings::getStatsWelcomeScreen()
52+bool AccountsService::getStatsWelcomeScreen()
4653{
4754 return m_statsWelcomeScreen;
4855}
4956
50−void AccountsBindings::setStatsWelcomeScreen(bool statsWelcomeScreen)
57+void AccountsService::setStatsWelcomeScreen(bool statsWelcomeScreen)
5158{
5259 m_statsWelcomeScreen = statsWelcomeScreen;
5360 statsWelcomeScreenChanged();
tests/mocks/AccountsService/AccountsBindings.h → tests/mocks/AccountsService/AccountsService.hrenamed+12−7
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2012,2013 Canonical, Ltd.
2+ * Copyright (C) 2013 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -17,16 +17,20 @@
1717 * Michael Terry <michael.terry@canonical.com>
1818 */
1919
20−#ifndef UNITY_MOCK_ACCOUNTSBINDINGS_H
21−#define UNITY_MOCK_ACCOUNTSBINDINGS_H
20+#ifndef UNITY_MOCK_ACCOUNTSSERVICE_H
21+#define UNITY_MOCK_ACCOUNTSSERVICE_H
2222
2323#include <QObject>
2424#include <QString>
2525#include <QVariant>
2626
27−class AccountsBindings: public QObject
27+class AccountsService: public QObject
2828{
2929 Q_OBJECT
30+ Q_PROPERTY (QString user
31+ READ getUser
32+ WRITE setUser
33+ NOTIFY userChanged)
3034 Q_PROPERTY (bool demoEdges
3135 READ getDemoEdges
3236 WRITE setDemoEdges
@@ -40,10 +44,10 @@ class AccountsBindings: public QObject
4044 NOTIFY statsWelcomeScreenChanged)
4145
4246public:
43− explicit AccountsBindings(QObject *parent = 0);
44−
45− Q_INVOKABLE void setUser(const QString &user);
47+ explicit AccountsService(QObject *parent = 0);
4648
49+ QString getUser();
50+ void setUser(const QString &user);
4751 bool getDemoEdges();
4852 void setDemoEdges(bool demoEdges);
4953 QString getBackgroundFile();
@@ -51,6 +55,7 @@ public:
5155 void setStatsWelcomeScreen(bool statsWelcomeScreen);
5256
5357Q_SIGNALS:
58+ void userChanged();
5459 void demoEdgesChanged();
5560 void backgroundFileChanged();
5661 void statsWelcomeScreenChanged();
tests/mocks/AccountsService/CMakeLists.txt+1−1
@@ -1,7 +1,7 @@
11add_definitions(-DTOP_SRCDIR="${CMAKE_SOURCE_DIR}")
22
33add_library(MockAccountsService-qml MODULE
4− AccountsBindings.cpp
4+ AccountsService.cpp
55 plugin.cpp
66 )
77
tests/mocks/AccountsService/plugin.cpp+3−3
@@ -18,7 +18,7 @@
1818 */
1919
2020#include "plugin.h"
21−#include "AccountsBindings.h"
21+#include "AccountsService.h"
2222
2323#include <QtQml>
2424
@@ -26,11 +26,11 @@ static QObject *service_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
2626{
2727 Q_UNUSED(engine)
2828 Q_UNUSED(scriptEngine)
29− return new AccountsBindings();
29+ return new AccountsService();
3030}
3131
3232void AccountsServicePlugin::registerTypes(const char *uri)
3333{
3434 Q_ASSERT(uri == QLatin1String("AccountsService"));
35− qmlRegisterSingletonType<AccountsBindings>(uri, 0, 1, "AccountsService", service_provider);
35+ qmlRegisterSingletonType<AccountsService>(uri, 0, 1, "AccountsService", service_provider);
3636}
tests/mocks/LightDM/demo/GreeterPrivate.cpp+4−2
@@ -55,11 +55,13 @@ void GreeterPrivate::handleRespond(const QString &response)
5555 QSettings settings(QDir::homePath() + "/.unity8-greeter-demo", QSettings::NativeFormat);
5656 QVariant password = settings.value("password", "none");
5757
58+ QString passwordValue;
5859 if (password == "pin") {
59− authenticated = (response == "1234");
60+ passwordValue = settings.value("passwordValue", "1234").toString();
6061 } else {
61− authenticated = (response == "password");
62+ passwordValue = settings.value("passwordValue", "password").toString();
6263 }
64+ authenticated = (response == passwordValue);
6365 Q_EMIT q->authenticationComplete();
6466}
6567
tests/mocks/Unity/CMakeLists.txt+2
@@ -17,6 +17,8 @@ add_definitions(-DQT_NO_KEYWORDS)
1717
1818set(UnityQML_SOURCES
1919 ${CMAKE_SOURCE_DIR}/plugins/Unity/categoryresults.cpp
20+ fake_applications_scope.cpp
21+ fake_preview.cpp
2022 fake_scope.cpp
2123 fake_scopes.cpp
2224 fake_categories.cpp
tests/mocks/Unity/Launcher/MockLauncherItem.cpp+16
@@ -33,6 +33,7 @@ MockLauncherItem::MockLauncherItem(const QString &appId, const QString& desktopF
3333 m_recent(false),
3434 m_progress(-1),
3535 m_count(0),
36+ m_focused(false),
3637 m_quickList(new MockQuickListModel(this))
3738{
3839
@@ -128,6 +129,21 @@ void MockLauncherItem::setCount(int count)
128129 }
129130}
130131
132+bool MockLauncherItem::focused() const
133+{
134+ return m_focused;
135+}
136+
137+void MockLauncherItem::setFocused(bool focused)
138+{
139+ if (m_focused != focused)
140+ {
141+ m_focused = focused;
142+ Q_EMIT focusedChanged(focused);
143+ }
144+}
145+
146+
131147unity::shell::launcher::QuickListModelInterface *MockLauncherItem::quickList() const
132148{
133149 return m_quickList;
tests/mocks/Unity/Launcher/MockLauncherItem.h+4
@@ -52,6 +52,9 @@ public:
5252 int count() const;
5353 void setCount(int count);
5454
55+ bool focused() const;
56+ void setFocused(bool focused);
57+
5558 unity::shell::launcher::QuickListModelInterface *quickList() const;
5659
5760private:
@@ -64,6 +67,7 @@ private:
6467 bool m_recent;
6568 int m_progress;
6669 int m_count;
70+ bool m_focused;
6771 MockQuickListModel *m_quickList;
6872};
6973
tests/mocks/Unity/Launcher/MockLauncherModel.cpp+9
@@ -25,6 +25,7 @@ MockLauncherModel::MockLauncherModel(QObject* parent): LauncherModelInterface(pa
2525 MockLauncherItem *item = new MockLauncherItem("phone-app", "/usr/share/applications/phone-app.desktop", "Phone", "phone-app", this);
2626 item->setProgress(0);
2727 m_list.append(item);
28+ item->setFocused(true);
2829 item = new MockLauncherItem("camera-app", "/usr/share/applications/camera-app.desktop", "Camera", "camera", this);
2930 item->setProgress(10);
3031 m_list.append(item);
@@ -49,6 +50,7 @@ MockLauncherModel::MockLauncherModel(QObject* parent): LauncherModelInterface(pa
4950 item = new MockLauncherItem("notes-app", "/usr/share/applications/notes-app.desktop", "Notepad", "notepad", this);
5051 item->setProgress(50);
5152 item->setCount(5);
53+ item->setFocused(true);
5254 m_list.append(item);
5355 item = new MockLauncherItem("calendar-app", "/usr/share/applications/calendar-app.desktop","Calendar", "calendar", this);
5456 m_list.append(item);
@@ -85,6 +87,8 @@ QVariant MockLauncherModel::data(const QModelIndex& index, int role) const
8587 return item->progress();
8688 case RoleCount:
8789 return item->count();
90+ case RoleFocused:
91+ return item->focused();
8892 }
8993
9094 return QVariant();
@@ -180,3 +184,8 @@ void MockLauncherModel::setUser(const QString &username)
180184 Q_UNUSED(username)
181185 // TODO: implement this...
182186}
187+
188+void MockLauncherModel::applicationFocused(const QString &appId)
189+{
190+ Q_UNUSED(appId)
191+}
tests/mocks/Unity/Launcher/MockLauncherModel.h+1
@@ -44,6 +44,7 @@ public:
4444 Q_INVOKABLE void requestRemove(const QString &appId);
4545 Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex);
4646 Q_INVOKABLE void setUser(const QString &username);
47+ Q_INVOKABLE void applicationFocused(const QString &appId);
4748
4849Q_SIGNALS:
4950 void quickListTriggered(const QString &appId, int index);
tests/mocks/Unity/fake_applications_scope.cppnew file+68
@@ -0,0 +1,68 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "fake_applications_scope.h"
18+
19+static const gchar * categories_model_schema[] = {
20+ "s", //ID
21+ "s", // DISPLAY_NAME
22+ "s", // ICON_HINT
23+ "s", // RENDERER_NAME
24+ "a{sv}" // HINTS
25+};
26+
27+ApplicationsScope::ApplicationsScope(bool visible, QObject* parent)
28+ : Scope(parent)
29+{
30+ m_id = "applications.scope";
31+ m_name = "Applications";
32+ m_visible = visible;
33+ m_categories->setModel(createCategoriesModel());
34+}
35+
36+DeeModel* ApplicationsScope::createCategoriesModel()
37+{
38+ DeeModel* category_model = dee_sequence_model_new();
39+ dee_model_set_schema_full(category_model, categories_model_schema, G_N_ELEMENTS(categories_model_schema));
40+ GVariant* hints = g_variant_new_array(g_variant_type_element(G_VARIANT_TYPE_VARDICT), NULL, 0);
41+
42+ GVariant* children[1];
43+ children[0] = g_variant_new_dict_entry(g_variant_new_string("content-type"),
44+ g_variant_new_variant(g_variant_new_string("apps")));
45+ GVariant* recentHints = g_variant_new_array(g_variant_type_element(G_VARIANT_TYPE_VARDICT), children, 1);
46+ dee_model_append(category_model,
47+ "recent",
48+ "Recent",
49+ "gtk-apply",
50+ "special",
51+ recentHints);
52+
53+ dee_model_append(category_model,
54+ "installed",
55+ "Installed",
56+ "gtk-apply",
57+ "grid",
58+ hints);
59+
60+ dee_model_append(category_model,
61+ "suggested",
62+ "Suggested",
63+ "gtk-apply",
64+ "grid",
65+ hints);
66+
67+ return category_model;
68+}
tests/mocks/Unity/fake_applications_scope.hnew file+33
@@ -0,0 +1,33 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef FAKE_APPLICATIONS_SCOPE_H
18+#define FAKE_APPLICATIONS_SCOPE_H
19+
20+#include "fake_scope.h"
21+
22+class ApplicationsScope : public Scope
23+{
24+ Q_OBJECT
25+
26+public:
27+ ApplicationsScope(bool visible, QObject* parent = 0);
28+
29+private:
30+ DeeModel* createCategoriesModel();
31+};
32+
33+#endif // FAKE_APPLICATIONS_SCOPE_H
tests/mocks/Unity/fake_categories.cpp+84−12
@@ -24,11 +24,20 @@
2424
2525#define CATEGORY_COLUMN 2
2626
27+// TODO: use something from libunity once it's public
28+enum CategoryColumn {
29+ ID,
30+ DISPLAY_NAME,
31+ ICON_HINT,
32+ RENDERER_NAME,
33+ HINTS
34+};
35+
2736Categories::Categories(QObject* parent)
2837 : DeeListModel(parent)
2938{
3039 // FIXME: need to clean up unused filters on countChanged
31− m_roles[Categories::RoleId] = "id";
40+ m_roles[Categories::RoleCategoryId] = "categoryId";
3241 m_roles[Categories::RoleName] = "name";
3342 m_roles[Categories::RoleIcon] = "icon";
3443 m_roles[Categories::RoleRenderer] = "renderer";
@@ -36,7 +45,6 @@ Categories::Categories(QObject* parent)
3645 m_roles[Categories::RoleHints] = "hints";
3746 m_roles[Categories::RoleResults] = "results";
3847 m_roles[Categories::RoleCount] = "count";
39− m_roles[Categories::RoleCategoryIndex] = "categoryIndex";
4048
4149 // TODO This should not be needed but accumulatting the count changes
4250 // makes the visualization more stable and also makes crashes on fast
@@ -74,6 +82,25 @@ Categories::onCountChanged()
7482 }
7583}
7684
85+void Categories::onRowCountChanged()
86+{
87+ QAbstractItemModel* model = qobject_cast<QAbstractItemModel*>(sender());
88+ // find the corresponding category index
89+ for (auto iter = m_overriddenCategories.begin(); iter != m_overriddenCategories.end(); ++iter) {
90+ if (iter.value() == model) {
91+ for (int i = 0; i < rowCount(); i++) {
92+ auto id = data(index(i), RoleCategoryId).toString();
93+ if (id != iter.key()) continue;
94+ QVector<int> roles;
95+ roles.append(RoleCount);
96+ QModelIndex changedIndex = index(i);
97+ Q_EMIT dataChanged(changedIndex, changedIndex, roles);
98+ break;
99+ }
100+ }
101+ }
102+}
103+
77104void
78105Categories::onEmitCountChanged()
79106{
@@ -93,6 +120,41 @@ Categories::roleNames() const
93120 return m_roles;
94121}
95122
123+void Categories::onOverrideModelDestroyed()
124+{
125+ QObject* model = sender();
126+ auto iter = m_overriddenCategories.begin();
127+ while (iter != m_overriddenCategories.end()) {
128+ if (iter.value() == model) {
129+ iter = m_overriddenCategories.erase(iter);
130+ continue;
131+ }
132+ ++iter;
133+ }
134+}
135+
136+void Categories::overrideResults(const QString& categoryId, QAbstractItemModel* model)
137+{
138+ m_overriddenCategories[categoryId] = model;
139+ // watch the model
140+ connect(model, &QObject::destroyed, this, &Categories::onOverrideModelDestroyed);
141+ connect(model, &QAbstractItemModel::rowsInserted, this, &Categories::onRowCountChanged);
142+ connect(model, &QAbstractItemModel::rowsRemoved, this, &Categories::onRowCountChanged);
143+ connect(model, &QAbstractItemModel::modelReset, this, &Categories::onRowCountChanged);
144+
145+ // emit the dataChanged signal if the category is already in the model
146+ for (int i = 0; i < rowCount(); i++) {
147+ auto id = data(index(i), RoleCategoryId).toString();
148+ if (id != categoryId) continue;
149+ QVector<int> roles;
150+ roles.append(RoleCount);
151+ roles.append(RoleResults);
152+ QModelIndex changedIndex = index(i);
153+ Q_EMIT dataChanged(changedIndex, changedIndex, roles);
154+ break;
155+ }
156+}
157+
96158void Categories::setResultModel(DeeModel* model)
97159{
98160 // FIXME: should ref it
@@ -154,27 +216,37 @@ Categories::data(const QModelIndex& index, int role) const
154216 }
155217
156218 switch (role) {
157− case RoleId:
158− return DeeListModel::data(index, 0); //ID
219+ case RoleCategoryId:
220+ return DeeListModel::data(index, CategoryColumn::ID);
159221 case RoleName:
160− return DeeListModel::data(index, 1); //DISPLAY_NAME
222+ return DeeListModel::data(index, CategoryColumn::DISPLAY_NAME);
161223 case RoleIcon:
162− return DeeListModel::data(index, 2); //ICON_HINT
224+ return DeeListModel::data(index, CategoryColumn::ICON_HINT);
163225 case RoleRenderer:
164− return DeeListModel::data(index, 3); //RENDERER_NAME
226+ return DeeListModel::data(index, CategoryColumn::RENDERER_NAME);
165227 case RoleContentType:
166228 {
167− auto hints = DeeListModel::data(index, 4).toHash();
168− return hints.contains("content-type") ? hints["content-type"] : QVariant(QString("default"));
229+ auto hints = DeeListModel::data(index, CategoryColumn::HINTS).toHash();
230+ return hints.contains("content-type") ? hints["content-type"] : QVariant(QString("default"));
169231 }
170232 case RoleHints:
171− return DeeListModel::data(index, 4); //HINTS
233+ return DeeListModel::data(index, CategoryColumn::HINTS);
172234 case RoleResults:
235+ if (m_overriddenCategories.size() > 0)
236+ {
237+ auto id = DeeListModel::data(index, CategoryColumn::ID).toString();
238+ if (m_overriddenCategories.find(id) != m_overriddenCategories.end())
239+ return QVariant::fromValue(m_overriddenCategories[id]);
240+ }
173241 return QVariant::fromValue(getFilter(index.row()));
174242 case RoleCount:
243+ if (m_overriddenCategories.size() > 0)
244+ {
245+ auto id = DeeListModel::data(index, CategoryColumn::ID).toString();
246+ if (m_overriddenCategories.find(id) != m_overriddenCategories.end())
247+ return QVariant::fromValue(m_overriddenCategories[id]->rowCount());
248+ }
175249 return QVariant::fromValue(getFilter(index.row())->rowCount());
176− case RoleCategoryIndex:
177− return QVariant::fromValue(index.row());
178250 default:
179251 return QVariant();
180252 }
tests/mocks/Unity/fake_categories.h+7−3
@@ -34,17 +34,18 @@ class Categories : public DeeListModel
3434public:
3535 Categories(QObject* parent = 0);
3636 enum Roles {
37− RoleId,
37+ RoleCategoryId,
3838 RoleName,
3939 RoleIcon,
4040 RoleRenderer,
4141 RoleContentType,
4242 RoleHints,
4343 RoleResults,
44− RoleCount,
45− RoleCategoryIndex
44+ RoleCount
4645 };
4746
47+ Q_INVOKABLE void overrideResults(const QString& categoryId, QAbstractItemModel* model);
48+
4849 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
4950
5051 QHash<int, QByteArray> roleNames() const;
@@ -54,7 +55,9 @@ public:
5455
5556private Q_SLOTS:
5657 void onCountChanged();
58+ void onRowCountChanged();
5759 void onEmitCountChanged();
60+ void onOverrideModelDestroyed();
5861
5962private:
6063 DeeModel* getResultsForCategory(unsigned index) const;
@@ -64,6 +67,7 @@ private:
6467 QTimer m_timer;
6568 QSet<DeeListModel*> m_timerFilters;
6669 QHash<int, QByteArray> m_roles;
70+ QMap<QString, QAbstractItemModel*> m_overriddenCategories;
6771 mutable QMap<int, DeeListModel*> m_filters;
6872};
6973
tests/mocks/Unity/fake_preview.cppnew file+66
@@ -0,0 +1,66 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "fake_preview.h"
18+
19+QString Preview::rendererName() const
20+{
21+ return "foo";
22+}
23+
24+QString Preview::title() const
25+{
26+ return "Title";
27+}
28+
29+QString Preview::subtitle() const
30+{
31+ return "Subtitle";
32+}
33+
34+QString Preview::description() const
35+{
36+ return "Description";
37+}
38+
39+QVariant Preview::actions()
40+{
41+ return QVariant();
42+}
43+
44+QVariant Preview::infoHints()
45+{
46+ return QVariant();
47+}
48+
49+QVariantMap Preview::infoHintsHash() const
50+{
51+ return QVariantMap();
52+}
53+
54+QString Preview::image() const
55+{
56+ return "";
57+}
58+
59+QString Preview::imageSourceUri() const
60+{
61+ return "";
62+}
63+
64+void Preview::execute(const QString& actionId, const QHash<QString, QVariant>& hints)
65+{
66+}
tests/mocks/Unity/fake_preview.hnew file+62
@@ -0,0 +1,62 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef FAKE_PREVIEW_H
18+#define FAKE_PREVIEW_H
19+
20+// Qt
21+#include <QObject>
22+#include <QString>
23+#include <QMetaType>
24+#include <QList>
25+#include <QVariantMap>
26+
27+class Q_DECL_EXPORT Preview : public QObject
28+{
29+ Q_OBJECT
30+
31+ Q_PROPERTY(QString rendererName READ rendererName NOTIFY previewChanged)
32+ Q_PROPERTY(QString title READ title NOTIFY previewChanged)
33+ Q_PROPERTY(QString subtitle READ subtitle NOTIFY previewChanged)
34+ Q_PROPERTY(QString description READ description NOTIFY previewChanged)
35+ Q_PROPERTY(QVariant actions READ actions NOTIFY previewChanged)
36+ Q_PROPERTY(QVariant infoHints READ infoHints NOTIFY previewChanged)
37+ Q_PROPERTY(QVariantMap infoMap READ infoHintsHash NOTIFY previewChanged)
38+ Q_PROPERTY(QString image READ image NOTIFY previewChanged)
39+ Q_PROPERTY(QString imageSourceUri READ imageSourceUri NOTIFY previewChanged)
40+
41+public:
42+ explicit Preview(QObject *parent = 0);
43+
44+ QString rendererName() const;
45+ QString title() const;
46+ QString subtitle() const;
47+ QString description() const;
48+ QVariant actions();
49+ QVariant infoHints();
50+ QVariantMap infoHintsHash() const;
51+ QString image() const;
52+ QString imageSourceUri() const;
53+
54+ Q_INVOKABLE void execute(const QString& actionId, const QHash<QString, QVariant>& hints);
55+
56+Q_SIGNALS:
57+ void previewChanged();
58+};
59+
60+Q_DECLARE_METATYPE(Preview *)
61+
62+#endif // FAKE_PREVIEW_H
tests/mocks/Unity/fake_scope.cpp+33−9
@@ -20,6 +20,8 @@
2020#include <dee.h>
2121#include "paths.h"
2222
23+#include "fake_preview.h"
24+
2325static DeeModel* create_categories_model(unsigned category_count);
2426static DeeModel* create_results_model(unsigned category_count, unsigned result_count);
2527
@@ -127,6 +129,36 @@ void Scope::setNoResultsHint(const QString& str) {
127129 }
128130}
129131
132+void Scope::activate(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
133+ const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
134+ const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata)
135+{
136+ Q_UNUSED(uri);
137+ Q_UNUSED(icon_hint);
138+ Q_UNUSED(category);
139+ Q_UNUSED(result_type);
140+ Q_UNUSED(mimetype);
141+ Q_UNUSED(title);
142+ Q_UNUSED(comment);
143+ Q_UNUSED(dnd_uri);
144+ Q_UNUSED(metadata);
145+}
146+
147+void Scope::preview(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
148+ const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
149+ const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata)
150+{
151+ Q_UNUSED(uri);
152+ Q_UNUSED(icon_hint);
153+ Q_UNUSED(category);
154+ Q_UNUSED(result_type);
155+ Q_UNUSED(mimetype);
156+ Q_UNUSED(title);
157+ Q_UNUSED(comment);
158+ Q_UNUSED(dnd_uri);
159+ Q_UNUSED(metadata);
160+}
161+
130162static const gchar * categories_model_schema[] = {
131163 "s", //ID
132164 "s", // DISPLAY_NAME
@@ -168,14 +200,6 @@ static const gchar * results_model_schema[] = {
168200 "a{sv}" // METADATA
169201};
170202
171−static const gchar * icons[] = {
172− "Applications.png",
173− "Home.png",
174− "Music.png",
175− "People.png",
176− "Videos.png",
177−};
178−
179203DeeModel* create_results_model(unsigned category_count, unsigned result_count) {
180204 DeeModel* results_model = dee_sequence_model_new();
181205 dee_model_set_schema_full(results_model, results_model_schema, G_N_ELEMENTS(results_model_schema));
@@ -187,7 +211,7 @@ DeeModel* create_results_model(unsigned category_count, unsigned result_count) {
187211
188212 dee_model_append(results_model,
189213 ("uri://result."+std::to_string(i)).c_str(),
190− (shellAppDirectory() + "Dash/graphics/scopeIcons/" + (icons[i%G_N_ELEMENTS(icons)])).toLatin1().data(),
214+ (shellAppDirectory() + "graphics/applicationIcons/dash.png").toLatin1().data(),
191215 category,
192216 0,
193217 "application/x-desktop",
tests/mocks/Unity/fake_scope.h+15−1
@@ -21,6 +21,8 @@
2121#include <QObject>
2222#include "fake_categories.h"
2323
24+class Preview;
25+
2426class Scope : public QObject
2527{
2628 Q_OBJECT
@@ -63,6 +65,13 @@ public:
6365 void setNoResultsHint(const QString& hint);
6466 void setFormFactor(const QString& form_factor);
6567
68+ Q_INVOKABLE void activate(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
69+ const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
70+ const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata);
71+ Q_INVOKABLE void preview(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
72+ const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
73+ const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata);
74+
6675Q_SIGNALS:
6776 void idChanged(const QString&);
6877 void nameChanged(const QString&);
@@ -78,7 +87,12 @@ Q_SIGNALS:
7887 void noResultsHintChanged();
7988 void formFactorChanged();
8089
81−private:
90+ // signals triggered by activate(..) or preview(..) requests.
91+ void previewReady(Preview *preview);
92+ void activateApplication(const QString &desktop);
93+
94+protected:
95+
8296 QString m_id;
8397 QString m_iconHint;
8498 QString m_description;
tests/mocks/Unity/fake_scopes.cpp+4−1
@@ -19,6 +19,9 @@
1919// Self
2020#include "fake_scopes.h"
2121
22+// Local
23+#include "fake_applications_scope.h"
24+
2225// TODO: Implement remaining pieces, like Categories (i.e. LensView now gives warnings)
2326
2427// Qt
@@ -53,7 +56,7 @@ void Scopes::updateScopes()
5356 addScope(new Scope("MockScope1", "People", true, this));
5457 addScope(new Scope("MockScope2", "Music", false, this));
5558 addScope(new Scope("home.scope", "Home", true, this));
56− addScope(new Scope("applications.scope", "Applications", true, this));
59+ addScope(new ApplicationsScope(true, this));
5760 addScope(new Scope("MockScope5", "Videos", true, this));
5861
5962 if (!m_loaded) {
tests/plugins/AccountsService/CMakeLists.txt+1−1
@@ -25,7 +25,7 @@ qt5_use_modules(mock-server Core DBus)
2525
2626add_executable(test-accountsservice
2727 ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsService.cpp
28− ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsBindings.cpp
28+ ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
2929 client.cpp
3030 )
3131qt5_use_modules(test-accountsservice Core DBus Test)
tests/plugins/AccountsService/client.cpp+11−11
@@ -17,8 +17,8 @@
1717 * Authored by: Michael Terry <michael.terry@canonical.com>
1818 */
1919
20−#include "AccountsBindings.h"
2120#include "AccountsService.h"
21+#include "AccountsServiceDBusAdaptor.h"
2222#include <QSignalSpy>
2323#include <QTest>
2424
@@ -31,28 +31,28 @@ private Q_SLOTS:
3131 void testInvalids()
3232 {
3333 // Test various invalid calls
34− AccountsService session;
34+ AccountsServiceDBusAdaptor session;
3535 QCOMPARE(session.getUserProperty("NOPE", "com.canonical.unity.AccountsService", "demo-edges"), QVariant());
3636 QCOMPARE(session.getUserProperty("testuser", "com.canonical.unity.AccountsService", "NOPE"), QVariant());
3737 }
3838
39− void testGetSetService()
39+ void testGetSetServiceDBusAdaptor()
4040 {
41− AccountsService session;
41+ AccountsServiceDBusAdaptor session;
4242 session.setUserProperty("testuser", "com.canonical.unity.AccountsService", "demo-edges", QVariant(true));
4343 QCOMPARE(session.getUserProperty("testuser", "com.canonical.unity.AccountsService", "demo-edges"), QVariant(true));
4444 session.setUserProperty("testuser", "com.canonical.unity.AccountsService", "demo-edges", QVariant(false));
4545 QCOMPARE(session.getUserProperty("testuser", "com.canonical.unity.AccountsService", "demo-edges"), QVariant(false));
4646 }
4747
48− void testGetSetBindings()
48+ void testGetSetService()
4949 {
50− AccountsBindings bindings;
51− bindings.setUser("testuser");
52− bindings.setDemoEdges(true);
53− QCOMPARE(bindings.getDemoEdges(), true);
54− bindings.setDemoEdges(false);
55− QCOMPARE(bindings.getDemoEdges(), false);
50+ AccountsService session;
51+ session.setUser("testuser");
52+ session.setDemoEdges(true);
53+ QCOMPARE(session.getDemoEdges(), true);
54+ session.setDemoEdges(false);
55+ QCOMPARE(session.getDemoEdges(), false);
5656 }
5757};
5858
tests/plugins/Unity/Launcher/CMakeLists.txt+41−4
@@ -1,22 +1,59 @@
1+pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
2+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=2)
3+
14include_directories(
25 ${CMAKE_CURRENT_BINARY_DIR}
36 ${CMAKE_SOURCE_DIR}/plugins/AccountsService
47 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher
58 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/backend
9+ ${GSETTINGS_QT_INCLUDE_DIRS}
610 )
711
812add_definitions(-DSM_BUSNAME=sessionBus)
913add_definitions(-DSRCDIR="${CMAKE_CURRENT_SOURCE_DIR}")
14+add_definitions(-DLAUNCHER_TESTING)
1015
11−set(testCommand ${CMAKE_CURRENT_BINARY_DIR}/launcherbackendtestExec
16+### LauncherBackendTest
17+set(testBackendCommand ${CMAKE_CURRENT_BINARY_DIR}/launcherbackendtestExec
1218 -o ${CMAKE_BINARY_DIR}/launcherbackendtest.xml,xunitxml
1319 -o -,txt)
14−add_test(NAME launcherbackendtest COMMAND ${testCommand})
15−add_custom_target(launcherbackendtest ${testCommand})
20+add_test(NAME launcherbackendtest COMMAND ${testBackendCommand})
21+add_custom_target(launcherbackendtest ${testBackendCommand})
1622add_executable(launcherbackendtestExec
1723 launcherbackendtest.cpp
18− ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsService.cpp
24+ ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
1925 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/backend/launcherbackend.cpp
2026 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/common/quicklistentry.cpp
2127 )
28+target_link_libraries(launcherbackendtestExec ${GSETTINGS_QT_LDFLAGS})
2229qt5_use_modules(launcherbackendtestExec Test Core DBus)
30+
31+### LauncherModelTest
32+set(testModelCommand ${CMAKE_CURRENT_BINARY_DIR}/launchermodeltestExec
33+ -o ${CMAKE_BINARY_DIR}/launchermodeltest.xml,xunitxml
34+ -o -,txt)
35+add_test(NAME launchermodeltest COMMAND ${testModelCommand})
36+add_custom_target(launchermodeltest ${testModelCommand})
37+add_executable(launchermodeltestExec
38+ launchermodeltest.cpp
39+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/launchermodel.cpp
40+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/launcheritem.cpp
41+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/quicklistmodel.cpp
42+ ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
43+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/backend/launcherbackend.cpp
44+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/common/quicklistentry.cpp
45+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
46+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
47+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
48+ )
49+target_link_libraries(launchermodeltestExec ${GSETTINGS_QT_LDFLAGS} )
50+qt5_use_modules(launchermodeltestExec Test Core DBus)
51+
52+# copy .desktop files into build directory for shadow builds
53+file(GLOB DESKTOP_FILES *.desktop)
54+
55+foreach(DESKTOP_FILE ${DESKTOP_FILES})
56+ file(COPY "${DESKTOP_FILE}"
57+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
58+ )
59+endforeach()
tests/plugins/Unity/Launcher/launcherbackendtest.cpp+14−48
@@ -20,7 +20,6 @@
2020#include "launcherbackend.h"
2121
2222#include <QtTest>
23−#include <QDebug>
2423
2524class LauncherBackendTest : public QObject
2625{
@@ -31,62 +30,29 @@ private Q_SLOTS:
3130 {
3231 LauncherBackend backend(false);
3332
34− backend.setStoredApplications(QStringList() << "relative.path" << "/full/path");
35− QCOMPARE(backend.storedApplications(), QStringList() << "/usr/share/applications/relative.path" << "/full/path");
36−
37− QCOMPARE(backend.desktopFile("one.desktop"), QString("/usr/share/applications/one.desktop"));
38− QCOMPARE(backend.desktopFile("two"), QString("/usr/share/applications/two"));
39− QCOMPARE(backend.desktopFile("/full"), QString("/full"));
40−
41− QCOMPARE(backend.desktopFile("/usr/share/applications/one.desktop"), QString("/usr/share/applications/one.desktop"));
42− }
43−
44− void testDesktopReading()
45− {
46− LauncherBackend backend(false);
47−
48− QCOMPARE(backend.displayName(SRCDIR "/rel-icon.desktop"), QString("Relative Icon"));
49− QCOMPARE(backend.icon(SRCDIR "/rel-icon.desktop"), QString("image://gicon/rel-icon"));
50−
51− QCOMPARE(backend.displayName(SRCDIR "/abs-icon.desktop"), QString("Absolute Icon"));
52− QCOMPARE(backend.icon(SRCDIR "/abs-icon.desktop"), QString("/path/to/icon.png"));
53−
54− QCOMPARE(backend.displayName(SRCDIR "/no-icon.desktop"), QString("No Icon"));
55− QCOMPARE(backend.icon(SRCDIR "/no-icon.desktop"), QString(""));
56−
57− QCOMPARE(backend.displayName(SRCDIR "/no-name.desktop"), QString(""));
58− QCOMPARE(backend.icon(SRCDIR "/no-name.desktop"), QString("image://gicon/no-name"));
59−
60− QCOMPARE(backend.displayName(SRCDIR "/no-exist.desktop"), QString(""));
61− QCOMPARE(backend.icon(SRCDIR "/no-exist.desktop"), QString(""));
33+ backend.setStoredApplications(QStringList() << "rel-icon" << "abs-icon" << "invalid");
34+ QCOMPARE(backend.storedApplications(), QStringList() << "rel-icon" << "abs-icon");
6235 }
6336
6437 void testPinning()
6538 {
6639 LauncherBackend backend(false);
6740
68− // Confirm that default entries are all pinned
69− auto defaultApps = backend.storedApplications();
70− QVERIFY(defaultApps.size() > 0);
71− for (auto app: defaultApps) {
72− QCOMPARE(backend.isPinned(app), true);
73− }
74−
75− backend.setStoredApplications(QStringList() << "one" << "two");
76− QCOMPARE(backend.isPinned("one"), false);
77− QCOMPARE(backend.isPinned("two"), false);
41+ backend.setStoredApplications(QStringList() << "rel-icon" << "abs-icon");
42+ QCOMPARE(backend.isPinned("rel-icon"), false);
43+ QCOMPARE(backend.isPinned("abs-icon"), false);
7844
79− backend.setPinned("two", true);
80− QCOMPARE(backend.isPinned("two"), true);
45+ backend.setPinned("rel-icon", true);
46+ QCOMPARE(backend.isPinned("rel-icon"), true);
8147
82− backend.setStoredApplications(QStringList() << "one" << "two" << "three");
83− QCOMPARE(backend.isPinned("two"), true);
84− QCOMPARE(backend.isPinned("three"), false);
48+ backend.setStoredApplications(QStringList() << "rel-icon" << "abs-icon" << "no-name");
49+ QCOMPARE(backend.isPinned("rel-icon"), true);
50+ QCOMPARE(backend.isPinned("no-name"), false);
8551
86− backend.setPinned("three", true);
87− backend.setStoredApplications(QStringList() << "one" << "two");
88− QCOMPARE(backend.isPinned("two"), true);
89− QCOMPARE(backend.isPinned("three"), false); // doesn't exist anymore!
52+ backend.setPinned("no-name", true);
53+ backend.setStoredApplications(QStringList() << "rel-icon" << "abs-icon");
54+ QCOMPARE(backend.isPinned("rel-icon"), true);
55+ QCOMPARE(backend.isPinned("no-name"), false); // doesn't exist anymore!
9056 }
9157};
9258
tests/plugins/Unity/Launcher/launchermodeltest.cppnew file+146
@@ -0,0 +1,146 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Michael Zanetti <michael.zanetti@canonical.com>
18+ */
19+
20+// unity-api
21+#include <unity/shell/launcher/LauncherModelInterface.h>
22+
23+#include "launcheritem.h"
24+#include "launchermodel.h"
25+
26+#include <QtTest>
27+
28+class LauncherModelTest : public QObject
29+{
30+ Q_OBJECT
31+
32+private:
33+ LauncherModel *launcherModel;
34+
35+private Q_SLOTS:
36+
37+ void initTestCase() {
38+ launcherModel = new LauncherModel(this);
39+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 0);
40+ }
41+
42+ void init() {
43+ qDebug() << "init";
44+ launcherModel->applicationFocused("abs-icon");
45+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
46+
47+ launcherModel->applicationFocused("no-icon.desktop");
48+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
49+
50+ launcherModel->applicationFocused(QString());
51+ }
52+
53+ void cleanup() {
54+ while (launcherModel->rowCount(QModelIndex()) > 0) {
55+ launcherModel->requestRemove(launcherModel->get(0)->appId());
56+ }
57+ }
58+
59+ void testMove() {
60+ QCOMPARE(launcherModel->get(0)->pinned(), false);
61+ QCOMPARE(launcherModel->get(1)->pinned(), false);
62+
63+ LauncherItemInterface *item0BeforeMove = launcherModel->get(0);
64+ LauncherItemInterface *item1BeforeMove = launcherModel->get(1);
65+ launcherModel->move(1, 0);
66+
67+ QCOMPARE(item0BeforeMove, launcherModel->get(1));
68+ QCOMPARE(item1BeforeMove, launcherModel->get(0));
69+
70+ // moved item must be pinned now
71+ QCOMPARE(item0BeforeMove->pinned(), false);
72+ QCOMPARE(item1BeforeMove->pinned(), true);
73+ }
74+
75+ void testPinning() {
76+ QCOMPARE(launcherModel->get(0)->pinned(), false);
77+ QCOMPARE(launcherModel->get(1)->pinned(), false);
78+ launcherModel->pin(launcherModel->get(0)->appId());
79+ QCOMPARE(launcherModel->get(0)->pinned(), true);
80+ QCOMPARE(launcherModel->get(1)->pinned(), false);
81+ }
82+
83+ void testRemove() {
84+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
85+ launcherModel->requestRemove(launcherModel->get(0)->appId());
86+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
87+ }
88+
89+ void testQuickListPinningRemoving() {
90+ // we start with 2 unpinned items
91+ QCOMPARE(launcherModel->get(0)->pinned(), false);
92+ QCOMPARE(launcherModel->get(1)->pinned(), false);
93+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
94+
95+ // find the Pin item in the quicklist
96+ QuickListModel *model = qobject_cast<QuickListModel*>(launcherModel->get(0)->quickList());
97+ int pinActionIndex = -1;
98+ for (int i = 0; i < model->rowCount(QModelIndex()); ++i) {
99+ if (model->get(i).actionId() == "pin_item") {
100+ pinActionIndex = i;
101+ break;
102+ }
103+ }
104+ QVERIFY(pinActionIndex >= 0);
105+
106+ // trigger pin item quicklist action => Item must be pinned now.
107+ launcherModel->quickListActionInvoked(launcherModel->get(0)->appId(), pinActionIndex);
108+ QCOMPARE(launcherModel->get(0)->pinned(), true);
109+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
110+
111+ // quicklist needs to transform to remove item. trigger it and check it item goes away
112+ launcherModel->quickListActionInvoked(launcherModel->get(0)->appId(), pinActionIndex);
113+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
114+ }
115+
116+ void testApplicationFocused() {
117+ // all apps unfocused at beginning...
118+ QCOMPARE(launcherModel->get(0)->focused(), false);
119+ QCOMPARE(launcherModel->get(1)->focused(), false);
120+
121+ launcherModel->applicationFocused("abs-icon");
122+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
123+ QCOMPARE(launcherModel->get(0)->focused(), true);
124+ QCOMPARE(launcherModel->get(1)->focused(), false);
125+
126+ launcherModel->applicationFocused("no-icon");
127+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
128+ QCOMPARE(launcherModel->get(0)->focused(), false);
129+ QCOMPARE(launcherModel->get(1)->focused(), true);
130+
131+ launcherModel->applicationFocused("rel-icon");
132+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 3);
133+ QCOMPARE(launcherModel->get(0)->focused(), false);
134+ QCOMPARE(launcherModel->get(1)->focused(), false);
135+ QCOMPARE(launcherModel->get(2)->focused(), true);
136+
137+ launcherModel->applicationFocused(QString());
138+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 3);
139+ QCOMPARE(launcherModel->get(0)->focused(), false);
140+ QCOMPARE(launcherModel->get(1)->focused(), false);
141+ QCOMPARE(launcherModel->get(2)->focused(), false);
142+ }
143+};
144+
145+QTEST_GUILESS_MAIN(LauncherModelTest)
146+#include "launchermodeltest.moc"
tests/plugins/Unity/filtersbindingstest.cpp+61−30
@@ -65,17 +65,17 @@ DeeModel* FiltersBindingsTest::createFilterModel()
6565
6666void FiltersBindingsTest::createMultiRangeFilter(DeeModel *model, const std::string &id, const std::string &name, int optionCount)
6767{
68− createFilter(model, "filter-multirange", id, name, optionCount);
68+ createFilter(model, "filter-multirange", id, name, optionCount, true);
6969}
7070
7171void FiltersBindingsTest::createRadioOptionFilter(DeeModel *model, const std::string &id, const std::string &name, int optionCount)
7272{
73− createFilter(model, "filter-radiooption", id, name, optionCount);
73+ createFilter(model, "filter-radiooption", id, name, optionCount, true);
7474}
7575
7676void FiltersBindingsTest::createCheckOptionFilter(DeeModel *model, const std::string &id, const std::string &name, int optionCount)
7777{
78− createFilter(model, "filter-checkoption", id, name, optionCount);
78+ createFilter(model, "filter-checkoption", id, name, optionCount, true);
7979}
8080
8181void FiltersBindingsTest::createRatingsFilter(DeeModel *model, const std::string &id, const std::string &name)
@@ -90,7 +90,7 @@ void FiltersBindingsTest::createRatingsFilter(DeeModel *model, const std::string
9090 GVariant *children[2];
9191 GVariant *key1 = g_variant_new_string("show-all-button");
9292 GVariant *key2 = g_variant_new_string("rating");
93− children[0] = g_variant_new_dict_entry(key1, g_variant_new_variant(g_variant_new_boolean(false)));
93+ children[0] = g_variant_new_dict_entry(key1, g_variant_new_variant(g_variant_new_boolean(true)));
9494 children[1] = g_variant_new_dict_entry(key2, g_variant_new_variant(g_variant_new_double(0.0f)));
9595 auto fhints = g_variant_new_array(G_VARIANT_TYPE("{sv}"), children, 2);
9696
@@ -102,7 +102,7 @@ void FiltersBindingsTest::createRatingsFilter(DeeModel *model, const std::string
102102 dee_model_append_row(model, row);
103103}
104104
105−void FiltersBindingsTest::createFilter(DeeModel *model, const std::string &renderer, const std::string &id, const std::string &name, int optionCount)
105+void FiltersBindingsTest::createFilter(DeeModel *model, const std::string &renderer, const std::string &id, const std::string &name, int optionCount, bool showAll)
106106{
107107 GVariant* row[8];
108108
@@ -114,7 +114,7 @@ void FiltersBindingsTest::createFilter(DeeModel *model, const std::string &rende
114114 GVariant *children[2];
115115 GVariant *key1 = g_variant_new_string("show-all-button");
116116 GVariant *key2 = g_variant_new_string("options");
117− children[0] = g_variant_new_dict_entry(key1, g_variant_new_variant(g_variant_new_boolean(false)));
117+ children[0] = g_variant_new_dict_entry(key1, g_variant_new_variant(g_variant_new_boolean(showAll)));
118118 children[1] = g_variant_new_dict_entry(key2, g_variant_new_variant(createOptions(optionCount)));
119119 auto fhints = g_variant_new_array(G_VARIANT_TYPE("{sv}"), children, 2);
120120
@@ -143,9 +143,9 @@ void FiltersBindingsTest::testMultiRangeFilter()
143143 auto multi_filter = dynamic_cast<MultiRangeFilter*>(bind_filter);
144144 QVERIFY(multi_filter != nullptr);
145145 auto options = multi_filter->options();
146− QCOMPARE(options->rowCount(), 1);
146+ QCOMPARE(options->rowCount(), 2);
147147
148− auto idx = options->index(0);
148+ auto idx = options->index(1);
149149 QVariant id_var = options->data(idx, GenericOptionsModel::RoleId);
150150 QVariant name_var = options->data(idx, GenericOptionsModel::RoleName);
151151 QVariant icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
@@ -168,9 +168,9 @@ void FiltersBindingsTest::testMultiRangeFilter()
168168 auto multi_filter = dynamic_cast<MultiRangeFilter*>(bind_filter);
169169 QVERIFY(multi_filter != nullptr);
170170 auto options = multi_filter->options();
171− QCOMPARE(options->rowCount(), 2);
171+ QCOMPARE(options->rowCount(), 3);
172172
173− auto idx = options->index(0);
173+ auto idx = options->index(1);
174174 QVariant id_var = options->data(idx, GenericOptionsModel::RoleId);
175175 QVariant name_var = options->data(idx, GenericOptionsModel::RoleName);
176176 QVariant icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
@@ -181,10 +181,10 @@ void FiltersBindingsTest::testMultiRangeFilter()
181181 QCOMPARE(icon_var.toString(), QString(""));
182182 QCOMPARE(active_var.toBool(), false);
183183
184− AbstractFilterOption* opt1 = options->getRawOption(0);
184+ AbstractFilterOption* opt1 = options->getRawOption(1);
185185 QCOMPARE(opt1->id(), QString("opt0"));
186186
187− AbstractFilterOption* opt2 = options->getRawOption(1);
187+ AbstractFilterOption* opt2 = options->getRawOption(2);
188188 QCOMPARE(opt2->id(), QString("opt1"));
189189
190190 delete multi_filter;
@@ -199,18 +199,21 @@ void FiltersBindingsTest::testMultiRangeFilter()
199199 auto multi_filter = dynamic_cast<MultiRangeFilter*>(bind_filter);
200200 QVERIFY(multi_filter != nullptr);
201201 auto options = multi_filter->options();
202− QCOMPARE(options->rowCount(), 3);
202+ QCOMPARE(options->rowCount(), 4);
203+
204+ AbstractFilterOption* showAll = options->getRawOption(0);
205+ QVERIFY(showAll->id().startsWith("show_all::"));
203206
204− AbstractFilterOption* opt0 = options->getRawOption(0);
207+ AbstractFilterOption* opt0 = options->getRawOption(1);
205208 QCOMPARE(opt0->id(), QString("opt0"));
206209
207− AbstractFilterOption* opt1 = options->getRawOption(1);
210+ AbstractFilterOption* opt1 = options->getRawOption(2);
208211 QCOMPARE(opt1->id(), QString("opt1"));
209212
210− AbstractFilterOption* opt2 = options->getRawOption(2);
213+ AbstractFilterOption* opt2 = options->getRawOption(3);
211214 QCOMPARE(opt2->id(), QString("opt2"));
212215
213− // verify combined filter options are bound to correct underlying unity options
216+ // verify filter options are bound to correct underlying unity options
214217 auto core_multi_filter = std::dynamic_pointer_cast<unity::dash::MultiRangeFilter>(core_filter);
215218 QCOMPARE(QString::fromStdString(core_multi_filter->options()[0]->id()), QString("opt0"));
216219 QCOMPARE(QString::fromStdString(core_multi_filter->options()[1]->id()), QString("opt1"));
@@ -274,7 +277,7 @@ void FiltersBindingsTest::testCheckOptionFilter()
274277 auto check_filter = dynamic_cast<CheckOptionFilter*>(bind_filter);
275278 QVERIFY(check_filter != nullptr);
276279 auto options = check_filter->options();
277− QCOMPARE(options->rowCount(), 3);
280+ QCOMPARE(options->rowCount(), 4);
278281
279282 QCOMPARE(check_filter->id(), QString("f1"));
280283 QCOMPARE(check_filter->name(), QString("Filter1"));
@@ -284,7 +287,7 @@ void FiltersBindingsTest::testCheckOptionFilter()
284287 QCOMPARE(check_filter->collapsed(), false);
285288 QCOMPARE(check_filter->filtering(), false);
286289
287− auto idx = options->index(0);
290+ auto idx = options->index(1);
288291 QVariant id_var = options->data(idx, GenericOptionsModel::RoleId);
289292 QVariant name_var = options->data(idx, GenericOptionsModel::RoleName);
290293 QVariant icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
@@ -295,7 +298,7 @@ void FiltersBindingsTest::testCheckOptionFilter()
295298 QCOMPARE(icon_var.toString(), QString(""));
296299 QCOMPARE(active_var.toBool(), false);
297300
298− idx = options->index(1);
301+ idx = options->index(2);
299302 id_var = options->data(idx, GenericOptionsModel::RoleId);
300303 name_var = options->data(idx, GenericOptionsModel::RoleName);
301304 icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
@@ -306,38 +309,55 @@ void FiltersBindingsTest::testCheckOptionFilter()
306309 QCOMPARE(icon_var.toString(), QString(""));
307310 QCOMPARE(active_var.toBool(), false);
308311
309− AbstractFilterOption* opt0 = options->getRawOption(0);
310− AbstractFilterOption* opt1 = options->getRawOption(1);
311− AbstractFilterOption* opt2 = options->getRawOption(2);
312+ AbstractFilterOption* showAll = options->getRawOption(0);
313+ AbstractFilterOption* opt0 = options->getRawOption(1);
314+ AbstractFilterOption* opt1 = options->getRawOption(2);
315+ AbstractFilterOption* opt2 = options->getRawOption(3);
312316
317+ QSignalSpy showAllSpy(showAll, SIGNAL(activeChanged(bool)));
313318 QSignalSpy opt0spy(opt0, SIGNAL(activeChanged(bool)));
314319 QSignalSpy opt1spy(opt1, SIGNAL(activeChanged(bool)));
315320 QSignalSpy opt2spy(opt2, SIGNAL(activeChanged(bool)));
316321 QSignalSpy dataChangedSpy(options, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&)));
317322
318323 // test active property changes
324+ QCOMPARE(showAll->active(), false);
319325 QCOMPARE(opt0->active(), false);
320326 QCOMPARE(opt1->active(), false);
321327 QCOMPARE(opt2->active(), false);
322328
323329 opt0->setActive(true);
330+ QCOMPARE(showAllSpy.count(), 0);
324331 QCOMPARE(opt0spy.count(), 1);
325332 QCOMPARE(opt1spy.count(), 0);
326333 QCOMPARE(opt2spy.count(), 0);
334+ QCOMPARE(showAll->active(), false);
327335 QCOMPARE(opt0->active(), true);
328336 QCOMPARE(opt1->active(), false);
329337 QCOMPARE(opt2->active(), false);
330338
331339 opt1->setActive(true);
340+ QCOMPARE(showAllSpy.count(), 0);
332341 QCOMPARE(opt0spy.count(), 2);
333342 QCOMPARE(opt1spy.count(), 1);
334343 QCOMPARE(opt2spy.count(), 0);
344+ QCOMPARE(showAll->active(), false);
335345 QCOMPARE(opt0->active(), false);
336346 QCOMPARE(opt1->active(), true);
337347 QCOMPARE(opt2->active(), false);
338348
339349 QCOMPARE(dataChangedSpy.count(), 3);
340350
351+ showAll->setActive(true);
352+ QCOMPARE(showAllSpy.count(), 1);
353+ QCOMPARE(opt0spy.count(), 2);
354+ QCOMPARE(opt1spy.count(), 2);
355+ QCOMPARE(opt2spy.count(), 0);
356+ QCOMPARE(showAll->active(), true);
357+ QCOMPARE(opt0->active(), false);
358+ QCOMPARE(opt1->active(), false);
359+ QCOMPARE(opt2->active(), false);
360+
341361 delete check_filter;
342362 }
343363}
@@ -357,7 +377,7 @@ void FiltersBindingsTest::testRadioOptionFilter()
357377 auto radio_filter = dynamic_cast<RadioOptionFilter*>(bind_filter);
358378 QVERIFY(radio_filter != nullptr);
359379 auto options = radio_filter->options();
360− QCOMPARE(options->rowCount(), 3);
380+ QCOMPARE(options->rowCount(), 4);
361381
362382 auto idx = options->index(0);
363383 QVariant id_var = options->data(idx, GenericOptionsModel::RoleId);
@@ -365,12 +385,23 @@ void FiltersBindingsTest::testRadioOptionFilter()
365385 QVariant icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
366386 QVariant active_var = options->data(idx, GenericOptionsModel::RoleActive);
367387
388+ QVERIFY(id_var.toString().startsWith("show_all::"));
389+ QVERIFY(name_var.toString().size() > 0);
390+ QCOMPARE(icon_var.toString(), QString(""));
391+ QCOMPARE(active_var.toBool(), false);
392+
393+ idx = options->index(1);
394+ id_var = options->data(idx, GenericOptionsModel::RoleId);
395+ name_var = options->data(idx, GenericOptionsModel::RoleName);
396+ icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
397+ active_var = options->data(idx, GenericOptionsModel::RoleActive);
398+
368399 QCOMPARE(id_var.toString(), QString("opt0"));
369400 QCOMPARE(name_var.toString(), QString("Option 0"));
370401 QCOMPARE(icon_var.toString(), QString(""));
371402 QCOMPARE(active_var.toBool(), false);
372403
373− idx = options->index(1);
404+ idx = options->index(2);
374405 id_var = options->data(idx, GenericOptionsModel::RoleId);
375406 name_var = options->data(idx, GenericOptionsModel::RoleName);
376407 icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
@@ -381,9 +412,9 @@ void FiltersBindingsTest::testRadioOptionFilter()
381412 QCOMPARE(icon_var.toString(), QString(""));
382413 QCOMPARE(active_var.toBool(), false);
383414
384− AbstractFilterOption* opt0 = options->getRawOption(0);
385− AbstractFilterOption* opt1 = options->getRawOption(1);
386− AbstractFilterOption* opt2 = options->getRawOption(2);
415+ AbstractFilterOption* opt0 = options->getRawOption(1);
416+ AbstractFilterOption* opt1 = options->getRawOption(2);
417+ AbstractFilterOption* opt2 = options->getRawOption(3);
387418
388419 QSignalSpy opt0spy(opt0, SIGNAL(activeChanged(bool)));
389420 QSignalSpy opt1spy(opt1, SIGNAL(activeChanged(bool)));
@@ -432,11 +463,11 @@ void FiltersBindingsTest::testRatingsFilter()
432463 auto rating_filter = dynamic_cast<RatingsFilter*>(bind_filter);
433464 QVERIFY(rating_filter != nullptr);
434465 auto options = rating_filter->options();
435− QCOMPARE(options->rowCount(), 5);
466+ QCOMPARE(options->rowCount(), 6);
436467
437468 RatingFilterOption* opt[5];
438469 for (int i = 0; i<5; i++) {
439− opt[i] = dynamic_cast<RatingFilterOption *>(options->getRawOption(i));
470+ opt[i] = dynamic_cast<RatingFilterOption *>(options->getRawOption(i+1));
440471 }
441472
442473 QSignalSpy opt0spy(opt[0], SIGNAL(activeChanged(bool)));
tests/plugins/Unity/filtersbindingstest.h+1−1
@@ -41,7 +41,7 @@ class FiltersBindingsTest : public QObject
4141 void createCheckOptionFilter(DeeModel *model, const std::string &id, const std::string &name, int optionCount);
4242 void createRadioOptionFilter(DeeModel *model, const std::string &id, const std::string &name, int optionCount);
4343 void createRatingsFilter(DeeModel *model, const std::string &id, const std::string &name);
44− void createFilter(DeeModel *model, const std::string &renderer, const std::string &id, const std::string &name, int optionCount);
44+ void createFilter(DeeModel *model, const std::string &renderer, const std::string &id, const std::string &name, int optionCount, bool showAll);
4545};
4646
4747#endif // FILTERSBINDINGSTEST_H
tests/qmltests/Launcher/tst_Launcher.qml+8
@@ -198,6 +198,14 @@ Item {
198198 compare(findChild(delegate, "progressOverlay").visible, LauncherModel.get(i).progress >= 0)
199199 }
200200 }
201+
202+ function test_focusedHighlight() {
203+ var launcherListView = findChild(launcher, "launcherListView");
204+ for (var i = 0; i < launcherListView.count; ++i) {
205+ var delegate = findChild(launcherListView, "launcherDelegate" + i)
206+ compare(findChild(delegate, "focusedHighlight").visible, LauncherModel.get(i).focused)
207+ }
208+ }
201209 }
202210
203211 UT.UnityTestCase {