on xenial help sign in
Merged trunk.
808987aPawel Stolowski
Applications/Application.qml+1−1
@@ -16,7 +16,7 @@
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18import "applications.js" as ApplicationsModel
18import "applications.js" as ApplicationsModel
19−import Ubuntu.Application 0.1
19+import Unity.Application 0.1
20
20
21/* This class is temporary. It is meant to be API compatible with qthybris' Application
21/* This class is temporary. It is meant to be API compatible with qthybris' Application
22 class.
22 class.
Bottombar/Bottombar.qml+5−3
@@ -18,7 +18,7 @@ import QtQuick 2.0
18import "../Components"
18import "../Components"
19import "../Components/Math.js" as MathLocal
19import "../Components/Math.js" as MathLocal
20import Unity 0.1
20import Unity 0.1
21−import Ubuntu.Application 0.1
21+import Unity.Application 0.1
22import Ubuntu.Gestures 0.1
22import Ubuntu.Gestures 0.1
23
23
24Item {
24Item {
@@ -107,7 +107,7 @@ Item {
107 height: distanceThreshold
107 height: distanceThreshold
108 anchors.bottom: parent.bottom
108 anchors.bottom: parent.bottom
109
109
110− distanceThreshold: units.gu(8)
110+ distanceThreshold: units.gu(1)
111 enabled: !theHud.shown && bottombar.enabled && applicationIsOnForeground
111 enabled: !theHud.shown && bottombar.enabled && applicationIsOnForeground
112 direction: Direction.Upwards
112 direction: Direction.Upwards
113
113
@@ -119,6 +119,8 @@ Item {
119 if (previousStatus == DirectionalDragArea.Recognized) {
119 if (previousStatus == DirectionalDragArea.Recognized) {
120 if (hudButton.mouseOver) {
120 if (hudButton.mouseOver) {
121 hudButton.clicked()
121 hudButton.clicked()
122+ } else {
123+ bottombar.state = "hidden"
122 }
124 }
123 }
125 }
124 } else if (status === DirectionalDragArea.Undecided) {
126 } else if (status === DirectionalDragArea.Undecided) {
@@ -142,7 +144,7 @@ Item {
142
144
143 InputFilterArea {
145 InputFilterArea {
144 anchors.fill: parent
146 anchors.fill: parent
145− blockInput: hudButton.visible
147+ blockInput: (hudButton.opacity == 1)
146 }
148 }
147
149
148 states: [
150 states: [
CMakeLists.txt+4
@@ -62,10 +62,13 @@ set(SHELL_PRIVATE_LIBDIR ${CMAKE_INSTALL_LIBDIR}/unity8)
62
62
63configure_file(paths.h.in ${CMAKE_CURRENT_BINARY_DIR}/paths.h @ONLY)
63configure_file(paths.h.in ${CMAKE_CURRENT_BINARY_DIR}/paths.h @ONLY)
64
64
65+pkg_check_modules(UNITY-MIR REQUIRED unity-mir)
66+
65include_directories(
67include_directories(
66 ${CMAKE_CURRENT_BINARY_DIR}
68 ${CMAKE_CURRENT_BINARY_DIR}
67 ${CMAKE_CURRENT_SOURCE_DIR}
69 ${CMAKE_CURRENT_SOURCE_DIR}
68 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
70 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
71+ ${UNITY-MIR_INCLUDE_DIRS}
69 )
72 )
70
73
71set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
74set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
@@ -118,6 +121,7 @@ target_link_libraries(${SHELL_APP}
118 ${Qt5Qml_LIBRARIES}
121 ${Qt5Qml_LIBRARIES}
119 ${Qt5Quick_LIBRARIES}
122 ${Qt5Quick_LIBRARIES}
120 ${XCB_LDFLAGS}
123 ${XCB_LDFLAGS}
124+ ${CMAKE_DL_LIBS}
121 )
125 )
122
126
123# install binaries
127# install binaries
Components/ApplicationManagerWrapper.qml+89−42
@@ -15,15 +15,15 @@
15 */
15 */
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18−import Ubuntu.Application 0.1
18+import Unity.Application 0.1
19
19
20Item {
20Item {
21 id: applicationManager
21 id: applicationManager
22
22
23− property var mainStageApplications: ApplicationManager.mainStageApplications
23+ property alias mainStageApplications: mainStageModel
24− property var sideStageApplications: ApplicationManager.sideStageApplications
24+ property alias sideStageApplications: sideStageModel
25− property var mainStageFocusedApplication: ApplicationManager.mainStageFocusedApplication
25+ property variant mainStageFocusedApplication: null
26− property var sideStageFocusedApplication: ApplicationManager.sideStageFocusedApplication
26+ property variant sideStageFocusedApplication: null
27 property bool sideStageEnabled: true
27 property bool sideStageEnabled: true
28 signal focusRequested(string desktopFile)
28 signal focusRequested(string desktopFile)
29 property bool keyboardVisible: ApplicationManager.keyboardVisible
29 property bool keyboardVisible: ApplicationManager.keyboardVisible
@@ -31,32 +31,76 @@ Item {
31
31
32 property bool fake: ApplicationManager.fake ? ApplicationManager.fake : false
32 property bool fake: ApplicationManager.fake ? ApplicationManager.fake : false
33
33
34− Component.onCompleted: {
34+ ApplicationsModelStageFiltered {
35− // Start the watcher so that the ApplicationManager applications model can be populated.
35+ id: mainStageModel
36− ApplicationManager.startWatcher();
36+ stage: ApplicationInfo.MainStage
37+ }
38+
39+ ApplicationsModelStageFiltered {
40+ id: sideStageModel
41+ stage: ApplicationInfo.SideStage
42+ }
43+
44+ Connections {
45+ target: ApplicationManager
46+ onFocusedApplicationIdChanged: {
47+ var app = ApplicationManager.findApplication(ApplicationManager.focusedApplicationId)
48+ if (!app) { //nothing at all focused, so clear all
49+ mainStageFocusedApplication = null;
50+ sideStageFocusedApplication = null;
51+ } else {
52+ if (app.stage == ApplicationInfo.MainStage) {
53+ mainStageFocusedApplication = app;
54+ // possible the side stage app being unfocused fired this signal, so check for it
55+ if (sideStageFocusedApplication && !sideStageFocusedApplication.focused)
56+ sideStageFocusedApplication = null;
57+ } else {
58+ sideStageFocusedApplication = app;
59+ // possible the main stage app being unfocused fired this signal, so check for it
60+ if (mainStageFocusedApplication && !mainStageFocusedApplication.focused)
61+ mainStageFocusedApplication = null;
62+ }
63+ }
64+ }
37 }
65 }
38
66
39 function activateApplication(desktopFile, argument) {
67 function activateApplication(desktopFile, argument) {
40− var application;
68+ var appId;
41− application = getApplicationFromDesktopFile(desktopFile, ApplicationInfo.MainStage);
69+
42− if (application == null) {
70+ // HACK: Applications identified sometimes with with appId, but mostly with desktopFile.
43− application = getApplicationFromDesktopFile(desktopFile, ApplicationInfo.SideStage);
71+ // TODO: convert entire shell to use appId only.
72+ if (desktopFile.indexOf(".desktop") >= 0) {
73+ appId = desktopFileToAppId(desktopFile);
74+ } else {
75+ appId = desktopFile;
44 }
76 }
77+
78+ var application = ApplicationManager.findApplication(appId);
45− if (application != null) {
79+ if (application !== null) {
46 return application;
80 return application;
47 }
81 }
48
82
49 var execFlags = sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;
83 var execFlags = sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;
50
84
51 if (argument) {
85 if (argument) {
52− return ApplicationManager.startProcess(desktopFile, execFlags, [argument]);
86+ return ApplicationManager.startApplication(appId, execFlags, [argument]);
53 } else {
87 } else {
54− return ApplicationManager.startProcess(desktopFile, execFlags);
88+ return ApplicationManager.startApplication(appId, execFlags);
55 }
89 }
56 }
90 }
57
91
58− function stopProcess(application) {
92+ function stopApplication(application) {
93+ var appId;
94+
95+ // HACK: Applications identified sometimes with with appId, but mostly with desktopFile.
96+ // TODO: convert entire shell to use appId only.
97+ if (typeof application == "string") {
98+ appId = application;
99+ } else {
100+ appId = desktopFileToAppId(application.desktopFile);
101+ }
102+
59− ApplicationManager.stopProcess(application)
103+ ApplicationManager.stopApplication(appId);
60 }
104 }
61
105
62 function focusApplication(application) {
106 function focusApplication(application) {
@@ -64,51 +108,54 @@ Item {
64 return;
108 return;
65 }
109 }
66
110
67− ApplicationManager.focusApplication(application.handle);
111+ ApplicationManager.focusApplication(application.appId);
68 }
112 }
69
113
70 function unfocusCurrentApplication() {
114 function unfocusCurrentApplication() {
71− ApplicationManager.unfocusCurrentApplication(ApplicationInfo.MainStage);
115+ ApplicationManager.unfocusCurrentApplication();
72 }
116 }
73
117
74 function moveRunningApplicationStackPosition(from, to, stage) {
118 function moveRunningApplicationStackPosition(from, to, stage) {
75− var applications;
119+ if (from == to || from < 0 || to < 0) return;
120+
76 if (stage == ApplicationInfo.SideStage) {
121 if (stage == ApplicationInfo.SideStage) {
77− applications = ApplicationManager.sideStageApplications;
122+ sideStageModel.move(from, to);
78 } else {
123 } else {
79− applications = ApplicationManager.mainStageApplications;
124+ mainStageModel.move(from, to);
80 }
125 }
81− // FIXME: applications.move(0, 0) crashes
82− if (from !== to && from >= 0 && to >= 0) applications.move(from, to);
83 }
126 }
84
127
85 function getApplicationFromDesktopFile(desktopFile, stage) {
128 function getApplicationFromDesktopFile(desktopFile, stage) {
86− var foundSideStageApp, foundMainStageApp;
129+ var appId;
87
130
88− foundMainStageApp = __find(desktopFile, ApplicationManager.mainStageApplications)
131+ // HACK: Applications identified sometimes with with appId, but mostly with desktopFile.
89− if (stage == ApplicationInfo.MainStage) {
132+ // TODO: convert entire shell to use appId only.
90− return foundMainStageApp;
133+ if (desktopFile.indexOf(".desktop") >= 0) {
91− }
134+ appId = desktopFileToAppId(desktopFile);
92− foundSideStageApp = __find(desktopFile, ApplicationManager.sideStageApplications)
135+ } else {
93− if (stage == ApplicationInfo.SideStage) {
136+ appId = desktopFile;
94− return foundSideStageApp;
95 }
137 }
96
138
97− // if stage not specified, return whichever app running on either stage
139+ for (var i = 0, len = ApplicationManager.count; i < len; i++ ) {
98− return (foundMainStageApp) ? foundMainStageApp : foundSideStageApp;
140+ var app = ApplicationManager.get(i);
99−
100
141
101− function __find(desktopFile, applications) {
142+ // if stage not specified, return whichever app running on either stage
102− for (var i = 0; i < applications.count; i++ ) {
143+ if (app.appId == appId && (stage == undefined || app.stage == stage)) {
103− var application = applications.get(i);
104− if (application.desktopFile == desktopFile) {
105− return application;
144+ return app;
106− }
107 }
145 }
108− return null;
109 }
146 }
110 }
147 }
111
148
149+ function desktopFileToAppId(desktopFile) {
150+ var right = desktopFile.lastIndexOf(".desktop");
151+ var left = desktopFile.lastIndexOf("/");
152+ if (left == -1 || right == -1 || left == right) {
153+ console.log("ApplicationManagerWrapper: unable to extract appId from '" + desktopFile + "'");
154+ return "";
155+ }
156+ return desktopFile.substring(left+1, right);
157+ }
158+
112 Connections {
159 Connections {
113 target: ApplicationManager
160 target: ApplicationManager
114 onFocusRequested: {
161 onFocusRequested: {
Components/ApplicationScreenshot.qml+2−2
@@ -16,7 +16,7 @@
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19−import Ubuntu.Application 0.1
19+import Unity.Application 0.1
20
20
21Item {
21Item {
22 id: applicationScreenshot
22 id: applicationScreenshot
@@ -56,6 +56,6 @@ Item {
56 width: applicationScreenshot.application ? parent.width : 0
56 width: applicationScreenshot.application ? parent.width : 0
57 height: applicationScreenshot.application ? parent.height : 0
57 height: applicationScreenshot.application ? parent.height : 0
58 visible: applicationScreenshot.application != null && ready
58 visible: applicationScreenshot.application != null && ready
59− source: applicationScreenshot.application
59+ source: ApplicationManager.findApplication((application) ? application.appId : "")
60 }
60 }
61}
61}
Components/ApplicationsModelStageFiltered.qmlnew file+49
@@ -0,0 +1,49 @@
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+import QtQuick 2.0
18+import Utils 0.1
19+import Unity.Application 0.1
20+
21+SortFilterProxyModel {
22+ id: root
23+ property int stage
24+
25+ function get(index) {
26+ return model.get(mapRowToSource(index));
27+ }
28+
29+ function move(from, to) {
30+ var realFrom = mapRowToSource(from);
31+ if (realFrom == -1) {
32+ console.log("ERROR; invalid from=" + from + " index in move operation");
33+ return;
34+ }
35+ var realTo = mapRowToSource(to);
36+ if (realTo == -1) {
37+ // assuming wanting to move to end of list
38+ realTo = model.count - 1;
39+ }
40+
41+ if (realFrom == realTo) return;
42+ model.move(realFrom, realTo);
43+ }
44+
45+ model: ApplicationManager
46+ dynamicSortFilter: true
47+ filterRole: ApplicationManager.RoleStage
48+ filterRegExp: RegExp(stage)
49+}
Components/CrossFadeImage.qmldeleted−151
@@ -1,151 +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−
17−import QtQuick 2.0
18−
19−Item {
20− property url source
21−
22− /*
23− * true: fade out old image in parallel with fading in the new one.
24− * false: fade in new image above old one.
25− *
26− * The reason why this is required is that crossfading has the isse that in
27− * the middle of the animation, both images are only 50% opaque which make
28− * any background shine through. Not wanted for background images etc, but
29− * wanted for overlays.
30− */
31− property bool crossFade: true
32−
33− /*
34− * true: the very first source url should be faded in already.
35− * false: the very first source url should just be shown without animation.
36− */
37− property bool fadeInFirst: true
38−
39− readonly property size sourceSize: __currentImage.sourceSize
40− readonly property var status: __currentImage ? __currentImage.status : Image.Null
41− readonly property bool running: crossFadeImages.running || nextImageFadeIn.running
42−
43− property Image __currentImage: image1
44− property Image __nextImage: image2
45−
46− function swapImages() {
47− __currentImage.z = 0
48− __nextImage.z = 1
49− if (crossFade) {
50− crossFadeImages.start();
51− } else {
52− nextImageFadeIn.start();
53− }
54−
55− var tmpImage = __currentImage
56− __currentImage = __nextImage
57− __nextImage = tmpImage
58− }
59−
60− onSourceChanged: {
61− // On creation, the souce handler is called before image pointers are set.
62− if (__currentImage === null) {
63− __currentImage = image1;
64− __nextImage = image2;
65− }
66−
67− crossFadeImages.stop();
68− nextImageFadeIn.stop();
69−
70− // Don't fade in initial picture, only fade changes
71− if (__currentImage.source == "" && !fadeInFirst) {
72− __currentImage.source = source;
73− } else {
74− nextImageFadeIn.stop();
75− __nextImage.opacity = 0.0;
76− __nextImage.source = source;
77−
78− // If case the image is still in QML's cache, status will be "Ready" immediately
79− if (__nextImage.status == Image.Ready || __nextImage.source == "") {
80− swapImages();
81− }
82− }
83− }
84−
85− Connections {
86− target: __nextImage
87− onStatusChanged: {
88− if (__nextImage.status == Image.Ready || __nextImage.status == Image.Error) {
89− swapImages();
90− }
91− }
92− }
93−
94− Image {
95− id: image1
96− anchors.fill: parent
97− cache: false
98− asynchronous: true
99− fillMode: Image.PreserveAspectCrop
100− z: 1
101− }
102−
103− Image {
104− id: image2
105− anchors.fill: parent
106− cache: false
107− asynchronous: true
108− fillMode: Image.PreserveAspectCrop
109− z: 0
110− }
111−
112− NumberAnimation {
113− id: nextImageFadeIn
114− target: __nextImage
115− property: "opacity"
116− duration: 400
117− to: 1.0
118− easing.type: Easing.InOutQuad
119−
120− onRunningChanged: {
121− if (!running) {
122− __nextImage.source = "";
123− }
124− }
125− }
126−
127− ParallelAnimation {
128− id: crossFadeImages
129− NumberAnimation {
130− target: __nextImage
131− property: "opacity"
132− duration: 400
133− to: 1.0
134− easing.type: Easing.InOutQuad
135− }
136−
137− NumberAnimation {
138− target: __currentImage
139− property: "opacity"
140− duration: 400
141− to: 0
142− easing.type: Easing.InOutQuad
143− }
144−
145− onRunningChanged: {
146− if (!running) {
147− __nextImage.source = "";
148− }
149− }
150− }
151−}
Components/EdgeDemo.qml+29−22
@@ -43,15 +43,12 @@ Item {
43 }
43 }
44
44
45 function hideEdgeDemoInShell() {
45 function hideEdgeDemoInShell() {
46− var user = LightDM.Users.data(greeter.currentIndex, LightDM.UserRoles.NameRole);
46+ AccountsService.demoEdges = false;
47− AccountsService.setUserProperty(user, "demo-edges", false);
48− d.showEdgeDemo = false;
49 stopDemo();
47 stopDemo();
50 }
48 }
51
49
52 function hideEdgeDemoInGreeter() {
50 function hideEdgeDemoInGreeter() {
53− // TODO: AccountsService.setUserProperty("lightdm", "demo-edges", false);
51+ // TODO: AccountsService.demoEdges = false as lightdm user
54− d.showEdgeDemoInGreeter = false;
55 }
52 }
56
53
57 function hideEdgeDemos() {
54 function hideEdgeDemos() {
@@ -71,6 +68,24 @@ Item {
71 if (d.finalEdgeDemo) d.finalEdgeDemo.destroy()
68 if (d.finalEdgeDemo) d.finalEdgeDemo.destroy()
72 }
69 }
73
70
71+ function startDemo() {
72+ if (!d.overlay) {
73+ d.overlay = Qt.createComponent("EdgeDemoOverlay.qml")
74+ }
75+
76+ launcherEnabled = false;
77+ dashEnabled = false;
78+ panelEnabled = false;
79+ panelContentEnabled = false;
80+
81+ // Begin with either greeter or dash, depending on which is visible
82+ if (greeter && greeter.shown) {
83+ startRightEdgeDemo()
84+ } else {
85+ startTopEdgeDemo()
86+ }
87+ }
88+
74 QtObject {
89 QtObject {
75 id: d
90 id: d
76 property Component overlay
91 property Component overlay
@@ -79,22 +94,18 @@ Item {
79 property QtObject bottomEdgeDemo
94 property QtObject bottomEdgeDemo
80 property QtObject leftEdgeDemo
95 property QtObject leftEdgeDemo
81 property QtObject finalEdgeDemo
96 property QtObject finalEdgeDemo
82− property bool showEdgeDemo: false
97+ property bool showEdgeDemo: AccountsService.demoEdges
83− property bool showEdgeDemoInGreeter: d.showEdgeDemo // TODO: AccountsService.getUserProperty("lightdm", "demo-edges")
98+ property bool showEdgeDemoInGreeter: AccountsService.demoEdges // TODO: AccountsService.demoEdges as lightdm user
84
99
85− onShowEdgeDemoInGreeterChanged: {
100+ onShowEdgeDemoChanged: {
86− if (!d.overlay && d.showEdgeDemoInGreeter) {
101+ stopDemo()
87− d.overlay = Qt.createComponent("EdgeDemoOverlay.qml")
102+ if (d.showEdgeDemo) {
88− startRightEdgeDemo()
103+ startDemo()
89 }
104 }
90 }
105 }
91 }
106 }
92
107
93 function startRightEdgeDemo() {
108 function startRightEdgeDemo() {
94− launcherEnabled = false;
95− demo.dashEnabled = false;
96− demo.panelEnabled = false;
97− demo.panelContentEnabled = false;
98 if (demo.greeter) {
109 if (demo.greeter) {
99 d.rightEdgeDemo = d.overlay.createObject(demo.greeter, {
110 d.rightEdgeDemo = d.overlay.createObject(demo.greeter, {
100 "edge": "right",
111 "edge": "right",
@@ -123,11 +134,6 @@ Item {
123
134
124 onUnlocked: hide()
135 onUnlocked: hide()
125 onShownChanged: if (!greeter.shown) hide()
136 onShownChanged: if (!greeter.shown) hide()
126−
127− onSelected: {
128− var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole)
129− d.showEdgeDemo = AccountsService.getUserProperty(user, "demo-edges")
130− }
131 }
137 }
132
138
133 function startTopEdgeDemo() {
139 function startTopEdgeDemo() {
@@ -163,7 +169,7 @@ Item {
163 "edge": "bottom",
169 "edge": "bottom",
164 "title": i18n.tr("Close"),
170 "title": i18n.tr("Close"),
165 "text": i18n.tr("Swipe up again to close the settings screen"),
171 "text": i18n.tr("Swipe up again to close the settings screen"),
166− "anchors.fill": demo.indicators,
172+ "anchors.fill": demo.indicators.content,
167 });
173 });
168 }
174 }
169 if (d.bottomEdgeDemo) {
175 if (d.bottomEdgeDemo) {
@@ -218,8 +224,9 @@ Item {
218 d.finalEdgeDemo = d.overlay.createObject(demo.underlay, {
224 d.finalEdgeDemo = d.overlay.createObject(demo.underlay, {
219 "edge": "none",
225 "edge": "none",
220 "title": i18n.tr("Well done"),
226 "title": i18n.tr("Well done"),
221− "text": i18n.tr("You have now mastered the edge gestures and can start using the phone"),
227+ "text": i18n.tr("You have now mastered the edge gestures and can start using the phone<br><br>Tap anywhere to start"),
222 "anchors.fill": demo.dash,
228 "anchors.fill": demo.dash,
229+ "showSkip": false,
223 });
230 });
224 }
231 }
225 if (d.finalEdgeDemo) {
232 if (d.finalEdgeDemo) {
Components/EdgeDemoOverlay.qml+9−1
@@ -17,7 +17,7 @@
17import Powerd 0.1
17import Powerd 0.1
18import QtQuick 2.0
18import QtQuick 2.0
19import QtGraphicalEffects 1.0
19import QtGraphicalEffects 1.0
20−import Ubuntu.Application 0.1
20+import Unity.Application 0.1
21import Ubuntu.Components 0.1
21import Ubuntu.Components 0.1
22
22
23Showable {
23Showable {
@@ -43,6 +43,11 @@ Showable {
43 */
43 */
44 property alias skipText: skipLabel.text
44 property alias skipText: skipLabel.text
45
45
46+ /*
47+ * This is the visible status of the skip button.
48+ */
49+ property alias showSkip: skipLabel.visible
50+
46 /*
51 /*
47 * Whether this demo is running currently.
52 * Whether this demo is running currently.
48 */
53 */
@@ -148,7 +153,10 @@ Showable {
148 font.underline: true
153 font.underline: true
149
154
150 MouseArea {
155 MouseArea {
156+ // Make clickable area bigger than just the link because
157+ // otherwise, the edge demo will feel hard to dismiss.
151 anchors.fill: parent
158 anchors.fill: parent
159+ anchors.margins: -units.gu(5)
152 onClicked: overlay.doSkip()
160 onClicked: overlay.doSkip()
153 }
161 }
154 }
162 }
Components/IconUtil.jsdeleted−42
@@ -1,42 +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−
17−.pragma library
18−
19−// FIXME: a quick hack to get icons out of gicons and fallback to
20−// base icon for annotated icons. Doesn't correctly handle all icons.
21−// Proper global solution needed.
22−function from_gicon(name) {
23− var icon_name = name;
24− var annotated_re = /^. UnityProtocolAnnotatedIcon/;
25− if (annotated_re.test(name)) {
26− var base_icon_re = /'base-icon':.+?'(.+?)'/;
27− var base_icon = name.toString().match(base_icon_re);
28− icon_name = base_icon[1];
29− } else {
30− var themed_re = /^. GThemedIcon\s*([^\s]+)\s*/;
31− var themed = name.match(themed_re);
32− if (themed) {
33− return "image://gicon/" + themed[1];
34− }
35− }
36− var name_re = /^[a-z0-9\._-]+$/;
37− if (name_re.test(icon_name)) {
38− return "image://gicon/" + icon_name;
39− } else {
40− return icon_name;
41− }
42−}
Components/LazyImage.qmlnew file+172
@@ -0,0 +1,172 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Michał Sawicz <michal.sawicz@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+import QtQuick 2.0
21+import Ubuntu.Components 0.1
22+
23+Item {
24+ id: root
25+
26+ property url source
27+ // TODO convert into enums when available in QML
28+ property string scaleTo
29+
30+ property real initialWidth: units.gu(10)
31+ property real initialHeight: units.gu(10)
32+
33+ property alias sourceSize: image.sourceSize
34+ property alias fillMode: image.fillMode
35+ property alias asynchronous: image.asynchronous
36+ property alias cache: image.cache
37+ property alias horizontalAlignment: image.horizontalAlignment
38+ property alias verticalAlignment: image.verticalAlignment
39+
40+ state: "default"
41+
42+ onSourceChanged: {
43+ if (state === "ready") {
44+ state = "default";
45+ image.nextSource = source;
46+ } else {
47+ image.source = source;
48+ }
49+ }
50+
51+ UbuntuShape {
52+ id: placeholder
53+ objectName: "placeholder"
54+ color: "#22FFFFFF"
55+ anchors.fill: parent
56+ visible: opacity != 0
57+
58+ ActivityIndicator {
59+ id: activity
60+ anchors.centerIn: parent
61+ opacity: 0
62+ visible: opacity != 0
63+
64+ running: visible
65+ }
66+
67+ Image {
68+ id: errorImage
69+ objectName: "errorImage"
70+ anchors.centerIn: parent
71+ opacity: 0
72+ visible: opacity != 0
73+
74+ source: "graphics/close.png"
75+ sourceSize { width: units.gu(3); height: units.gu(3) }
76+ }
77+ }
78+
79+ UbuntuShape {
80+ id: shape
81+ objectName: "shape"
82+ anchors.fill: parent
83+ opacity: 0
84+ visible: opacity != 0
85+
86+ image: Image {
87+ id: image
88+ objectName: "image"
89+
90+ property url nextSource
91+
92+ width: root.scaleTo == "height" ? implicitWidth * root.height / implicitHeight : implicitWidth
93+ height: root.scaleTo == "width" ? implicitHeight * root.width / implicitWidth : implicitHeight
94+ fillMode: Image.PreserveAspectCrop
95+ asynchronous: true
96+ cache: false
97+ horizontalAlignment: Image.AlignHCenter
98+ verticalAlignment: Image.AlignVCenter
99+ sourceSize.width: root.scaleTo == "width" ? root.width : 0
100+ sourceSize.height: root.scaleTo == "height" ? root.height : 0
101+ }
102+ }
103+
104+ states: [
105+ State {
106+ name: "default"
107+ when: image.source == ""
108+ PropertyChanges { target: root; implicitWidth: root.initialWidth; implicitHeight: root.initialHeight }
109+ PropertyChanges { target: errorImage; opacity: 0 }
110+ },
111+ State {
112+ name: "loading"
113+ extend: "default"
114+ when: image.status === Image.Loading
115+ PropertyChanges { target: activity; opacity: 1 }
116+ },
117+ State {
118+ name: "ready"
119+ when: image.status === Image.Ready && image.source != ""
120+ PropertyChanges { target: root; implicitWidth: image.width; implicitHeight: image.height }
121+ PropertyChanges { target: shape; opacity: 1 }
122+ PropertyChanges { target: placeholder; opacity: 0 }
123+ },
124+ State {
125+ name: "error"
126+ extend: "default"
127+ when: image.status === Image.Error
128+ PropertyChanges { target: errorImage; opacity: 1.0 }
129+ }
130+ ]
131+
132+ transitions: [
133+ Transition {
134+ to: "ready"
135+ objectName: "readyTransition"
136+ SequentialAnimation {
137+ PropertyAction { target: shape; property: "visible" }
138+ ParallelAnimation {
139+ NumberAnimation { target: shape; property: "opacity"; easing.type: Easing.Linear }
140+ UbuntuNumberAnimation { target: root; properties: "implicitWidth,implicitHeight" }
141+ NumberAnimation {
142+ targets: [placeholder, activity, errorImage]; property: "opacity";
143+ easing.type: Easing.Linear; duration: UbuntuAnimation.SnapDuration
144+ }
145+ }
146+ }
147+ },
148+
149+ Transition {
150+ to: "*"
151+ objectName: "genericTransition"
152+ SequentialAnimation {
153+ ParallelAnimation {
154+ NumberAnimation { target: shape; property: "opacity"; easing.type: Easing.Linear }
155+ NumberAnimation {
156+ targets: [placeholder, activity, errorImage]; property: "opacity";
157+ easing.type: Easing.Linear; duration: UbuntuAnimation.SnapDuration
158+ }
159+ UbuntuNumberAnimation { target: root; properties: "implicitWidth,implicitHeight" }
160+ }
161+ PropertyAction { target: shape; property: "visible" }
162+ }
163+
164+ onRunningChanged: {
165+ if (!running && state === "default" && image.nextSource !== "") {
166+ image.source = image.nextSource;
167+ image.nextSource = "";
168+ }
169+ }
170+ }
171+ ]
172+}
Components/ResponsiveGridView.qml+1−1
@@ -67,7 +67,7 @@ Item {
67
67
68 function columnsForSpacing(spacing) {
68 function columnsForSpacing(spacing) {
69 // minimum margin is half of the spacing
69 // minimum margin is half of the spacing
70− return Math.floor((parent.width - spacing/2) / (delegateWidth + spacing));
70+ return Math.max(1, Math.floor((parent.width - spacing/2) / (delegateWidth + spacing)));
71 }
71 }
72
72
73 property real allocatableHorizontalSpace: parent.width - columns * delegateWidth
73 property real allocatableHorizontalSpace: parent.width - columns * delegateWidth
Components/Stage.qml+1−1
@@ -15,7 +15,7 @@
15 */
15 */
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18−import Ubuntu.Application 0.1
18+import Unity.Application 0.1
19import Ubuntu.Components 0.1
19import Ubuntu.Components 0.1
20import Ubuntu.Gestures 0.1
20import Ubuntu.Gestures 0.1
21
21
Components/VolumeControl.qml+5−20
@@ -21,37 +21,22 @@ Item {
21 id: root
21 id: root
22 objectName: "volumeControl"
22 objectName: "volumeControl"
23 visible: false
23 visible: false
24− property int volume
25
24
26 QDBusActionGroup {
25 QDBusActionGroup {
27 id: actionGroup
26 id: actionGroup
28 busType: 1
27 busType: 1
29− busName: "com.canonical.settings.sound"
28+ busName: "com.canonical.indicator.sound"
30− objectPath: "/com/canonical/settings/sound"
29+ objectPath: "/com/canonical/indicator/sound"
31
30
32− property variant actionObject: action("volume")
31+ property variant actionObject: action("scroll")
33− property variant serverVolume: actionObject.valid ? actionObject.state: 0
34− }
35−
36− Binding {
37− target: root
38− property: "volume"
39− value: actionGroup.serverVolume * 100
40− }
41−
42− onVolumeChanged: {
43− if (actionGroup.serverVolume != volume) {
44− var targetVolume = Math.min(1, Math.max(0, volume / 100));
45− actionGroup.actionObject.updateState(targetVolume);
46− }
47 }
32 }
48
33
49 function volumeUp() {
34 function volumeUp() {
50− actionGroup.actionObject.updateState(Math.min(1, volume/100 + 0.10));
35+ actionGroup.actionObject.activate(1);
51 }
36 }
52
37
53 function volumeDown() {
38 function volumeDown() {
54− actionGroup.actionObject.updateState(Math.max(0, volume/100 - 0.10));
39+ actionGroup.actionObject.activate(-1);
55 }
40 }
56
41
57 Component.onCompleted: actionGroup.start()
42 Component.onCompleted: actionGroup.start()
Components/graphics/close@20.pngnew file

Binary file not shown.

Dash/Apps/AppPreview.qml+12−2
@@ -20,7 +20,6 @@ import Ubuntu.Components.ListItems 0.1 as ListItem
20import Ubuntu.DownloadDaemonListener 0.1
20import Ubuntu.DownloadDaemonListener 0.1
21import ".."
21import ".."
22import "../../Components"
22import "../../Components"
23−import "../../Components/IconUtil.js" as IconUtil
24
23
25DashPreview {
24DashPreview {
26 id: root
25 id: root
@@ -111,6 +110,10 @@ DashPreview {
111 onFinished: {
110 onFinished: {
112 root.previewData.execute(progressBar.model[0].id, { })
111 root.previewData.execute(progressBar.model[0].id, { })
113 }
112 }
113+
114+ onError: {
115+ root.previewData.execute(progressBar.model[1].id, { "error": error });
116+ }
114 }
117 }
115
118
116 }
119 }
@@ -137,7 +140,7 @@ DashPreview {
137 anchors { left: parent.left; right: parent.right }
140 anchors { left: parent.left; right: parent.right }
138
141
139 appName: root.previewData.title
142 appName: root.previewData.title
140− icon: IconUtil.from_gicon(root.previewData.appIcon)
143+ icon: root.previewData.appIcon
141 rating: Math.round(root.previewData.rating * 10)
144 rating: Math.round(root.previewData.rating * 10)
142 reviews: root.previewData.numRatings
145 reviews: root.previewData.numRatings
143 rated: root.previewData.infoMap["rated"] ? root.previewData.infoMap["rated"].value : 0
146 rated: root.previewData.infoMap["rated"] ? root.previewData.infoMap["rated"].value : 0
@@ -188,12 +191,19 @@ DashPreview {
188 ListItem.ThinDivider { }
191 ListItem.ThinDivider { }
189
192
190 AppReviews {
193 AppReviews {
194+ id: appReviews
191 objectName: "appReviews"
195 objectName: "appReviews"
196+ // TODO: This should make this visible when the feature for reviews/comments is complete.
197+ visible: false
192 anchors { left: parent.left; right: parent.right }
198 anchors { left: parent.left; right: parent.right }
193
199
194 model: root.previewData.infoMap["comments"] ? root.previewData.infoMap["comments"].value : undefined
200 model: root.previewData.infoMap["comments"] ? root.previewData.infoMap["comments"].value : undefined
195
201
196 onSendReview: root.sendUserReview(review);
202 onSendReview: root.sendUserReview(review);
203+
204+ onEditing: {
205+ root.ensureVisible(appReviews.textArea);
206+ }
197 }
207 }
198 }
208 }
199 }
209 }
Dash/Apps/AppReviews.qml+3
@@ -23,8 +23,10 @@ Column {
23 id: root
23 id: root
24
24
25 property var model
25 property var model
26+ property alias textArea: reviewField
26
27
27 signal sendReview(string review)
28 signal sendReview(string review)
29+ signal editing
28
30
29 spacing: units.gu(2)
31 spacing: units.gu(2)
30 state: ""
32 state: ""
@@ -93,6 +95,7 @@ Column {
93 if(reviewField.focus){
95 if(reviewField.focus){
94 root.state = "editing";
96 root.state = "editing";
95 reviewField.selectAll();
97 reviewField.selectAll();
98+ root.editing();
96 }
99 }
97 }
100 }
98
101
Dash/Apps/ApplicationsFilterGrid.qml+1−2
@@ -17,7 +17,6 @@
17import QtQuick 2.0
17import QtQuick 2.0
18import "../../Components"
18import "../../Components"
19import "../../Applications"
19import "../../Applications"
20−import "../../Components/IconUtil.js" as IconUtil
21
20
22FilterGrid {
21FilterGrid {
23 id: filterGrid
22 id: filterGrid
@@ -50,7 +49,7 @@ FilterGrid {
50 text: model.title ? model.title : application.name // FIXME: this is temporary
49 text: model.title ? model.title : application.name // FIXME: this is temporary
51 imageWidth: units.gu(8)
50 imageWidth: units.gu(8)
52 imageHeight: units.gu(7.5)
51 imageHeight: units.gu(7.5)
53− source: IconUtil.from_gicon(icon)
52+ source: icon
54 onClicked: filterGrid.clicked(index, application.desktopFile);
53 onClicked: filterGrid.clicked(index, application.desktopFile);
55 }
54 }
56}
55}
Dash/Apps/RunningApplicationTile.qml+2−3
@@ -16,7 +16,7 @@
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19−import Ubuntu.Application 0.1
19+import Unity.Application 0.1
20import "../../Components/"
20import "../../Components/"
21import "../../Components/ListItems"
21import "../../Components/ListItems"
22
22
@@ -76,10 +76,9 @@ AbstractButton {
76
76
77 ApplicationImage {
77 ApplicationImage {
78 id: applicationImage
78 id: applicationImage
79− source: application
79+ source: ApplicationManager.findApplication((application) ? application.appId : "")
80 width: shapedApplicationImage.width
80 width: shapedApplicationImage.width
81 height: shapedApplicationImage.height
81 height: shapedApplicationImage.height
82− fillMode: ApplicationImage.PreserveAspectCrop
83 }
82 }
84
83
85 UbuntuShape {
84 UbuntuShape {
Dash/Apps/RunningApplicationsGrid.qml+4−4
@@ -52,22 +52,22 @@ ResponsiveFlowView {
52
52
53 RunningApplicationTile {
53 RunningApplicationTile {
54 id: runningAppTile
54 id: runningAppTile
55− objectName: "runningAppTile " + model.application.name
55+ objectName: "runningAppTile " + model.name
56 anchors {
56 anchors {
57 top: parent.top
57 top: parent.top
58 horizontalCenter: parent.horizontalCenter
58 horizontalCenter: parent.horizontalCenter
59 }
59 }
60− application: model.application
60+ application: model
61 onRequestedActivationMode: { root.terminationModeEnabled = false }
61 onRequestedActivationMode: { root.terminationModeEnabled = false }
62 onRequestedTerminationMode: {
62 onRequestedTerminationMode: {
63 if (canEnableTerminationMode)
63 if (canEnableTerminationMode)
64 root.terminationModeEnabled = true
64 root.terminationModeEnabled = true
65 }
65 }
66 onRequestedApplicationTermination: {
66 onRequestedApplicationTermination: {
67− shell.applicationManager.stopProcess(application)
67+ shell.applicationManager.stopApplication(model.appId)
68 }
68 }
69 onRequestedApplicationActivation: {
69 onRequestedApplicationActivation: {
70− shell.activateApplication(application.desktopFile)
70+ shell.activateApplication(model.appId)
71 }
71 }
72
72
73 terminationModeEnabled: root.terminationModeEnabled
73 terminationModeEnabled: root.terminationModeEnabled
Dash/DashBar.qml+2−3
@@ -83,9 +83,8 @@ Item {
83 }
83 }
84
84
85 delegate:
85 delegate:
86− Item {
86+ // FIXME: Use Panel's integrated trigger() once that works again.
87− signal clicked()
87+ MouseArea {
88−
89 width: itemSize
88 width: itemSize
90 height: dashBar.height
89 height: dashBar.height
91 anchors.top: parent.top
90 anchors.top: parent.top
Dash/DashPreview.qml+13
@@ -20,6 +20,7 @@ import Ubuntu.Components 0.1
20Rectangle {
20Rectangle {
21 id: root
21 id: root
22
22
23+ property int keyboardSize: Qt.inputMethod.visible ? Qt.inputMethod.keyboardRectangle.height : 0
23 property var previewData
24 property var previewData
24
25
25 property string title: ""
26 property string title: ""
@@ -38,6 +39,14 @@ Rectangle {
38 color: Qt.rgba(0, 0, 0, .3)
39 color: Qt.rgba(0, 0, 0, .3)
39 clip: true
40 clip: true
40
41
42+ function ensureVisible(item) {
43+ var o = leftFlickable.mapFromItem(item, 0, 0, item.width, item.height);
44+ var keyboardY = shell.height - root.keyboardSize;
45+ if ((o.y + o.height) > keyboardY) {
46+ leftFlickable.contentY += o.y + o.height - keyboardY;
47+ }
48+ }
49+
41 Connections {
50 Connections {
42 target: shell.applicationManager
51 target: shell.applicationManager
43 onMainStageFocusedApplicationChanged: {
52 onMainStageFocusedApplicationChanged: {
@@ -128,12 +137,16 @@ Rectangle {
128
137
129 Flickable {
138 Flickable {
130 id: leftFlickable
139 id: leftFlickable
140+ objectName: "leftFlickable"
131 anchors.top: parent.top
141 anchors.top: parent.top
132 anchors.bottom: parent.bottom
142 anchors.bottom: parent.bottom
133 width: root.narrowMode ? contentRow.width : contentRow.width * root.previewWidthRatio
143 width: root.narrowMode ? contentRow.width : contentRow.width * root.previewWidthRatio
134 contentHeight: leftColumn.height
144 contentHeight: leftColumn.height
145+ anchors.bottomMargin: root.keyboardSize
135 clip: true
146 clip: true
136
147
148+ Behavior on contentY { NumberAnimation { duration: 300 } }
149+
137 Column {
150 Column {
138 id: leftColumn
151 id: leftColumn
139 objectName: "leftColumn"
152 objectName: "leftColumn"
Dash/Generic/GenericCarousel.qml+1−2
@@ -17,7 +17,6 @@
17import QtQuick 2.0
17import QtQuick 2.0
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19import "../../Components"
19import "../../Components"
20−import "../../Components/IconUtil.js" as IconUtil
21
20
22Carousel {
21Carousel {
23 id: genericCarousel
22 id: genericCarousel
@@ -42,7 +41,7 @@ Carousel {
42 image: Image {
41 image: Image {
43 asynchronous: true
42 asynchronous: true
44 sourceSize { width: item.width; height: item.height }
43 sourceSize { width: item.width; height: item.height }
45− source: model ? IconUtil.from_gicon(model.icon) : ""
44+ source: model ? model.icon : ""
46 }
45 }
47 }
46 }
48
47
Dash/Generic/GenericFilterGrid.qml+1−2
@@ -16,7 +16,6 @@
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18import "../../Components"
18import "../../Components"
19−import "../../Components/IconUtil.js" as IconUtil
20
19
21FilterGrid {
20FilterGrid {
22 id: filtergrid
21 id: filtergrid
@@ -41,7 +40,7 @@ FilterGrid {
41 imageWidth: filtergrid.iconWidth
40 imageWidth: filtergrid.iconWidth
42 imageHeight: filtergrid.iconHeight
41 imageHeight: filtergrid.iconHeight
43
42
44− source: IconUtil.from_gicon(model.icon)
43+ source: model.icon
45
44
46 fillMode: Image.PreserveAspectCrop
45 fillMode: Image.PreserveAspectCrop
47
46
Dash/Generic/GenericPreview.qml+1−2
@@ -18,7 +18,6 @@ import QtQuick 2.0
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19import "../../Components"
19import "../../Components"
20import "../../Components/ListItems" as ListItems
20import "../../Components/ListItems" as ListItems
21−import "../../Components/IconUtil.js" as IconUtil
22import ".."
21import ".."
23
22
24DashPreview {
23DashPreview {
@@ -27,7 +26,7 @@ DashPreview {
27 title: previewData.title
26 title: previewData.title
28 previewWidthRatio: 0.6
27 previewWidthRatio: 0.6
29
28
30− property url url: IconUtil.from_gicon(previewData.image)
29+ property url url: previewData.image
31
30
32 header: UbuntuShape {
31 header: UbuntuShape {
33 id: urlLoader
32 id: urlLoader
Dash/GenericScopeView.qml+28−13
@@ -18,14 +18,14 @@ import QtQuick 2.0
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19import "../Components"
19import "../Components"
20import "../Components/ListItems" as ListItems
20import "../Components/ListItems" as ListItems
21−import "../Components/IconUtil.js" as IconUtil
22
21
23ScopeView {
22ScopeView {
24 id: scopeView
23 id: scopeView
25− property alias previewShown: previewLoader.onScreen
24+ readonly property alias previewShown: previewLoader.onScreen
26
25
27 onIsCurrentChanged: {
26 onIsCurrentChanged: {
28 pageHeader.resetSearch();
27 pageHeader.resetSearch();
28+ previewLoader.open = false;
29 }
29 }
30
30
31 onMovementStarted: categoryView.showHeader()
31 onMovementStarted: categoryView.showHeader()
@@ -36,6 +36,12 @@ ScopeView {
36 value: pageHeader.searchQuery
36 value: pageHeader.searchQuery
37 }
37 }
38
38
39+ Binding {
40+ target: pageHeader
41+ property: "searchQuery"
42+ value: scopeView.scope.searchQuery
43+ }
44+
39 Connections {
45 Connections {
40 target: panel
46 target: panel
41 onSearchClicked: if (isCurrent) {
47 onSearchClicked: if (isCurrent) {
@@ -44,6 +50,12 @@ ScopeView {
44 }
50 }
45 }
51 }
46
52
53+ Connections {
54+ target: scopeView.scope
55+ onShowDash: previewLoader.open = false;
56+ onHideDash: previewLoader.open = false;
57+ }
58+
47 ScopeListView {
59 ScopeListView {
48 id: categoryView
60 id: categoryView
49 anchors.fill: parent
61 anchors.fill: parent
@@ -53,13 +65,14 @@ ScopeView {
53 onAtYEndChanged: if (atYEnd) endReached()
65 onAtYEndChanged: if (atYEnd) endReached()
54 onMovingChanged: if (moving && atYEnd) endReached()
66 onMovingChanged: if (moving && atYEnd) endReached()
55
67
56− property int expandedIndex: -1
68+ property string expandedCategoryId: ""
57
69
58 delegate: ListItems.Base {
70 delegate: ListItems.Base {
59 highlightWhenPressed: false
71 highlightWhenPressed: false
60
72
61 readonly property bool expandable: rendererLoader.item ? rendererLoader.item.expandable : false
73 readonly property bool expandable: rendererLoader.item ? rendererLoader.item.expandable : false
62 readonly property bool filtered: rendererLoader.item ? rendererLoader.item.filter : true
74 readonly property bool filtered: rendererLoader.item ? rendererLoader.item.filter : true
75+ readonly property string category: categoryId
63
76
64 Loader {
77 Loader {
65 id: rendererLoader
78 id: rendererLoader
@@ -74,14 +87,14 @@ ScopeView {
74 onLoaded: {
87 onLoaded: {
75 if (source.toString().indexOf("Apps/RunningApplicationsGrid.qml") != -1) {
88 if (source.toString().indexOf("Apps/RunningApplicationsGrid.qml") != -1) {
76 // TODO: the running apps grid doesn't support standard scope results model yet
89 // TODO: the running apps grid doesn't support standard scope results model yet
77− item.firstModel = results.firstModel
90+ item.firstModel = Qt.binding(function() { return results.firstModel })
78− item.secondModel = results.secondModel
91+ item.secondModel = Qt.binding(function() { return results.secondModel })
79 } else {
92 } else {
80− item.model = results
93+ item.model = Qt.binding(function() { return results })
81 }
94 }
82− item.objectName = categoryId
95+ item.objectName = Qt.binding(function() { return categoryId })
83 if (item.expandable) {
96 if (item.expandable) {
84− var shouldFilter = index != categoryView.expandedIndex;
97+ var shouldFilter = categoryId != categoryView.expandedCategoryId;
85 if (shouldFilter != item.filter) {
98 if (shouldFilter != item.filter) {
86 item.filter = shouldFilter;
99 item.filter = shouldFilter;
87 }
100 }
@@ -117,10 +130,10 @@ ScopeView {
117 }
130 }
118 Connections {
131 Connections {
119 target: categoryView
132 target: categoryView
120− onExpandedIndexChanged: {
133+ onExpandedCategoryIdChanged: {
121 var item = rendererLoader.item;
134 var item = rendererLoader.item;
122 if (item.expandable) {
135 if (item.expandable) {
123− var shouldFilter = index != categoryView.expandedIndex;
136+ var shouldFilter = categoryId != categoryView.expandedCategoryId;
124 if (shouldFilter != item.filter) {
137 if (shouldFilter != item.filter) {
125 // If the filter animation will be seen start it, otherwise, just flip the switch
138 // If the filter animation will be seen start it, otherwise, just flip the switch
126 var shrinkingVisible = shouldFilter && y + item.collapsedHeight < categoryView.height;
139 var shrinkingVisible = shouldFilter && y + item.collapsedHeight < categoryView.height;
@@ -151,10 +164,10 @@ ScopeView {
151 return "";
164 return "";
152 }
165 }
153 onClicked: {
166 onClicked: {
154− if (categoryView.expandedIndex != delegateIndex)
167+ if (categoryView.expandedCategoryId != delegate.category)
155− categoryView.expandedIndex = delegateIndex;
168+ categoryView.expandedCategoryId = delegate.category;
156 else
169 else
157− categoryView.expandedIndex = -1;
170+ categoryView.expandedCategoryId = "";
158 }
171 }
159 }
172 }
160 pageHeader: PageHeader {
173 pageHeader: PageHeader {
@@ -180,6 +193,7 @@ ScopeView {
180 case "grid": {
193 case "grid": {
181 switch (contentType) {
194 switch (contentType) {
182 case "video": return "Generic/GenericFilterGridPotrait.qml";
195 case "video": return "Generic/GenericFilterGridPotrait.qml";
196+ case "music": return "Music/MusicFilterGrid.qml";
183 default: return "Generic/GenericFilterGrid.qml";
197 default: return "Generic/GenericFilterGrid.qml";
184 }
198 }
185 }
199 }
@@ -247,6 +261,7 @@ ScopeView {
247 }
261 }
248
262
249 Loader {
263 Loader {
264+ objectName: "previewLoader"
250 id: previewLoader
265 id: previewLoader
251 property var previewData
266 property var previewData
252 height: effect.bottomGapPx - effect.topGapPx
267 height: effect.bottomGapPx - effect.topGapPx
Dash/Music/MusicFilterGrid.qml+12−2
@@ -29,19 +29,29 @@ FilterGrid {
29 readonly property int iconWidth: (width / columns) * 0.8
29 readonly property int iconWidth: (width / columns) * 0.8
30 readonly property int iconHeight: iconWidth
30 readonly property int iconHeight: iconWidth
31
31
32− signal clicked(int index)
32+ signal clicked(int index, var delegateItem, real itemY)
33+ signal pressAndHold(int index, var delegateItem, real itemY)
33
34
34 delegate: AlbumTile {
35 delegate: AlbumTile {
36+ id: tile
35 objectName: "delegate" + index
37 objectName: "delegate" + index
36 width: filterGrid.cellWidth
38 width: filterGrid.cellWidth
37 height: filterGrid.cellHeight
39 height: filterGrid.cellHeight
38 iconWidth: filterGrid.iconWidth
40 iconWidth: filterGrid.iconWidth
39 iconHeight: filterGrid.iconHeight
41 iconHeight: filterGrid.iconHeight
42+
40 artist: model.title
43 artist: model.title
41 album: model.comment
44 album: model.comment
42 source: model.icon
45 source: model.icon
46+
43 onClicked: {
47 onClicked: {
48+ var data = { model: model }
44− filterGrid.clicked(index);
49+ filterGrid.clicked(index, data, tile.y)
50+ }
51+
52+ onPressAndHold: {
53+ var data = { model: model }
54+ filterGrid.pressAndHold(index, data, tile.y)
45 }
55 }
46 }
56 }
47}
57}
Dash/graphics/phone/home.pngdeleted

Binary file not shown.

Dash/graphics/phone/music.pngdeleted

Binary file not shown.

Dash/graphics/phone/videos.pngdeleted

Binary file not shown.

Dash/graphics/tablet/apps.pngdeleted

Binary file not shown.

Dash/graphics/tablet/home.pngdeleted

Binary file not shown.

Dash/graphics/tablet/music.pngdeleted

Binary file not shown.

Dash/graphics/tablet/people.pngdeleted

Binary file not shown.

Dash/graphics/tablet/videos.pngdeleted

Binary file not shown.

Greeter/Greeter.qml+2
@@ -26,6 +26,8 @@ Showable {
26 enabled: shown
26 enabled: shown
27 created: greeterContentLoader.status == Loader.Ready && greeterContentLoader.item.ready
27 created: greeterContentLoader.status == Loader.Ready && greeterContentLoader.item.ready
28
28
29+ property url defaultBackground
30+
29 // 1 when fully shown and 0 when fully hidden
31 // 1 when fully shown and 0 when fully hidden
30 property real showProgress: MathLocal.clamp((width + x) / width, 0, 1)
32 property real showProgress: MathLocal.clamp((width + x) / width, 0, 1)
31
33
Greeter/GreeterContent.qml+21−3
@@ -15,6 +15,7 @@
15 */
15 */
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18+import AccountsService 0.1
18import Ubuntu.Components 0.1
19import Ubuntu.Components 0.1
19import LightDM 0.1 as LightDM
20import LightDM 0.1 as LightDM
20import "../Components"
21import "../Components"
@@ -39,12 +40,29 @@ MouseArea {
39 color: "black"
40 color: "black"
40 }
41 }
41
42
43+ property url backgroundValue: AccountsService.backgroundFile != undefined && AccountsService.backgroundFile.length > 0 ? AccountsService.backgroundFile : greeter.defaultBackground
44+ onBackgroundValueChanged: wallpaper.source = backgroundValue
45+
42 CrossFadeImage {
46 CrossFadeImage {
43 id: wallpaper
47 id: wallpaper
44−
48+ objectName: "wallpaper"
45− source: shell.background
46 anchors.fill: parent
49 anchors.fill: parent
47− fadeInFirst: false
50+ fillMode: Image.PreserveAspectCrop
51+ }
52+
53+ // See Shell.qml's backgroundSettings treatment for why we need a separate
54+ // Image, but it boils down to avoiding binding loop detection.
55+ Image {
56+ source: wallpaper.source
57+ height: 0
58+ width: 0
59+ sourceSize.height: 0
60+ sourceSize.width: 0
61+ onStatusChanged: {
62+ if (status == Image.Error && source != greeter.defaultBackground) {
63+ wallpaper.source = greeter.defaultBackground
64+ }
65+ }
48 }
66 }
49
67
50 Rectangle {
68 Rectangle {
Greeter/Infographics.qml+1−2
@@ -286,9 +286,8 @@ Item {
286 objectName: "backgroundCircle"
286 objectName: "backgroundCircle"
287
287
288 anchors.fill: parent
288 anchors.fill: parent
289− opacity: 0.9
290
289
291− source: "graphics/infographic_circle.png"
290+ source: "graphics/infographic_circle_back.png"
292 }
291 }
293
292
294 Timer {
293 Timer {
Greeter/graphics/infographic_circle.pngdeleted

Binary file not shown.

Greeter/graphics/infographic_circle_back.pngnew file

Binary file not shown.

Launcher/Launcher.qml+4−4
@@ -35,7 +35,7 @@ Item {
35 readonly property bool shown: panel.x > -panel.width
35 readonly property bool shown: panel.x > -panel.width
36
36
37 // emitted when an application is selected
37 // emitted when an application is selected
38− signal launcherApplicationSelected(string desktopFile)
38+ signal launcherApplicationSelected(string appId)
39
39
40 // emitted when the apps dash should be shown because of a swipe gesture
40 // emitted when the apps dash should be shown because of a swipe gesture
41 signal dash()
41 signal dash()
@@ -159,7 +159,7 @@ Item {
159
159
160 onApplicationSelected: {
160 onApplicationSelected: {
161 root.state = ""
161 root.state = ""
162− launcherApplicationSelected(desktopFile)
162+ launcherApplicationSelected(appId)
163 }
163 }
164 onDashItemSelected: {
164 onDashItemSelected: {
165 root.state = ""
165 root.state = ""
@@ -192,12 +192,12 @@ Item {
192
192
193 direction: Direction.Rightwards
193 direction: Direction.Rightwards
194
194
195− enabled: root.available && root.state !== "visible"
195+ enabled: root.available
196 width: root.dragAreaWidth
196 width: root.dragAreaWidth
197 height: root.height
197 height: root.height
198
198
199 onTouchXChanged: {
199 onTouchXChanged: {
200− if (status !== DirectionalDragArea.Recognized)
200+ if (status !== DirectionalDragArea.Recognized || launcher.state == "visible")
201 return;
201 return;
202
202
203 // When the gesture finally gets recognized, the finger will likely be
203 // When the gesture finally gets recognized, the finger will likely be
Launcher/LauncherDelegate.qml+21−10
@@ -24,6 +24,7 @@ Item {
24 property int count: -1
24 property int count: -1
25 property int progress: -1
25 property int progress: -1
26 property bool highlighted: false
26 property bool highlighted: false
27+ property bool itemFocused: false
27 property real maxAngle: 0
28 property real maxAngle: 0
28 property bool inverted: false
29 property bool inverted: false
29
30
@@ -43,24 +44,25 @@ Item {
43 onCountChanged: shaderEffectSource.scheduleUpdate();
44 onCountChanged: shaderEffectSource.scheduleUpdate();
44 onProgressChanged: shaderEffectSource.scheduleUpdate();
45 onProgressChanged: shaderEffectSource.scheduleUpdate();
45 onHighlightedChanged: shaderEffectSource.scheduleUpdate();
46 onHighlightedChanged: shaderEffectSource.scheduleUpdate();
47+ onItemFocusedChanged: shaderEffectSource.scheduleUpdate();
46
48
47 Item {
49 Item {
48 id: iconItem
50 id: iconItem
49− width: parent.itemWidth
51+ width: parent.itemWidth + units.gu(1)
50− height: parent.itemHeight
52+ height: parent.itemHeight + units.gu(1)
51 anchors.centerIn: parent
53 anchors.centerIn: parent
52
54
53 UbuntuShape {
55 UbuntuShape {
54 id: iconShape
56 id: iconShape
55 anchors.fill: parent
57 anchors.fill: parent
56− anchors.margins: units.gu(0.5)
58+ anchors.margins: units.gu(1)
57 radius: "medium"
59 radius: "medium"
58
60
59 image: Image {
61 image: Image {
60 id: iconImage
62 id: iconImage
61 sourceSize.width: iconShape.width
63 sourceSize.width: iconShape.width
62 sourceSize.height: iconShape.height
64 sourceSize.height: iconShape.height
63− source: "../graphics/applicationIcons/" + root.iconName + ".png"
65+ source: root.iconName
64 }
66 }
65 }
67 }
66
68
@@ -78,7 +80,7 @@ Item {
78 anchors {
80 anchors {
79 right: parent.right
81 right: parent.right
80 top: parent.top
82 top: parent.top
81− margins: -units.dp(1)
83+ margins: units.dp(3)
82 }
84 }
83 width: Math.min(root.itemWidth, Math.max(units.gu(3), countLabel.implicitWidth + units.gu(2.5)))
85 width: Math.min(root.itemWidth, Math.max(units.gu(3), countLabel.implicitWidth + units.gu(2.5)))
84 height: units.gu(3)
86 height: units.gu(3)
@@ -105,9 +107,9 @@ Item {
105 left: iconItem.left
107 left: iconItem.left
106 right: iconItem.right
108 right: iconItem.right
107 bottom: iconItem.bottom
109 bottom: iconItem.bottom
108− leftMargin: units.gu(0.5)
110+ leftMargin: units.gu(1)
109− rightMargin: units.gu(0.5)
111+ rightMargin: units.gu(1)
110− bottomMargin: units.gu(0.5)
112+ bottomMargin: units.gu(1)
111 }
113 }
112 height: units.gu(1.5)
114 height: units.gu(1.5)
113 visible: root.progress > -1
115 visible: root.progress > -1
@@ -136,14 +138,23 @@ Item {
136 }
138 }
137 }
139 }
138 }
140 }
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+ }
139 }
150 }
140
151
141 ShaderEffect {
152 ShaderEffect {
142 id: transformEffect
153 id: transformEffect
143 anchors.centerIn: parent
154 anchors.centerIn: parent
144 anchors.verticalCenterOffset: root.offset
155 anchors.verticalCenterOffset: root.offset
145− width: parent.itemWidth
156+ width: iconItem.width
146− height: parent.itemHeight
157+ height: iconItem.height
147 property real itemOpacity: root.itemOpacity
158 property real itemOpacity: root.itemOpacity
148 property real brightness: Math.max(-1, root.brightness)
159 property real brightness: Math.max(-1, root.brightness)
149 property real angle: root.angle
160 property real angle: root.angle
Launcher/LauncherPanel.qml+12−5
@@ -34,7 +34,7 @@ Item {
34 property bool preventHiding: moving || dndArea.draggedIndex >= 0 || dndArea.quickListPopover !== null || dndArea.pressed
34 property bool preventHiding: moving || dndArea.draggedIndex >= 0 || dndArea.quickListPopover !== null || dndArea.pressed
35 property int highlightIndex: -1
35 property int highlightIndex: -1
36
36
37− signal applicationSelected(string desktopFile)
37+ signal applicationSelected(string appId)
38 signal dashItemSelected(int index)
38 signal dashItemSelected(int index)
39
39
40 BorderImage {
40 BorderImage {
@@ -50,8 +50,6 @@ Item {
50 id: mainColumn
50 id: mainColumn
51 anchors {
51 anchors {
52 fill: parent
52 fill: parent
53− leftMargin: units.gu(0.5)
54− rightMargin: units.gu(0.5)
55 }
53 }
56
54
57 MouseArea {
55 MouseArea {
@@ -94,6 +92,8 @@ Item {
94 fill: parent
92 fill: parent
95 topMargin: -extensionSize + units.gu(0.5)
93 topMargin: -extensionSize + units.gu(0.5)
96 bottomMargin: -extensionSize + units.gu(1)
94 bottomMargin: -extensionSize + units.gu(1)
95+ leftMargin: units.gu(0.5)
96+ rightMargin: units.gu(0.5)
97 }
97 }
98 topMargin: extensionSize
98 topMargin: extensionSize
99 bottomMargin: extensionSize
99 bottomMargin: extensionSize
@@ -156,6 +156,7 @@ Item {
156 iconName: model.icon
156 iconName: model.icon
157 count: model.count
157 count: model.count
158 progress: model.progress
158 progress: model.progress
159+ itemFocused: model.focused
159 inverted: root.inverted
160 inverted: root.inverted
160 z: -Math.abs(offset)
161 z: -Math.abs(offset)
161 maxAngle: 55
162 maxAngle: 55
@@ -299,7 +300,7 @@ Item {
299 } else if (clickedItem.angle < -12) {
300 } else if (clickedItem.angle < -12) {
300 launcherListView.flick(0, launcherListView.clickFlickSpeed);
301 launcherListView.flick(0, launcherListView.clickFlickSpeed);
301 } else {
302 } else {
302− root.applicationSelected(LauncherModel.get(index).desktopFile);
303+ root.applicationSelected(LauncherModel.get(index).appId);
303 }
304 }
304 return;
305 return;
305 }
306 }
@@ -310,7 +311,7 @@ Item {
310 } else if (clickedItem.angle < -30) {
311 } else if (clickedItem.angle < -30) {
311 launcherListView.flick(0, launcherListView.clickFlickSpeed);
312 launcherListView.flick(0, launcherListView.clickFlickSpeed);
312 } else {
313 } else {
313− root.applicationSelected(LauncherModel.get(index).desktopFile);
314+ root.applicationSelected(LauncherModel.get(index).appId);
314 }
315 }
315 }
316 }
316
317
@@ -512,6 +513,12 @@ Item {
512 objectName: "quickListEntry" + index
513 objectName: "quickListEntry" + index
513 text: (model.clickable ? "" : "<b>") + model.label + (model.clickable ? "" : "</b>")
514 text: (model.clickable ? "" : "<b>") + model.label + (model.clickable ? "" : "</b>")
514 highlightWhenPressed: model.clickable
515 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+
515 onClicked: {
522 onClicked: {
516 if (!model.clickable) {
523 if (!model.clickable) {
517 return;
524 return;
Launcher/graphics/focused_app_arrow@30.pngnew file

Binary file not shown.

MouseTouchAdaptor.cpp+29−12
@@ -39,24 +39,16 @@ Qt::MouseButton translateMouseButton(xcb_button_t detail)
39} // end of anonymous namespace
39} // end of anonymous namespace
40
40
41MouseTouchAdaptor::MouseTouchAdaptor()
41MouseTouchAdaptor::MouseTouchAdaptor()
42− : m_targetWindow(0)
43− , m_leftButtonIsPressed(false)
42+ : m_leftButtonIsPressed(false)
44{
43{
45 m_touchDevice = new QTouchDevice;
44 m_touchDevice = new QTouchDevice;
46 m_touchDevice->setType(QTouchDevice::TouchScreen);
45 m_touchDevice->setType(QTouchDevice::TouchScreen);
47 QWindowSystemInterface::registerTouchDevice(m_touchDevice);
46 QWindowSystemInterface::registerTouchDevice(m_touchDevice);
48}
47}
49
48
50−void MouseTouchAdaptor::setTargetWindow(QWindow *window)
51−{
52− m_targetWindow = window;
53−}
54−
55bool MouseTouchAdaptor::nativeEventFilter(const QByteArray & eventType,
49bool MouseTouchAdaptor::nativeEventFilter(const QByteArray & eventType,
56 void * message, long * /*result*/)
50 void * message, long * /*result*/)
57{
51{
58− Q_ASSERT(m_targetWindow);
59−
60 if (eventType != "xcb_generic_event_t") {
52 if (eventType != "xcb_generic_event_t") {
61 // wrong backend.
53 // wrong backend.
62 qWarning("MouseTouchAdaptor: XCB backend not in use. Adaptor inoperative!");
54 qWarning("MouseTouchAdaptor: XCB backend not in use. Adaptor inoperative!");
@@ -91,7 +83,9 @@ bool MouseTouchAdaptor::handleButtonPress(xcb_button_press_event_t *pressEvent)
91
83
92 QPoint windowPos(pressEvent->event_x, pressEvent->event_y);
84 QPoint windowPos(pressEvent->event_x, pressEvent->event_y);
93
85
86+ QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(pressEvent->event));
87+
94− QTouchEventSequence touchEvent = QTest::touchEvent(m_targetWindow, m_touchDevice,
88+ QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
95 false /* autoCommit */);
89 false /* autoCommit */);
96 touchEvent.press(0 /* touchId */, windowPos);
90 touchEvent.press(0 /* touchId */, windowPos);
97 touchEvent.commit(false /* processEvents */);
91 touchEvent.commit(false /* processEvents */);
@@ -110,7 +104,9 @@ bool MouseTouchAdaptor::handleButtonRelease(xcb_button_release_event_t *releaseE
110
104
111 QPoint windowPos(releaseEvent->event_x, releaseEvent->event_y);
105 QPoint windowPos(releaseEvent->event_x, releaseEvent->event_y);
112
106
107+ QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(releaseEvent->event));
108+
113− QTouchEventSequence touchEvent = QTest::touchEvent(m_targetWindow, m_touchDevice,
109+ QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
114 false /* autoCommit */);
110 false /* autoCommit */);
115 touchEvent.release(0 /* touchId */, windowPos);
111 touchEvent.release(0 /* touchId */, windowPos);
116 touchEvent.commit(false /* processEvents */);
112 touchEvent.commit(false /* processEvents */);
@@ -127,10 +123,31 @@ bool MouseTouchAdaptor::handleMotionNotify(xcb_motion_notify_event_t *event)
127
123
128 QPoint windowPos(event->event_x, event->event_y);
124 QPoint windowPos(event->event_x, event->event_y);
129
125
126+ QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(event->event));
127+
130− QTouchEventSequence touchEvent = QTest::touchEvent(m_targetWindow, m_touchDevice,
128+ QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
131 false /* autoCommit */);
129 false /* autoCommit */);
132 touchEvent.move(0 /* touchId */, windowPos);
130 touchEvent.move(0 /* touchId */, windowPos);
133 touchEvent.commit(false /* processEvents */);
131 touchEvent.commit(false /* processEvents */);
134
132
135 return true;
133 return true;
136}
134}
135+
136+QWindow *MouseTouchAdaptor::findQWindowWithXWindowID(WId windowId)
137+{
138+ QWindowList windowList = QGuiApplication::topLevelWindows();
139+ QWindow *foundWindow = nullptr;
140+
141+ int i = 0;
142+ while (!foundWindow && i < windowList.count()) {
143+ QWindow *window = windowList[i];
144+ if (window->winId() == windowId) {
145+ foundWindow = window;
146+ } else {
147+ ++i;
148+ }
149+ }
150+
151+ Q_ASSERT(foundWindow);
152+ return foundWindow;
153+}
MouseTouchAdaptor.h+2−5
@@ -20,11 +20,11 @@
20#define MOUSE_TOUCH_ADAPTOR_H
20#define MOUSE_TOUCH_ADAPTOR_H
21
21
22#include <QtCore/QAbstractNativeEventFilter>
22#include <QtCore/QAbstractNativeEventFilter>
23+#include <QWindow>
23#include <xcb/xcb.h>
24#include <xcb/xcb.h>
24
25
25class QMouseEvent;
26class QMouseEvent;
26class QTouchDevice;
27class QTouchDevice;
27−class QWindow;
28
28
29// Transforms QMouseEvents into single-finger QTouchEvents.
29// Transforms QMouseEvents into single-finger QTouchEvents.
30class MouseTouchAdaptor : public QAbstractNativeEventFilter {
30class MouseTouchAdaptor : public QAbstractNativeEventFilter {
@@ -32,9 +32,6 @@ class MouseTouchAdaptor : public QAbstractNativeEventFilter {
32public:
32public:
33 MouseTouchAdaptor();
33 MouseTouchAdaptor();
34
34
35− // The window that will receive the generated QTouchEvents
36− void setTargetWindow(QWindow *window);
37−
38 // Filters mouse events and posts the equivalent QTouchEvents.
35 // Filters mouse events and posts the equivalent QTouchEvents.
39 virtual bool nativeEventFilter(const QByteArray & eventType, void *message, long *result);
36 virtual bool nativeEventFilter(const QByteArray & eventType, void *message, long *result);
40
37
@@ -43,8 +40,8 @@ private:
43 bool handleButtonPress(xcb_button_press_event_t *pressEvent);
40 bool handleButtonPress(xcb_button_press_event_t *pressEvent);
44 bool handleButtonRelease(xcb_button_release_event_t *releaseEvent);
41 bool handleButtonRelease(xcb_button_release_event_t *releaseEvent);
45 bool handleMotionNotify(xcb_motion_notify_event_t *event);
42 bool handleMotionNotify(xcb_motion_notify_event_t *event);
43+ QWindow *findQWindowWithXWindowID(WId windowId);
46
44
47− QWindow *m_targetWindow;
48 QTouchDevice *m_touchDevice;
45 QTouchDevice *m_touchDevice;
49 bool m_leftButtonIsPressed;
46 bool m_leftButtonIsPressed;
50};
47};
Panel/IndicatorItem.qml+2−3
@@ -26,13 +26,12 @@ Item {
26 property bool highlighted: false
26 property bool highlighted: false
27 property bool dimmed: false
27 property bool dimmed: false
28 property var indicatorProperties: undefined
28 property var indicatorProperties: undefined
29+ property bool indicatorVisible: loader.item ? loader.item.enabled : false
29
30
30 opacity: dimmed ? 0.4 : 1
31 opacity: dimmed ? 0.4 : 1
31 Behavior on opacity { StandardAnimation {} }
32 Behavior on opacity { StandardAnimation {} }
32
33
33− // only visible when non-empty
34− visible: loader.item != undefined && loader.status == Loader.Ready ? loader.item.enabled : false
35− width: visible ? loader.item.width : 0
34+ width: loader.item ? loader.item.width : 0
36
35
37 Loader {
36 Loader {
38 id: loader
37 id: loader
Panel/IndicatorRow.qml+19−1
@@ -16,6 +16,7 @@
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19+import Unity.Indicators 0.1 as Indicators
19import "../Components"
20import "../Components"
20
21
21Item {
22Item {
@@ -25,6 +26,7 @@ Item {
25 readonly property int currentItemIndex: currentItem ? currentItem.ownIndex : -1
26 readonly property int currentItemIndex: currentItem ? currentItem.ownIndex : -1
26 property alias row: row
27 property alias row: row
27 property QtObject indicatorsModel: null
28 property QtObject indicatorsModel: null
29+ property var visibleIndicators: defined
28
30
29 width: units.gu(40)
31 width: units.gu(40)
30 height: units.gu(3)
32 height: units.gu(3)
@@ -55,7 +57,8 @@ Item {
55 Item {
57 Item {
56 id: itemWrapper
58 id: itemWrapper
57 height: indicatorRow.height
59 height: indicatorRow.height
58− width: childrenRect.width
60+ width: indicatorItem.width
61+ visible: indicatorItem.indicatorVisible
59
62
60 property int ownIndex: index
63 property int ownIndex: index
61 property alias highlighted: indicatorItem.highlighted
64 property alias highlighted: indicatorItem.highlighted
@@ -70,6 +73,21 @@ Item {
70
73
71 widgetSource: model.widgetSource
74 widgetSource: model.widgetSource
72 indicatorProperties : model.indicatorProperties
75 indicatorProperties : model.indicatorProperties
76+
77+ Component.onCompleted: {
78+ if (visibleIndicators == undefined) {
79+ visibleIndicators = {}
80+ }
81+ indicatorRow.visibleIndicators[model.identifier] = indicatorVisible;
82+ indicatorRow.visibleIndicatorsChanged();
83+ }
84+ onIndicatorVisibleChanged: {
85+ if (visibleIndicators == undefined) {
86+ visibleIndicators = {}
87+ }
88+ indicatorRow.visibleIndicators[model.identifier] = indicatorVisible;
89+ indicatorRow.visibleIndicatorsChanged();
90+ }
73 }
91 }
74
92
75 opacity: {
93 opacity: {
Panel/Indicators.qml+18−2
@@ -35,6 +35,7 @@ Showable {
35 property bool partiallyOpened: height > panelHeight && !fullyOpened
35 property bool partiallyOpened: height > panelHeight && !fullyOpened
36 property real visualBottom: Math.max(y+height, y+indicatorRow.y+indicatorRow.height)
36 property real visualBottom: Math.max(y+height, y+indicatorRow.y+indicatorRow.height)
37 property bool contentEnabled: true
37 property bool contentEnabled: true
38+ readonly property alias content: menuContent
38
39
39 // TODO: Perhaps we need a animation standard for showing/hiding? Each showable seems to
40 // TODO: Perhaps we need a animation standard for showing/hiding? Each showable seems to
40 // use its own values. Need to ask design about this.
41 // use its own values. Need to ask design about this.
@@ -180,11 +181,19 @@ Showable {
180 clip: !indicators.fullyOpened
181 clip: !indicators.fullyOpened
181 activeHeader: indicators.state == "hint" || indicators.state == "reveal"
182 activeHeader: indicators.state == "hint" || indicators.state == "reveal"
182 enabled: contentEnabled
183 enabled: contentEnabled
184+ visibleIndicators: indicatorRow.visibleIndicators
183
185
184 Connections {
186 Connections {
187+ property bool enableIndexChangeSignal: true
188+
185− target: indicatorRow
189+ target: enableIndexChangeSignal ? indicatorRow : null
186 onCurrentItemIndexChanged: {
190 onCurrentItemIndexChanged: {
191+ var oldActive = enableIndexChangeSignal;
192+ enableIndexChangeSignal = false;
193+
187 menuContent.setCurrentMenuIndex(indicatorRow.currentItemIndex);
194 menuContent.setCurrentMenuIndex(indicatorRow.currentItemIndex);
195+
196+ enableIndexChangeSignal = oldActive;
188 }
197 }
189 }
198 }
190
199
@@ -256,9 +265,16 @@ Showable {
256 state: indicators.state
265 state: indicators.state
257
266
258 Connections {
267 Connections {
268+ property bool enableIndexChangeSignal: true
269+
259− target: menuContent
270+ target: enableIndexChangeSignal ? menuContent : null
260 onCurrentMenuIndexChanged: {
271 onCurrentMenuIndexChanged: {
272+ var oldActive = enableIndexChangeSignal;
273+ enableIndexChangeSignal = false;
274+
261 indicatorRow.setCurrentItem(menuContent.currentMenuIndex);
275 indicatorRow.setCurrentItem(menuContent.currentMenuIndex);
276+
277+ enableIndexChangeSignal = oldActive;
262 }
278 }
263 }
279 }
264 }
280 }
Panel/Indicators/DatetimeIndicatorWidget.qml+4−2
@@ -25,6 +25,7 @@ Indicators.IndicatorWidget {
25 id: indicatorWidget
25 id: indicatorWidget
26
26
27 width: timeLabel.width + units.gu(1)
27 width: timeLabel.width + units.gu(1)
28+ rootMenuType: "com.canonical.indicator.root.time"
28
29
29 property alias label: timeLabel.text
30 property alias label: timeLabel.text
30
31
@@ -52,14 +53,15 @@ Indicators.IndicatorWidget {
52
53
53 onActionStateChanged: {
54 onActionStateChanged: {
54 if (action == undefined || !action.valid) {
55 if (action == undefined || !action.valid) {
56+ enabled = false;
55 return;
57 return;
56 }
58 }
57
59
58 if (action.state == undefined) {
60 if (action.state == undefined) {
59− visible = false;
61+ enabled = false;
60 return;
62 return;
61 }
63 }
62
64
63− indicatorWidget.visible = action.state[3];
65+ enabled = action.state[3];
64 }
66 }
65}
67}
Panel/Indicators/DefaultIndicatorWidget.qml+3−6
@@ -24,7 +24,8 @@ import Unity.IndicatorsLegacy 0.1 as Indicators
24Indicators.IndicatorWidget {
24Indicators.IndicatorWidget {
25 id: indicatorWidget
25 id: indicatorWidget
26
26
27+ enabled:true
27− width: itemRow.width + units.gu(1)
28+ width: itemRow.width + units.gu(0.5)
28
29
29 property alias label: itemLabel.text
30 property alias label: itemLabel.text
30 property alias iconSource: itemImage.source
31 property alias iconSource: itemImage.source
@@ -67,14 +68,10 @@ Indicators.IndicatorWidget {
67 }
68 }
68
69
69 if (action.state == undefined) {
70 if (action.state == undefined) {
70− label = "";
71− iconSource = "";
72− enabled = false;
73 return;
71 return;
74 }
72 }
75
73
76 label = action.state[Indicators.ActionState.Label];
74 label = action.state[Indicators.ActionState.Label];
77− iconSource = "image://gicon/" + action.state[Indicators.ActionState.IconSource];
75+ iconSource = "image://theme/" + action.state[Indicators.ActionState.IconSource];
78− enabled = action.state[Indicators.ActionState.Visible];
79 }
76 }
80}
77}
Panel/Indicators/DefaultIndicatorWidget2.qml+43−16
@@ -24,10 +24,11 @@ import Unity.Indicators 0.1 as Indicators
24Indicators.IndicatorWidget {
24Indicators.IndicatorWidget {
25 id: indicatorWidget
25 id: indicatorWidget
26
26
27− width: itemRow.width + units.gu(1)
27+ width: itemRow.width + units.gu(0.5)
28
28
29− property alias label: itemLabel.text
29+ property alias leftLabel: itemLeftLabel.text
30− property alias iconSource: itemImage.source
30+ property alias rightLabel: itemRightLabel.text
31+ property var icons: undefined
31
32
32 Row {
33 Row {
33 id: itemRow
34 id: itemRow
@@ -39,19 +40,43 @@ Indicators.IndicatorWidget {
39 }
40 }
40 spacing: units.gu(0.5)
41 spacing: units.gu(0.5)
41
42
42− // FIXME : Should us Ubuntu.Icon . results in low res images
43+ Label {
43− Image {
44+ id: itemLeftLabel
44− id: itemImage
45− objectName: "itemImage"
45+ objectName: "leftLabel"
46− visible: source != ""
46+ color: Theme.palette.selected.backgroundText
47− height: indicatorWidget.iconSize
47+ opacity: 0.8
48− width: indicatorWidget.iconSize
48+ font.family: "Ubuntu"
49+ fontSize: "medium"
49 anchors.verticalCenter: parent.verticalCenter
50 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+ }
50 }
75 }
51
76
52 Label {
77 Label {
53− id: itemLabel
78+ id: itemRightLabel
54− objectName: "itemLabel"
79+ objectName: "rightLabel"
55 color: Theme.palette.selected.backgroundText
80 color: Theme.palette.selected.backgroundText
56 opacity: 0.8
81 opacity: 0.8
57 font.family: "Ubuntu"
82 font.family: "Ubuntu"
@@ -63,14 +88,16 @@ Indicators.IndicatorWidget {
63
88
64 onActionStateChanged: {
89 onActionStateChanged: {
65 if (actionState == undefined) {
90 if (actionState == undefined) {
66− label = "";
91+ leftLabel = "";
67− iconSource = "";
92+ rightLabel = "";
93+ icons = undefined;
68 enabled = false;
94 enabled = false;
69 return;
95 return;
70 }
96 }
71
97
72− label = actionState.label;
98+ leftLabel = actionState.leftLabel ? actionState.leftLabel : "";
99+ rightLabel = actionState.rightLabel ? actionState.rightLabel : "";
73− iconSource = actionState.icon;
100+ icons = actionState.icons;
74 enabled = actionState.visible;
101 enabled = actionState.visible;
75 }
102 }
76}
103}
Panel/Indicators/MessagingIndicatorWidget.qml+1−1
@@ -21,5 +21,5 @@ import QtQuick 2.0
21
21
22DefaultIndicatorWidget {
22DefaultIndicatorWidget {
23 // default the icon so we have something to show when we don't have the bus.
23 // default the icon so we have something to show when we don't have the bus.
24− iconSource: "image://gicon/indicator-messages"
24+ iconSource: "image://theme/indicator-messages"
25}
25}
Panel/Indicators/NetworkIndicatorWidget.qml+10−7
@@ -24,7 +24,7 @@ import Unity.IndicatorsLegacy 0.1 as Indicators
24Indicators.IndicatorWidget {
24Indicators.IndicatorWidget {
25 id: indicatorWidget
25 id: indicatorWidget
26
26
27− width: networkIcon.width + units.gu(1)
27+ width: networkIcon.width + units.gu(0.5)
28
28
29 property int signalStrength: 0
29 property int signalStrength: 0
30 property int connectionState: Indicators.NetworkConnection.Initial
30 property int connectionState: Indicators.NetworkConnection.Initial
@@ -43,14 +43,17 @@ Indicators.IndicatorWidget {
43
43
44 onActionStateChanged: {
44 onActionStateChanged: {
45 if (action == undefined || !action.valid) {
45 if (action == undefined || !action.valid) {
46+ enabled = false;
46 return;
47 return;
47 }
48 }
48
49
49 if (action.state == undefined) {
50 if (action.state == undefined) {
51+ enabled = false;
50 connectionState = 0;
52 connectionState = 0;
51 return;
53 return;
52 }
54 }
53
55
56+ enabled = true;
54 connectionState = action.state[Indicators.NetworkActionState.Connection];
57 connectionState = action.state[Indicators.NetworkActionState.Connection];
55 if (connectionState == Indicators.NetworkConnection.Activated) {
58 if (connectionState == Indicators.NetworkConnection.Activated) {
56 signalStrength = action.state[Indicators.NetworkActionState.SignalStrength];
59 signalStrength = action.state[Indicators.NetworkActionState.SignalStrength];
@@ -94,16 +97,16 @@ Indicators.IndicatorWidget {
94 function get_icon_for_signal(con_state, value) {
97 function get_icon_for_signal(con_state, value) {
95 if (con_state >= Indicators.NetworkConnection.Activating && con_state <= Indicators.NetworkConnection.Deactivating) {
98 if (con_state >= Indicators.NetworkConnection.Activating && con_state <= Indicators.NetworkConnection.Deactivating) {
96 if (value == 0) {
99 if (value == 0) {
97− return "image://gicon/nm-signal-00";
100+ return "image://theme/nm-signal-00";
98 } else if (value <= 25) {
101 } else if (value <= 25) {
99− return "image://gicon/nm-signal-25";
102+ return "image://theme/nm-signal-25";
100 } else if (value <= 50) {
103 } else if (value <= 50) {
101− return "image://gicon/nm-signal-50";
104+ return "image://theme/nm-signal-50";
102 } else if (value <= 75) {
105 } else if (value <= 75) {
103− return "image://gicon/nm-signal-75";
106+ return "image://theme/nm-signal-75";
104 }
107 }
105− return "image://gicon/nm-signal-100";
108+ return "image://theme/nm-signal-100";
106 }
109 }
107− return "image://gicon/wifi-none";
110+ return "image://theme/wifi-none";
108 }
111 }
109}
112}
Panel/Indicators/SoundIndicatorWidget.qml+2−1
@@ -21,5 +21,6 @@ import QtQuick 2.0
21
21
22DefaultIndicatorWidget {
22DefaultIndicatorWidget {
23 // default the icon so we have something to show when we don't have the bus.
23 // default the icon so we have something to show when we don't have the bus.
24− iconSource: "image://gicon/audio-volume-high"
24+ iconSource: "image://theme/audio-volume-high"
25+ enabled: true
25}
26}
Panel/IndicatorsDataModel.qml+2−2
@@ -42,8 +42,8 @@ Indicators.IndicatorsModel {
42 'indicator-messages' : {
42 'indicator-messages' : {
43 'title': 'Messaging',
43 'title': 'Messaging',
44 'description' : '',
44 'description' : '',
45− 'widgetSource' : ApplicationPaths.shellAppDirectory()+'/Panel/Indicators/MessagingIndicatorWidget.qml',
45+ 'widgetSource' : ApplicationPaths.shellAppDirectory()+'/Panel/Indicators/DefaultIndicatorWidget2.qml',
46− 'pageSource' : ApplicationPaths.shellAppDirectory()+'/Panel/Indicators/MessagingIndicatorPage.qml'
46+ 'pageSource' : ApplicationPaths.shellAppDirectory()+'/Panel/Indicators/DefaultIndicatorPage2.qml'
47 },
47 },
48 'indicator-sound' : {
48 'indicator-sound' : {
49 'title': 'Sound',
49 'title': 'Sound',
Panel/MenuContent.qml+37−9
@@ -17,6 +17,7 @@
17import QtQuick 2.0
17import QtQuick 2.0
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19import Unity.Indicators 0.1 as Indicators
19import Unity.Indicators 0.1 as Indicators
20+import Utils 0.1
20import "../Components"
21import "../Components"
21
22
22// FIXME : We dont want to use MainView.
23// FIXME : We dont want to use MainView.
@@ -27,20 +28,23 @@ MainView {
27
28
28 property QtObject indicatorsModel: null
29 property QtObject indicatorsModel: null
29 property bool __contentActive: false
30 property bool __contentActive: false
30− readonly property int currentMenuIndex : tabs.selectedTabIndex
31+ readonly property int currentMenuIndex : filteredIndicators.mapToSource(tabs.selectedTabIndex)
31 backgroundColor: "#221e1c" // FIXME not in palette yet
32 backgroundColor: "#221e1c" // FIXME not in palette yet
32 property int contentReleaseInterval: 20000
33 property int contentReleaseInterval: 20000
33 property bool activeHeader: false
34 property bool activeHeader: false
35+ property alias visibleIndicators: visibleIndicatorsModel.visible
34
36
35 width: units.gu(40)
37 width: units.gu(40)
36 height: units.gu(42)
38 height: units.gu(42)
37
39
38 function setCurrentMenuIndex(index) {
40 function setCurrentMenuIndex(index) {
39− if (currentMenuIndex !== index) {
41+ var filteredIndex = filteredIndicators.mapFromSource(index)
40− if (currentMenuIndex == -1) {
42+
43+ if (tabs.selectedTabIndex !== filteredIndex) {
44+ if (tabs.selectedTabIndex == -1) {
41 tabs.tabBar.animate = false;
45 tabs.tabBar.animate = false;
42 }
46 }
43− tabs.selectedTabIndex = index;
47+ tabs.selectedTabIndex = filteredIndex;
44 tabs.tabBar.animate = true;
48 tabs.tabBar.animate = true;
45 }
49 }
46 }
50 }
@@ -61,6 +65,20 @@ MainView {
61 tabs.tabBar.alwaysSelectionMode = activeHeader;
65 tabs.tabBar.alwaysSelectionMode = activeHeader;
62 }
66 }
63
67
68+ SortFilterProxyModel {
69+ id: filteredIndicators
70+ model: visibleIndicatorsModel
71+ dynamicSortFilter: true
72+
73+ filterRole: Indicators.IndicatorsModelRole.IsVisible
74+ filterRegExp: RegExp("^true$")
75+ }
76+
77+ Indicators.VisibleIndicatorsModel {
78+ id: visibleIndicatorsModel
79+ model: indicatorsModel
80+ }
81+
64 Tabs {
82 Tabs {
65 id: tabs
83 id: tabs
66 objectName: "tabs"
84 objectName: "tabs"
@@ -69,8 +87,8 @@ MainView {
69
87
70 Repeater {
88 Repeater {
71 id: repeater
89 id: repeater
72− model: indicatorsModel
90+ model: filteredIndicators
73− objectName: "menus"
91+ objectName: "tabsRepeater"
74
92
75 // FIXME: This is needed because tabs dont handle repeaters well.
93 // FIXME: This is needed because tabs dont handle repeaters well.
76 // Due to the child ordering happening after child insertion.
94 // Due to the child ordering happening after child insertion.
@@ -91,7 +109,7 @@ MainView {
91 source: pageSource
109 source: pageSource
92 asynchronous: true
110 asynchronous: true
93
111
94− property bool contentActive: content.__contentActive
112+ property bool contentActive: content.__contentActive && menuActivator.content[index].active
95
113
96 onContentActiveChanged: {
114 onContentActiveChanged: {
97 if (contentActive && item) {
115 if (contentActive && item) {
@@ -114,7 +132,7 @@ MainView {
114 item[pName] = indicatorProperties[pName]
132 item[pName] = indicatorProperties[pName]
115 }
133 }
116 }
134 }
117− if (contentActive && menus.visible) {
135+ if (contentActive && tabs.visible) {
118 item.start()
136 item.start()
119 }
137 }
120 }
138 }
@@ -128,6 +146,16 @@ MainView {
128 id: contentReleaseTimer
146 id: contentReleaseTimer
129
147
130 interval: contentReleaseInterval
148 interval: contentReleaseInterval
149+ onTriggered: {
131− onTriggered: content.__contentActive = false
150+ content.__contentActive = false;
151+ menuActivator.clear();
152+ }
153+ }
154+
155+ Indicators.MenuContentActivator {
156+ id: menuActivator
157+ running: content.__contentActive
158+ baseIndex: content.currentMenuIndex
159+ count: indicatorsModel.count
132 }
160 }
133}
161}
Shell.qml+60−28
@@ -15,12 +15,15 @@
15 */
15 */
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18+import AccountsService 0.1
18import GSettings 1.0
19import GSettings 1.0
19−import Ubuntu.Application 0.1
20+import Unity.Application 0.1
20import Ubuntu.Components 0.1
21import Ubuntu.Components 0.1
21import Ubuntu.Gestures 0.1
22import Ubuntu.Gestures 0.1
23+import Unity.Launcher 0.1
22import LightDM 0.1 as LightDM
24import LightDM 0.1 as LightDM
23import Powerd 0.1
25import Powerd 0.1
26+import SessionBroadcast 0.1
24import "Dash"
27import "Dash"
25import "Greeter"
28import "Greeter"
26import "Launcher"
29import "Launcher"
@@ -63,6 +66,12 @@ FocusScope {
63
66
64 property var applicationManager: ApplicationManagerWrapper {}
67 property var applicationManager: ApplicationManagerWrapper {}
65
68
69+ Binding {
70+ target: LauncherModel
71+ property: "applicationManager"
72+ value: ApplicationManager
73+ }
74+
66 Component.onCompleted: {
75 Component.onCompleted: {
67 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
76 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
68
77
@@ -73,6 +82,11 @@ FocusScope {
73 applicationManager.unfocusCurrentApplication();
82 applicationManager.unfocusCurrentApplication();
74 }
83 }
75
84
85+ readonly property bool applicationFocused: !!applicationManager.mainStageFocusedApplication
86+ || !!applicationManager.sideStageFocusedApplication
87+ // Used for autopilot testing.
88+ readonly property string currentFocusedAppId: ApplicationManager.focusedApplicationId
89+
76 readonly property bool fullscreenMode: {
90 readonly property bool fullscreenMode: {
77 if (greeter.shown || lockscreen.shown) {
91 if (greeter.shown || lockscreen.shown) {
78 return false;
92 return false;
@@ -146,6 +160,10 @@ FocusScope {
146 }
160 }
147 }
161 }
148
162
163+ OSKController {
164+ anchors.fill: parent // as needs to know the geometry of the shell
165+ }
166+
149 VolumeControl {
167 VolumeControl {
150 id: volumeControl
168 id: volumeControl
151 }
169 }
@@ -180,6 +198,7 @@ FocusScope {
180
198
181 anchors.fill: parent
199 anchors.fill: parent
182 source: shell.background
200 source: shell.background
201+ fillMode: Image.PreserveAspectCrop
183 }
202 }
184
203
185 Rectangle {
204 Rectangle {
@@ -244,7 +263,7 @@ FocusScope {
244 property bool fullyShown: shown && x == 0 && parent.x == 0
263 property bool fullyShown: shown && x == 0 && parent.x == 0
245 property bool fullyHidden: !shown && x == width
264 property bool fullyHidden: !shown && x == width
246 available: !greeter.shown
265 available: !greeter.shown
247− hides: [launcher, panel.indicators]
266+ hides: [panel.indicators]
248 shown: false
267 shown: false
249 opacity: 1.0
268 opacity: 1.0
250 showAnimation: StandardAnimation { property: "x"; duration: 350; to: 0; easing.type: Easing.OutCubic }
269 showAnimation: StandardAnimation { property: "x"; duration: 350; to: 0; easing.type: Easing.OutCubic }
@@ -445,6 +464,8 @@ FocusScope {
445 hides: [launcher, panel.indicators, hud]
464 hides: [launcher, panel.indicators, hud]
446 shown: true
465 shown: true
447
466
467+ defaultBackground: shell.background
468+
448 y: panel.panelHeight
469 y: panel.panelHeight
449 width: parent.width
470 width: parent.width
450 height: parent.height - panel.panelHeight
471 height: parent.height - panel.panelHeight
@@ -465,6 +486,12 @@ FocusScope {
465 }
486 }
466
487
467 onUnlocked: greeter.hide()
488 onUnlocked: greeter.hide()
489+ onSelected: {
490+ // Update launcher items for new user
491+ var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
492+ AccountsService.user = user;
493+ LauncherModel.setUser(user);
494+ }
468
495
469 onLeftTeaserPressedChanged: {
496 onLeftTeaserPressedChanged: {
470 if (leftTeaserPressed) {
497 if (leftTeaserPressed) {
@@ -475,7 +502,8 @@ FocusScope {
475
502
476 InputFilterArea {
503 InputFilterArea {
477 anchors.fill: parent
504 anchors.fill: parent
478− blockInput: greeter.shown || lockscreen.shown
505+ blockInput: !applicationFocused || greeter.shown || lockscreen.shown || launcher.shown
506+ || panel.indicators.shown || hud.shown
479 }
507 }
480
508
481 Connections {
509 Connections {
@@ -487,10 +515,8 @@ FocusScope {
487
515
488 function setFocused(focused) {
516 function setFocused(focused) {
489 if (!focused) {
517 if (!focused) {
490− // FIXME: *FocusedApplication are not updated when unfocused, hence the need to check whether
491− // the stage was actually shown
492− if (mainStage.fullyShown) powerConnection.previousMainApp = applicationManager.mainStageFocusedApplication;
518+ powerConnection.previousMainApp = applicationManager.mainStageFocusedApplication;
493− if (sideStage.fullyShown) powerConnection.previousSideApp = applicationManager.sideStageFocusedApplication;
519+ powerConnection.previousSideApp = applicationManager.sideStageFocusedApplication;
494 applicationManager.unfocusCurrentApplication();
520 applicationManager.unfocusCurrentApplication();
495 } else {
521 } else {
496 if (powerConnection.previousMainApp) {
522 if (powerConnection.previousMainApp) {
@@ -523,6 +549,17 @@ FocusScope {
523 }
549 }
524 }
550 }
525
551
552+ function showHome() {
553+ greeter.hide()
554+ // Animate if moving between application and dash
555+ if (!stages.shown) {
556+ dash.setCurrentScope("home.scope", true, false)
557+ } else {
558+ dash.setCurrentScope("home.scope", false, false)
559+ }
560+ stages.hide()
561+ }
562+
526 Item {
563 Item {
527 id: overlay
564 id: overlay
528
565
@@ -541,8 +578,13 @@ FocusScope {
541 searchVisible: !greeter.shown && !lockscreen.shown
578 searchVisible: !greeter.shown && !lockscreen.shown
542
579
543 InputFilterArea {
580 InputFilterArea {
544− anchors.fill: parent
581+ anchors {
582+ top: parent.top
583+ left: parent.left
584+ right: parent.right
585+ }
586+ height: (panel.fullscreenMode) ? shell.edgeSize : panel.panelHeight
545− blockInput: panel.indicators.shown
587+ blockInput: true
546 }
588 }
547 }
589 }
548
590
@@ -562,11 +604,6 @@ FocusScope {
562 onMainStageFocusedApplicationChanged: hud.hide()
604 onMainStageFocusedApplicationChanged: hud.hide()
563 onSideStageFocusedApplicationChanged: hud.hide()
605 onSideStageFocusedApplicationChanged: hud.hide()
564 }
606 }
565−
566− InputFilterArea {
567− anchors.fill: parent
568− blockInput: hud.shown
569− }
570 }
607 }
571
608
572 Revealer {
609 Revealer {
@@ -588,9 +625,8 @@ FocusScope {
588 Bottombar {
625 Bottombar {
589 theHud: hud
626 theHud: hud
590 anchors.fill: parent
627 anchors.fill: parent
591− enabled: !panel.indicators.shown
628+ enabled: hud.available
592− applicationIsOnForeground: applicationManager.mainStageFocusedApplication
629+ applicationIsOnForeground: applicationFocused
593− || applicationManager.sideStageFocusedApplication
594 }
630 }
595
631
596 InputFilterArea {
632 InputFilterArea {
@@ -611,16 +647,7 @@ FocusScope {
611 width: parent.width
647 width: parent.width
612 dragAreaWidth: shell.edgeSize
648 dragAreaWidth: shell.edgeSize
613 available: (!greeter.shown || greeter.narrowMode) && edgeDemo.launcherEnabled
649 available: (!greeter.shown || greeter.narrowMode) && edgeDemo.launcherEnabled
614− onDashItemSelected: {
650+ onDashItemSelected: showHome()
615− greeter.hide()
616− // Animate if moving between application and dash
617− if (!stages.shown) {
618− dash.setCurrentScope("home.scope", true, false)
619− } else {
620− dash.setCurrentScope("home.scope", false, false)
621− }
622− stages.hide();
623− }
624 onDash: {
651 onDash: {
625 if (stages.shown) {
652 if (stages.shown) {
626 dash.setCurrentScope("applications.scope", true, false)
653 dash.setCurrentScope("applications.scope", true, false)
@@ -630,7 +657,7 @@ FocusScope {
630 }
657 }
631 onLauncherApplicationSelected:{
658 onLauncherApplicationSelected:{
632 greeter.hide()
659 greeter.hide()
633− shell.activateApplication(desktopFile)
660+ shell.activateApplication(appId)
634 }
661 }
635 onShownChanged: {
662 onShownChanged: {
636 if (shown) {
663 if (shown) {
@@ -728,4 +755,9 @@ FocusScope {
728 indicators: panel.indicators
755 indicators: panel.indicators
729 underlay: underlay
756 underlay: underlay
730 }
757 }
758+
759+ Connections {
760+ target: SessionBroadcast
761+ onShowHome: showHome()
762+ }
731}
763}
SideStage/SideStage.qml+1−1
@@ -15,7 +15,7 @@
15 */
15 */
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18−import Ubuntu.Application 0.1
18+import Unity.Application 0.1
19import Ubuntu.Components 0.1
19import Ubuntu.Components 0.1
20import "../Components"
20import "../Components"
21
21
build+9
@@ -57,6 +57,15 @@ mk_build_deps() {
57 [ ! -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
57 [ ! -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
58}
58}
59
59
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+
60if [ -f "/usr/bin/ninja" ] ; then
69if [ -f "/usr/bin/ninja" ] ; then
61 GENERATOR="-G Ninja"
70 GENERATOR="-G Ninja"
62 # Ninja does not need -j, it parallelizes automatically.
71 # Ninja does not need -j, it parallelizes automatically.
debian/changelog+318
@@ -1,3 +1,321 @@
1+unity8 (7.81.3+13.10.20130927.3-0ubuntu1) saucy; urgency=low
2+
3+ [ Michal Hruby ]
4+ * Correctly handle image URI scheme in results.
5+
6+ [ Michał Sawicz ]
7+ * Make SHOW_DASH and HIDE_DASH close the current preview. (LP:
8+ #1231404)
9+ * Add a LazyImage component that shows an activity spinner for long-
10+ loading images and handles aspect ratio properly.
11+ * Fix Qt 5.1 FTBFS and suppress some build warnings.
12+
13+ [ Albert Astals ]
14+ * Make sure we always have least have one column in the gridview. (LP:
15+ #1225391)
16+ * LVWPH: Make sure we always overshoot vertically. (LP: #1229851)
17+ * Remember the expanded categoryId and not the expanded index The
18+ index can change on search, and we still want to maintain it
19+ expanded in that case. (LP: #1230216)
20+ * Fix showHeader in an edge case of notShownByItsOwn Not all the tests
21+ i've added fail without the code fix, but i've added them just to be
22+ more covered . (LP: #1230187)
23+
24+ [ Diego Sarmentero ]
25+ * Handling error signal from the DownloadTracker plugin (BUG:
26+ #1229744). (LP: #1229744)
27+ * Remove "Reviews and Comments" section from Application Preview until
28+ the feature is ready (BUG: #1226632) - Detect when the keyboard is
29+ being shown to allow the user to scroll the Preview even more if
30+ necessary to interact with the components at the bottom of that
31+ preview, and don't leave those components obscured behind the
32+ keyboard (BUG: #1226638). (LP: #1226632, #1224717, #1226638)
33+
34+ [ Nick Dedekind ]
35+ * Brought messaging indicator inline with UnityMenuModel &
36+ UnityMenuAction. (LP: #1217676, #1217678)
37+
38+ [ Pawel Stolowski ]
39+ * Support canned search queries returned by Home Scope.
40+ * Cancel previous actions and previews on new activation / preview.
41+ Expose previewed data row in Preview object.
42+
43+ [ Michael Terry ]
44+ * Only enable the Bottombar when the HUD is available. (LP: #1220306)
45+ * Increase the "Skip intro" clickable area, making dismissing the edge
46+ demo intro feel more natural. (LP: #1220632)
47+
48+ [ Michael Zanetti ]
49+ * drop our CrossFadeImage in favor of the SDK one. (LP: #1227783)
50+
51+ [ Ubuntu daily release ]
52+ * Automatic snapshot from revision 358
53+
54+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Fri, 27 Sep 2013 14:13:22 +0000
55+
56+unity8 (7.81.3+13.10.20130924.2-0ubuntu1) saucy; urgency=low
57+
58+ [ Michal Hruby ]
59+ * Fix the signal prototypes on music grid renderer. (LP: #1228390)
60+
61+ [ Michael Zanetti ]
62+ * use less auto variables, align coding style, constify and Qt'ify API
63+ in AccountsService plugin.
64+
65+ [ Nick Dedekind ]
66+ * Re-enable MenuContentActivator in Indicators.
67+
68+ [ Albert Astals ]
69+ * LVWPH: Update the section header on list change events.
70+
71+ [ Pawel Stolowski ]
72+ * Check results model ptr returned by GetResultsFromCategory method
73+ from UnityCore. (LP: #1228097, #1211595)
74+
75+ [ Ubuntu daily release ]
76+ * Automatic snapshot from revision 340
77+
78+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 24 Sep 2013 14:40:01 +0000
79+
80+unity8 (7.81.3+13.10.20130919.3-0ubuntu1) saucy; urgency=low
81+
82+ [ Michal Hruby ]
83+ * Add support for music grid renderer to GenericScopeView.
84+
85+ [ Nick Dedekind ]
86+ * Fixed the removal of messaging widget due to incompatible action
87+ state. (LP: #1225017)
88+
89+ [ Christopher Lee ]
90+ * Addition of initial autopilot tests for the application lifecycle.
91+
92+ [ Lars Uebernickel ]
93+ * VolumeControl: use action of the new indicator indicator-sound
94+ recently gained an action to increase and decrease the volume. This
95+ patch makes use of that to get rid of a bus round trip (to get the
96+ current volume) and a race (when the volume gets set between
97+ fetching the current volume and setting the new volume). (LP:
98+ #1219057)
99+
100+ [ Michael Terry ]
101+ * When AccountsService.backgroundFile is unset/invalid, have the
102+ greeter fall back to whatever the shell background is.
103+ * Add a tiny SessionBroadcast plugin that listens to unity-greeter-
104+ session-broadcast for the ShowHome signal.
105+
106+ [ Daniel d'Andrada ]
107+ * Remove obsolete, unused graphics.
108+ * Make MouseTouchAdaptor work with multiple QWindows.
109+
110+ [ Michael Zanetti ]
111+ * change how icons are searched a) try to find it the Icon as is b)
112+ prepend with Path if a Path variable is given c) fall back to the
113+ image://theme/ with just the icon name . (LP: #1225186)
114+ * fix an issue with removing a running app from the launcher and
115+ always store pinning to the config.
116+ * collapse any open preview when programmatically switching current
117+ dash index. (LP: #1221137)
118+
119+ [ Ubuntu daily release ]
120+ * Automatic snapshot from revision 333
121+
122+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 19 Sep 2013 15:15:07 +0000
123+
124+unity8 (7.81.3+13.10.20130916-0ubuntu1) saucy; urgency=low
125+
126+ [ Michael Zanetti ]
127+ * allow left edge gesture to minimize apps even when launcher is
128+ already visible.
129+ * Don't hide the launcher on changes in the stages.
130+ * ssh is now installed per default, but it's set to manual in the
131+ ssh.override.
132+
133+ [ Ubuntu daily release ]
134+ * Automatic snapshot from revision 320
135+
136+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 16 Sep 2013 11:49:28 +0000
137+
138+unity8 (7.81.3+13.10.20130912-0ubuntu1) saucy; urgency=low
139+
140+ [ Michael Zanetti ]
141+ * add support for finding icons from click package apps in the
142+ launcher.
143+ * update to latest launcher API for better integration with the
144+ AppManager.
145+
146+ [ Ricardo Mendoza ]
147+ * Fixes problems related to image 20130912.0, amongst: * Fix autopilot
148+ tests by preventing blocking of input during HUD button animations,
149+ only when fully visible * Fix loading of unity-mir library, major
150+ version wasn't specified so unless the dev package was there it
151+ would fail.
152+
153+ [ Ubuntu daily release ]
154+ * Automatic snapshot from revision 316
155+
156+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 12 Sep 2013 13:47:59 +0000
157+
158+unity8 (7.81.3+13.10.20130911.1-0ubuntu1) saucy; urgency=low
159+
160+ [ Michael Terry ]
161+ * Switch from deprecated image://gicon/ to new image://theme/.
162+
163+ [ Gerry Boland ]
164+ * Add OSKController so shell can control OSK correctly on Mir.
165+ * Remove InputFilterArea for bottom edge swipes, as applications also
166+ listen for such swipes for Toolbar reveal.
167+
168+ [ Ricardo Mendoza ]
169+ * Select the backend to use dynamically on runtime according to the
170+ QPA selected by the system.
171+
172+ [ Ubuntu daily release ]
173+ * Automatic snapshot from revision 311
174+
175+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 11 Sep 2013 16:22:55 +0000
176+
177+unity8 (7.81.3+13.10.20130911-0ubuntu1) saucy; urgency=low
178+
179+ [ Michal Hruby ]
180+ * Hide all gicon strings from the shell and use the image://theme icon
181+ provider that was recently added to the SDK.
182+
183+ [ Gerry Boland ]
184+ * Convert to new ApplicationManager API.
185+
186+ [ Nick Dedekind ]
187+ * Updated access point design as per spec.
188+ * Indicator visibility based on connection with backend service.
189+
190+ [ Albert Astals ]
191+ * Dash: Make assignments bindings This way if the model changes the
192+ item value also changes.
193+
194+ [ Michael Zanetti ]
195+ * adds support for highlighting the currently focused application in
196+ the launcher, adds tests.
197+ * include ~/.local/share/applications in launcher's .desktop file
198+ search path.
199+ * shrink size of area for revealing the HUD button and make it
200+ disappear on release again. fixes 1219035. (LP: #1219035)
201+ * revert revision 304 as it makes the Shell crash.
202+
203+ [ Michael Terry ]
204+ * Allow testers to set custom password or pin in demo mode, rather
205+ than hardcoding them.
206+ * Have the greeter use AccountsService to determine its background.
207+ (LP: #1218402)
208+ * Listen to changes in the "show edge demo" AccountsService setting.
209+
210+ [ Daniel d'Andrada ]
211+ * Update fake/mock plugins so that "./run --fake" works well again -
212+ You can now see the thumbnails of the fake running applications once
213+ again. - You no longer get hundreds of warnings due to icons not
214+ found.
215+ * Reset apps scope when returning from app to dash (LP #1193419) If an
216+ app is on foreground and you perform a long left-edge swipe to
217+ minimize it, and therefore return to the dash, the dash should be in
218+ the Applications scope and showing the running/recents applications.
219+ (LP: #1193419)
220+
221+ [ Ubuntu daily release ]
222+ * Automatic snapshot from revision 306
223+
224+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 11 Sep 2013 00:54:31 +0000
225+
226+unity8 (7.81.3+13.10.20130905.2-0ubuntu1) saucy; urgency=low
227+
228+ [ Michael Zanetti ]
229+ * Integrate Launcher with AppManager.
230+
231+ [ Nick Dedekind ]
232+ * Removed FIXME from slider int->double conversion.
233+
234+ [ Ubuntu daily release ]
235+ * Automatic snapshot from revision 291
236+
237+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 05 Sep 2013 10:48:02 +0000
238+
239+unity8 (7.81.3+13.10.20130904.1-0ubuntu1) saucy; urgency=low
240+
241+ [ Nicolas d'Offay ]
242+ * Switched infographic background at design's request.
243+
244+ [ Ubuntu daily release ]
245+ * Automatic snapshot from revision 287
246+
247+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 04 Sep 2013 07:34:57 +0000
248+
249+unity8 (7.81.3+13.10.20130904-0ubuntu1) saucy; urgency=low
250+
251+ [ mhall119 ]
252+ * Add a little bit of text to the last step of the tour telling the
253+ user how to end it and get to their phone.
254+
255+ [ Jussi Pakkanen ]
256+ * Use CCache if it is installed.
257+
258+ [ Nick Dedekind ]
259+ * Multiple icon/label support for indicators.
260+
261+ [ Albert Astals ]
262+ * Remove unneeded role.
263+
264+ [ Lars Uebernickel ]
265+ * Fall back to "ubuntu-mobile" icon theme if $UBUNTU_ICON_THEME is
266+ unset.
267+
268+ [ Michael Zanetti ]
269+ * Use MouseAreas in DashBar to enable clicking again.
270+ * load launcher default config from existing dconf key.
271+
272+ [ Ubuntu daily release ]
273+ * Automatic snapshot from revision 285
274+
275+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 04 Sep 2013 03:02:57 +0000
276+
277+unity8 (7.81.3+13.10.20130903.1-0ubuntu1) saucy; urgency=low
278+
279+ [ Michael Zanetti ]
280+ * workaround quicklist text color.
281+
282+ [ Ubuntu daily release ]
283+ * Automatic snapshot from revision 277
284+
285+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 03 Sep 2013 06:09:36 +0000
286+
287+unity8 (7.81.3+13.10.20130830-0ubuntu1) saucy; urgency=low
288+
289+ [ Pawel Stolowski ]
290+ * Implement a virtual 'All' filter option.
291+
292+ [ Ubuntu daily release ]
293+ * Automatic snapshot from revision 275
294+
295+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Fri, 30 Aug 2013 12:44:40 +0000
296+
297+unity8 (7.81.3+13.10.20130829.2-0ubuntu1) saucy; urgency=low
298+
299+ [ Michael Terry ]
300+ * Implement launcher item backend via AccountsService.
301+
302+ [ Ubuntu daily release ]
303+ * Automatic snapshot from revision 272
304+
305+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 29 Aug 2013 19:09:44 +0000
306+
307+unity8 (7.81.3+13.10.20130829.1-0ubuntu1) saucy; urgency=low
308+
309+ [ Michael Terry ]
310+ * Make sure greeter and lockscreen backgrounds are always defined,
311+ even if the wallpaper preference string is bogus. (LP: #1208889,
312+ #1208894)
313+
314+ [ Ubuntu daily release ]
315+ * Automatic snapshot from revision 270
316+
317+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 29 Aug 2013 11:09:43 +0000
318+
1unity8 (7.81.3+13.10.20130829-0ubuntu1) saucy; urgency=low
319unity8 (7.81.3+13.10.20130829-0ubuntu1) saucy; urgency=low
2
320
3 [ Andrea Cimitan ]
321 [ Andrea Cimitan ]
debian/control+11−8
@@ -9,6 +9,7 @@ Build-Depends: cmake,
9 libgl1-mesa-dev[!armhf] | libgl-dev[!armhf],
9 libgl1-mesa-dev[!armhf] | libgl-dev[!armhf],
10 libgl1-mesa-dri,
10 libgl1-mesa-dri,
11 libgles2-mesa-dev[armhf],
11 libgles2-mesa-dev[armhf],
12+ libgsettings-qt-dev,
12 libhud-client2-dev,
13 libhud-client2-dev,
13 libjson-perl,
14 libjson-perl,
14 libnih-dbus-dev,
15 libnih-dbus-dev,
@@ -20,8 +21,9 @@ Build-Depends: cmake,
20 libqt5v8-5-private-dev,
21 libqt5v8-5-private-dev,
21 libsigc++-2.0-dev,
22 libsigc++-2.0-dev,
22 libunity-api-dev (>= 7.80.3),
23 libunity-api-dev (>= 7.80.3),
23− libunity-core-6.0-dev (<< 7.80),
24+ libunity-core-6.0-dev (>= 7.1.1),
24 libunity-dev (>= 7.0.12),
25 libunity-dev (>= 7.0.12),
26+ libunity-mir-dev,
25 libunity-scopes-json-def-phone,
27 libunity-scopes-json-def-phone,
26 libupstart-dev,
28 libupstart-dev,
27 libusermetricsoutput1-dev,
29 libusermetricsoutput1-dev,
@@ -53,7 +55,7 @@ Vcs-Browser: https://bazaar.launchpad.net/~unity-team/unity8/trunk
53Package: indicators-client
55Package: indicators-client
54Architecture: amd64 armhf i386
56Architecture: amd64 armhf i386
55Depends: qmenumodel-qml (>= 0.2.7),
57Depends: qmenumodel-qml (>= 0.2.7),
56− qtdeclarative5-ubuntu-ui-toolkit-plugin | qt-components-ubuntu,
58+ qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 0.1.46+13.10.20130829.1-0ubuntu1),
57 unity8 (= ${binary:Version}),
59 unity8 (= ${binary:Version}),
58 ${misc:Depends},
60 ${misc:Depends},
59 ${shlibs:Depends},
61 ${shlibs:Depends},
@@ -64,13 +66,14 @@ Package: unity8
64Architecture: any
66Architecture: any
65Provides: indicator-renderer,
67Provides: indicator-renderer,
66Depends: gsettings-desktop-schemas,
68Depends: gsettings-desktop-schemas,
69+ libunity-mir1,
67 qmenumodel-qml (>= 0.2.7),
70 qmenumodel-qml (>= 0.2.7),
68 qtdeclarative5-dee-plugin,
71 qtdeclarative5-dee-plugin,
69 qtdeclarative5-gsettings1.0,
72 qtdeclarative5-gsettings1.0,
70− qtdeclarative5-ubuntu-ui-toolkit-plugin,
73+ qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 0.1.46+13.10.20130829.1-0ubuntu1),
71 qtdeclarative5-unity-notifications-plugin | unity-notifications-impl,
74 qtdeclarative5-unity-notifications-plugin | unity-notifications-impl,
72 qtdeclarative5-xmllistmodel-plugin,
75 qtdeclarative5-xmllistmodel-plugin,
73− unity-launcher-impl-2,
76+ unity-launcher-impl-3,
74 unity-notifications-impl-1,
77 unity-notifications-impl-1,
75 unity8-fake-env | qtubuntu-shell,
78 unity8-fake-env | qtubuntu-shell,
76 unity8-private (= ${binary:Version}),
79 unity8-private (= ${binary:Version}),
@@ -86,18 +89,18 @@ Description: Unity 8 shell
86
89
87Package: unity8-autopilot
90Package: unity8-autopilot
88Architecture: all
91Architecture: all
92+Depends: gir1.2-glib-2.0,
89−Depends: indicators-client (>= ${source:Version}),
93+ indicators-client (>= ${source:Version}),
90 libautopilot-qt,
94 libautopilot-qt,
91 libqt5test5,
95 libqt5test5,
92 libqt5widgets5,
96 libqt5widgets5,
93 python-evdev,
97 python-evdev,
98+ python-gi,
94 unity8 (>= ${source:Version}),
99 unity8 (>= ${source:Version}),
95 unity8-fake-env (>= ${source:Version}),
100 unity8-fake-env (>= ${source:Version}),
96 ${misc:Depends},
101 ${misc:Depends},
97 ${python:Depends},
102 ${python:Depends},
98 ${shlibs:Depends},
103 ${shlibs:Depends},
99−Recommends: gir1.2-glib-2.0,
100− python-gi,
101Description: Test package for Unity 8 shell
104Description: Test package for Unity 8 shell
102 Autopilot tests for the unity8 package
105 Autopilot tests for the unity8 package
103
106
@@ -119,7 +122,7 @@ Pre-Depends: ${misc:Pre-Depends},
119Depends: ${misc:Depends},
122Depends: ${misc:Depends},
120 ${shlibs:Depends},
123 ${shlibs:Depends},
121Provides: unity-launcher-impl,
124Provides: unity-launcher-impl,
122− unity-launcher-impl-2,
125+ unity-launcher-impl-3,
123Description: Unity 8 private libs
126Description: Unity 8 private libs
124 The Unity 8 shell is the primary user interface for Ubuntu devices.
127 The Unity 8 shell is the primary user interface for Ubuntu devices.
125 .
128 .
debian/unity8-private.install+1
@@ -3,6 +3,7 @@ usr/lib/*/unity8/qml/HudClient
3usr/lib/*/unity8/qml/LightDM
3usr/lib/*/unity8/qml/LightDM
4usr/lib/*/unity8/qml/ListViewWithPageHeader
4usr/lib/*/unity8/qml/ListViewWithPageHeader
5usr/lib/*/unity8/qml/Powerd
5usr/lib/*/unity8/qml/Powerd
6+usr/lib/*/unity8/qml/SessionBroadcast
6usr/lib/*/unity8/qml/Ubuntu
7usr/lib/*/unity8/qml/Ubuntu
7usr/lib/*/unity8/qml/Unity
8usr/lib/*/unity8/qml/Unity
8usr/lib/*/unity8/qml/Utils
9usr/lib/*/unity8/qml/Utils
debian/unity8.install−1
@@ -13,4 +13,3 @@ usr/share/unity8/Panel
13usr/share/unity8/Shell.qml
13usr/share/unity8/Shell.qml
14usr/share/unity8/SideStage
14usr/share/unity8/SideStage
15usr/share/unity8/graphics
15usr/share/unity8/graphics
16−usr/share/unity8/unity/indicators/*
main.cpp+76−9
@@ -25,13 +25,17 @@
25#include <QtQml/QQmlContext>
25#include <QtQml/QQmlContext>
26#include <qpa/qplatformnativeinterface.h>
26#include <qpa/qplatformnativeinterface.h>
27#include <QLibrary>
27#include <QLibrary>
28+#include <QDebug>
28#include <libintl.h>
29#include <libintl.h>
30+#include <dlfcn.h>
29
31
30// local
32// local
31#include "paths.h"
33#include "paths.h"
32#include "MouseTouchAdaptor.h"
34#include "MouseTouchAdaptor.h"
33#include "ApplicationArguments.h"
35#include "ApplicationArguments.h"
34
36
37+#include <unity-mir/qmirserver.h>
38+
35namespace {
39namespace {
36
40
37void prependImportPaths(QQmlEngine *engine, const QStringList &paths)
41void prependImportPaths(QQmlEngine *engine, const QStringList &paths)
@@ -65,13 +69,14 @@ void appendImportPaths(QQmlEngine *engine, const QStringList &paths)
65
69
66void resolveIconTheme() {
70void resolveIconTheme() {
67 const char *ubuntuIconTheme = getenv("UBUNTU_ICON_THEME");
71 const char *ubuntuIconTheme = getenv("UBUNTU_ICON_THEME");
68− if (ubuntuIconTheme != NULL) {
72+ if (ubuntuIconTheme == NULL) {
69− QIcon::setThemeName(ubuntuIconTheme);
73+ ubuntuIconTheme = "ubuntu-mobile";
70 }
74 }
75+ QIcon::setThemeName(ubuntuIconTheme);
71}
76}
72} // namespace {
77} // namespace {
73
78
74−int main(int argc, char** argv)
79+int startShell(int argc, const char** argv, void* server)
75{
80{
76 /* Workaround Qt platform integration plugin not advertising itself
81 /* Workaround Qt platform integration plugin not advertising itself
77 as having the following capabilities:
82 as having the following capabilities:
@@ -81,12 +86,29 @@ int main(int argc, char** argv)
81 setenv("QML_FORCE_THREADED_RENDERER", "1", 1);
86 setenv("QML_FORCE_THREADED_RENDERER", "1", 1);
82 setenv("QML_FIXED_ANIMATION_STEP", "1", 1);
87 setenv("QML_FIXED_ANIMATION_STEP", "1", 1);
83
88
89+ const bool isUbuntuMirServer = qgetenv("QT_QPA_PLATFORM") == "ubuntumirserver";
90+
84 QGuiApplication::setApplicationName("Unity 8");
91 QGuiApplication::setApplicationName("Unity 8");
85− QGuiApplication application(argc, argv);
92+ QGuiApplication *application;
93+ if (isUbuntuMirServer) {
94+ QLibrary unityMir("unity-mir", 1);
95+ unityMir.load();
96+
97+ typedef QGuiApplication* (*createServerApplication_t)(int&, const char **, void*);
98+ createServerApplication_t createQMirServerApplication = (createServerApplication_t) unityMir.resolve("createQMirServerApplication");
99+ if (!createQMirServerApplication) {
100+ qDebug() << "unable to resolve symbol: createQMirServerApplication";
101+ return 4;
102+ }
103+
104+ application = createQMirServerApplication(argc, argv, server);
105+ } else {
106+ application = new QGuiApplication(argc, (char**)argv);
107+ }
86
108
87 resolveIconTheme();
109 resolveIconTheme();
88
110
89− QStringList args = application.arguments();
111+ QStringList args = application->arguments();
90 ApplicationArguments qmlArgs(args);
112 ApplicationArguments qmlArgs(args);
91
113
92 // The testability driver is only loaded by QApplication but not by QGuiApplication.
114 // The testability driver is only loaded by QApplication but not by QGuiApplication.
@@ -122,8 +144,7 @@ int main(int argc, char** argv)
122 MouseTouchAdaptor *mouseTouchAdaptor = 0;
144 MouseTouchAdaptor *mouseTouchAdaptor = 0;
123 if (args.contains(QLatin1String("-mousetouch"))) {
145 if (args.contains(QLatin1String("-mousetouch"))) {
124 mouseTouchAdaptor = new MouseTouchAdaptor;
146 mouseTouchAdaptor = new MouseTouchAdaptor;
125− mouseTouchAdaptor->setTargetWindow(view);
126− application.installNativeEventFilter(mouseTouchAdaptor);
147+ application->installNativeEventFilter(mouseTouchAdaptor);
127 }
148 }
128
149
129 QPlatformNativeInterface* nativeInterface = QGuiApplication::platformNativeInterface();
150 QPlatformNativeInterface* nativeInterface = QGuiApplication::platformNativeInterface();
@@ -138,18 +159,64 @@ int main(int argc, char** argv)
138 QUrl source("Shell.qml");
159 QUrl source("Shell.qml");
139 prependImportPaths(view->engine(), ::overrideImportPaths());
160 prependImportPaths(view->engine(), ::overrideImportPaths());
140 appendImportPaths(view->engine(), ::fallbackImportPaths());
161 appendImportPaths(view->engine(), ::fallbackImportPaths());
162+
163+ QStringList importPath = view->engine()->importPathList().filter("qt5/imports");
164+ if (isUbuntuMirServer) {
165+ importPath.first().append("/Unity-Mir");
166+ view->engine()->addImportPath(importPath.first());
167+ }
168+
141 view->setSource(source);
169 view->setSource(source);
142 view->setColor("transparent");
170 view->setColor("transparent");
143
171
144− if (qgetenv("QT_QPA_PLATFORM") == "ubuntu" || args.contains(QLatin1String("-fullscreen"))) {
172+ if (qgetenv("QT_QPA_PLATFORM") == "ubuntu" || isUbuntuMirServer || args.contains(QLatin1String("-fullscreen"))) {
145 view->showFullScreen();
173 view->showFullScreen();
146 } else {
174 } else {
147 view->show();
175 view->show();
148 }
176 }
149
177
150− int result = application.exec();
178+ int result = application->exec();
151
179
152 delete mouseTouchAdaptor;
180 delete mouseTouchAdaptor;
181+ delete application;
153
182
154 return result;
183 return result;
155}
184}
185+
186+int main(int argc, const char *argv[])
187+{
188+ // For ubuntumirserver/ubuntumirclient
189+ if (qgetenv("QT_QPA_PLATFORM").startsWith("ubuntumir")) {
190+ setenv("QT_QPA_PLATFORM", "ubuntumirserver", 1);
191+
192+ // If we use unity-mir directly, we automatically link to the Mir-server
193+ // platform-api bindings, which result in unexpected behaviour when
194+ // running the non-Mir scenario.
195+ QLibrary unityMir("unity-mir", 1);
196+ unityMir.load();
197+ if (!unityMir.isLoaded()) {
198+ qDebug() << "Library unity-mir not found/loaded";
199+ return 1;
200+ }
201+
202+ typedef QMirServer* (*createServer_t)(int, const char **);
203+ createServer_t createQMirServer = (createServer_t) unityMir.resolve("createQMirServer");
204+ if (!createQMirServer) {
205+ qDebug() << "unable to resolve symbol: createQMirServer";
206+ return 2;
207+ }
208+
209+ QMirServer* mirServer = createQMirServer(argc, argv);
210+
211+ typedef int (*runWithClient_t)(QMirServer*, std::function<int(int, const char**, void*)>);
212+ runWithClient_t runWithClient = (runWithClient_t) unityMir.resolve("runQMirServerWithClient");
213+ if (!runWithClient) {
214+ qDebug() << "unable to resolve symbol: runWithClient";
215+ return 3;
216+ }
217+
218+ return runWithClient(mirServer, startShell);
219+ } else {
220+ return startShell(argc, argv, nullptr);
221+ }
222+}
plugins/AccountsService/AccountsService.cpp+67−37
@@ -17,58 +17,88 @@
17 */
17 */
18
18
19#include "AccountsService.h"
19#include "AccountsService.h"
20−#include <QDBusConnection>
20+#include "AccountsServiceDBusAdaptor.h"
21−#include <QDBusConnectionInterface>
21+
22−#include <QDBusMessage>
22+#include <QStringList>
23−#include <QDBusVariant>
24
23
25AccountsService::AccountsService(QObject* parent)
24AccountsService::AccountsService(QObject* parent)
26 : QObject(parent),
25 : QObject(parent),
27− accounts_manager(NULL),
26+ m_service(new AccountsServiceDBusAdaptor(this)),
28− users()
27+ m_user(qgetenv("USER"))
29{
28{
30− auto connection = QDBusConnection::SM_BUSNAME();
29+ connect(m_service, SIGNAL(propertiesChanged(const QString &, const QString &, const QStringList &)),
31− auto interface = connection.interface();
30+ this, SLOT(propertiesChanged(const QString &, const QString &, const QStringList &)));
32− interface->startService("org.freedesktop.Accounts");
31+ connect(m_service, SIGNAL(maybeChanged(const QString &)),
33− accounts_manager = new QDBusInterface("org.freedesktop.Accounts",
32+ this, SLOT(maybeChanged(const QString &)));
34− "/org/freedesktop/Accounts",
35− "org.freedesktop.Accounts",
36− connection, this);
37}
33}
38
34
39−QVariant AccountsService::getUserProperty(const QString &user, const QString &property)
35+QString AccountsService::user() const
40{
36{
41− auto iface = getUserInterface(user);
37+ return m_user;
42− if (iface != nullptr && iface->isValid()) {
38+}
43− auto answer = iface->call("Get", "com.canonical.unity.AccountsService", property);
39+
44− if (answer.type() == QDBusMessage::ReplyMessage) {
40+void AccountsService::setUser(const QString &user)
45− return answer.arguments()[0].value<QDBusVariant>().variant();
41+{
46− }
42+ m_user = user;
43+ Q_EMIT userChanged();
44+
45+ updateDemoEdges();
46+ updateBackgroundFile();
47+}
48+
49+bool AccountsService::demoEdges() const
50+{
51+ return m_demoEdges;
52+}
53+
54+void AccountsService::setDemoEdges(bool demoEdges)
55+{
56+ m_demoEdges = demoEdges;
57+ m_service->setUserProperty(m_user, "com.canonical.unity.AccountsService", "demo-edges", demoEdges);
58+}
59+
60+QString AccountsService::backgroundFile() const
61+{
62+ return m_backgroundFile;
63+}
64+
65+void AccountsService::updateDemoEdges()
66+{
67+ auto demoEdges = m_service->getUserProperty(m_user, "com.canonical.unity.AccountsService", "demo-edges").toBool();
68+ if (m_demoEdges != demoEdges) {
69+ m_demoEdges = demoEdges;
70+ Q_EMIT demoEdgesChanged();
47 }
71 }
48− return QVariant();
49}
72}
50
73
51−void AccountsService::setUserProperty(const QString &user, const QString &property, const QVariant &value)
74+void AccountsService::updateBackgroundFile()
52{
75{
53− auto iface = getUserInterface(user);
76+ auto backgroundFile = m_service->getUserProperty(m_user, "org.freedesktop.Accounts.User", "BackgroundFile").toString();
54− if (iface != nullptr && iface->isValid()) {
77+ if (m_backgroundFile != backgroundFile) {
55− // The value needs to be carefully wrapped
78+ m_backgroundFile = backgroundFile;
56− iface->call("Set", "com.canonical.unity.AccountsService", property, QVariant::fromValue(QDBusVariant(value)));
79+ Q_EMIT backgroundFileChanged();
57 }
80 }
58}
81}
59
82
60−QDBusInterface *AccountsService::getUserInterface(const QString &user)
83+void AccountsService::propertiesChanged(const QString &user, const QString &interface, const QStringList &changed)
61{
84{
62− auto iface = users.value(user);
85+ if (m_user != user) {
63− if (iface == nullptr && accounts_manager->isValid()) {
86+ return;
64− auto answer = accounts_manager->call("FindUserByName", user);
87+ }
65− if (answer.type() == QDBusMessage::ReplyMessage) {
88+
66− iface = new QDBusInterface("org.freedesktop.Accounts",
89+ if (interface == "com.canonical.unity.AccountsService") {
67− answer.arguments()[0].value<QDBusObjectPath>().path(),
90+ if (changed.contains("demo-edges")) {
68− "org.freedesktop.DBus.Properties",
91+ updateDemoEdges();
69− accounts_manager->connection(), this);
70− users.insert(user, iface);
71 }
92 }
72 }
93 }
94+}
95+
96+void AccountsService::maybeChanged(const QString &user)
97+{
98+ if (m_user != user) {
73− return iface;
99+ return;
100+ }
101+
102+ // Standard properties might have changed
103+ updateBackgroundFile();
74}
104}
plugins/AccountsService/AccountsService.h+34−8
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2012,2013 Canonical, Ltd.
2+ * Copyright (C) 2013 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -19,26 +19,52 @@
19#ifndef UNITY_ACCOUNTSSERVICE_H
19#ifndef UNITY_ACCOUNTSSERVICE_H
20#define UNITY_ACCOUNTSSERVICE_H
20#define UNITY_ACCOUNTSSERVICE_H
21
21
22−#include <QDBusInterface>
23−#include <QMap>
24#include <QObject>
22#include <QObject>
25#include <QString>
23#include <QString>
26
24
25+class AccountsServiceDBusAdaptor;
26+
27class AccountsService: public QObject
27class AccountsService: public QObject
28{
28{
29 Q_OBJECT
29 Q_OBJECT
30+ Q_PROPERTY (QString user
31+ READ user
32+ WRITE setUser
33+ NOTIFY userChanged)
34+ Q_PROPERTY (bool demoEdges
35+ READ demoEdges
36+ WRITE setDemoEdges
37+ NOTIFY demoEdgesChanged)
38+ Q_PROPERTY (QString backgroundFile
39+ READ backgroundFile
40+ NOTIFY backgroundFileChanged)
30
41
31public:
42public:
32 explicit AccountsService(QObject *parent = 0);
43 explicit AccountsService(QObject *parent = 0);
33
44
34− Q_INVOKABLE QVariant getUserProperty(const QString &user, const QString &property);
45+ QString user() const;
46+ void setUser(const QString &user);
47+ bool demoEdges() const;
48+ void setDemoEdges(bool demoEdges);
49+ QString backgroundFile() const;
50+
51+Q_SIGNALS:
52+ void userChanged();
53+ void demoEdgesChanged();
54+ void backgroundFileChanged();
55+
56+private Q_SLOTS:
35− Q_INVOKABLE void setUserProperty(const QString &user, const QString &property, const QVariant &value);
57+ void propertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
58+ void maybeChanged(const QString &user);
36
59
37private:
60private:
38− QDBusInterface *getUserInterface(const QString &user);
61+ void updateDemoEdges();
62+ void updateBackgroundFile();
39
63
40− QDBusInterface *accounts_manager;
64+ AccountsServiceDBusAdaptor *m_service;
41− QMap<QString, QDBusInterface *> users;
65+ QString m_user;
66+ bool m_demoEdges;
67+ QString m_backgroundFile;
42};
68};
43
69
44#endif
70#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+ m_accountsManager(NULL),
28+ m_users()
29+{
30+ QDBusConnection connection = QDBusConnection::SM_BUSNAME();
31+ QDBusConnectionInterface *interface = connection.interface();
32+ interface->startService("org.freedesktop.Accounts");
33+ m_accountsManager = 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+ QDBusInterface *iface = getUserInterface(user);
42+ if (iface != nullptr && iface->isValid()) {
43+ QDBusMessage 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+ QDBusInterface *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 = m_users.constBegin(); i != m_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+ QDBusInterface *iface = m_users.value(user);
90+ if (iface == nullptr && m_accountsManager->isValid()) {
91+ QDBusMessage answer = m_accountsManager->call("FindUserByName", user);
92+ if (answer.type() == QDBusMessage::ReplyMessage) {
93+ QString path = answer.arguments()[0].value<QDBusObjectPath>().path();
94+
95+ iface = new QDBusInterface("org.freedesktop.Accounts",
96+ path,
97+ "org.freedesktop.DBus.Properties",
98+ m_accountsManager->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+ m_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 *m_accountsManager;
51+ QMap<QString, QDBusInterface *> m_users;
52+};
53+
54+#endif
plugins/AccountsService/CMakeLists.txt+1
@@ -4,6 +4,7 @@ add_definitions(-DSM_BUSNAME=systemBus)
4
4
5add_library(AccountsService-qml MODULE
5add_library(AccountsService-qml MODULE
6 AccountsService.cpp
6 AccountsService.cpp
7+ AccountsServiceDBusAdaptor.cpp
7 plugin.cpp
8 plugin.cpp
8 )
9 )
9
10
plugins/AccountsService/com.canonical.unity.AccountsService.xml+7
@@ -6,6 +6,9 @@
6 <annotation name="org.freedesktop.Accounts.Authentication.ChangeOwn"
6 <annotation name="org.freedesktop.Accounts.Authentication.ChangeOwn"
7 value="com.canonical.unity.AccountsService.ModifyOwnUser"/>
7 value="com.canonical.unity.AccountsService.ModifyOwnUser"/>
8
8
9+ <annotation name="org.freedesktop.Accounts.Authentication.ReadAny"
10+ value="com.canonical.unity.AccountsService.ModifyAnyUser"/>
11+
9 <annotation name="org.freedesktop.Accounts.Authentication.ChangeAny"
12 <annotation name="org.freedesktop.Accounts.Authentication.ChangeAny"
10 value="com.canonical.unity.AccountsService.ModifyAnyUser"/>
13 value="com.canonical.unity.AccountsService.ModifyAnyUser"/>
11
14
@@ -13,5 +16,9 @@
13 <annotation name="org.freedesktop.Accounts.DefaultValue" value="true"/>
16 <annotation name="org.freedesktop.Accounts.DefaultValue" value="true"/>
14 </property>
17 </property>
15
18
19+ <property name="launcher-items" type="aa{sv}" access="readwrite">
20+ <annotation name="org.freedesktop.Accounts.DefaultValue" value="[{'defaults': <true>}]"/>
21+ </property>
22+
16 </interface>
23 </interface>
17</node>
24</node>
plugins/AccountsService/plugin.cpp+2
@@ -19,6 +19,7 @@
19#include "plugin.h"
19#include "plugin.h"
20#include "AccountsService.h"
20#include "AccountsService.h"
21
21
22+#include <QDBusMetaType>
22#include <QtQml>
23#include <QtQml>
23
24
24static QObject *service_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
25static QObject *service_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
@@ -31,5 +32,6 @@ static QObject *service_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
31void AccountsServicePlugin::registerTypes(const char *uri)
32void AccountsServicePlugin::registerTypes(const char *uri)
32{
33{
33 Q_ASSERT(uri == QLatin1String("AccountsService"));
34 Q_ASSERT(uri == QLatin1String("AccountsService"));
35+ qDBusRegisterMetaType<QList<QVariantMap>>();
34 qmlRegisterSingletonType<AccountsService>(uri, 0, 1, "AccountsService", service_provider);
36 qmlRegisterSingletonType<AccountsService>(uri, 0, 1, "AccountsService", service_provider);
35}
37}
plugins/CMakeLists.txt+1
@@ -3,6 +3,7 @@ add_subdirectory(HudClient)
3add_subdirectory(LightDM)
3add_subdirectory(LightDM)
4add_subdirectory(ListViewWithPageHeader)
4add_subdirectory(ListViewWithPageHeader)
5add_subdirectory(Powerd)
5add_subdirectory(Powerd)
6+add_subdirectory(SessionBroadcast)
6add_subdirectory(Ubuntu)
7add_subdirectory(Ubuntu)
7add_subdirectory(Unity)
8add_subdirectory(Unity)
8add_subdirectory(Utils)
9add_subdirectory(Utils)
plugins/ListViewWithPageHeader/listviewwithpageheader.cpp+20−1
@@ -170,6 +170,8 @@ ListViewWithPageHeader::ListViewWithPageHeader()
170 connect(this, SIGNAL(contentHeightChanged()), this, SLOT(onContentHeightChanged()));
170 connect(this, SIGNAL(contentHeightChanged()), this, SLOT(onContentHeightChanged()));
171 connect(this, SIGNAL(heightChanged()), this, SLOT(onHeightChanged()));
171 connect(this, SIGNAL(heightChanged()), this, SLOT(onHeightChanged()));
172 connect(m_contentYAnimation, SIGNAL(stopped()), this, SLOT(onShowHeaderAnimationFinished()));
172 connect(m_contentYAnimation, SIGNAL(stopped()), this, SLOT(onShowHeaderAnimationFinished()));
173+
174+ setFlickableDirection(VerticalFlick);
173}
175}
174
176
175ListViewWithPageHeader::~ListViewWithPageHeader()
177ListViewWithPageHeader::~ListViewWithPageHeader()
@@ -199,6 +201,7 @@ void ListViewWithPageHeader::setModel(QAbstractItemModel *model)
199 connect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
201 connect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
200#endif
202#endif
201 Q_EMIT modelChanged();
203 Q_EMIT modelChanged();
204+ polish();
202 // TODO?
205 // TODO?
203// Q_EMIT contentHeightChanged();
206// Q_EMIT contentHeightChanged();
204// Q_EMIT contentYChanged();
207// Q_EMIT contentYChanged();
@@ -482,7 +485,7 @@ void ListViewWithPageHeader::viewportMoved(Qt::Orientations orient)
482 // or the header is partially shown and we are not doing a maximizeVisibleArea either
485 // or the header is partially shown and we are not doing a maximizeVisibleArea either
483 const bool scrolledUp = m_previousContentY > contentY();
486 const bool scrolledUp = m_previousContentY > contentY();
484 const bool notRebounding = contentY() + height() < contentHeight();
487 const bool notRebounding = contentY() + height() < contentHeight();
485− const bool notShownByItsOwn = contentY() + diff > m_headerItem->y() + m_headerItem->height();
488+ const bool notShownByItsOwn = contentY() + diff >= m_headerItem->y() + m_headerItem->height();
486 const bool maximizeVisibleAreaRunning = m_contentYAnimation->isRunning() && contentYAnimationType == ContentYAnimationMaximizeVisibleArea;
489 const bool maximizeVisibleAreaRunning = m_contentYAnimation->isRunning() && contentYAnimationType == ContentYAnimationMaximizeVisibleArea;
487
490
488 if (!scrolledUp && contentY() == -m_minYExtent) {
491 if (!scrolledUp && contentY() == -m_minYExtent) {
@@ -1006,6 +1009,22 @@ void ListViewWithPageHeader::onModelUpdated(const QQmlChangeSet &changeSet, bool
1006 }
1009 }
1007 }
1010 }
1008
1011
1012+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
1013+ Q_FOREACH(const QQuickChangeSet::Change &change, changeSet.changes()) {
1014+#else
1015+ Q_FOREACH(const QQmlChangeSet::Change &change, changeSet.changes()) {
1016+#endif
1017+// qDebug() << "ListViewWithPageHeader::onModelUpdated Change" << change.index << change.count;
1018+ for (int i = change.index; i < change.count; ++i) {
1019+ ListItem *item = itemAtIndex(i);
1020+ if (item && item->m_sectionItem) {
1021+ QQmlContext *context = QQmlEngine::contextForObject(item->m_sectionItem)->parentContext();
1022+ const QString sectionText = m_delegateModel->stringValue(i, m_sectionProperty);
1023+ context->setContextProperty(QLatin1String("section"), sectionText);
1024+ }
1025+ }
1026+ }
1027+
1009 if (m_firstVisibleIndex != oldFirstVisibleIndex) {
1028 if (m_firstVisibleIndex != oldFirstVisibleIndex) {
1010 adjustMinYExtent();
1029 adjustMinYExtent();
1011 }
1030 }
plugins/ListViewWithPageHeader/listviewwithpageheader.h+1
@@ -63,6 +63,7 @@ class ListViewWithPageHeader : public QQuickFlickable, public QQuickItemChangeLi
63
63
64 friend class ListViewWithPageHeaderTest;
64 friend class ListViewWithPageHeaderTest;
65 friend class ListViewWithPageHeaderTestSection;
65 friend class ListViewWithPageHeaderTestSection;
66+ friend class ListViewWithPageHeaderTestExternalModel;
66
67
67public:
68public:
68 ListViewWithPageHeader();
69 ListViewWithPageHeader();
plugins/SessionBroadcast/CMakeLists.txtnew file+13
@@ -0,0 +1,13 @@
1+include(Plugins)
2+
3+add_definitions(-DSM_BUSNAME=systemBus)
4+
5+add_library(SessionBroadcast-qml MODULE
6+ SessionBroadcast.cpp
7+ plugin.cpp
8+ )
9+
10+qt5_use_modules(SessionBroadcast-qml DBus Qml)
11+
12+export_qmlfiles(SessionBroadcast SessionBroadcast)
13+export_qmlplugin(SessionBroadcast 0.1 SessionBroadcast TARGETS SessionBroadcast-qml)
plugins/SessionBroadcast/SessionBroadcast.cppnew file+41
@@ -0,0 +1,41 @@
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 "SessionBroadcast.h"
20+#include <QDBusConnection>
21+
22+SessionBroadcast::SessionBroadcast(QObject* parent)
23+ : QObject(parent)
24+{
25+ auto connection = QDBusConnection::SM_BUSNAME();
26+
27+ connection.connect("com.canonical.Unity.Greeter.Broadcast",
28+ "/com/canonical/Unity/Greeter/Broadcast",
29+ "com.canonical.Unity.Greeter.Broadcast",
30+ "ShowHome",
31+ this,
32+ SLOT(onShowHome(const QString &)));
33+}
34+
35+void SessionBroadcast::onShowHome(const QString &username)
36+{
37+ // Only listen to requests meant for us
38+ if (username == qgetenv("USER")) {
39+ Q_EMIT showHome();
40+ }
41+}
plugins/SessionBroadcast/SessionBroadcast.hnew file+41
@@ -0,0 +1,41 @@
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_SESSIONBROADCAST_H
20+#define UNITY_SESSIONBROADCAST_H
21+
22+#include <QObject>
23+#include <QString>
24+
25+class QDBusInterface;
26+
27+class SessionBroadcast: public QObject
28+{
29+ Q_OBJECT
30+
31+public:
32+ explicit SessionBroadcast(QObject *parent = 0);
33+
34+Q_SIGNALS:
35+ void showHome();
36+
37+private Q_SLOTS:
38+ void onShowHome(const QString &username);
39+};
40+
41+#endif
plugins/SessionBroadcast/plugin.cppnew file+35
@@ -0,0 +1,35 @@
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+#include "plugin.h"
20+#include "SessionBroadcast.h"
21+
22+#include <QtQml>
23+
24+static QObject *broadcast_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
25+{
26+ Q_UNUSED(engine)
27+ Q_UNUSED(scriptEngine)
28+ return new SessionBroadcast();
29+}
30+
31+void SessionBroadcastPlugin::registerTypes(const char *uri)
32+{
33+ Q_ASSERT(uri == QLatin1String("SessionBroadcast"));
34+ qmlRegisterSingletonType<SessionBroadcast>(uri, 0, 1, "SessionBroadcast", broadcast_provider);
35+}
plugins/SessionBroadcast/plugin.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+ * Authors: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#ifndef UNITY_SESSIONBROADCAST_PLUGIN_H
20+#define UNITY_SESSIONBROADCAST_PLUGIN_H
21+
22+#include <QQmlExtensionPlugin>
23+
24+class SessionBroadcastPlugin : public QQmlExtensionPlugin
25+{
26+ Q_OBJECT
27+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28+
29+public:
30+ void registerTypes(const char *uri);
31+};
32+
33+#endif
plugins/SessionBroadcast/qmldirnew file+3
@@ -0,0 +1,3 @@
1+module SessionBroadcast
2+plugin SessionBroadcast-qml
3+typeinfo plugin.qmltypes
plugins/Unity/CMakeLists.txt+3
@@ -43,9 +43,12 @@ set(QMLPLUGIN_SRC
43 preview.cpp
43 preview.cpp
44 previewaction.cpp
44 previewaction.cpp
45 previewinfohint.cpp
45 previewinfohint.cpp
46+ result.cpp
47+ showallfilteroption.cpp
46 signalslist.cpp
48 signalslist.cpp
47 socialpreview.cpp
49 socialpreview.cpp
48 socialpreviewcomment.cpp
50 socialpreviewcomment.cpp
51+ iconutils.cpp
49 variantutils.cpp
52 variantutils.cpp
50)
53)
51
54
plugins/Unity/Indicators/CMakeLists.txt+10
@@ -12,6 +12,7 @@ find_package(Qt5Core REQUIRED)
12find_package(Qt5Quick REQUIRED)
12find_package(Qt5Quick REQUIRED)
13
13
14add_subdirectory(qml)
14add_subdirectory(qml)
15+add_subdirectory(Messaging)
15add_subdirectory(Network)
16add_subdirectory(Network)
16
17
17include_directories(
18include_directories(
@@ -34,11 +35,20 @@ set(IndicatorsQML_SOURCES
34 rootactionstate.cpp
35 rootactionstate.cpp
35 unitymenumodelcache.cpp
36 unitymenumodelcache.cpp
36 unitymenumodelstack.cpp
37 unitymenumodelstack.cpp
38+ visibleindicatorsmodel.cpp
37)
39)
38add_definitions(-DUNITYINDICATORS_LIBRARY)
40add_definitions(-DUNITYINDICATORS_LIBRARY)
39
41
42+set(IndicatorsQML_RESOURCES
43+ resources/indicators.qrc
44+)
45+
46+qt5_add_resources(IndicatorsQML_RESOURCES_RCC
47+ ${IndicatorsQML_RESOURCES}
48+)
40
49
41add_library(IndicatorsQml SHARED
50add_library(IndicatorsQml SHARED
51+ ${IndicatorsQML_RESOURCES_RCC}
42 ${IndicatorsQML_SOURCES}
52 ${IndicatorsQML_SOURCES}
43)
53)
44
54
plugins/Unity/IndicatorsLegacy/Messaging/CMakeLists.txt → plugins/Unity/Indicators/Messaging/CMakeLists.txtrenamed

The content is the same.

plugins/Unity/IndicatorsLegacy/Messaging/qml/ActionButton.qml → plugins/Unity/Indicators/Messaging/qml/ActionButton.qmlrenamed

The content is the same.

plugins/Unity/IndicatorsLegacy/Messaging/qml/ActionTextField.qml → plugins/Unity/Indicators/Messaging/qml/ActionTextField.qmlrenamed+10−7
@@ -22,11 +22,12 @@ import QtQuick 2.0
22import Ubuntu.Components 0.1
22import Ubuntu.Components 0.1
23
23
24Item {
24Item {
25− property alias actionGroup: sendButton.actionGroup
25+ id: textField
26− property alias action: sendButton.action
27−
28 property alias text: replyField.text
26 property alias text: replyField.text
29 property alias buttonText: sendButton.text
27 property alias buttonText: sendButton.text
28+ property bool activateEnabled: false
29+
30+ signal activate(var value)
30
31
31 TextField {
32 TextField {
32 id: replyField
33 id: replyField
@@ -50,17 +51,19 @@ Item {
50 }
51 }
51 }
52 }
52
53
53− ActionButton {
54+ Button {
54 id: sendButton
55 id: sendButton
55−
56− actionParameter: replyField.text
57 anchors {
56 anchors {
58 top: parent.top
57 top: parent.top
59 bottom: parent.bottom
58 bottom: parent.bottom
60 right: parent.right
59 right: parent.right
61 }
60 }
62 width: units.gu(9)
61 width: units.gu(9)
63− enabled: replyField.text !== ""
62+ enabled: replyField.text !== "" && textField.activateEnabled
64 color: enabled ? "#c94212" : "#bababa"
63 color: enabled ? "#c94212" : "#bababa"
64+
65+ onClicked: {
66+ textField.activate(replyField.text);
67+ }
65 }
68 }
66}
69}
plugins/Unity/Indicators/Messaging/qml/CMakeLists.txtnew file+5
@@ -0,0 +1,5 @@
1+# export_qmlfiles macro
2+include(Plugins)
3+
4+# export the qmldir, *.qml files.
5+export_qmlfiles(Unity.Indicators.Messaging Unity/Indicators/Messaging)
plugins/Unity/IndicatorsLegacy/Messaging/qml/GroupedMessage.qml → plugins/Unity/Indicators/Messaging/qml/GroupedMessage.qmlrenamed+13−18
@@ -20,20 +20,19 @@
20
20
21import QtQuick 2.0
21import QtQuick 2.0
22import Ubuntu.Components 0.1
22import Ubuntu.Components 0.1
23−import Unity.IndicatorsLegacy 0.1 as Indicators
23+import Unity.Indicators 0.1 as Indicators
24
24
25−Indicators.BasicMenuItem {
25+Indicators.BaseMenuItem {
26 id: groupedMessage
26 id: groupedMessage
27+
28+ property alias title: __title.text
27 property alias count: label.text
29 property alias count: label.text
30+ property string appIcon: "qrc:/indicators/artwork/messaging/default_app.svg"
28
31
29− color: "#221e1b"
32+ signal activateApp()
30− implicitHeight: units.gu(10)
33+ signal dismiss()
31
34
32− Indicators.MenuAction {
35+ implicitHeight: units.gu(10)
33− id: menuAction
34− actionGroup: groupedMessage.actionGroup
35− action: menu ? menu.action : ""
36− }
37
36
38 Row {
37 Row {
39 anchors.fill: parent
38 anchors.fill: parent
@@ -44,17 +43,17 @@ Indicators.BasicMenuItem {
44 height: units.gu(6)
43 height: units.gu(6)
45 width: units.gu(6)
44 width: units.gu(6)
46 image: Image {
45 image: Image {
47− source: menu && (menu.extra.canonical_icon.length > 0) ? "image://gicon/" + encodeURI(menu.extra.canonical_icon) : "qrc:/indicators/artwork/messaging/default_app.svg"
46+ source: groupedMessage.appIcon
48 fillMode: Image.PreserveAspectFit
47 fillMode: Image.PreserveAspectFit
49 }
48 }
50 }
49 }
51
50
52 Label {
51 Label {
52+ id: __title
53 anchors.verticalCenter: parent.verticalCenter
53 anchors.verticalCenter: parent.verticalCenter
54 color: "#e8e1d0"
54 color: "#e8e1d0"
55 font.weight: Font.DemiBold
55 font.weight: Font.DemiBold
56 fontSize: "medium"
56 fontSize: "medium"
57− text: menu && menu.label ? menu.label : ""
58 }
57 }
59
58
60 Label {
59 Label {
@@ -65,7 +64,7 @@ Indicators.BasicMenuItem {
65 color: "#e8e1d0"
64 color: "#e8e1d0"
66 font.weight: Font.DemiBold
65 font.weight: Font.DemiBold
67 fontSize: "medium"
66 fontSize: "medium"
68− text: menuAction.valid ? menuAction.state[0] : "0"
67+ text: "0"
69 }
68 }
70 }
69 }
71
70
@@ -82,15 +81,11 @@ Indicators.BasicMenuItem {
82 MouseArea {
81 MouseArea {
83 anchors.fill: parent
82 anchors.fill: parent
84 onClicked: {
83 onClicked: {
85− if (menuAction.valid) {
84+ groupedMessage.activateApp();
86− menuAction.activate(true);
87− }
88 }
85 }
89 }
86 }
90
87
91 onItemRemoved: {
88 onItemRemoved: {
92− if (menuAction.valid) {
89+ groupedMessage.dismiss();
93− menuAction.activate(false);
94− }
95 }
90 }
96}
91}
plugins/Unity/IndicatorsLegacy/Messaging/qml/HeroMessage.qml → plugins/Unity/Indicators/Messaging/qml/HeroMessage.qmlrenamed+25−22
@@ -20,25 +20,30 @@
20
20
21import QtQuick 2.0
21import QtQuick 2.0
22import Ubuntu.Components 0.1
22import Ubuntu.Components 0.1
23−import Unity.IndicatorsLegacy 0.1 as Indicators
23+import Unity.Indicators 0.1 as Indicators
24
24
25−Indicators.BasicMenuItem {
25+Indicators.BaseMenuItem {
26 id: heroMessage
26 id: heroMessage
27
27
28− property variant actionsDescription: null
29 property alias heroMessageHeader: __heroMessageHeader
28 property alias heroMessageHeader: __heroMessageHeader
30 property real collapsedHeight: heroMessageHeader.y + heroMessageHeader.bodyBottom + units.gu(2)
29 property real collapsedHeight: heroMessageHeader.y + heroMessageHeader.bodyBottom + units.gu(2)
31 property real expandedHeight: collapsedHeight
30 property real expandedHeight: collapsedHeight
32
31
33− color: "#221e1c"
32+ property alias avatar: __heroMessageHeader.avatar
33+ property alias appIcon: __heroMessageHeader.icon
34+
35+ signal activateApp
36+ signal dismiss
34
37
35 removable: state !== "expanded"
38 removable: state !== "expanded"
36 implicitHeight: collapsedHeight
39 implicitHeight: collapsedHeight
37
40
38− Indicators.MenuAction {
41+ Rectangle {
39− id: menuAction
42+ id: background
40− actionGroup: heroMessage.actionGroup
43+ property real alpha: 0.0
41− action: menu ? menu.action : ""
44+ anchors.fill: parent
45+ color: Qt.rgba(1.0, 1.0, 1.0, alpha)
46+ z: -1
42 }
47 }
43
48
44 HeroMessageHeader {
49 HeroMessageHeader {
@@ -48,25 +53,22 @@ Indicators.BasicMenuItem {
48 anchors.left: parent.left
53 anchors.left: parent.left
49 anchors.right: parent.right
54 anchors.right: parent.right
50
55
51− avatar: menu && (menu.extra.canonical_icon.length > 0) ? "image://gicon/" + encodeURI(menu.extra.canonical_icon) : "qrc:/indicators/artwork/messaging/default_contact.png"
56+ avatar: "qrc:/indicators/artwork/messaging/default_contact.png"
52− icon: menu && (menu.extra.canonical_app_icon.length > 0) ? "image://gicon/" + encodeURI(menu.extra.canonical_app_icon) : ""
53 appIcon: icon
57 appIcon: icon
54
58
55 state: heroMessage.state
59 state: heroMessage.state
56
60
57 onAppIconClicked: {
61 onAppIconClicked: {
58− if (menuAction.valid) {
62+ deselectMenu();
59− deactivateMenu();
63+ heroMessage.activateApp();
60− action.activate(true);
61− }
62 }
64 }
63 }
65 }
64
66
65 onClicked: {
67 onClicked: {
66− if (menuActivated) {
68+ if (menuSelected) {
67− deactivateMenu();
69+ deselectMenu();
68 } else {
70 } else {
69− activateMenu();
71+ selectMenu();
70 }
72 }
71 }
73 }
72
74
@@ -84,13 +86,16 @@ Indicators.BasicMenuItem {
84
86
85 states: State {
87 states: State {
86 name: "expanded"
88 name: "expanded"
87− when: menuActivated
89+ when: menuSelected
88
90
89 PropertyChanges {
91 PropertyChanges {
90 target: heroMessage
92 target: heroMessage
91− color: "#333130"
92 implicitHeight: heroMessage.expandedHeight
93 implicitHeight: heroMessage.expandedHeight
93 }
94 }
95+ PropertyChanges {
96+ target: background
97+ alpha: 0.05
98+ }
94 PropertyChanges {
99 PropertyChanges {
95 target: __topHLine
100 target: __topHLine
96 opacity: 0.0
101 opacity: 0.0
@@ -113,8 +118,6 @@ Indicators.BasicMenuItem {
113 }
118 }
114
119
115 onItemRemoved: {
120 onItemRemoved: {
116− if (menuAction.valid) {
121+ heroMessage.dismiss();
117− menuAction.activate(false);
118− }
119 }
122 }
120}
123}
plugins/Unity/IndicatorsLegacy/Messaging/qml/HeroMessageHeader.qml → plugins/Unity/Indicators/Messaging/qml/HeroMessageHeader.qmlrenamed

The content is the same.

plugins/Unity/Indicators/Messaging/qml/MessageMenuItemFactory.qmlnew file+180
@@ -0,0 +1,180 @@
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+ * Renato Araujo Oliveira Filho <renato@canonical.com>
18+ * Olivier Tilloy <olivier.tilloy@canonical.com>
19+ */
20+
21+import QtQuick 2.0
22+import Ubuntu.Components 0.1
23+import Unity.Indicators 0.1 as Indicators
24+import QMenuModel 0.1 as QMenuModel
25+import "utils.js" as Utils
26+
27+Indicators.BaseMenuItem {
28+ id: menuItem
29+ property var actionsDescription: menu ? menu.ext.xCanonicalMessageActions : undefined
30+
31+ implicitHeight: contents.status == Loader.Ready ? contents.item.implicitHeight : 0
32+
33+ property var model: null
34+
35+ Loader {
36+ id: contents
37+ anchors.fill: parent
38+
39+ sourceComponent: loadMessage(actionsDescription);
40+
41+ // Binding all properties for the item, to make sure that any change in the
42+ // property will be propagated to the contents.item at any time
43+ Binding {
44+ target: contents.item
45+ property: "menuSelected"
46+ value: menuSelected
47+ when: (contents.status == Loader.Ready)
48+ }
49+
50+ Binding {
51+ target: contents.item
52+ property: "menu"
53+ value: menu
54+ when: (contents.status == Loader.Ready)
55+ }
56+
57+ Connections {
58+ target: contents.item ? contents.item : null
59+ onSelectMenu: selectMenu()
60+ onDeselectMenu: deselectMenu()
61+ }
62+
63+ Component {
64+ id: simpleTextMessage
65+ SimpleTextMessage {
66+ // text
67+ title: menu && menu.label ? menu.label : ""
68+ time: menu ? Utils.formatDate(menu.ext.xCanonicalTime) : ""
69+ message: menu && menu.ext.xCanonicalText ? menu.ext.xCanonicalText : ""
70+ // icons
71+ avatar: menu && menu.ext.icon !== undefined ? menu.ext.icon : "qrc:/indicators/artwork/messaging/default_contact.png"
72+ appIcon: menu && menu.ext.xCanonicalAppIcon !== undefined ? menu.ext.xCanonicalAppIcon : "qrc:/indicators/artwork/messaging/default_app.svg"
73+
74+ onActivateApp: {
75+ menuItem.model.activate(modelIndex, true);
76+ }
77+ onDismiss: {
78+ menuItem.model.activate(modelIndex, false);
79+ }
80+ }
81+ }
82+ Component {
83+ id: textMessage
84+ TextMessage {
85+ property var replyAction: QMenuModel.UnityMenuAction {
86+ model: menuItem.model
87+ index: modelIndex
88+ name: menu && actionsDescription[0].name ? actionsDescription[0].name : ""
89+ }
90+
91+ // text
92+ title: menu && menu.label ? menu.label : ""
93+ time: menu ? Utils.formatDate(menu.ext.xCanonicalTime) : ""
94+ message: menu && menu.ext.xCanonicalText ? menu.ext.xCanonicalText : ""
95+ replyButtonText: actionsDescription && actionsDescription[0].label ? actionsDescription[0].label : "Send"
96+ // icons
97+ avatar: menu && menu.ext.icon !== undefined ? menu.ext.icon : "qrc:/indicators/artwork/messaging/default_contact.png"
98+ appIcon: menu && menu.ext.xCanonicalAppIcon !== undefined ? menu.ext.xCanonicalAppIcon : "qrc:/indicators/artwork/messaging/default_app.svg"
99+ // actions
100+ replyEnabled: replyAction.valid && replyAction.enabled
101+
102+ onActivateApp: {
103+ menuItem.model.activate(modelIndex, true);
104+ }
105+ onDismiss: {
106+ menuItem.model.activate(modelIndex, false);
107+ }
108+ onReply: {
109+ replyAction.activate(value);
110+ }
111+ }
112+ }
113+ Component {
114+ id: snapDecision
115+ SnapDecision {
116+ property var activateAction: QMenuModel.UnityMenuAction {
117+ model: menuItem.model
118+ index: modelIndex
119+ name: menu && actionsDescription[0].name ? actionsDescription[0].name : ""
120+ }
121+ property var replyAction: QMenuModel.UnityMenuAction {
122+ model: menuItem.model
123+ index: modelIndex
124+ name: menu && actionsDescription[1].name ? actionsDescription[1].name : ""
125+ }
126+
127+ // text
128+ title: menu && menu.label ? menu.label : ""
129+ time: menu ? Utils.formatDate(menu.ext.xCanonicalTime) : ""
130+ message: menu && menu.ext.xCanonicalText ? menu.ext.xCanonicalText : ""
131+ actionButtonText: actionsDescription && actionsDescription[0].label ? actionsDescription[0].label : "Call back"
132+ replyButtonText: actionsDescription && actionsDescription[1].label ? actionsDescription[1].label : "Send"
133+ replyMessages: actionsDescription && actionsDescription[1]["parameter-hint"] ? actionsDescription[1]["parameter-hint"] : ""
134+ // icons
135+ avatar: menu && menu.ext.icon !== undefined ? menu.ext.icon : "qrc:/indicators/artwork/messaging/default_contact.png"
136+ appIcon: menu && menu.ext.xCanonicalAppIcon !== undefined ? menu.ext.xCanonicalAppIcon : "qrc:/indicators/artwork/messaging/default_app.svg"
137+ // actions
138+ activateEnabled: activateAction.valid && activateAction.enabled
139+ replyEnabled: replyAction.valid && replyAction.enabled
140+
141+ onActivateApp: {
142+ menuItem.model.activate(modelIndex, true);
143+ }
144+ onDismiss: {
145+ menuItem.model.activate(modelIndex, false);
146+ }
147+ onActivate: {
148+ activateAction.activate();
149+ }
150+ onReply: {
151+ replyAction.activate(value);
152+ }
153+ }
154+ }
155+ }
156+
157+ function loadMessage(actions)
158+ {
159+ var parameterType = ""
160+ for (var actIndex in actions) {
161+ var desc = actions[actIndex];
162+ if (desc["parameter-type"] !== undefined) {
163+ parameterType += desc["parameter-type"];
164+ } else {
165+ parameterType += "_";
166+ }
167+ }
168+
169+ if (parameterType === "") {
170+ return simpleTextMessage;
171+ } else if (parameterType === "s") {
172+ return textMessage;
173+ } else if (parameterType === "_s") {
174+ return snapDecision;
175+ } else {
176+ console.debug("Unknown paramater type: " + parameterType);
177+ }
178+ return undefined;
179+ }
180+}
plugins/Unity/IndicatorsLegacy/Messaging/qml/QuickReply.qml → plugins/Unity/Indicators/Messaging/qml/QuickReply.qmlrenamed+10−5
@@ -23,12 +23,13 @@ import Ubuntu.Components 0.1
23import Unity.IndicatorsLegacy 0.1 as Indicators
23import Unity.IndicatorsLegacy 0.1 as Indicators
24
24
25Item {
25Item {
26− property alias actionGroup: actionTextField.actionGroup
26+ id: quickReply
27− property alias action: actionTextField.action
28−
29 property alias buttonText: actionTextField.buttonText
27 property alias buttonText: actionTextField.buttonText
30 property real expandedHeight: childrenRect.height
28 property real expandedHeight: childrenRect.height
31 property alias messages : messagelistRepeater.model
29 property alias messages : messagelistRepeater.model
30+ property alias replyEnabled: actionTextField.activateEnabled
31+
32+ signal reply(var value)
32
33
33 Item {
34 Item {
34 id: header
35 id: header
@@ -83,10 +84,9 @@ Item {
83
84
84 height: childrenRect.height
85 height: childrenRect.height
85
86
86− Rectangle {
87+ Item {
87 width: messagelist.width
88 width: messagelist.width
88 height: units.gu(5)
89 height: units.gu(5)
89− color: "#333230"
90
90
91 Label {
91 Label {
92 id: __label
92 id: __label
@@ -150,6 +150,11 @@ Item {
150
150
151 anchors.fill: parent
151 anchors.fill: parent
152 anchors.margins: units.gu(1)
152 anchors.margins: units.gu(1)
153+ activateEnabled: replyEnabled
154+
155+ onActivate: {
156+ quickReply.reply(value)
157+ }
153 }
158 }
154
159
155 Indicators.HLine {
160 Indicators.HLine {
plugins/Unity/IndicatorsLegacy/Messaging/qml/SimpleTextMessage.qml → plugins/Unity/Indicators/Messaging/qml/SimpleTextMessage.qmlrenamed+7−4
@@ -20,17 +20,20 @@
20
20
21import QtQuick 2.0
21import QtQuick 2.0
22import Ubuntu.Components 0.1
22import Ubuntu.Components 0.1
23−import "utils.js" as Utils
24
23
25HeroMessage {
24HeroMessage {
26 id: __heroMessage
25 id: __heroMessage
27
26
27+ property string title: ""
28+ property string time: ""
29+ property string message: ""
30+
28 property alias footer: footerLoader.sourceComponent
31 property alias footer: footerLoader.sourceComponent
29
32
30 expandedHeight: fullMessage.y + fullMessage.height + units.gu(2)
33 expandedHeight: fullMessage.y + fullMessage.height + units.gu(2)
31− heroMessageHeader.titleText.text: menu ? menu.label : ""
34+ heroMessageHeader.titleText.text: title
32− heroMessageHeader.subtitleText.text: menu ? Utils.formatDate(menu.extra.canonical_time) : ""
35+ heroMessageHeader.subtitleText.text: time
33− heroMessageHeader.bodyText.text: menu ? menu.extra.canonical_text : ""
36+ heroMessageHeader.bodyText.text: message
34
37
35 Item {
38 Item {
36 id: fullMessage
39 id: fullMessage
plugins/Unity/IndicatorsLegacy/Messaging/qml/SnapDecision.qml → plugins/Unity/Indicators/Messaging/qml/SnapDecision.qmlrenamed+33−14
@@ -20,19 +20,33 @@
20
20
21import QtQuick 2.0
21import QtQuick 2.0
22import Ubuntu.Components 0.1
22import Ubuntu.Components 0.1
23−import Unity.IndicatorsLegacy 0.1 as Indicators
23+import Unity.Indicators 0.1 as Indicators
24import "utils.js" as Utils
24import "utils.js" as Utils
25
25
26HeroMessage {
26HeroMessage {
27 id: snapDecision
27 id: snapDecision
28
28
29+ property string title: ""
30+ property string time: ""
31+ property string message: ""
32+
33+ property bool activateEnabled: true
34+ property alias actionButtonText: actionButton.text
35+
36+ property bool replyEnabled: true
37+ property alias replyMessages: quickreply.messages
38+ property alias replyButtonText: quickreply.buttonText
39+
29 expandedHeight: buttons.y + buttons.height + quickreply.height + units.gu(2)
40 expandedHeight: buttons.y + buttons.height + quickreply.height + units.gu(2)
30− heroMessageHeader.titleText.text: menu ? menu.label : ""
41+ heroMessageHeader.titleText.text: title
31− heroMessageHeader.subtitleText.text: menu ? menu.extra.canonical_text : ""
42+ heroMessageHeader.subtitleText.text: message
32 heroMessageHeader.subtitleText.color: "#e8e1d0"
43 heroMessageHeader.subtitleText.color: "#e8e1d0"
33− heroMessageHeader.bodyText.text: menu ? Utils.formatDate(menu.extra.canonical_time) : ""
44+ heroMessageHeader.bodyText.text: time
34 heroMessageHeader.bodyText.color: "#8f8f88"
45 heroMessageHeader.bodyText.color: "#8f8f88"
35
46
47+ signal activate
48+ signal reply(string value)
49+
36 Item {
50 Item {
37 id: buttons
51 id: buttons
38
52
@@ -62,16 +76,19 @@ HeroMessage {
62 }
76 }
63 }
77 }
64
78
65− ActionButton {
79+ Button {
66− actionGroup: snapDecision.actionGroup
80+ id: actionButton
67− action: actionsDescription[0].name
81+ text: "Call back"
68−
69− text: actionsDescription ? actionsDescription[0].label : "Call back"
70− color: "#c94212"
82+ color: enabled ? "#c94212" : "#bababa"
71 anchors.right: parent.right
83 anchors.right: parent.right
72 anchors.top: parent.top
84 anchors.top: parent.top
73 anchors.bottom: parent.bottom
85 anchors.bottom: parent.bottom
74 width: (parent.width - units.gu(1)) / 2
86 width: (parent.width - units.gu(1)) / 2
87+ enabled: snapDecision.activateEnabled
88+
89+ onClicked: {
90+ snapDecision.activate();
91+ }
75 }
92 }
76
93
77 states: State {
94 states: State {
@@ -95,11 +112,12 @@ HeroMessage {
95 QuickReply {
112 QuickReply {
96 id: quickreply
113 id: quickreply
97
114
115+ onReply: {
98− actionGroup: snapDecision.actionGroup
116+ snapDecision.reply(value);
99− action: actionsDescription[1].name
117+ }
100
118
101− messages: actionsDescription ? actionsDescription[1]["parameter-hint"] : ""
119+ messages: ""
102− buttonText: actionsDescription ? actionsDescription[1].label : "send"
120+ buttonText: "Send"
103 anchors {
121 anchors {
104 top: buttons.bottom
122 top: buttons.bottom
105 topMargin: units.gu(2)
123 topMargin: units.gu(2)
@@ -109,6 +127,7 @@ HeroMessage {
109 height: 0
127 height: 0
110 opacity: 0.0
128 opacity: 0.0
111 enabled: false
129 enabled: false
130+ replyEnabled: snapDecision.replyEnabled
112
131
113 states: State {
132 states: State {
114 name: "expanded"
133 name: "expanded"
plugins/Unity/IndicatorsLegacy/Messaging/qml/TextMessage.qml → plugins/Unity/Indicators/Messaging/qml/TextMessage.qmlrenamed+12−4
@@ -20,16 +20,24 @@
20
20
21import QtQuick 2.0
21import QtQuick 2.0
22import Ubuntu.Components 0.1
22import Ubuntu.Components 0.1
23−import Unity.IndicatorsLegacy 0.1 as Indicators
23+import Unity.Indicators 0.1 as Indicators
24
24
25SimpleTextMessage {
25SimpleTextMessage {
26 id: simpleMessage
26 id: simpleMessage
27
27
28+ property bool replyEnabled: false
29+ property string replyButtonText: "Send"
30+
31+ signal reply(string value)
32+
28 footer: ActionTextField {
33 footer: ActionTextField {
29 anchors.fill: parent
34 anchors.fill: parent
30− actionGroup: simpleMessage.actionGroup
31− action: actionsDescription[0].name
32
35
33− buttonText: actionsDescription ? actionsDescription[0].label : "Send"
36+ activateEnabled: simpleMessage.replyEnabled
37+ buttonText: simpleMessage.replyButtonText
38+
39+ onActivate: {
40+ simpleMessage.reply(value);
41+ }
34 }
42 }
35}
43}
plugins/Unity/IndicatorsLegacy/Messaging/qml/qmldir → plugins/Unity/Indicators/Messaging/qml/qmldirrenamed+2−2
@@ -1,11 +1,11 @@
1−module Unity.IndicatorsLegacy.Messaging
1+module Unity.Indicators.Messaging
2
2
3ActionButton 0.1 ActionButton.qml
3ActionButton 0.1 ActionButton.qml
4ActionTextField 0.1 ActionTextField.qml
4ActionTextField 0.1 ActionTextField.qml
5GroupedMessage 0.1 GroupedMessage.qml
5GroupedMessage 0.1 GroupedMessage.qml
6HeroMessage 0.1 HeroMessage.qml
6HeroMessage 0.1 HeroMessage.qml
7HeroMessageHeader 0.1 HeroMessageHeader.qml
7HeroMessageHeader 0.1 HeroMessageHeader.qml
8−MessageMenuItem 0.1 MessageMenuItem.qml
8+MessageMenuItemFactory 0.1 MessageMenuItemFactory.qml
9QuickReply 0.1 QuickReply.qml
9QuickReply 0.1 QuickReply.qml
10SimpleTextMessage 0.1 SimpleTextMessage.qml
10SimpleTextMessage 0.1 SimpleTextMessage.qml
11SnapDecision 0.1 SnapDecision.qml
11SnapDecision 0.1 SnapDecision.qml
plugins/Unity/IndicatorsLegacy/Messaging/qml/utils.js → plugins/Unity/Indicators/Messaging/qml/utils.jsrenamed

The content is the same.

plugins/Unity/Indicators/Network/qml/AccessPoint.qml+71−26
@@ -22,13 +22,15 @@ import Ubuntu.Components 0.1
22import Ubuntu.Components.ListItems 0.1 as ListItem
22import Ubuntu.Components.ListItems 0.1 as ListItem
23import Unity.Indicators 0.1 as Indicators
23import Unity.Indicators 0.1 as Indicators
24
24
25−Indicators.FramedMenuItem {
25+Indicators.BaseMenuItem {
26− id: accessPoint
26+ id: menuItem
27+ implicitHeight: units.gu(5.5)
27
28
28 property bool checked: false
29 property bool checked: false
29 property bool secure: false
30 property bool secure: false
30 property bool adHoc: false
31 property bool adHoc: false
31 property int signalStrength: 0
32 property int signalStrength: 0
33+ property alias text: label.text
32
34
33 signal activate()
35 signal activate()
34
36
@@ -37,36 +39,79 @@ Indicators.FramedMenuItem {
37 checkBoxActive.checked = checked;
39 checkBoxActive.checked = checked;
38 }
40 }
39
41
40− icon: {
42+ onClicked: {
41− var imageName = "nm-signal-100"
43+ checkBoxActive.clicked();
42−
44+ }
43− if (adHoc) {
45+
44− imageName = "nm-adhoc";
46+ CheckBox {
45− } else if (signalStrength == 0) {
47+ id: checkBoxActive
46− imageName = "nm-signal-00";
48+ height: units.gu(3)
47− } else if (signalStrength <= 25) {
49+ width: units.gu(3)
48− imageName = "nm-signal-25";
50+
49− } else if (signalStrength <= 50) {
51+ anchors {
50− imageName = "nm-signal-50";
52+ left: parent.left
51− } else if (signalStrength <= 75) {
53+ leftMargin: menuItem.__contentsMargins
52− imageName = "nm-signal-75";
54+ verticalCenter: parent.verticalCenter
53 }
55 }
54
56
55− if (secure) {
57+ onClicked: {
56− imageName += "-secure";
58+ menuItem.activate();
57 }
59 }
58− return "image://gicon/" + imageName;
59 }
60 }
60
61
61− iconFrame: false
62+ Image {
62− control: CheckBox {
63+ id: iconSignal
63− id: checkBoxActive
64− height: units.gu(4)
65− width: units.gu(4)
66− anchors.centerIn: parent
67
64
68− onClicked: {
65+ width: height
69− accessPoint.activate();
66+ height: Math.min(units.gu(5), parent.height - units.gu(1))
67+ anchors {
68+ left: checkBoxActive.right
69+ leftMargin: units.gu(1)
70+ verticalCenter: parent.verticalCenter
71+ }
72+
73+ source: {
74+ var imageName = "nm-signal-100"
75+
76+ if (adHoc) {
77+ imageName = "nm-adhoc";
78+ } else if (signalStrength == 0) {
79+ imageName = "nm-signal-00";
80+ } else if (signalStrength <= 25) {
81+ imageName = "nm-signal-25";
82+ } else if (signalStrength <= 50) {
83+ imageName = "nm-signal-50";
84+ } else if (signalStrength <= 75) {
85+ imageName = "nm-signal-75";
86+ }
87+ return "image://theme/" + imageName;
88+ }
89+ }
90+
91+ Label {
92+ id: label
93+ anchors {
94+ left: iconSignal.right
95+ leftMargin: units.gu(1)
96+ verticalCenter: parent.verticalCenter
97+ right: iconSecure.visible ? iconSecure.left : parent.right
98+ rightMargin: menuItem.__contentsMargins
99+ }
100+ elide: Text.ElideRight
101+ opacity: label.enabled ? 1.0 : 0.5
102+ }
103+
104+ Image {
105+ id: iconSecure
106+ visible: secure
107+ source: "qrc:/indicators/artwork/network/secure.svg"
108+
109+ width: height
110+ height: Math.min(units.gu(4), parent.height - units.gu(1))
111+ anchors {
112+ right: parent.right
113+ rightMargin: units.gu(1)
114+ verticalCenter: parent.verticalCenter
70 }
115 }
71 }
116 }
72}
117}
plugins/Unity/Indicators/indicator.cpp−2
@@ -51,7 +51,6 @@ void Indicator::init(const QString& busName, const QSettings& settings)
51 }
51 }
52 }
52 }
53
53
54−
55 QVariantMap properties;
54 QVariantMap properties;
56 properties.clear();
55 properties.clear();
57 properties.insert("busType", 1);
56 properties.insert("busType", 1);
@@ -87,7 +86,6 @@ void Indicator::setPosition(int position)
87 }
86 }
88}
87}
89
88
90−
91QVariant Indicator::indicatorProperties() const
89QVariant Indicator::indicatorProperties() const
92{
90{
93 return m_properties;
91 return m_properties;
plugins/Unity/Indicators/indicator.h−4
@@ -29,10 +29,6 @@
29class UNITYINDICATORS_EXPORT Indicator : public QObject
29class UNITYINDICATORS_EXPORT Indicator : public QObject
30{
30{
31 Q_OBJECT
31 Q_OBJECT
32− Q_PROPERTY(QString identifier READ identifier NOTIFY identifierChanged)
33− Q_PROPERTY(int position READ position NOTIFY positionChanged)
34− Q_PROPERTY(QVariant indicatorProperties READ indicatorProperties NOTIFY indicatorPropertiesChanged)
35−
36public:
32public:
37 typedef QSharedPointer<Indicator> Ptr;
33 typedef QSharedPointer<Indicator> Ptr;
38
34
plugins/Unity/Indicators/indicators.h+1−1
@@ -79,7 +79,7 @@ public:
79 WidgetSource,
79 WidgetSource,
80 PageSource,
80 PageSource,
81 IndicatorProperties,
81 IndicatorProperties,
82− IsValid
82+ IsVisible
83 };
83 };
84
84
85 IndicatorsModelRole(QObject*parent=0):QObject(parent) {}
85 IndicatorsModelRole(QObject*parent=0):QObject(parent) {}
plugins/Unity/Indicators/indicatorsmodel.cpp−3
@@ -206,7 +206,6 @@ QHash<int, QByteArray> IndicatorsModel::roleNames() const
206 roles[IndicatorsModelRole::WidgetSource] = "widgetSource";
206 roles[IndicatorsModelRole::WidgetSource] = "widgetSource";
207 roles[IndicatorsModelRole::PageSource] = "pageSource";
207 roles[IndicatorsModelRole::PageSource] = "pageSource";
208 roles[IndicatorsModelRole::IndicatorProperties] = "indicatorProperties";
208 roles[IndicatorsModelRole::IndicatorProperties] = "indicatorProperties";
209− roles[IndicatorsModelRole::IsValid] = "isValid";
210 }
209 }
211 return roles;
210 return roles;
212}
211}
@@ -269,8 +268,6 @@ QVariant IndicatorsModel::data(const QModelIndex &index, int role) const
269 return QVariant(indicator->indicatorProperties());
268 return QVariant(indicator->indicatorProperties());
270 }
269 }
271 break;
270 break;
272− case IndicatorsModelRole::IsValid:
273− return (indicator ? true : false);
274 case IndicatorsModelRole::Title:
271 case IndicatorsModelRole::Title:
275 case IndicatorsModelRole::Description:
272 case IndicatorsModelRole::Description:
276 case IndicatorsModelRole::WidgetSource:
273 case IndicatorsModelRole::WidgetSource:
plugins/Unity/Indicators/indicatorsmodel.h+2−1
@@ -44,7 +44,7 @@ public:
44 Q_INVOKABLE void load();
44 Q_INVOKABLE void load();
45 Q_INVOKABLE void unload();
45 Q_INVOKABLE void unload();
46
46
47− Q_INVOKABLE QVariant data(int row, int role = Qt::DisplayRole) const;
47+ Q_INVOKABLE QVariant data(int row, int role) const;
48
48
49 /* QAbstractItemModel */
49 /* QAbstractItemModel */
50 QHash<int, QByteArray> roleNames() const;
50 QHash<int, QByteArray> roleNames() const;
@@ -56,6 +56,7 @@ public:
56 void setIndicatorData(const QVariant& data);
56 void setIndicatorData(const QVariant& data);
57 QVariant indicatorData() const;
57 QVariant indicatorData() const;
58
58
59+
59Q_SIGNALS:
60Q_SIGNALS:
60 void countChanged();
61 void countChanged();
61 void indicatorDataChanged(const QVariant& data);
62 void indicatorDataChanged(const QVariant& data);
plugins/Unity/Indicators/plugin.cpp+4
@@ -32,6 +32,7 @@
32#include "rootactionstate.h"
32#include "rootactionstate.h"
33#include "unitymenumodelcache.h"
33#include "unitymenumodelcache.h"
34#include "unitymenumodelstack.h"
34#include "unitymenumodelstack.h"
35+#include "visibleindicatorsmodel.h"
35
36
36static QObject* menuModelCacheSingleton(QQmlEngine* engine, QJSEngine* scriptEngine) {
37static QObject* menuModelCacheSingleton(QQmlEngine* engine, QJSEngine* scriptEngine) {
37 Q_UNUSED(engine);
38 Q_UNUSED(engine);
@@ -41,12 +42,15 @@ static QObject* menuModelCacheSingleton(QQmlEngine* engine, QJSEngine* scriptEng
41
42
42void Indicators2Plugin::registerTypes(const char *uri)
43void Indicators2Plugin::registerTypes(const char *uri)
43{
44{
45+ Q_INIT_RESOURCE(indicators);
46+
44 qmlRegisterType<IndicatorsManager>(uri, 0, 1, "IndicatorsManager");
47 qmlRegisterType<IndicatorsManager>(uri, 0, 1, "IndicatorsManager");
45 qmlRegisterType<IndicatorsModel>(uri, 0, 1, "IndicatorsModel");
48 qmlRegisterType<IndicatorsModel>(uri, 0, 1, "IndicatorsModel");
46 qmlRegisterType<MenuContentActivator>(uri, 0, 1, "MenuContentActivator");
49 qmlRegisterType<MenuContentActivator>(uri, 0, 1, "MenuContentActivator");
47 qmlRegisterType<UnityMenuModelStack>(uri, 0, 1, "UnityMenuModelStack");
50 qmlRegisterType<UnityMenuModelStack>(uri, 0, 1, "UnityMenuModelStack");
48 qmlRegisterType<RootActionState>(uri, 0, 1, "RootActionState");
51 qmlRegisterType<RootActionState>(uri, 0, 1, "RootActionState");
49 qmlRegisterType<ModelPrinter>(uri, 0, 1, "ModelPrinter");
52 qmlRegisterType<ModelPrinter>(uri, 0, 1, "ModelPrinter");
53+ qmlRegisterType<VisibleIndicatorsModel>(uri, 0, 1, "VisibleIndicatorsModel");
50
54
51 qmlRegisterSingletonType<UnityMenuModelCache>(uri, 0, 1, "UnityMenuModelCache", menuModelCacheSingleton);
55 qmlRegisterSingletonType<UnityMenuModelCache>(uri, 0, 1, "UnityMenuModelCache", menuModelCacheSingleton);
52
56
plugins/Unity/Indicators/qml/BaseMenuItem.qml+1−1
@@ -24,7 +24,7 @@ import Ubuntu.Components.ListItems 0.1 as ListItem
24ListItem.Standard {
24ListItem.Standard {
25 id: baseMenu
25 id: baseMenu
26
26
27− property bool menuActivated: false
27+ property bool menuSelected: false
28
28
29 signal selectMenu()
29 signal selectMenu()
30 signal deselectMenu()
30 signal deselectMenu()
plugins/Unity/Indicators/qml/IndicatorBase.qml−5
@@ -24,8 +24,6 @@ import Unity.Indicators 0.1 as Indicators
24Item {
24Item {
25 id: indicatorItem
25 id: indicatorItem
26
26
27− // FIXME : should be disabled until bus available when we have desktop indicators
28− // for now, disable when we dont habe the correct profile.
29 enabled: menuObjectPaths.hasOwnProperty(device)
27 enabled: menuObjectPaths.hasOwnProperty(device)
30
28
31 //const
29 //const
@@ -39,9 +37,6 @@ Item {
39
37
40 property string deviceMenuObjectPath: menuObjectPaths.hasOwnProperty(device) ? menuObjectPaths[device] : ""
38 property string deviceMenuObjectPath: menuObjectPaths.hasOwnProperty(device) ? menuObjectPaths[device] : ""
41
39
42− signal actionGroupUpdated()
43− signal modelUpdated()
44−
45 property alias menuModel: cachedModel.model
40 property alias menuModel: cachedModel.model
46
41
47 CachedUnityMenuModel {
42 CachedUnityMenuModel {
plugins/Unity/Indicators/qml/IndicatorPage.qml+33−6
@@ -60,7 +60,34 @@ IndicatorBase {
60 // Only allow flicking if the content doesn't fit on the page
60 // Only allow flicking if the content doesn't fit on the page
61 interactive: contentHeight > height
61 interactive: contentHeight > height
62
62
63+ property int selectedIndex: -1
64+ property bool blockCurrentIndexChange: false
65+ // for count = 0
66+ onCountChanged: {
67+ if (count == 0 && selectedIndex != -1) {
68+ selectedIndex = -1;
69+ }
70+ }
71+ // for highlight following
72+ onSelectedIndexChanged: {
63− currentIndex: -1
73+ if (currentIndex != selectedIndex) {
74+ var blocked = blockCurrentIndexChange;
75+ blockCurrentIndexChange = true;
76+
77+ currentIndex = selectedIndex;
78+
79+ blockCurrentIndexChange = blocked;
80+ }
81+ }
82+ // for item addition/removal
83+ onCurrentIndexChanged: {
84+ if (!blockCurrentIndexChange) {
85+ if (selectedIndex != -1 && selectedIndex != currentIndex) {
86+ selectedIndex = currentIndex;
87+ }
88+ }
89+ }
90+
64 delegate: Item {
91 delegate: Item {
65 id: menuDelegate
92 id: menuDelegate
66
93
@@ -89,10 +116,10 @@ IndicatorBase {
89 menuStack.push(mainMenu.model.submenu(index));
116 menuStack.push(mainMenu.model.submenu(index));
90 }
117 }
91
118
92− if (item.hasOwnProperty("menuActivated")) {
119+ if (item.hasOwnProperty("menuSelected")) {
93− item.menuActivated = Qt.binding(function() { return ListView.isCurrentItem; });
120+ item.menuSelected = Qt.binding(function() { return mainMenu.selectedIndex == index; });
94− item.selectMenu.connect(function() { ListView.view.currentIndex = index });
121+ item.selectMenu.connect(function() { mainMenu.selectedIndex = index; });
95− item.deselectMenu.connect(function() { ListView.view.currentIndex = -1 });
122+ item.deselectMenu.connect(function() { mainMenu.selectedIndex = -1; });
96 }
123 }
97 if (item.hasOwnProperty("menu")) {
124 if (item.hasOwnProperty("menu")) {
98 item.menu = Qt.binding(function() { return model; });
125 item.menu = Qt.binding(function() { return model; });
@@ -149,7 +176,7 @@ IndicatorBase {
149
176
150 function reset()
177 function reset()
151 {
178 {
152− mainMenu.currentIndex = -1;
179+ mainMenu.selectedIndex = -1;
153 mainMenu.positionViewAtBeginning();
180 mainMenu.positionViewAtBeginning();
154 }
181 }
155}
182}
plugins/Unity/Indicators/qml/IndicatorWidget.qml+1
@@ -24,6 +24,7 @@ IndicatorBase {
24 id: indicatorWidget
24 id: indicatorWidget
25
25
26 active: true
26 active: true
27+ enabled: false
27 property int iconSize: height - units.gu(0.5)
28 property int iconSize: height - units.gu(0.5)
28
29
29 property var actionState: Indicators.RootActionState {
30 property var actionState: Indicators.RootActionState {
plugins/Unity/Indicators/qml/MenuItemFactory.qml+68−33
@@ -20,6 +20,7 @@
20import QtQuick 2.0
20import QtQuick 2.0
21import Unity.Indicators 0.1 as Indicators
21import Unity.Indicators 0.1 as Indicators
22import Unity.Indicators.Network 0.1 as ICNetwork
22import Unity.Indicators.Network 0.1 as ICNetwork
23+import Unity.Indicators.Messaging 0.1 as ICMessaging
23import QMenuModel 0.1 as QMenuModel
24import QMenuModel 0.1 as QMenuModel
24
25
25Item {
26Item {
@@ -38,6 +39,9 @@ Item {
38 "com.canonical.indicator.slider" : sliderMenu,
39 "com.canonical.indicator.slider" : sliderMenu,
39 "com.canonical.indicator.switch" : switchMenu,
40 "com.canonical.indicator.switch" : switchMenu,
40
41
42+ "com.canonical.indicator.messages.messageitem" : messageItem,
43+ "com.canonical.indicator.messages.sourceitem" : groupedMessage,
44+
41 "com.canonical.unity.slider" : sliderMenu,
45 "com.canonical.unity.slider" : sliderMenu,
42 "com.canonical.unity.switch" : switchMenu,
46 "com.canonical.unity.switch" : switchMenu,
43
47
@@ -45,15 +49,17 @@ Item {
45 "unity.widgets.systemsettings.tablet.accesspoint" : accessPoint,
49 "unity.widgets.systemsettings.tablet.accesspoint" : accessPoint,
46 }
50 }
47
51
52+ Component { id: divMenu; Indicators.DivMenuItem {} }
53+
48 Component {
54 Component {
49 id: sliderMenu;
55 id: sliderMenu;
50 Indicators.SliderMenuItem {
56 Indicators.SliderMenuItem {
51 property QtObject menu: null
57 property QtObject menu: null
52
58
53 text: menu && menu.label ? menu.label : ""
59 text: menu && menu.label ? menu.label : ""
54− icon: menu ? menu.icon : ""
60+ icon: menu && menu.icon ? menu.icon : ""
55− minIcon: menu.ext.minIcon
61+ minIcon: menu && menu.ext.minIcon ? menu.ext.minIcon : ""
56− maxIcon: menu.ext.maxIcon
62+ maxIcon: menu && menu.ext.maxIcon ? menu.ext.maxIcon : ""
57
63
58 minimumValue: menu.ext.minValue ? menu.ext.minValue : 0.0
64 minimumValue: menu.ext.minValue ? menu.ext.minValue : 0.0
59 maximumValue: {
65 maximumValue: {
@@ -73,29 +79,12 @@ Item {
73 'max-icon': 'icon'});
79 'max-icon': 'icon'});
74 }
80 }
75
81
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…
81 onChangeState: {
82 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);
83+ model.changeState(modelIndex, value);
87− } else {
88− model.changeState(modelIndex, value * 1.000001);
89− }
90− } else {
91− model.changeState(modelIndex, value);
92− }
93 }
84 }
94 }
85 }
95 }
86 }
96
87
97− Component { id: divMenu; Indicators.DivMenuItem {} }
98−
99 Component {
88 Component {
100 id: buttonMenu;
89 id: buttonMenu;
101 Indicators.ButtonMenuItem {
90 Indicators.ButtonMenuItem {
@@ -104,7 +93,9 @@ Item {
104 text: menu && menu.label ? menu.label : ""
93 text: menu && menu.label ? menu.label : ""
105 enabled: menu ? menu.sensitive : false
94 enabled: menu ? menu.sensitive : false
106
95
96+ onActivate: {
107− onActivate: model.activate(modelIndex);
97+ model.activate(modelIndex);
98+ }
108 }
99 }
109 }
100 }
110 Component {
101 Component {
@@ -133,12 +124,14 @@ Item {
133 property QtObject menu: null
124 property QtObject menu: null
134
125
135 text: menu && menu.label ? menu.label : ""
126 text: menu && menu.label ? menu.label : ""
136− icon: menu ? menu.icon : ""
127+ icon: menu && menu.icon ? menu.icon : ""
137 checkable: menu ? (menu.isCheck || menu.isRadio) : false
128 checkable: menu ? (menu.isCheck || menu.isRadio) : false
138 checked: checkable ? menu.isToggled : false
129 checked: checkable ? menu.isToggled : false
139 enabled: menu ? menu.sensitive : false
130 enabled: menu ? menu.sensitive : false
140
131
132+ onActivate: {
141− onActivate: model.activate(modelIndex);
133+ model.activate(modelIndex);
134+ }
142 }
135 }
143 }
136 }
144
137
@@ -148,11 +141,13 @@ Item {
148 property QtObject menu: null
141 property QtObject menu: null
149
142
150 text: menu && menu.label ? menu.label : ""
143 text: menu && menu.label ? menu.label : ""
151− icon: menu ? menu.icon : ""
144+ icon: menu && menu.icon ? menu.icon : ""
152 checked: menu ? menu.isToggled : false
145 checked: menu ? menu.isToggled : false
153 enabled: menu ? menu.sensitive : false
146 enabled: menu ? menu.sensitive : false
154
147
148+ onActivate: {
155− onActivate: model.activate(modelIndex);
149+ model.activate(modelIndex);
150+ }
156 }
151 }
157 }
152 }
158
153
@@ -174,17 +169,17 @@ Item {
174 id: accessPoint;
169 id: accessPoint;
175 ICNetwork.AccessPoint {
170 ICNetwork.AccessPoint {
176 property QtObject menu: null
171 property QtObject menu: null
177−// property var strenthAction: QMenuModel.UnityMenuAction {
172+ property var strengthAction: QMenuModel.UnityMenuAction {
178−// model: menuFactory.model ? menuFactory.model : null
173+ model: menuFactory.model ? menuFactory.model : null
174+ index: modelIndex
179−// name: menu ? menu.ext.xCanonicalWifiApStrengthAction : ""
175+ name: menu ? menu.ext.xCanonicalWifiApStrengthAction : ""
180−// }
176+ }
181
177
182 text: menu && menu.label ? menu.label : ""
178 text: menu && menu.label ? menu.label : ""
183− icon: menu ? menu.icon : ""
184 secure: menu ? menu.ext.xCanonicalWifiApIsSecure : false
179 secure: menu ? menu.ext.xCanonicalWifiApIsSecure : false
185 adHoc: menu ? menu.ext.xCanonicalWifiApIsAdhoc : false
180 adHoc: menu ? menu.ext.xCanonicalWifiApIsAdhoc : false
186 checked: menu ? menu.isToggled : false
181 checked: menu ? menu.isToggled : false
187−// signalStrength: strenthAction.valid ? strenthAction.state : 0
182+ signalStrength: strengthAction.valid ? strengthAction.state : 0
188 enabled: menu ? menu.sensitive : false
183 enabled: menu ? menu.sensitive : false
189
184
190 Component.onCompleted: {
185 Component.onCompleted: {
@@ -192,7 +187,47 @@ Item {
192 'x-canonical-wifi-ap-is-secure': 'bool',
187 'x-canonical-wifi-ap-is-secure': 'bool',
193 'x-canonical-wifi-ap-strength-action': 'string'});
188 'x-canonical-wifi-ap-strength-action': 'string'});
194 }
189 }
190+ onActivate: {
195− onActivate: model.activate(modelIndex);
191+ model.activate(modelIndex);
192+ }
193+ }
194+ }
195+
196+ Component {
197+ id: messageItem
198+ ICMessaging.MessageMenuItemFactory {
199+
200+ property QtObject menu: null
201+ model: menuFactory.model ? menuFactory.model : null
202+
203+ Component.onCompleted: {
204+ model.loadExtendedAttributes(modelIndex, {'x-canonical-time': 'int64',
205+ 'x-canonical-text': 'string',
206+ 'x-canonical-message-actions': 'variant',
207+ 'icon': 'icon',
208+ 'x-canonical-app-icon': 'icon'});
209+ }
210+ }
211+ }
212+
213+ Component {
214+ id: groupedMessage
215+ ICMessaging.GroupedMessage {
216+ property QtObject menu: null
217+
218+ title: menu && menu.label ? menu.label : ""
219+ count: menu && menu.actionState[0] ? menu.actionState[0] : "0"
220+ appIcon: menu && menu.ext.icon !== undefined ? menu.ext.icon : "qrc:/indicators/artwork/messaging/default_app.svg"
221+
222+ Component.onCompleted: {
223+ model.loadExtendedAttributes(modelIndex, {'icon': 'icon'});
224+ }
225+ onActivateApp: {
226+ model.activate(modelIndex, true);
227+ }
228+ onDismiss: {
229+ model.activate(modelIndex, false);
230+ }
196 }
231 }
197 }
232 }
198
233
plugins/Unity/IndicatorsLegacy/resources/artwork/messaging/default_app.svg → plugins/Unity/Indicators/resources/artwork/messaging/default_app.svgrenamed

The content is the same.

plugins/Unity/IndicatorsLegacy/resources/artwork/messaging/default_contact.png → plugins/Unity/Indicators/resources/artwork/messaging/default_contact.pngrenamed

Binary file not shown.

plugins/Unity/IndicatorsLegacy/resources/artwork/messaging/message_sms01_54px.png → plugins/Unity/Indicators/resources/artwork/messaging/message_sms01_54px.pngrenamed

Binary file not shown.

plugins/Unity/Indicators/resources/artwork/network/secure.svgnew file+71
@@ -0,0 +1,71 @@
1+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2+<!-- Created with Inkscape (http://www.inkscape.org/) -->
3+
4+<svg
5+ xmlns:dc="http://purl.org/dc/elements/1.1/"
6+ xmlns:cc="http://creativecommons.org/ns#"
7+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8+ xmlns:svg="http://www.w3.org/2000/svg"
9+ xmlns="http://www.w3.org/2000/svg"
10+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
11+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
12+ width="64"
13+ height="64"
14+ id="svg2986"
15+ version="1.1"
16+ inkscape:version="0.48.4 r9939"
17+ sodipodi:docname="secure.svg">
18+ <defs
19+ id="defs2988" />
20+ <sodipodi:namedview
21+ id="base"
22+ pagecolor="#ffffff"
23+ bordercolor="#666666"
24+ borderopacity="1.0"
25+ inkscape:pageopacity="0.0"
26+ inkscape:pageshadow="2"
27+ inkscape:zoom="7.9180415"
28+ inkscape:cx="7.5048745"
29+ inkscape:cy="29.401628"
30+ inkscape:current-layer="layer1"
31+ showgrid="true"
32+ inkscape:grid-bbox="true"
33+ inkscape:document-units="px"
34+ inkscape:snap-grids="false"
35+ inkscape:window-width="1549"
36+ inkscape:window-height="876"
37+ inkscape:window-x="51"
38+ inkscape:window-y="24"
39+ inkscape:window-maximized="1">
40+ <inkscape:grid
41+ type="xygrid"
42+ id="grid3012"
43+ empspacing="5"
44+ visible="true"
45+ enabled="true"
46+ snapvisiblegridlinesonly="true" />
47+ </sodipodi:namedview>
48+ <metadata
49+ id="metadata2991">
50+ <rdf:RDF>
51+ <cc:Work
52+ rdf:about="">
53+ <dc:format>image/svg+xml</dc:format>
54+ <dc:type
55+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
56+ <dc:title />
57+ </cc:Work>
58+ </rdf:RDF>
59+ </metadata>
60+ <g
61+ id="layer1"
62+ inkscape:label="Layer 1"
63+ inkscape:groupmode="layer"
64+ transform="translate(0,32)">
65+ <path
66+ inkscape:connector-curvature="0"
67+ d="M 29.999999,-18 C 25.568001,-18 22,-14.432 22,-10 v 6 h -2 c -1.107999,0 -2,0.892 -2,2 v 18 c 0,1.108 0.892001,2 2,2 h 24 c 1.108,0 2,-0.892 2,-2 V -2 c 0,-1.108 -0.892,-2 -2,-2 h -2 v -6 c 0,-4.432 -3.568001,-8 -8.000001,-8 h -4 z m 0,4 h 4 c 2.216,0 4,1.784 4,4 v 6 H 26.000001 v -6 c 0,-2.216 1.784,-4 3.999998,-4 z"
68+ style="fill:#dfdbd2;fill-rule:evenodd"
69+ id="path8" />
70+ </g>
71+</svg>
plugins/Unity/Indicators/resources/indicators.qrcnew file+8
@@ -0,0 +1,8 @@
1+<RCC>
2+ <qresource prefix="/indicators">
3+ <file>artwork/network/secure.svg</file>
4+ <file>artwork/messaging/default_contact.png</file>
5+ <file>artwork/messaging/default_app.svg</file>
6+ <file>artwork/messaging/message_sms01_54px.png</file>
7+ </qresource>
8+</RCC>
plugins/Unity/Indicators/rootactionstate.cpp+52−22
@@ -108,25 +108,32 @@ bool RootActionState::isValid() const
108 return m_menu && m_menu->rowCount() > 0;
108 return m_menu && m_menu->rowCount() > 0;
109}
109}
110
110
111−QString RootActionState::label() const
111+QString RootActionState::leftLabel() const
112{
112{
113 if (!isValid()) return QString();
113 if (!isValid()) return QString();
114
114
115− return m_cachedState.value("label", QVariant::fromValue(QString())).toString();
115+ return m_cachedState.value("pre-label", QVariant::fromValue(QString())).toString();
116}
116}
117
117
118−QString RootActionState::icon() const
118+QString RootActionState::rightLabel() const
119{
119{
120 if (!isValid()) return QString();
120 if (!isValid()) return QString();
121
121
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();
123}
130}
124
131
125QString RootActionState::accessibleName() const
132QString RootActionState::accessibleName() const
126{
133{
127 if (!isValid()) return QString();
134 if (!isValid()) return QString();
128
135
129− return m_cachedState.value("accessible-name", QVariant::fromValue(QString())).toString();
136+ return m_cachedState.value("accessible-desc", QVariant::fromValue(QString())).toString();
130}
137}
131
138
132bool RootActionState::isVisible() const
139bool RootActionState::isVisible() const
@@ -141,15 +148,15 @@ static QString iconUri(GIcon *icon)
141 QString uri;
148 QString uri;
142
149
143 if (G_IS_THEMED_ICON (icon)) {
150 if (G_IS_THEMED_ICON (icon)) {
144−
145 const gchar* const* iconNames = g_themed_icon_get_names (G_THEMED_ICON (icon));
151 const gchar* const* iconNames = g_themed_icon_get_names (G_THEMED_ICON (icon));
146− guint index = 0;
152+
153+ QStringList iconNameList;
147− while(iconNames[index] != NULL) {
154+ for (uint index = 0; iconNames[index] != NULL; index++) {
148− if (QIcon::hasThemeIcon(iconNames[index])) {
155+ iconNameList << iconNames[index];
156+ }
157+
158+ if (!iconNameList.empty()) {
149− uri = QString("image://theme/%1").arg(iconNames[index]);
159+ uri = QString("image://theme/%1").arg(iconNameList.join(","));
150− break;
151− }
152− index++;
153 }
160 }
154 }
161 }
155 else if (G_IS_FILE_ICON (icon)) {
162 else if (G_IS_FILE_ICON (icon)) {
@@ -198,16 +205,39 @@ QVariant RootActionState::toQVariant(GVariant* state) const
198 while (g_variant_iter_loop (&iter, "{sv}", &key, &vvalue))
205 while (g_variant_iter_loop (&iter, "{sv}", &key, &vvalue))
199 {
206 {
200 QString str = QString::fromUtf8(key);
207 QString str = QString::fromUtf8(key);
201− if (str == "icon") {
208+ if (str == "icon" && !qmap.contains("icons")) {
209+ QStringList icons;
210+
202 // FIXME - should be sending a url.
211 // FIXME - should be sending a url.
203− GIcon *icon = g_icon_deserialize (vvalue);
212+ GIcon *gicon = g_icon_deserialize (vvalue);
204− if (icon) {
213+ if (gicon) {
205− qmap.insert(str, iconUri(icon));
214+ icons << iconUri(gicon);
206− g_object_unref (icon);
215+ g_object_unref (gicon);
207 }
216 }
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+ }
210 }
237 }
238+ // will overwrite icon.
239+ qmap.insert("icons", icons);
240+
211 } else {
241 } else {
212 qmap.insert(str, ActionStateParser::toQVariant(vvalue));
242 qmap.insert(str, ActionStateParser::toQVariant(vvalue));
213 }
243 }
@@ -230,12 +260,12 @@ QVariant RootActionState::toQVariant(GVariant* state) const
230 &visible);
260 &visible);
231
261
232 qmap["label"] = label ? QString::fromUtf8(label) : "";
262 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) : "";
234 qmap["visible"] = visible;
264 qmap["visible"] = visible;
235
265
236 gicon = g_icon_new_for_string (icon, NULL);
266 gicon = g_icon_new_for_string (icon, NULL);
237 if (gicon) {
267 if (gicon) {
238− qmap["icon"] = iconUri(gicon);
268+ qmap["icons"] = QStringList() << iconUri(gicon);
239 g_object_unref (gicon);
269 g_object_unref (gicon);
240 }
270 }
241
271
plugins/Unity/Indicators/rootactionstate.h+9−6
@@ -32,8 +32,9 @@ class UNITYINDICATORS_EXPORT RootActionState : public ActionStateParser
32 Q_PROPERTY(UnityMenuModel* menu READ menu WRITE setMenu NOTIFY menuChanged)
32 Q_PROPERTY(UnityMenuModel* menu READ menu WRITE setMenu NOTIFY menuChanged)
33
33
34 Q_PROPERTY(bool valid READ isValid NOTIFY validChanged)
34 Q_PROPERTY(bool valid READ isValid NOTIFY validChanged)
35− Q_PROPERTY(QString label READ label NOTIFY labelChanged)
35+ Q_PROPERTY(QString leftLabel READ leftLabel NOTIFY leftLabelChanged)
36− Q_PROPERTY(QString icon READ icon NOTIFY iconChanged)
36+ Q_PROPERTY(QString rightLabel READ rightLabel NOTIFY rightLabelChanged)
37+ Q_PROPERTY(QStringList icons READ icons NOTIFY iconsChanged)
37 Q_PROPERTY(QString accessibleName READ accessibleName NOTIFY accessibleNameChanged)
38 Q_PROPERTY(QString accessibleName READ accessibleName NOTIFY accessibleNameChanged)
38 Q_PROPERTY(bool visible READ isVisible NOTIFY visibleChanged)
39 Q_PROPERTY(bool visible READ isVisible NOTIFY visibleChanged)
39public:
40public:
@@ -47,8 +48,9 @@ public:
47 void setIndex(int index);
48 void setIndex(int index);
48
49
49 bool isValid() const;
50 bool isValid() const;
50− QString label() const;
51+ QString leftLabel() const;
51− QString icon() const;
52+ QString rightLabel() const;
53+ QStringList icons() const;
52 QString accessibleName() const;
54 QString accessibleName() const;
53 bool isVisible() const;
55 bool isVisible() const;
54
56
@@ -62,8 +64,9 @@ Q_SIGNALS:
62 void indexChanged();
64 void indexChanged();
63
65
64 void validChanged();
66 void validChanged();
65− void labelChanged();
67+ void leftLabelChanged();
66− void iconChanged();
68+ void rightLabelChanged();
69+ void iconsChanged();
67 void accessibleNameChanged();
70 void accessibleNameChanged();
68 void visibleChanged();
71 void visibleChanged();
69
72
plugins/Unity/Indicators/visibleindicatorsmodel.cppnew file+94
@@ -0,0 +1,94 @@
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+
17+// self
18+#include "visibleindicatorsmodel.h"
19+#include "indicators.h"
20+
21+VisibleIndicatorsModel::VisibleIndicatorsModel(QObject *parent)
22+ : QIdentityProxyModel(parent),
23+ m_inserting(false)
24+{
25+ QObject::connect(this, SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int)), this, SLOT(onBeginRowInserted(QModelIndex, int, int)));
26+ QObject::connect(this, SIGNAL(rowsInserted(QModelIndex, int, int)), this, SLOT(onRowInserted(QModelIndex, int, int)));
27+}
28+
29+QHash<int, QByteArray> VisibleIndicatorsModel::roleNames() const
30+{
31+ static QHash<int, QByteArray> roles;
32+ if (roles.isEmpty())
33+ {
34+ roles[IndicatorsModelRole::Identifier] = "identifier";
35+ roles[IndicatorsModelRole::Position] = "position";
36+ roles[IndicatorsModelRole::Title] = "title";
37+ roles[IndicatorsModelRole::Description] = "description";
38+ roles[IndicatorsModelRole::WidgetSource] = "widgetSource";
39+ roles[IndicatorsModelRole::PageSource] = "pageSource";
40+ roles[IndicatorsModelRole::IndicatorProperties] = "indicatorProperties";
41+ roles[IndicatorsModelRole::IsVisible] = "isVisible";
42+ }
43+ return roles;
44+}
45+
46+void VisibleIndicatorsModel::setSourceModel(QAbstractItemModel *model)
47+{
48+ if (sourceModel() != model) {
49+ QIdentityProxyModel::setSourceModel(model);
50+ Q_EMIT modelChanged();
51+ }
52+}
53+
54+QVariantMap VisibleIndicatorsModel::visible() const
55+{
56+ return m_visible;
57+}
58+
59+void VisibleIndicatorsModel::onBeginRowInserted(const QModelIndex&, int, int)
60+{
61+ m_inserting = true;
62+}
63+
64+void VisibleIndicatorsModel::onRowInserted(const QModelIndex&, int, int)
65+{
66+ m_inserting = false;
67+}
68+
69+void VisibleIndicatorsModel::setVisible(const QVariantMap& visible)
70+{
71+ if (m_visible != visible) {
72+ m_visible = visible;
73+ Q_EMIT visibleChanged();
74+
75+ // need to tell the view that the visible data has changed.
76+ if (!m_inserting && rowCount() > 0) {
77+ Q_EMIT dataChanged(index(0, 0), index(rowCount() - 1, 0), QVector<int>() << IndicatorsModelRole::IsVisible);
78+ }
79+ }
80+}
81+
82+QVariant VisibleIndicatorsModel::data(const QModelIndex &index, int role) const
83+{
84+ if (role != IndicatorsModelRole::IsVisible) {
85+ return QIdentityProxyModel::data(index, role);
86+ }
87+
88+ if (!index.isValid()) {
89+ return false;
90+ }
91+
92+ QString ident = QIdentityProxyModel::data(index, IndicatorsModelRole::Identifier).toString();
93+ return m_visible.value(ident, false).toBool();
94+}
plugins/Unity/Indicators/visibleindicatorsmodel.hnew file+56
@@ -0,0 +1,56 @@
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:
17+ * Nick Dedekind <nick.dedekind@canonical.com>
18+ */
19+
20+#ifndef VISIBLEINDICATORSMODEL_H
21+#define VISIBLEINDICATORSMODEL_H
22+
23+#include <QIdentityProxyModel>
24+
25+class VisibleIndicatorsModel : public QIdentityProxyModel
26+{
27+ Q_OBJECT
28+
29+ Q_PROPERTY(QAbstractItemModel* model READ sourceModel WRITE setSourceModel NOTIFY modelChanged)
30+ Q_PROPERTY(QVariantMap visible READ visible WRITE setVisible NOTIFY visibleChanged)
31+
32+public:
33+ explicit VisibleIndicatorsModel(QObject *parent = 0);
34+
35+ virtual void setSourceModel(QAbstractItemModel *model);
36+ virtual QHash<int, QByteArray> roleNames() const;
37+ virtual QVariant data(const QModelIndex &index, int role) const;
38+
39+ QVariantMap visible() const;
40+ void setVisible(const QVariantMap& visible);
41+
42+public Q_SLOTS:
43+ void onBeginRowInserted(const QModelIndex&, int start, int end);
44+ void onRowInserted(const QModelIndex&, int start, int end);
45+
46+Q_SIGNALS:
47+ void totalCountChanged();
48+ void modelChanged();
49+ void visibleChanged();
50+
51+private:
52+ QVariantMap m_visible;
53+ bool m_inserting;
54+};
55+
56+#endif // VISIBLEINDICATORSMODEL_H
plugins/Unity/IndicatorsLegacy/CMakeLists.txt−1
@@ -8,7 +8,6 @@ find_package(Qt5Core REQUIRED)
8find_package(Qt5Quick REQUIRED)
8find_package(Qt5Quick REQUIRED)
9
9
10add_subdirectory(qml)
10add_subdirectory(qml)
11−add_subdirectory(Messaging)
12add_subdirectory(Network)
11add_subdirectory(Network)
13
12
14include_directories(
13include_directories(
plugins/Unity/IndicatorsLegacy/Messaging/qml/CMakeLists.txtdeleted−5
@@ -1,5 +0,0 @@
1−# export_qmlfiles macro
2−include(Plugins)
3−
4−# export the qmldir, *.qml files.
5−export_qmlfiles(Unity.IndicatorsLegacy.Messaging Unity/IndicatorsLegacy/Messaging)
plugins/Unity/IndicatorsLegacy/Messaging/qml/MessageMenuItem.qmldeleted−96
@@ -1,96 +0,0 @@
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− * Renato Araujo Oliveira Filho <renato@canonical.com>
18− * Olivier Tilloy <olivier.tilloy@canonical.com>
19− */
20−
21−import QtQuick 2.0
22−import Ubuntu.Components 0.1
23−import Unity.IndicatorsLegacy 0.1 as Indicators
24−
25−Indicators.BasicMenuItem {
26− property variant actionsDescription: menu ? menu.extra.canonical_message_actions : undefined
27−
28− onActionGroupChanged: loadItem()
29− onActionsDescriptionChanged: loadItem()
30− implicitHeight: contents.status == Loader.Ready ? contents.item.implicitHeight : 0
31−
32− Loader {
33− id: contents
34−
35− anchors.fill: parent
36− // Binding all properties for the item, to make sure that any change in the
37− // property will be propagated to the contents.item at any time
38− Binding {
39− target: contents.item
40− property: "menuActivated"
41− value: menuActivated
42− when: (contents.status == Loader.Ready)
43− }
44−
45− Binding {
46− target: contents.item
47− property: "actionGroup"
48− value: actionGroup
49− when: (contents.status == Loader.Ready)
50− }
51−
52− Binding {
53− target: contents.item
54− property: "menu"
55− value: menu
56− when: (contents.status == Loader.Ready)
57− }
58−
59− Binding {
60− target: contents.item
61− property: "actionsDescription"
62− value: actionsDescription
63− when: (contents.status == Loader.Ready)
64− }
65−
66− Connections {
67− target: contents.item ? contents.item : null
68− onActivateMenu: activateMenu()
69− onDeactivateMenu: deactivateMenu()
70− }
71− }
72−
73−
74− function loadItem()
75− {
76− var parameterType = ""
77− for (var actIndex in actionsDescription) {
78− var desc = actionsDescription[actIndex];
79− if (desc["parameter-type"] !== undefined) {
80− parameterType += desc["parameter-type"];
81− } else {
82− parameterType += "_";
83− }
84− }
85−
86− if (parameterType === "") {
87− contents.source = "SimpleTextMessage.qml";
88− } else if (parameterType === "s") {
89− contents.source = "TextMessage.qml";
90− } else if (parameterType === "_s") {
91− contents.source = "SnapDecision.qml";
92− } else {
93− console.debug("Unknown paramater type: " + parameterType);
94− }
95− }
96−}
plugins/Unity/IndicatorsLegacy/Network/qml/AccessPoint.qml+2−2
@@ -47,10 +47,10 @@ Indicators.MenuItem {
47 imageName += "-secure";
47 imageName += "-secure";
48 }
48 }
49
49
50− return "image://gicon/" + imageName;
50+ return "image://theme/" + imageName;
51 }
51 }
52
52
53− icon: menu && wifiApStrength ? getNetworkIcon(menu) : "image://gicon/wifi-none"
53+ icon: menu && wifiApStrength ? getNetworkIcon(menu) : "image://theme/wifi-none"
54 iconFrame: false
54 iconFrame: false
55 control: CheckBox {
55 control: CheckBox {
56 id: checkBoxActive
56 id: checkBoxActive
plugins/Unity/IndicatorsLegacy/qml/IndicatorWidget.qml+2−2
@@ -23,7 +23,7 @@ import Unity.IndicatorsLegacy 0.1 as Indicators
23IndicatorBase {
23IndicatorBase {
24 id: indicatorWidget
24 id: indicatorWidget
25
25
26−// enabled: false // FIXME : should be disabled until bus available when we have desktop indicators
26+ enabled: false
27 property var action: undefined
27 property var action: undefined
28 property bool started: (busType != 0) && (busName != "") && (deviceMenuObjectPath != "")
28 property bool started: (busType != 0) && (busName != "") && (deviceMenuObjectPath != "")
29 property int iconSize: height - units.gu(0.5)
29 property int iconSize: height - units.gu(0.5)
@@ -40,7 +40,6 @@ IndicatorBase {
40 actionGroup.stop();
40 actionGroup.stop();
41 }
41 }
42 }
42 }
43− onActionChanged: actionStateChanged()
44 onActionGroupUpdated: update_state()
43 onActionGroupUpdated: update_state()
45 onModelUpdated: update_state()
44 onModelUpdated: update_state()
46
45
@@ -57,6 +56,7 @@ IndicatorBase {
57
56
58 if (extra.canonical_type === rootMenuType) {
57 if (extra.canonical_type === rootMenuType) {
59 action = actionGroup.action(proxyModel.data(0, Indicators.FlatMenuProxyModelRole.Action));
58 action = actionGroup.action(proxyModel.data(0, Indicators.FlatMenuProxyModelRole.Action));
59+ actionStateChanged();
60 }
60 }
61 }
61 }
62
62
plugins/Unity/IndicatorsLegacy/qml/MenuItemFactory.qml−8
@@ -19,7 +19,6 @@
19
19
20import QtQuick 2.0
20import QtQuick 2.0
21import Unity.IndicatorsLegacy 0.1 as Indicators
21import Unity.IndicatorsLegacy 0.1 as Indicators
22−import Unity.IndicatorsLegacy.Messaging 0.1 as ICMessaging
23import Unity.IndicatorsLegacy.Network 0.1 as ICNetwork
22import Unity.IndicatorsLegacy.Network 0.1 as ICNetwork
24
23
25Item {
24Item {
@@ -47,10 +46,6 @@ Item {
47 "com.canonical.indicator.slider" : sliderMenu,
46 "com.canonical.indicator.slider" : sliderMenu,
48 "com.canonical.indicator.switch" : switchMenu,
47 "com.canonical.indicator.switch" : switchMenu,
49
48
50− "com.canonical.indicator.messages.messageitem" : messageItem,
51− "com.canonical.indicator.messages.snapdecision" : snapDecision,
52− "com.canonical.indicator.messages.sourceitem" : groupedMessage,
53−
54 "unity.widget.systemsettings.tablet.sectiontitle" : wifiSection,
49 "unity.widget.systemsettings.tablet.sectiontitle" : wifiSection,
55 "unity.widgets.systemsettings.tablet.wifisection" : wifiSection,
50 "unity.widgets.systemsettings.tablet.wifisection" : wifiSection,
56 "unity.widgets.systemsettings.tablet.accesspoint" : accessPoint,
51 "unity.widgets.systemsettings.tablet.accesspoint" : accessPoint,
@@ -62,9 +57,6 @@ Item {
62 Component { id: divMenu; Indicators.DivMenuItem {} }
57 Component { id: divMenu; Indicators.DivMenuItem {} }
63 Component { id: sectionMenu; Indicators.SectionMenuItem {} }
58 Component { id: sectionMenu; Indicators.SectionMenuItem {} }
64 Component { id: progressMenu; Indicators.ProgressMenuItem {} }
59 Component { id: progressMenu; Indicators.ProgressMenuItem {} }
65− Component { id: messageItem; ICMessaging.MessageMenuItem {} }
66− Component { id: snapDecision; ICMessaging.SnapDecision {} }
67− Component { id: groupedMessage; ICMessaging.GroupedMessage {} }
68 Component { id: wifiSection; ICNetwork.WifiSection {} }
60 Component { id: wifiSection; ICNetwork.WifiSection {} }
69 Component { id: accessPoint; ICNetwork.AccessPoint {} }
61 Component { id: accessPoint; ICNetwork.AccessPoint {} }
70 Component { id: indicatorMenu; Indicators.MenuItem {} }
62 Component { id: indicatorMenu; Indicators.MenuItem {} }
plugins/Unity/IndicatorsLegacy/resources/indicators.qrc−3
@@ -1,7 +1,4 @@
1<RCC>
1<RCC>
2 <qresource prefix="/indicators">
2 <qresource prefix="/indicators">
3− <file>artwork/messaging/default_contact.png</file>
4− <file>artwork/messaging/default_app.svg</file>
5− <file>artwork/messaging/message_sms01_54px.png</file>
6 </qresource>
3 </qresource>
7</RCC>
4</RCC>
plugins/Unity/Launcher/CMakeLists.txt+11−2
@@ -1,8 +1,14 @@
1include(FindPkgConfig)
1include(FindPkgConfig)
2−pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=2)
2+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=3)
3+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=1)
4+pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
5+
6+add_definitions(-DSM_BUSNAME=systemBus)
3
7
4include_directories(
8include_directories(
5 ${CMAKE_CURRENT_SOURCE_DIR}
9 ${CMAKE_CURRENT_SOURCE_DIR}
10+ ${CMAKE_SOURCE_DIR}/plugins/AccountsService
11+ ${GSETTINGS_QT_INCLUDE_DIRS}
6)
12)
7
13
8set(QMLLAUNCHERPLUGIN_SRC
14set(QMLLAUNCHERPLUGIN_SRC
@@ -12,6 +18,7 @@ set(QMLLAUNCHERPLUGIN_SRC
12 quicklistmodel.cpp
18 quicklistmodel.cpp
13 common/quicklistentry.cpp
19 common/quicklistentry.cpp
14 backend/launcherbackend.cpp
20 backend/launcherbackend.cpp
21+ ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
15 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
22 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
16 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
23 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
17 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
24 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
@@ -21,7 +28,9 @@ add_library(UnityLauncher-qml MODULE
21 ${QMLLAUNCHERPLUGIN_SRC}
28 ${QMLLAUNCHERPLUGIN_SRC}
22 )
29 )
23
30
31+target_link_libraries(UnityLauncher-qml ${GSETTINGS_QT_LDFLAGS})
32+
24−qt5_use_modules(UnityLauncher-qml Qml)
33+qt5_use_modules(UnityLauncher-qml DBus Qml)
25
34
26# export the qmldir and qmltypes files
35# export the qmldir and qmltypes files
27export_qmlfiles(Unity.Launcher Unity/Launcher)
36export_qmlfiles(Unity.Launcher Unity/Launcher)
plugins/Unity/Launcher/backend/launcherbackend.cpp+261−59
@@ -2,6 +2,7 @@
2 * Copyright (C) 2013 Canonical, Ltd.
2 * Copyright (C) 2013 Canonical, Ltd.
3 *
3 *
4 * Authors:
4 * Authors:
5+ * Michael Terry <michael.terry@canonical.com>
5 * Michael Zanetti <michael.zanetti@canonical.com>
6 * Michael Zanetti <michael.zanetti@canonical.com>
6 *
7 *
7 * This program is free software; you can redistribute it and/or modify
8 * This program is free software; you can redistribute it and/or modify
@@ -17,63 +18,45 @@
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 */
19
20
21+#include "AccountsServiceDBusAdaptor.h"
20#include "launcherbackend.h"
22#include "launcherbackend.h"
21
23
22−#include <QHash>
24+#include <QDir>
23−
25+#include <QDBusArgument>
24−LauncherBackend::LauncherBackend(QObject *parent):
26+#include <QFileInfo>
25− QObject(parent)
27+#include <QGSettings>
26−{
28+#include <QDebug>
27−
28− // TODO: load default pinned ones from default config, instead of hardcoding here...
29−
30− m_storedApps <<
31− QLatin1String("dialer-app.desktop") <<
32− QLatin1String("messaging-app.desktop") <<
33− QLatin1String("address-book-app.desktop") <<
34− QLatin1String("camera-app.desktop") <<
35− QLatin1String("gallery-app.desktop") <<
36− QLatin1String("facebook-webapp.desktop") <<
37− QLatin1String("webbrowser-app.desktop") <<
38− QLatin1String("twitter-webapp.desktop") <<
39− QLatin1String("gmail-webapp.desktop") <<
40− QLatin1String("ubuntu-weather-app.desktop") <<
41− QLatin1String("notes-app.desktop") <<
42− QLatin1String("calendar-app.desktop");
43−
44− // TODO: get stuff from desktop files instead this hardcoded map
45− m_displayNameMap.insert("dialer-app.desktop", "Dialer");
46− m_displayNameMap.insert("messaging-app.desktop", "Messaging");
47− m_displayNameMap.insert("address-book-app.desktop", "Contacts");
48− m_displayNameMap.insert("camera-app.desktop", "Camera");
49− m_displayNameMap.insert("gallery-app.desktop", "Gallery");
50− m_displayNameMap.insert("facebook-webapp.desktop", "Facebook");
51− m_displayNameMap.insert("webbrowser-app.desktop", "Browser");
52− m_displayNameMap.insert("twitter-webapp.desktop", "Twitter");
53− m_displayNameMap.insert("gmail-webapp.desktop", "GMail");
54− m_displayNameMap.insert("ubuntu-weather-app.desktop", "Weather");
55− m_displayNameMap.insert("notes-app.desktop", "Notes");
56− m_displayNameMap.insert("calendar-app.desktop", "Calendar");
57−
58− // TODO: get stuff from desktop files instead this hardcoded map
59− m_iconMap.insert("dialer-app.desktop", "phone-app");
60− m_iconMap.insert("messaging-app.desktop", "messages-app");
61− m_iconMap.insert("address-book-app.desktop", "contacts-app");
62− m_iconMap.insert("camera-app.desktop", "camera");
63− m_iconMap.insert("gallery-app.desktop", "gallery");
64− m_iconMap.insert("facebook-webapp.desktop", "facebook");
65− m_iconMap.insert("webbrowser-app.desktop", "browser");
66− m_iconMap.insert("twitter-webapp.desktop", "twitter");
67− m_iconMap.insert("gmail-webapp.desktop", "gmail");
68− m_iconMap.insert("ubuntu-weather-app.desktop", "weather");
69− m_iconMap.insert("notes-app.desktop", "notepad");
70− m_iconMap.insert("calendar-app.desktop", "calendar");
71
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+};
40+
41+LauncherBackend::LauncherBackend(bool useStorage, QObject *parent):
42+ QObject(parent),
43+ m_accounts(nullptr)
44+{
45+ if (useStorage) {
46+ m_accounts = new AccountsServiceDBusAdaptor(this);
47+ }
48+ m_user = qgetenv("USER");
49+ syncFromAccounts();
72}
50}
73
51
74LauncherBackend::~LauncherBackend()
52LauncherBackend::~LauncherBackend()
75{
53{
54+ m_storedApps.clear();
76
55
56+ Q_FOREACH(LauncherBackendItem *item, m_itemCache) {
57+ delete item;
58+ }
59+ m_itemCache.clear();
77}
60}
78
61
79QStringList LauncherBackend::storedApplications() const
62QStringList LauncherBackend::storedApplications() const
@@ -83,38 +66,99 @@ QStringList LauncherBackend::storedApplications() const
83
66
84void LauncherBackend::setStoredApplications(const QStringList &appIds)
67void LauncherBackend::setStoredApplications(const QStringList &appIds)
85{
68{
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+ }
74+ }
75+ }
86 m_storedApps = appIds;
76 m_storedApps = appIds;
87− // TODO: Cleanup pinned state from settings for apps not in list any more.
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+ }
89+ }
90+ syncToAccounts();
88}
91}
89
92
90QString LauncherBackend::desktopFile(const QString &appId) const
93QString LauncherBackend::desktopFile(const QString &appId) const
91{
94{
92− // TODO: return real path instead of this hardcoded one
95+ LauncherBackendItem *item = m_itemCache.value(appId);
93− return QLatin1String("/usr/share/applications/") + appId;
96+ if (item) {
97+ return item->desktopFile;
98+ }
99+
100+ return findDesktopFile(appId);
94}
101}
95
102
96QString LauncherBackend::displayName(const QString &appId) const
103QString LauncherBackend::displayName(const QString &appId) const
97{
104{
98− return m_displayNameMap.value(appId);
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();
99}
118}
100
119
101QString LauncherBackend::icon(const QString &appId) const
120QString LauncherBackend::icon(const QString &appId) const
102{
121{
103− return m_iconMap.value(appId);
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;
132+ }
133+ }
134+
135+ return iconName;
104}
136}
105
137
106bool LauncherBackend::isPinned(const QString &appId) const
138bool LauncherBackend::isPinned(const QString &appId) const
107{
139{
140+ LauncherBackendItem *item = m_itemCache.value(appId);
141+ if (item) {
108− // TODO: return app's pinned state from settings
142+ return item->pinned;
109− Q_UNUSED(appId)
143+ }
110 return false;
144 return false;
111}
145}
112
146
113void LauncherBackend::setPinned(const QString &appId, bool pinned)
147void LauncherBackend::setPinned(const QString &appId, bool pinned)
114{
148{
115− // TODO: Store pinned state in settings.
149+ if (!m_storedApps.contains(appId)) {
116− Q_UNUSED(appId)
150+ return;
117− Q_UNUSED(pinned)
151+ }
152+
153+ LauncherBackendItem *item = m_itemCache.value(appId);
154+ if (!item) {
155+ item = new LauncherBackendItem();
156+ m_itemCache.insert(appId, item);
157+ }
158+ if (item->pinned != pinned) {
159+ item->pinned = pinned;
160+ syncToAccounts();
161+ }
118}
162}
119
163
120QList<QuickListEntry> LauncherBackend::quickList(const QString &appId) const
164QList<QuickListEntry> LauncherBackend::quickList(const QString &appId) const
@@ -143,9 +187,167 @@ int LauncherBackend::count(const QString &appId) const
143 return 0;
187 return 0;
144}
188}
145
189
190+void LauncherBackend::setUser(const QString &username)
191+{
192+ if (qgetenv("USER") == "lightdm" && m_user != username) {
193+ m_user = username;
194+ syncFromAccounts();
195+ }
196+}
197+
146void LauncherBackend::triggerQuickListAction(const QString &appId, const QString &quickListId)
198void LauncherBackend::triggerQuickListAction(const QString &appId, const QString &quickListId)
147{
199{
148 // TODO: execute the given quicklist action
200 // TODO: execute the given quicklist action
149 Q_UNUSED(appId)
201 Q_UNUSED(appId)
150 Q_UNUSED(quickListId)
202 Q_UNUSED(quickListId)
151}
203}
204+
205+void LauncherBackend::syncFromAccounts()
206+{
207+ QList<QVariantMap> apps;
208+ bool defaults = true;
209+
210+ m_storedApps.clear();
211+
212+ if (m_accounts && !m_user.isEmpty()) {
213+ QVariant variant = m_accounts->getUserProperty(m_user, "com.canonical.unity.AccountsService", "launcher-items");
214+ apps = qdbus_cast<QList<QVariantMap>>(variant.value<QDBusArgument>());
215+ defaults = isDefaultsItem(apps);
216+ }
217+
218+ if (m_accounts && defaults) { // Checking accounts as it'll be null when !useStorage
219+ QGSettings gSettings("com.canonical.Unity.Launcher", "/com/canonical/unity/launcher/");
220+ Q_FOREACH(const QString &entry, gSettings.get("favorites").toStringList()) {
221+ if (entry.startsWith("application://")) {
222+ QString appId = entry;
223+ // Transform "application://foobar.desktop" to "foobar"
224+ appId.remove("application://");
225+ if (appId.endsWith(".desktop")) {
226+ appId.chop(8);
227+ }
228+ QString df = findDesktopFile(appId);
229+
230+ if (!df.isEmpty()) {
231+ m_storedApps << appId;
232+
233+ if (!m_itemCache.contains(appId)) {
234+ m_itemCache.insert(appId, parseDesktopFile(df));
235+ }
236+ m_itemCache.value(appId)->pinned = true;
237+ }
238+ }
239+ }
240+ } else {
241+ for (const QVariant &app: apps) {
242+ loadFromVariant(app.toMap());
243+ }
244+ }
245+}
246+
247+void LauncherBackend::syncToAccounts()
248+{
249+ if (m_accounts && !m_user.isEmpty()) {
250+ QList<QVariantMap> items;
251+
252+ Q_FOREACH(const QString &appId, m_storedApps) {
253+ items << itemToVariant(appId);
254+ }
255+
256+ m_accounts->setUserProperty(m_user, "com.canonical.unity.AccountsService", "launcher-items", QVariant::fromValue(items));
257+ }
258+}
259+
260+QString LauncherBackend::findDesktopFile(const QString &appId) const
261+{
262+ int dashPos = -1;
263+ QString helper = appId;
264+
265+ QStringList searchDirs;
266+ searchDirs << QDir::homePath() + "/.local/share/applications";
267+ searchDirs << "/usr/share/applications";
268+
269+#ifdef LAUNCHER_TESTING
270+ searchDirs << "";
271+#endif
272+
273+ do {
274+ if (dashPos != -1) {
275+ helper = helper.replace(dashPos, 1, '/');
276+ }
277+
278+ Q_FOREACH(const QString &searchDir, searchDirs) {
279+ QFileInfo fileInfo(QDir(searchDir), helper + ".desktop");
280+ if (fileInfo.exists()) {
281+ return fileInfo.absoluteFilePath();
282+ }
283+ }
284+
285+ dashPos = helper.indexOf("-");
286+ } while (dashPos != -1);
287+
288+ return QString();
289+}
290+
291+LauncherBackendItem* LauncherBackend::parseDesktopFile(const QString &desktopFile) const
292+{
293+ QSettings settings(desktopFile, QSettings::IniFormat);
294+
295+ LauncherBackendItem* item = new LauncherBackendItem();
296+ item->desktopFile = desktopFile;
297+ item->displayName = settings.value("Desktop Entry/Name").toString();
298+
299+ QString iconString = settings.value("Desktop Entry/Icon").toString();
300+ QString pathString = settings.value("Desktop Entry/Path").toString();
301+ if (QFileInfo(iconString).exists()) {
302+ item->icon = QFileInfo(iconString).absoluteFilePath();
303+ } else if (QFileInfo(pathString + '/' + iconString).exists()) {
304+ item->icon = pathString + '/' + iconString;
305+ } else {
306+ item->icon = "image://theme/" + iconString;
307+ }
308+ item->pinned = false;
309+ return item;
310+}
311+
312+void LauncherBackend::loadFromVariant(const QVariantMap &details)
313+{
314+ if (!details.contains("id")) {
315+ return;
316+ }
317+ QString appId = details.value("id").toString();
318+
319+ LauncherBackendItem *item = m_itemCache.value(appId);
320+ if (item) {
321+ delete item;
322+ }
323+
324+ item = new LauncherBackendItem();
325+
326+ item->desktopFile = details.value("desktopFile").toString();
327+ item->displayName = details.value("name").toString();
328+ item->icon = details.value("icon").toString();
329+ item->pinned = details.value("is-pinned").toBool();
330+
331+ m_itemCache.insert(appId, item);
332+ m_storedApps.append(appId);
333+}
334+
335+QVariantMap LauncherBackend::itemToVariant(const QString &appId) const
336+{
337+ LauncherBackendItem *item = m_itemCache.value(appId);
338+ QVariantMap details;
339+ details.insert("id", appId);
340+ details.insert("name", item->displayName);
341+ details.insert("icon", item->icon);
342+ details.insert("desktopFile", item->desktopFile);
343+ details.insert("is-pinned", item->pinned);
344+ return details;
345+}
346+
347+bool LauncherBackend::isDefaultsItem(const QList<QVariantMap> &apps) const
348+{
349+ // To differentiate between an empty list and a list that hasn't been set
350+ // yet (and should thus be populated with the defaults), we use a special
351+ // list of one item with the 'defaults' field set to true.
352+ return (apps.size() == 1 && apps[0].value("defaults").toBool());
353+}
plugins/Unity/Launcher/backend/launcherbackend.h+36−5
@@ -22,20 +22,24 @@
22#include "common/quicklistentry.h"
22#include "common/quicklistentry.h"
23
23
24#include <QObject>
24#include <QObject>
25+#include <QSettings>
25#include <QStringList>
26#include <QStringList>
26−#include <QHash>
27+
28+class AccountsServiceDBusAdaptor;
27
29
28/**
30/**
29 * @brief An interface that provides all the data needed by the launcher.
31 * @brief An interface that provides all the data needed by the launcher.
30 */
32 */
31
33
34+class LauncherBackendItem;
35+
32class LauncherBackend : public QObject
36class LauncherBackend : public QObject
33{
37{
34 Q_OBJECT
38 Q_OBJECT
35
39
36
40
37public:
41public:
38− LauncherBackend(QObject *parent = 0);
42+ LauncherBackend(bool useStorage = true, QObject *parent = 0);
39 virtual ~LauncherBackend();
43 virtual ~LauncherBackend();
40
44
41 /**
45 /**
@@ -57,12 +61,18 @@ public:
57
61
58 /**
62 /**
59 * @brief Get the full path to the .desktop file.
63 * @brief Get the full path to the .desktop file.
64+ *
65+ * The application does not need to be in the list of stored applications.
66+ *
60 * @returns The full path to the .dekstop file.
67 * @returns The full path to the .dekstop file.
61 */
68 */
62 QString desktopFile(const QString &appId) const;
69 QString desktopFile(const QString &appId) const;
63
70
64 /**
71 /**
65 * @brief Get the user friendly name of an application.
72 * @brief Get the user friendly name of an application.
73+ *
74+ * The application does not need to be in the list of stored applications.
75+ *
66 * @param appId The ID of the application.
76 * @param appId The ID of the application.
67 * @returns The user friendly name of the application.
77 * @returns The user friendly name of the application.
68 */
78 */
@@ -70,6 +80,9 @@ public:
70
80
71 /**
81 /**
72 * @brief Get the icon of an application.
82 * @brief Get the icon of an application.
83+ *
84+ * The application does not need to be in the list of stored applications.
85+ *
73 * @param appId The ID of the application.
86 * @param appId The ID of the application.
74 * @returns The full path to the icon for the application.
87 * @returns The full path to the icon for the application.
75 */
88 */
@@ -118,15 +131,33 @@ public:
118 */
131 */
119 int count(const QString &appId) const;
132 int count(const QString &appId) const;
120
133
134+ /**
135+ * @brief Sets the username for which to look up launcher items.
136+ * @param username The username to use.
137+ */
138+ void setUser(const QString &username);
139+
121Q_SIGNALS:
140Q_SIGNALS:
122 void quickListChanged(const QString &appId, const QList<QuickListEntry> &quickList);
141 void quickListChanged(const QString &appId, const QList<QuickListEntry> &quickList);
123 void progressChanged(const QString &appId, int progress);
142 void progressChanged(const QString &appId, int progress);
124 void countChanged(const QString &appId, int count);
143 void countChanged(const QString &appId, int count);
125
144
126private:
145private:
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+
152+ bool isDefaultsItem(const QList<QVariantMap> &apps) const;
153+ void syncFromAccounts();
154+ void syncToAccounts();
155+
127− QStringList m_storedApps;
156+ QList<QString> m_storedApps;
128− QHash<QString, QString> m_displayNameMap;
157+ mutable QHash<QString, LauncherBackendItem*> m_itemCache;
129− QHash<QString, QString> m_iconMap;
158+
159+ AccountsServiceDBusAdaptor *m_accounts;
160+ QString m_user;
130};
161};
131
162
132#endif // LAUNCHERBACKEND_H
163#endif // LAUNCHERBACKEND_H
plugins/Unity/Launcher/launcheritem.cpp+15−7
@@ -20,10 +20,9 @@
20#include "launcheritem.h"
20#include "launcheritem.h"
21#include "quicklistmodel.h"
21#include "quicklistmodel.h"
22
22
23−LauncherItem::LauncherItem(const QString &appId, const QString &desktopFile, const QString &name, const QString &icon, QObject *parent) :
23+LauncherItem::LauncherItem(const QString &appId, const QString &name, const QString &icon, QObject *parent) :
24 LauncherItemInterface(parent),
24 LauncherItemInterface(parent),
25 m_appId(appId),
25 m_appId(appId),
26− m_desktopFile(desktopFile),
27 m_name(name),
26 m_name(name),
28 m_icon(icon),
27 m_icon(icon),
29 m_pinned(false),
28 m_pinned(false),
@@ -31,6 +30,7 @@ LauncherItem::LauncherItem(const QString &appId, const QString &desktopFile, con
31 m_recent(false),
30 m_recent(false),
32 m_progress(-1),
31 m_progress(-1),
33 m_count(0),
32 m_count(0),
33+ m_focused(false),
34 m_quickList(new QuickListModel(this))
34 m_quickList(new QuickListModel(this))
35{
35{
36 QuickListEntry nameAction;
36 QuickListEntry nameAction;
@@ -47,11 +47,6 @@ QString LauncherItem::appId() const
47 return m_appId;
47 return m_appId;
48}
48}
49
49
50−QString LauncherItem::desktopFile() const
51−{
52− return m_desktopFile;
53−}
54−
55QString LauncherItem::name() const
50QString LauncherItem::name() const
56{
51{
57 return m_name;
52 return m_name;
@@ -131,6 +126,19 @@ void LauncherItem::setCount(int count)
131 }
126 }
132}
127}
133
128
129+bool LauncherItem::focused() const
130+{
131+ return m_focused;
132+}
133+
134+void LauncherItem::setFocused(bool focused)
135+{
136+ if (m_focused != focused) {
137+ m_focused = focused;
138+ Q_EMIT focusedChanged(focused);
139+ }
140+}
141+
134unity::shell::launcher::QuickListModelInterface *LauncherItem::quickList() const
142unity::shell::launcher::QuickListModelInterface *LauncherItem::quickList() const
135{
143{
136 return m_quickList;
144 return m_quickList;
plugins/Unity/Launcher/launcheritem.h+5−3
@@ -32,10 +32,9 @@ class LauncherItem: public LauncherItemInterface
32{
32{
33 Q_OBJECT
33 Q_OBJECT
34public:
34public:
35− LauncherItem(const QString &appId, const QString &desktopFile, const QString &name, const QString &icon, QObject *parent = 0);
35+ LauncherItem(const QString &appId, const QString &name, const QString &icon, QObject *parent = 0);
36
36
37 QString appId() const;
37 QString appId() const;
38− QString desktopFile() const;
39 QString name() const;
38 QString name() const;
40 QString icon() const;
39 QString icon() const;
41
40
@@ -54,6 +53,9 @@ public:
54 int count() const;
53 int count() const;
55 void setCount(int count);
54 void setCount(int count);
56
55
56+ bool focused() const;
57+ void setFocused(bool focused);
58+
57 unity::shell::launcher::QuickListModelInterface *quickList() const;
59 unity::shell::launcher::QuickListModelInterface *quickList() const;
58
60
59Q_SIGNALS:
61Q_SIGNALS:
@@ -62,7 +64,6 @@ Q_SIGNALS:
62
64
63private:
65private:
64 QString m_appId;
66 QString m_appId;
65− QString m_desktopFile;
66 QString m_name;
67 QString m_name;
67 QString m_icon;
68 QString m_icon;
68 bool m_pinned;
69 bool m_pinned;
@@ -70,6 +71,7 @@ private:
70 bool m_recent;
71 bool m_recent;
71 int m_progress;
72 int m_progress;
72 int m_count;
73 int m_count;
74+ bool m_focused;
73 QuickListModel *m_quickList;
75 QuickListModel *m_quickList;
74};
76};
75
77
plugins/Unity/Launcher/launchermodel.cpp+129−12
@@ -21,16 +21,20 @@
21#include "launcheritem.h"
21#include "launcheritem.h"
22#include "backend/launcherbackend.h"
22#include "backend/launcherbackend.h"
23
23
24+#include <unity/shell/application/ApplicationInfoInterface.h>
25+
26+using namespace unity::shell::application;
27+
24LauncherModel::LauncherModel(QObject *parent):
28LauncherModel::LauncherModel(QObject *parent):
25 LauncherModelInterface(parent),
29 LauncherModelInterface(parent),
26− m_backend(new LauncherBackend(this))
30+ m_backend(new LauncherBackend(true, this)),
31+ m_appManager(0)
27{
32{
28 connect(m_backend, SIGNAL(countChanged(QString,int)), SLOT(countChanged(QString,int)));
33 connect(m_backend, SIGNAL(countChanged(QString,int)), SLOT(countChanged(QString,int)));
29 connect(m_backend, SIGNAL(progressChanged(QString,int)), SLOT(progressChanged(QString,int)));
34 connect(m_backend, SIGNAL(progressChanged(QString,int)), SLOT(progressChanged(QString,int)));
30
35
31 Q_FOREACH (const QString &entry, m_backend->storedApplications()) {
36 Q_FOREACH (const QString &entry, m_backend->storedApplications()) {
32 LauncherItem *item = new LauncherItem(entry,
37 LauncherItem *item = new LauncherItem(entry,
33− m_backend->desktopFile(entry),
34 m_backend->displayName(entry),
38 m_backend->displayName(entry),
35 m_backend->icon(entry),
39 m_backend->icon(entry),
36 this);
40 this);
@@ -61,9 +65,7 @@ QVariant LauncherModel::data(const QModelIndex &index, int role) const
61 LauncherItem *item = m_list.at(index.row());
65 LauncherItem *item = m_list.at(index.row());
62 switch(role) {
66 switch(role) {
63 case RoleAppId:
67 case RoleAppId:
64− return item->desktopFile();
68+ return item->appId();
65− case RoleDesktopFile:
66− return item->desktopFile();
67 case RoleName:
69 case RoleName:
68 return item->name();
70 return item->name();
69 case RoleIcon:
71 case RoleIcon:
@@ -74,6 +76,8 @@ QVariant LauncherModel::data(const QModelIndex &index, int role) const
74 return item->count();
76 return item->count();
75 case RoleProgress:
77 case RoleProgress:
76 return item->progress();
78 return item->progress();
79+ case RoleFocused:
80+ return item->focused();
77 }
81 }
78
82
79 return QVariant();
83 return QVariant();
@@ -111,9 +115,11 @@ void LauncherModel::move(int oldIndex, int newIndex)
111 m_list.move(oldIndex, newIndex);
115 m_list.move(oldIndex, newIndex);
112 endMoveRows();
116 endMoveRows();
113
117
114− storeAppList();
118+ if (!m_list.at(newIndex)->pinned()) {
115−
116− pin(m_list.at(newIndex)->appId());
119+ pin(m_list.at(newIndex)->appId());
120+ } else {
121+ storeAppList();
122+ }
117}
123}
118
124
119void LauncherModel::pin(const QString &appId, int index)
125void LauncherModel::pin(const QString &appId, int index)
@@ -123,6 +129,7 @@ void LauncherModel::pin(const QString &appId, int index)
123 if (currentIndex >= 0) {
129 if (currentIndex >= 0) {
124 if (index == -1 || index == currentIndex) {
130 if (index == -1 || index == currentIndex) {
125 m_list.at(currentIndex)->setPinned(true);
131 m_list.at(currentIndex)->setPinned(true);
132+ m_backend->setPinned(appId, true);
126 QModelIndex modelIndex = this->index(currentIndex);
133 QModelIndex modelIndex = this->index(currentIndex);
127 Q_EMIT dataChanged(modelIndex, modelIndex);
134 Q_EMIT dataChanged(modelIndex, modelIndex);
128 } else {
135 } else {
@@ -134,13 +141,15 @@ void LauncherModel::pin(const QString &appId, int index)
134 }
141 }
135 beginInsertRows(QModelIndex(), index, index);
142 beginInsertRows(QModelIndex(), index, index);
136 LauncherItem *item = new LauncherItem(appId,
143 LauncherItem *item = new LauncherItem(appId,
137− m_backend->desktopFile(appId),
138 m_backend->displayName(appId),
144 m_backend->displayName(appId),
139 m_backend->icon(appId));
145 m_backend->icon(appId));
140 item->setPinned(true);
146 item->setPinned(true);
147+ m_backend->setPinned(appId, true);
141 m_list.insert(index, item);
148 m_list.insert(index, item);
142 endInsertRows();
149 endInsertRows();
143 }
150 }
151+
152+ storeAppList();
144}
153}
145
154
146void LauncherModel::requestRemove(const QString &appId)
155void LauncherModel::requestRemove(const QString &appId)
@@ -150,6 +159,11 @@ void LauncherModel::requestRemove(const QString &appId)
150 return;
159 return;
151 }
160 }
152
161
162+ if (m_appManager->findApplication(appId)) {
163+ m_list.at(index)->setPinned(false);
164+ return;
165+ }
166+
153 beginRemoveRows(QModelIndex(), index, index);
167 beginRemoveRows(QModelIndex(), index, index);
154 m_list.takeAt(index)->deleteLater();
168 m_list.takeAt(index)->deleteLater();
155 endRemoveRows();
169 endRemoveRows();
@@ -186,15 +200,58 @@ void LauncherModel::quickListActionInvoked(const QString &appId, int actionIndex
186
200
187void LauncherModel::setUser(const QString &username)
201void LauncherModel::setUser(const QString &username)
188{
202{
189− Q_UNUSED(username)
203+ m_backend->setUser(username);
190− // TODO: Implement this...
191}
204}
192
205
206+ApplicationManagerInterface *LauncherModel::applicationManager() const
207+{
208+ return m_appManager;
209+}
210+
211+void LauncherModel::setApplicationManager(unity::shell::application::ApplicationManagerInterface *appManager)
212+{
213+ // Is there already another appmanager set?
214+ if (m_appManager) {
215+ // Disconnect any signals
216+ disconnect(this, SLOT(applicationAdded(QModelIndex,int)));
217+ disconnect(this, SLOT(applicationRemoved(QModelIndex,int)));
218+ disconnect(this, SLOT(focusedAppIdChanged()));
219+
220+ // remove any recent/running apps from the launcher
221+ QList<int> recentAppIndices;
222+ for (int i = 0; i < m_list.count(); ++i) {
223+ if (m_list.at(i)->recent()) {
224+ recentAppIndices << i;
225+ }
226+ }
227+ int run = 0;
228+ while (recentAppIndices.count() > 0) {
229+ beginRemoveRows(QModelIndex(), recentAppIndices.first() - run, recentAppIndices.first() - run);
230+ m_list.takeAt(recentAppIndices.first() - run)->deleteLater();
231+ endRemoveRows();
232+ recentAppIndices.takeFirst();
233+ ++run;
234+ }
235+ }
236+
237+ m_appManager = appManager;
238+ connect(m_appManager, SIGNAL(rowsInserted(QModelIndex, int, int)), SLOT(applicationAdded(QModelIndex,int)));
239+ connect(m_appManager, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), SLOT(applicationRemoved(QModelIndex,int)));
240+ connect(m_appManager, SIGNAL(focusedApplicationIdChanged()), SLOT(focusedAppIdChanged()));
241+
242+ Q_EMIT applicationManagerChanged();
243+
244+ for (int i = 0; i < appManager->count(); ++i) {
245+ applicationAdded(QModelIndex(), i);
246+ }
247+}
248+
249+
193void LauncherModel::storeAppList()
250void LauncherModel::storeAppList()
194{
251{
195 QStringList appIds;
252 QStringList appIds;
196 Q_FOREACH(LauncherItem *item, m_list) {
253 Q_FOREACH(LauncherItem *item, m_list) {
197− if (item->pinned() || item->recent()) {
254+ if (item->pinned()) {
198 appIds << item->appId();
255 appIds << item->appId();
199 }
256 }
200 }
257 }
@@ -232,3 +289,63 @@ void LauncherModel::countChanged(const QString &appId, int count)
232 Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleCount);
289 Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleCount);
233 }
290 }
234}
291}
292+
293+void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
294+{
295+ Q_UNUSED(parent);
296+
297+ ApplicationInfoInterface *app = m_appManager->get(row);
298+
299+ bool found = false;
300+ Q_FOREACH(LauncherItem *item, m_list) {
301+ if (app->appId() == item->appId()) {
302+ found = true;
303+ break;
304+ }
305+ }
306+ if (found) {
307+ // Shall we paint some running/recent app highlight? If yes, do it here.
308+ } else {
309+ LauncherItem *item = new LauncherItem(app->appId(), app->name(), app->icon().toString());
310+ item->setRecent(true);
311+ item->setFocused(app->focused());
312+
313+ beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
314+ m_list.append(item);
315+ endInsertRows();
316+ }
317+}
318+
319+void LauncherModel::applicationRemoved(const QModelIndex &parent, int row)
320+{
321+ Q_UNUSED(parent)
322+
323+ int appIndex = -1;
324+ for (int i = 0; i < m_list.count(); ++i) {
325+ if (m_list.at(i)->appId() == m_appManager->get(row)->appId()) {
326+ appIndex = i;
327+ break;
328+ }
329+ }
330+
331+ if (appIndex > -1 && !m_list.at(appIndex)->pinned()) {
332+ beginRemoveRows(QModelIndex(), appIndex, appIndex);
333+ m_list.takeAt(appIndex)->deleteLater();
334+ endRemoveRows();
335+ }
336+}
337+
338+void LauncherModel::focusedAppIdChanged()
339+{
340+ QString appId = m_appManager->focusedApplicationId();
341+ for (int i = 0; i < m_list.count(); ++i) {
342+ LauncherItem *item = m_list.at(i);
343+ if (!item->focused() && item->appId() == appId) {
344+ item->setFocused(true);
345+ Q_EMIT dataChanged(index(i), index(i), QVector<int>() << RoleFocused);
346+ } else if (item->focused() && item->appId() != appId) {
347+ item->setFocused(false);
348+ Q_EMIT dataChanged(index(i), index(i), QVector<int>() << RoleFocused);
349+ }
350+ }
351+}
plugins/Unity/Launcher/launchermodel.h+11−1
@@ -17,11 +17,12 @@
17 * Michael Zanetti <michael.zanetti@canonical.com>
17 * Michael Zanetti <michael.zanetti@canonical.com>
18 */
18 */
19
19
20−#ifndef LAUNCHERMODELH
20+#ifndef LAUNCHERMODEL_H
21#define LAUNCHERMODEL_H
21#define LAUNCHERMODEL_H
22
22
23// unity-api
23// unity-api
24#include <unity/shell/launcher/LauncherModelInterface.h>
24#include <unity/shell/launcher/LauncherModelInterface.h>
25+#include <unity/shell/application/ApplicationManagerInterface.h>
25
26
26// Qt
27// Qt
27#include <QAbstractListModel>
28#include <QAbstractListModel>
@@ -30,6 +31,7 @@ class LauncherItem;
30class LauncherBackend;
31class LauncherBackend;
31
32
32using namespace unity::shell::launcher;
33using namespace unity::shell::launcher;
34+using namespace unity::shell::application;
33
35
34class LauncherModel: public LauncherModelInterface
36class LauncherModel: public LauncherModelInterface
35{
37{
@@ -50,6 +52,9 @@ public:
50 Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex);
52 Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex);
51 Q_INVOKABLE void setUser(const QString &username);
53 Q_INVOKABLE void setUser(const QString &username);
52
54
55+ unity::shell::application::ApplicationManagerInterface* applicationManager() const;
56+ void setApplicationManager(unity::shell::application::ApplicationManagerInterface *appManager);
57+
53private:
58private:
54 void storeAppList();
59 void storeAppList();
55 int findApplication(const QString &appId);
60 int findApplication(const QString &appId);
@@ -58,9 +63,14 @@ private Q_SLOTS:
58 void progressChanged(const QString &appId, int progress);
63 void progressChanged(const QString &appId, int progress);
59 void countChanged(const QString &appId, int count);
64 void countChanged(const QString &appId, int count);
60
65
66+ void applicationAdded(const QModelIndex &parent, int row);
67+ void applicationRemoved(const QModelIndex &parent, int row);
68+ void focusedAppIdChanged();
69+
61private:
70private:
62 QList<LauncherItem*> m_list;
71 QList<LauncherItem*> m_list;
63 LauncherBackend *m_backend;
72 LauncherBackend *m_backend;
73+ ApplicationManagerInterface *m_appManager;
64};
74};
65
75
66#endif // LAUNCHERMODEL_H
76#endif // LAUNCHERMODEL_H
plugins/Unity/applicationpreview.cpp+5−1
@@ -19,6 +19,7 @@
19
19
20// local
20// local
21#include "applicationpreview.h"
21#include "applicationpreview.h"
22+#include "iconutils.h"
22
23
23#include <QDebug>
24#include <QDebug>
24
25
@@ -61,7 +62,10 @@ QString ApplicationPreview::license() const
61QString ApplicationPreview::appIcon() const
62QString ApplicationPreview::appIcon() const
62{
63{
63 if (m_unityAppPreview) {
64 if (m_unityAppPreview) {
64− return QString::fromUtf8(g_icon_to_string(m_unityAppPreview->app_icon()));
65+ auto giconString = g_icon_to_string(m_unityAppPreview->app_icon());
66+ QString result(gIconToDeclarativeImageProviderString(QString::fromUtf8(giconString)));
67+ g_free(giconString);
68+ return result;
65 } else {
69 } else {
66 qWarning() << "Preview not set";
70 qWarning() << "Preview not set";
67 }
71 }
plugins/Unity/categories.cpp+12−4
@@ -21,6 +21,7 @@
21// self
21// self
22#include "categories.h"
22#include "categories.h"
23#include "categoryresults.h"
23#include "categoryresults.h"
24+#include <QDebug>
24
25
25// Qt
26// Qt
26#include <QDebug>
27#include <QDebug>
@@ -46,7 +47,6 @@ Categories::Categories(QObject* parent)
46 m_roles[Categories::RoleHints] = "hints";
47 m_roles[Categories::RoleHints] = "hints";
47 m_roles[Categories::RoleResults] = "results";
48 m_roles[Categories::RoleResults] = "results";
48 m_roles[Categories::RoleCount] = "count";
49 m_roles[Categories::RoleCount] = "count";
49− m_roles[Categories::RoleCategoryIndex] = "categoryIndex";
50
50
51 // TODO This should not be needed but accumulatting the count changes
51 // TODO This should not be needed but accumulatting the count changes
52 // makes the visualization more stable and also makes crashes on fast
52 // makes the visualization more stable and also makes crashes on fast
@@ -66,7 +66,17 @@ Categories::getResults(int index) const
66
66
67 unsigned categoryIndex = static_cast<unsigned>(index);
67 unsigned categoryIndex = static_cast<unsigned>(index);
68 auto unity_results = m_unityScope->GetResultsForCategory(categoryIndex);
68 auto unity_results = m_unityScope->GetResultsForCategory(categoryIndex);
69+ if (unity_results) {
69− results->setModel(unity_results->model());
70+ results->setModel(unity_results->model());
71+ } else {
72+ // No results model returned by unity core; this can be the case when the global
73+ // results model of this scope is still not set in unity core. Don't set backend
74+ // model in DeeListModel - it will still beahve properly as an empty model. Since
75+ // we're connected to the category model change signal, and it is set by unity core
76+ // at the same time as results model (on channel opening), we'll reset category
77+ // results models with proper models when we're notifed again.
78+ qWarning() << "No results model for category" << categoryIndex;
79+ }
70
80
71 m_results.insert(index, results);
81 m_results.insert(index, results);
72 }
82 }
@@ -291,8 +301,6 @@ Categories::data(const QModelIndex& index, int role) const
291 }
301 }
292 qDebug() << "Get count of cat" << DeeListModel::data(realIndex, CategoryColumn::ID).toString() << realRow << "at pos" << index.row() << "Count=" << getResults(realIndex.row())->rowCount();
302 qDebug() << "Get count of cat" << DeeListModel::data(realIndex, CategoryColumn::ID).toString() << realRow << "at pos" << index.row() << "Count=" << getResults(realIndex.row())->rowCount();
293 return QVariant::fromValue(getResults(realRow)->rowCount());
303 return QVariant::fromValue(getResults(realRow)->rowCount());
294− case RoleCategoryIndex:
295− return QVariant::fromValue(index.row()); // no remapping to realIndex
296 default:
304 default:
297 return QVariant();
305 return QVariant();
298 }
306 }
plugins/Unity/categories.h+1−2
@@ -53,8 +53,7 @@ public:
53 RoleProgressSource,
53 RoleProgressSource,
54 RoleHints,
54 RoleHints,
55 RoleResults,
55 RoleResults,
56− RoleCount,
56+ RoleCount
57− RoleCategoryIndex
58 };
57 };
59
58
60 Q_INVOKABLE void overrideResults(const QString& categoryId, QAbstractItemModel* model);
59 Q_INVOKABLE void overrideResults(const QString& categoryId, QAbstractItemModel* model);
plugins/Unity/categoryresults.cpp+5−2
@@ -19,6 +19,7 @@
19
19
20// self
20// self
21#include "categoryresults.h"
21#include "categoryresults.h"
22+#include "iconutils.h"
22
23
23// TODO: use something from libunity once it's public
24// TODO: use something from libunity once it's public
24enum ResultsColumn {
25enum ResultsColumn {
@@ -76,8 +77,10 @@ CategoryResults::data(const QModelIndex& index, int role) const
76 switch (role) {
77 switch (role) {
77 case RoleUri:
78 case RoleUri:
78 return DeeListModel::data(index, ResultsColumn::URI);
79 return DeeListModel::data(index, ResultsColumn::URI);
79− case RoleIconHint:
80+ case RoleIconHint: {
80− return DeeListModel::data(index, ResultsColumn::ICON_HINT);
81+ QString giconString(DeeListModel::data(index, ResultsColumn::ICON_HINT).toString());
82+ return QVariant::fromValue(gIconToDeclarativeImageProviderString(giconString));
83+ }
81 case RoleCategory:
84 case RoleCategory:
82 return DeeListModel::data(index, ResultsColumn::CATEGORY);
85 return DeeListModel::data(index, ResultsColumn::CATEGORY);
83 case RoleMimetype:
86 case RoleMimetype:
plugins/Unity/categoryresults.h+1−1
@@ -24,7 +24,7 @@
24// dee-qt
24// dee-qt
25#include "deelistmodel.h"
25#include "deelistmodel.h"
26
26
27−class CategoryResults : public DeeListModel
27+class Q_DECL_EXPORT CategoryResults : public DeeListModel
28{
28{
29 Q_OBJECT
29 Q_OBJECT
30
30
plugins/Unity/checkoptionfilter.cpp+3−1
@@ -52,9 +52,11 @@ void CheckOptionFilter::onOptionsChanged(unity::dash::CheckOptionFilter::CheckOp
52
52
53 m_options = new UnityOptionsModel(this, options,
53 m_options = new UnityOptionsModel(this, options,
54 m_unityCheckOptionFilter->option_added,
54 m_unityCheckOptionFilter->option_added,
55− m_unityCheckOptionFilter->option_removed);
55+ m_unityCheckOptionFilter->option_removed,
56+ m_unityCheckOptionFilter->show_all_button);
56
57
57 connect(m_options, SIGNAL(activeChanged(AbstractFilterOption *)), m_options, SLOT(ensureTheOnlyActive(AbstractFilterOption *)));
58 connect(m_options, SIGNAL(activeChanged(AbstractFilterOption *)), m_options, SLOT(ensureTheOnlyActive(AbstractFilterOption *)));
59+ connect(m_options, SIGNAL(showAllActivated()), this, SLOT(clear()));
58
60
59 /* Property change signals */
61 /* Property change signals */
60 m_signals << m_unityCheckOptionFilter->options.changed.connect(sigc::mem_fun(this, &CheckOptionFilter::onOptionsChanged));
62 m_signals << m_unityCheckOptionFilter->options.changed.connect(sigc::mem_fun(this, &CheckOptionFilter::onOptionsChanged));
plugins/Unity/filter.h+3−2
@@ -56,11 +56,12 @@ public:
56 bool filtering() const;
56 bool filtering() const;
57 virtual GenericOptionsModel* options() const = 0;
57 virtual GenericOptionsModel* options() const = 0;
58
58
59− Q_INVOKABLE void clear();
60−
61 static Filter* newFromUnityFilter(unity::dash::Filter::Ptr unityFilter);
59 static Filter* newFromUnityFilter(unity::dash::Filter::Ptr unityFilter);
62 bool hasUnityFilter(unity::dash::Filter::Ptr unityFilter) const;
60 bool hasUnityFilter(unity::dash::Filter::Ptr unityFilter) const;
63
61
62+public Q_SLOTS:
63+ void clear();
64+
64Q_SIGNALS:
65Q_SIGNALS:
65 void optionsChanged();
66 void optionsChanged();
66
67
plugins/Unity/genericoptionsmodel.cpp+20−3
@@ -22,10 +22,18 @@
22
22
23// local
23// local
24#include "abstractfilteroption.h"
24#include "abstractfilteroption.h"
25+#include "showallfilteroption.h"
25
26
26−GenericOptionsModel::GenericOptionsModel(QObject *parent)
27+GenericOptionsModel::GenericOptionsModel(bool showAllOption, QObject *parent)
27 : QAbstractListModel(parent)
28 : QAbstractListModel(parent)
28{
29{
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+ }
29}
37}
30
38
31GenericOptionsModel::~GenericOptionsModel()
39GenericOptionsModel::~GenericOptionsModel()
@@ -73,7 +81,7 @@ QVariant GenericOptionsModel::data(const QModelIndex& index, int role) const
73
81
74int GenericOptionsModel::rowCount(const QModelIndex& /* parent */) const
82int GenericOptionsModel::rowCount(const QModelIndex& /* parent */) const
75{
83{
76− return m_options.size ();
84+ return m_options.size();
77}
85}
78
86
79void GenericOptionsModel::setActive(int idx, bool value)
87void GenericOptionsModel::setActive(int idx, bool value)
@@ -117,7 +125,10 @@ void GenericOptionsModel::ensureTheOnlyActive(AbstractFilterOption *activeOption
117
125
118void GenericOptionsModel::addOption(AbstractFilterOption *option, int index)
126void GenericOptionsModel::addOption(AbstractFilterOption *option, int index)
119{
127{
128+ if (index >= 0)
120− m_options.insert(index, option);
129+ m_options.insert(index, option);
130+ else
131+ m_options.append(option);
121
132
122 connect(option, SIGNAL(idChanged(const QString &)), this, SLOT(onOptionChanged()));
133 connect(option, SIGNAL(idChanged(const QString &)), this, SLOT(onOptionChanged()));
123 connect(option, SIGNAL(nameChanged(const QString &)), this, SLOT(onOptionChanged()));
134 connect(option, SIGNAL(nameChanged(const QString &)), this, SLOT(onOptionChanged()));
@@ -168,3 +179,9 @@ void GenericOptionsModel::onActiveChanged()
168 Q_EMIT activeChanged(option);
179 Q_EMIT activeChanged(option);
169 }
180 }
170}
181}
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
35 Q_ENUMS(Roles)
35 Q_ENUMS(Roles)
36
36
37public:
37public:
38− GenericOptionsModel(QObject *parent = nullptr);
38+ GenericOptionsModel(bool showAllOption = false, QObject *parent = nullptr);
39 ~GenericOptionsModel();
39 ~GenericOptionsModel();
40
40
41 enum Roles {
41 enum Roles {
@@ -59,13 +59,15 @@ public Q_SLOTS:
59
59
60Q_SIGNALS:
60Q_SIGNALS:
61 void activeChanged(AbstractFilterOption *option);
61 void activeChanged(AbstractFilterOption *option);
62+ void showAllActivated();
62
63
63protected Q_SLOTS:
64protected Q_SLOTS:
64 void onOptionChanged();
65 void onOptionChanged();
65 void onActiveChanged();
66 void onActiveChanged();
67+ void onShowAllClicked(bool active);
66
68
67protected:
69protected:
68− void addOption(AbstractFilterOption *option, int index);
70+ void addOption(AbstractFilterOption *option, int index = -1);
69 void removeOption(int index);
71 void removeOption(int index);
70 int indexOf(const QString &option_id);
72 int indexOf(const QString &option_id);
71
73
plugins/Unity/iconutils.cppnew file+91
@@ -0,0 +1,91 @@
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:
17+ * Michal Hruby <michal.hruby@canonical.com>
18+ */
19+
20+#include <QStringList>
21+#include <QUrl>
22+
23+#include <gio/gio.h>
24+#include "iconutils.h"
25+
26+#define BASE_THEME_ICON_URI "image://theme/"
27+
28+QString gIconToDeclarativeImageProviderString(QString const &giconString)
29+{
30+ if (giconString.isEmpty()) return giconString;
31+
32+ if (giconString.startsWith('/') || giconString.startsWith(QLatin1String("http")) ||
33+ giconString.startsWith(QLatin1String("file:")) || giconString.startsWith(QLatin1String("image:"))) {
34+ return giconString;
35+ }
36+
37+ if (!giconString.startsWith(QLatin1String(". "))) {
38+ // must be a themed icon
39+ QString themedIcon(BASE_THEME_ICON_URI);
40+ themedIcon.append(giconString);
41+ return themedIcon;
42+ }
43+
44+ // special case annotated icon
45+ if (giconString.startsWith(QLatin1String(". UnityProtocolAnnotatedIcon "))) {
46+ QString annotatedIcon;
47+ QString serializedData(QUrl::fromPercentEncoding(giconString.mid(29).toUtf8()));
48+ GVariant *variant = g_variant_parse(G_VARIANT_TYPE_VARDICT, serializedData.toUtf8().constData(), NULL, NULL, NULL);
49+ gchar *baseUri;
50+ if (variant != NULL && g_variant_lookup(variant, "base-icon", "&s", &baseUri)) {
51+ annotatedIcon = gIconToDeclarativeImageProviderString(QString(baseUri));
52+ // FIXME: enclose in image://annotated/... once unity supports that
53+ }
54+ if (variant != NULL) g_variant_unref(variant);
55+
56+ return annotatedIcon;
57+ }
58+
59+ // handle real gicon strings
60+ QString result;
61+ GError *error = NULL;
62+ GIcon *icon = g_icon_new_for_string(giconString.toLocal8Bit().constData(), &error);
63+ if (error != NULL || icon == NULL) {
64+ qWarning("Unable to deserialize icon: %s", giconString.toLocal8Bit().constData());
65+ g_clear_error(&error);
66+ return result;
67+ }
68+
69+ if (G_IS_THEMED_ICON(icon)) {
70+ QString themedIcon(BASE_THEME_ICON_URI);
71+ QStringList list;
72+ const char* const *iconNames = g_themed_icon_get_names(G_THEMED_ICON(icon));
73+ if (iconNames != NULL) {
74+ for (const char * const *iter = iconNames; *iter != NULL; ++iter) {
75+ list << QLatin1String(*iter);
76+ }
77+ }
78+ themedIcon.append(list.join(QString(",")));
79+ result = themedIcon;
80+ } else if (G_IS_FILE_ICON(icon)) {
81+ GFile *file = g_file_icon_get_file(G_FILE_ICON(icon));
82+ gchar *uri = g_file_get_uri(file);
83+ QString iconUri(uri);
84+ g_free(uri);
85+ result = iconUri;
86+ }
87+
88+ g_object_unref(icon);
89+
90+ return result;
91+}
plugins/Unity/iconutils.hnew file+27
@@ -0,0 +1,27 @@
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:
17+ * Michal Hruby <michal.hruby@canonical.com>
18+ */
19+
20+#ifndef ICONUTILS_H
21+#define ICONUTILS_H
22+
23+#include <QString>
24+
25+QString gIconToDeclarativeImageProviderString(QString const &giconString);
26+
27+#endif
plugins/Unity/multirangefilter.cpp+3−1
@@ -52,9 +52,11 @@ void MultiRangeFilter::onOptionsChanged(unity::dash::MultiRangeFilter::Options o
52
52
53 m_options = new UnityOptionsModel(this, options,
53 m_options = new UnityOptionsModel(this, options,
54 m_unityMultiRangeFilter->option_added,
54 m_unityMultiRangeFilter->option_added,
55− m_unityMultiRangeFilter->option_removed);
55+ m_unityMultiRangeFilter->option_removed,
56+ m_unityMultiRangeFilter->show_all_button);
56
57
57 connect(m_options, SIGNAL(activeChanged(AbstractFilterOption *)), m_options, SLOT(ensureTheOnlyActive(AbstractFilterOption *)));
58 connect(m_options, SIGNAL(activeChanged(AbstractFilterOption *)), m_options, SLOT(ensureTheOnlyActive(AbstractFilterOption *)));
59+ connect(m_options, SIGNAL(showAllActivated()), this, SLOT(clear()));
58
60
59 /* Property change signals */
61 /* Property change signals */
60 m_signals << m_unityMultiRangeFilter->options.changed.connect(sigc::mem_fun(this, &MultiRangeFilter::onOptionsChanged));
62 m_signals << m_unityMultiRangeFilter->options.changed.connect(sigc::mem_fun(this, &MultiRangeFilter::onOptionsChanged));
plugins/Unity/plugin.cpp+2
@@ -35,6 +35,7 @@
35#include "categoryresults.h"
35#include "categoryresults.h"
36#include "bottombarvisibilitycommunicatorshell.h"
36#include "bottombarvisibilitycommunicatorshell.h"
37#include "genericoptionsmodel.h"
37#include "genericoptionsmodel.h"
38+#include "result.h"
38
39
39// libqtdee
40// libqtdee
40#include "deelistmodel.h"
41#include "deelistmodel.h"
@@ -50,6 +51,7 @@ void UnityPlugin::registerTypes(const char *uri)
50 qmlRegisterUncreatableType<PreviewInfoHint>(uri, 0, 1, "PreviewInfoHint", "Can't create PreviewInfoHint object in QML.");
51 qmlRegisterUncreatableType<PreviewInfoHint>(uri, 0, 1, "PreviewInfoHint", "Can't create PreviewInfoHint object in QML.");
51 qmlRegisterUncreatableType<SocialPreviewComment>(uri, 0, 1, "SocialPreviewComment", "Can't create SocialPreviewComment object in QML.");
52 qmlRegisterUncreatableType<SocialPreviewComment>(uri, 0, 1, "SocialPreviewComment", "Can't create SocialPreviewComment object in QML.");
52 qmlRegisterUncreatableType<GenericOptionsModel>(uri, 0, 1, "GenericOptionsModel", "Can't create options model in QML.");
53 qmlRegisterUncreatableType<GenericOptionsModel>(uri, 0, 1, "GenericOptionsModel", "Can't create options model in QML.");
54+ qmlRegisterUncreatableType<Result>(uri, 0, 1, "Result", "Can't create result object in QML.");
53 qmlRegisterType<Scope>(uri, 0, 1, "Scope");
55 qmlRegisterType<Scope>(uri, 0, 1, "Scope");
54 qmlRegisterType<Scopes>(uri, 0, 1, "Scopes");
56 qmlRegisterType<Scopes>(uri, 0, 1, "Scopes");
55 qmlRegisterType<Categories>(uri, 0, 1, "Categories");
57 qmlRegisterType<Categories>(uri, 0, 1, "Categories");
plugins/Unity/preview.cpp+22−3
@@ -26,6 +26,7 @@
26#include "moviepreview.h"
26#include "moviepreview.h"
27#include "musicpreview.h"
27#include "musicpreview.h"
28#include "socialpreview.h"
28#include "socialpreview.h"
29+#include "iconutils.h"
29#include "variantutils.h"
30#include "variantutils.h"
30
31
31// Qt
32// Qt
@@ -38,9 +39,12 @@
38#include <UnityCore/MusicPreview.h>
39#include <UnityCore/MusicPreview.h>
39#include <UnityCore/SocialPreview.h>
40#include <UnityCore/SocialPreview.h>
40
41
42+#include <UnityCore/GLibWrapper.h>
43+
41Preview::Preview(QObject *parent):
44Preview::Preview(QObject *parent):
42 QObject(parent),
45 QObject(parent),
43− m_unityPreview(nullptr)
46+ m_unityPreview(nullptr),
47+ m_result(new Result(this))
44{
48{
45}
49}
46
50
@@ -102,7 +106,10 @@ QVariantMap Preview::infoHintsHash() const
102QString Preview::image() const
106QString Preview::image() const
103{
107{
104 if (m_unityPreview) {
108 if (m_unityPreview) {
105− return QString::fromUtf8(g_icon_to_string(m_unityPreview->image()));
109+ auto giconString = g_icon_to_string(m_unityPreview->image());
110+ QString result(gIconToDeclarativeImageProviderString(QString::fromUtf8(giconString)));
111+ g_free(giconString);
112+ return result;
106 } else {
113 } else {
107 qWarning() << "Preview not set";
114 qWarning() << "Preview not set";
108 }
115 }
@@ -119,6 +126,11 @@ QString Preview::imageSourceUri() const
119 return QString::null;
126 return QString::null;
120}
127}
121
128
129+QVariant Preview::result() const
130+{
131+ return QVariant::fromValue(m_result);
132+}
133+
122Preview* Preview::newFromUnityPreview(unity::dash::Preview::Ptr unityPreview)
134Preview* Preview::newFromUnityPreview(unity::dash::Preview::Ptr unityPreview)
123{
135{
124 Preview* preview = nullptr;
136 Preview* preview = nullptr;
@@ -147,6 +159,7 @@ Preview* Preview::newFromUnityPreview(unity::dash::Preview::Ptr unityPreview)
147void Preview::setUnityPreviewBase(unity::dash::Preview::Ptr unityPreview)
159void Preview::setUnityPreviewBase(unity::dash::Preview::Ptr unityPreview)
148{
160{
149 m_unityPreview = unityPreview;
161 m_unityPreview = unityPreview;
162+ m_result->setPreview(unityPreview);
150
163
151 qDeleteAll(m_infoHints);
164 qDeleteAll(m_infoHints);
152 m_infoHints.clear();
165 m_infoHints.clear();
@@ -177,8 +190,14 @@ void Preview::execute(const QString& actionId, const QHash<QString, QVariant>& h
177{
190{
178 if (m_unityPreview) {
191 if (m_unityPreview) {
179 auto unityHints = convertToHintsMap(hints);
192 auto unityHints = convertToHintsMap(hints);
193+ m_actionCancellable.Renew();
180− m_unityPreview->PerformAction(actionId.toStdString(), unityHints);
194+ m_unityPreview->PerformAction(actionId.toStdString(), unityHints, nullptr, m_actionCancellable);
181 } else {
195 } else {
182 qWarning() << "Preview not set";
196 qWarning() << "Preview not set";
183 }
197 }
184}
198}
199+
200+void Preview::cancelAction()
201+{
202+ m_actionCancellable.Cancel();
203+}
plugins/Unity/preview.h+7
@@ -31,7 +31,9 @@
31#include <UnityCore/Preview.h>
31#include <UnityCore/Preview.h>
32
32
33// local
33// local
34+#include "result.h"
34#include "previewaction.h"
35#include "previewaction.h"
36+#include <UnityCore/GLibWrapper.h>
35
37
36class Q_DECL_EXPORT Preview : public QObject
38class Q_DECL_EXPORT Preview : public QObject
37{
39{
@@ -46,6 +48,7 @@ class Q_DECL_EXPORT Preview : public QObject
46 Q_PROPERTY(QVariantMap infoMap READ infoHintsHash NOTIFY previewChanged)
48 Q_PROPERTY(QVariantMap infoMap READ infoHintsHash NOTIFY previewChanged)
47 Q_PROPERTY(QString image READ image NOTIFY previewChanged)
49 Q_PROPERTY(QString image READ image NOTIFY previewChanged)
48 Q_PROPERTY(QString imageSourceUri READ imageSourceUri NOTIFY previewChanged)
50 Q_PROPERTY(QString imageSourceUri READ imageSourceUri NOTIFY previewChanged)
51+ Q_PROPERTY(QVariant result READ result NOTIFY previewChanged)
49
52
50public:
53public:
51 explicit Preview(QObject *parent = 0);
54 explicit Preview(QObject *parent = 0);
@@ -60,8 +63,10 @@ public:
60 QVariantMap infoHintsHash() const;
63 QVariantMap infoHintsHash() const;
61 QString image() const;
64 QString image() const;
62 QString imageSourceUri() const;
65 QString imageSourceUri() const;
66+ QVariant result() const;
63
67
64 Q_INVOKABLE void execute(const QString& actionId, const QHash<QString, QVariant>& hints);
68 Q_INVOKABLE void execute(const QString& actionId, const QHash<QString, QVariant>& hints);
69+ Q_INVOKABLE void cancelAction();
65
70
66Q_SIGNALS:
71Q_SIGNALS:
67 void previewChanged();
72 void previewChanged();
@@ -70,6 +75,7 @@ protected:
70 virtual void setUnityPreview(unity::dash::Preview::Ptr unityPreview);
75 virtual void setUnityPreview(unity::dash::Preview::Ptr unityPreview);
71
76
72 unity::dash::Preview::Ptr m_unityPreview;
77 unity::dash::Preview::Ptr m_unityPreview;
78+ Result* m_result;
73
79
74private:
80private:
75 void setUnityPreviewBase(unity::dash::Preview::Ptr unityPreview);
81 void setUnityPreviewBase(unity::dash::Preview::Ptr unityPreview);
@@ -77,6 +83,7 @@ private:
77 QList<QObject *> m_actions;
83 QList<QObject *> m_actions;
78 QList<QObject *> m_infoHints;
84 QList<QObject *> m_infoHints;
79 QVariantMap m_infoHintsHash;
85 QVariantMap m_infoHintsHash;
86+ unity::glib::Cancellable m_actionCancellable;
80};
87};
81
88
82Q_DECLARE_METATYPE(Preview *)
89Q_DECLARE_METATYPE(Preview *)
plugins/Unity/radiooptionfilter.cpp+3−1
@@ -51,7 +51,9 @@ void RadioOptionFilter::onOptionsChanged(unity::dash::RadioOptionFilter::RadioOp
51 }
51 }
52 m_options = new UnityOptionsModel(this, m_unityRadioOptionFilter->options,
52 m_options = new UnityOptionsModel(this, m_unityRadioOptionFilter->options,
53 m_unityRadioOptionFilter->option_added,
53 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()));
55
57
56 m_signals << m_unityRadioOptionFilter->options.changed.connect(sigc::mem_fun(this, &RadioOptionFilter::onOptionsChanged));
58 m_signals << m_unityRadioOptionFilter->options.changed.connect(sigc::mem_fun(this, &RadioOptionFilter::onOptionsChanged));
57
59
plugins/Unity/ratingoptionsmodel.cpp+3−3
@@ -23,11 +23,11 @@
23// local
23// local
24#include "ratingfilteroption.h"
24#include "ratingfilteroption.h"
25
25
26−RatingOptionsModel::RatingOptionsModel(QObject *parent) :
26+RatingOptionsModel::RatingOptionsModel(bool showAllOption, QObject *parent) :
27− GenericOptionsModel(parent)
27+ GenericOptionsModel(showAllOption, parent)
28{
28{
29 for (int i=1; i<=5; i++) {
29 for (int i=1; i<=5; i++) {
30 auto opt = new RatingFilterOption(QString::number(i), i*0.2f, this);
30 auto opt = new RatingFilterOption(QString::number(i), i*0.2f, this);
31− addOption(opt, i-1);
31+ addOption(opt);
32 }
32 }
33}
33}
plugins/Unity/ratingoptionsmodel.h+1−1
@@ -27,7 +27,7 @@ class RatingOptionsModel : public GenericOptionsModel
27 Q_OBJECT
27 Q_OBJECT
28
28
29public:
29public:
30− RatingOptionsModel(QObject *parent);
30+ RatingOptionsModel(bool showAllOption, QObject *parent);
31};
31};
32
32
33#endif // RATINGOPTIONSMODEL_H
33#endif // RATINGOPTIONSMODEL_H
plugins/Unity/ratingsfilter.cpp+2−1
@@ -53,9 +53,10 @@ void RatingsFilter::setUnityFilter(unity::dash::Filter::Ptr filter)
53
53
54 delete m_options;
54 delete m_options;
55
55
56− m_options = new RatingOptionsModel(this);
56+ m_options = new RatingOptionsModel(m_unityRatingsFilter->show_all_button, this);
57 connect(m_options, SIGNAL(activeChanged(AbstractFilterOption *)), m_options, SLOT(ensureTheOnlyActive(AbstractFilterOption *)));
57 connect(m_options, SIGNAL(activeChanged(AbstractFilterOption *)), m_options, SLOT(ensureTheOnlyActive(AbstractFilterOption *)));
58 connect(m_options, SIGNAL(activeChanged(AbstractFilterOption *)), this, SLOT(onActiveChanged(AbstractFilterOption *)));
58 connect(m_options, SIGNAL(activeChanged(AbstractFilterOption *)), this, SLOT(onActiveChanged(AbstractFilterOption *)));
59+ connect(m_options, SIGNAL(showAllActivated()), this, SLOT(clear()));
59
60
60 Q_EMIT optionsChanged();
61 Q_EMIT optionsChanged();
61}
62}
plugins/Unity/result.cppnew file+82
@@ -0,0 +1,82 @@
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+#include "result.h"
21+#include "variantutils.h"
22+
23+Result::Result(QObject *parent) :
24+ QObject(parent)
25+{
26+}
27+
28+Result::Result(unity::dash::Preview::Ptr preview, QObject *parent) :
29+ QObject(parent),
30+ m_preview(preview)
31+{
32+}
33+
34+void Result::setPreview(unity::dash::Preview::Ptr preview)
35+{
36+ m_preview = preview;
37+}
38+
39+QString Result::uri() const
40+{
41+ return m_preview != nullptr ? QString::fromStdString(m_preview->preview_result.uri) : QString::null;
42+}
43+
44+QString Result::iconHint() const
45+{
46+ return m_preview != nullptr ? QString::fromStdString(m_preview->preview_result.icon_hint) : QString::null;
47+}
48+
49+unsigned Result::categoryIndex() const
50+{
51+ return m_preview != nullptr ? m_preview->preview_result.category_index : 0;
52+}
53+
54+unsigned Result::resultType() const
55+{
56+ return m_preview != nullptr ? m_preview->preview_result.result_type : 0;
57+}
58+
59+QString Result::mimeType() const
60+{
61+ return m_preview != nullptr ? QString::fromStdString(m_preview->preview_result.mimetype) : QString::null;
62+}
63+
64+QString Result::title() const
65+{
66+ return m_preview != nullptr ? QString::fromStdString(m_preview->preview_result.name) : QString::null;
67+}
68+
69+QString Result::comment() const
70+{
71+ return m_preview != nullptr ? QString::fromStdString(m_preview->preview_result.comment) : QString::null;
72+}
73+
74+QString Result::dndUri() const
75+{
76+ return m_preview != nullptr ? QString::fromStdString(m_preview->preview_result.dnd_uri) : QString::null;
77+}
78+
79+QVariant Result::metadata() const
80+{
81+ return m_preview != nullptr ? convertToQVariantHash(m_preview->preview_result.hints) : QVariant();
82+}
plugins/Unity/result.hnew file+69
@@ -0,0 +1,69 @@
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 RESULT_H
21+#define RESULT_H
22+
23+// Qt
24+#include <QObject>
25+#include <QVariant>
26+
27+// libunity-core
28+#include <UnityCore/Preview.h>
29+
30+class Q_DECL_EXPORT Result : public QObject
31+{
32+ Q_OBJECT
33+
34+ Q_PROPERTY(QString uri READ uri CONSTANT)
35+ Q_PROPERTY(QString iconHint READ iconHint CONSTANT)
36+ Q_PROPERTY(unsigned categoryIndex READ categoryIndex CONSTANT)
37+ Q_PROPERTY(unsigned resultType READ resultType CONSTANT)
38+ Q_PROPERTY(QString mimeType READ mimeType CONSTANT)
39+ Q_PROPERTY(QString title READ title CONSTANT)
40+ Q_PROPERTY(QString comment READ comment CONSTANT)
41+ Q_PROPERTY(QString dndUri READ dndUri CONSTANT)
42+ Q_PROPERTY(QVariant metadata READ metadata CONSTANT)
43+
44+public:
45+ Result(QObject *parent = nullptr);
46+ Result(unity::dash::Preview::Ptr preview, QObject *parent = nullptr);
47+
48+ void setPreview(unity::dash::Preview::Ptr preview);
49+
50+ QString uri() const;
51+ QString iconHint() const;
52+ unsigned categoryIndex() const;
53+ unsigned resultType() const;
54+ QString mimeType() const;
55+ QString title() const;
56+ QString comment() const;
57+ QString dndUri() const;
58+ QVariant metadata() const;
59+
60+private:
61+ /* Keep reference to the original preview to access result attributes via it, rather than keeping copies of them;
62+ this will save us a bit on copying, especially as UI is mostly interested in just uri.
63+ */
64+ unity::dash::Preview::Ptr m_preview;
65+};
66+
67+Q_DECLARE_METATYPE(Result *)
68+
69+#endif
plugins/Unity/scope.cpp+20−1
@@ -175,7 +175,19 @@ void Scope::preview(const QVariant &uri, const QVariant &icon_hint, const QVaria
175 const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata)
175 const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata)
176{
176{
177 auto res = createLocalResult(uri, icon_hint, category, result_type, mimetype, title, comment, dnd_uri, metadata);
177 auto res = createLocalResult(uri, icon_hint, category, result_type, mimetype, title, comment, dnd_uri, metadata);
178+ m_previewCancellable.Renew();
179+
180+ // canned queries don't have previews, must be activated
181+ if (uri.toString().startsWith("x-unity-no-preview-scopes-query://")) {
182+ m_unityScope->Activate(res);
183+ } else {
178− m_unityScope->Preview(res);
184+ m_unityScope->Preview(res, nullptr, m_previewCancellable);
185+ }
186+}
187+
188+void Scope::cancelActivation()
189+{
190+ m_previewCancellable.Cancel();
179}
191}
180
192
181void Scope::onActivated(unity::dash::LocalResult const& result, unity::dash::ScopeHandledType type, unity::glib::HintsMap const& hints)
193void Scope::onActivated(unity::dash::LocalResult const& result, unity::dash::ScopeHandledType type, unity::glib::HintsMap const& hints)
@@ -199,6 +211,13 @@ void Scope::onActivated(unity::dash::LocalResult const& result, unity::dash::Sco
199 qWarning() << "Missing goto-uri hint for GOTO_DASH_URI activation reply";
211 qWarning() << "Missing goto-uri hint for GOTO_DASH_URI activation reply";
200 }
212 }
201 break;
213 break;
214+ case unity::dash::PERFORM_SEARCH:
215+ if (hints.find("query") != hints.end()) {
216+ // note: this will emit searchQueryChanged, and shell will call setSearchQuery back with a new query,
217+ // but it will get ignored.
218+ setSearchQuery(QString::fromStdString(g_variant_get_string(hints.at("query"), nullptr)));
219+ }
220+ break;
202 default:
221 default:
203 qWarning() << "Unhandled activation response:" << type;
222 qWarning() << "Unhandled activation response:" << type;
204 }
223 }
plugins/Unity/scope.h+3
@@ -82,6 +82,8 @@ public:
82 Q_INVOKABLE void preview(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
82 Q_INVOKABLE void preview(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
83 const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
83 const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
84 const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata);
84 const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata);
85+ Q_INVOKABLE void cancelActivation();
86+
85 void setUnityScope(const unity::dash::Scope::Ptr& scope);
87 void setUnityScope(const unity::dash::Scope::Ptr& scope);
86 unity::dash::Scope::Ptr unityScope() const;
88 unity::dash::Scope::Ptr unityScope() const;
87
89
@@ -131,6 +133,7 @@ private:
131 QString m_searchQuery;
133 QString m_searchQuery;
132 QString m_noResultsHint;
134 QString m_noResultsHint;
133 QString m_formFactor;
135 QString m_formFactor;
136+ unity::glib::Cancellable m_previewCancellable;
134};
137};
135
138
136Q_DECLARE_METATYPE(Scope*)
139Q_DECLARE_METATYPE(Scope*)
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/socialpreview.cpp+5−1
@@ -19,6 +19,7 @@
19
19
20#include "socialpreview.h"
20#include "socialpreview.h"
21#include "socialpreviewcomment.h"
21#include "socialpreviewcomment.h"
22+#include "iconutils.h"
22
23
23#include <QDebug>
24#include <QDebug>
24
25
@@ -51,7 +52,10 @@ QString SocialPreview::content() const
51QString SocialPreview::avatar() const
52QString SocialPreview::avatar() const
52{
53{
53 if (m_unitySocialPreview) {
54 if (m_unitySocialPreview) {
54− return QString::fromUtf8(g_icon_to_string(m_unitySocialPreview->avatar()));
55+ auto giconString = g_icon_to_string(m_unitySocialPreview->avatar());
56+ QString result(gIconToDeclarativeImageProviderString(QString::fromUtf8(giconString)));
57+ g_free(giconString);
58+ return result;
55 } else {
59 } else {
56 qWarning() << "Preview not set";
60 qWarning() << "Preview not set";
57 }
61 }
plugins/Unity/unityoptionsmodel.cpp+5−4
@@ -26,8 +26,9 @@
26UnityOptionsModel::UnityOptionsModel(QObject *parent,
26UnityOptionsModel::UnityOptionsModel(QObject *parent,
27 const std::vector<unity::dash::FilterOption::Ptr> options,
27 const std::vector<unity::dash::FilterOption::Ptr> options,
28 sigc::signal<void, unity::dash::FilterOption::Ptr> optionAdded,
28 sigc::signal<void, unity::dash::FilterOption::Ptr> optionAdded,
29− sigc::signal<void, unity::dash::FilterOption::Ptr> optionRemoved) :
29+ sigc::signal<void, unity::dash::FilterOption::Ptr> optionRemoved,
30+ bool showAllOption) :
30− GenericOptionsModel(parent)
31+ GenericOptionsModel(showAllOption, parent)
31{
32{
32 setOptions(options, optionAdded, optionRemoved);
33 setOptions(options, optionAdded, optionRemoved);
33}
34}
@@ -38,7 +39,7 @@ void UnityOptionsModel::setOptions(const std::vector<unity::dash::FilterOption::
38{
39{
39 for (unsigned int i=0; i<options.size(); i++)
40 for (unsigned int i=0; i<options.size(); i++)
40 {
41 {
41− addOption(new FilterOption(options[i], this), i);
42+ addOption(new FilterOption(options[i], this));
42 }
43 }
43 optionAdded.connect(sigc::mem_fun(this, &UnityOptionsModel::onOptionAdded));
44 optionAdded.connect(sigc::mem_fun(this, &UnityOptionsModel::onOptionAdded));
44 optionRemoved.connect(sigc::mem_fun(this, &UnityOptionsModel::onOptionRemoved));
45 optionRemoved.connect(sigc::mem_fun(this, &UnityOptionsModel::onOptionRemoved));
@@ -50,7 +51,7 @@ void UnityOptionsModel::onOptionAdded(unity::dash::FilterOption::Ptr option)
50 if (index >= 0)
51 if (index >= 0)
51 {
52 {
52 beginInsertRows(QModelIndex(), index, index);
53 beginInsertRows(QModelIndex(), index, index);
53− addOption(new FilterOption(option, this), index);
54+ addOption(new FilterOption(option, this));
54 endInsertRows();
55 endInsertRows();
55 }
56 }
56}
57}
plugins/Unity/unityoptionsmodel.h+2−1
@@ -35,7 +35,8 @@ public:
35 UnityOptionsModel(QObject *parent,
35 UnityOptionsModel(QObject *parent,
36 const std::vector<unity::dash::FilterOption::Ptr> options,
36 const std::vector<unity::dash::FilterOption::Ptr> options,
37 sigc::signal<void, unity::dash::FilterOption::Ptr> optionAdded,
37 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);
39
40
40private:
41private:
41 void setOptions(const std::vector<unity::dash::FilterOption::Ptr> options,
42 void setOptions(const std::vector<unity::dash::FilterOption::Ptr> options,
plugins/Unity/variantutils.cpp+9
@@ -40,3 +40,12 @@ unity::glib::HintsMap convertToHintsMap(const QVariant &var)
40 }
40 }
41 return unity::glib::HintsMap();
41 return unity::glib::HintsMap();
42}
42}
43+
44+QVariantHash convertToQVariantHash(const unity::glib::HintsMap& var)
45+{
46+ QVariantHash hash;
47+ for (auto hint: var) {
48+ hash.insert(QString::fromStdString(hint.first), DeeListModel::VariantForData(hint.second));
49+ }
50+ return hash;
51+}
plugins/Unity/variantutils.h+1
@@ -28,5 +28,6 @@
28
28
29unity::glib::HintsMap convertToHintsMap(const QHash<QString, QVariant> &val);
29unity::glib::HintsMap convertToHintsMap(const QHash<QString, QVariant> &val);
30unity::glib::HintsMap convertToHintsMap(const QVariant &var);
30unity::glib::HintsMap convertToHintsMap(const QVariant &var);
31+QVariantHash convertToQVariantHash(const unity::glib::HintsMap& var);
31
32
32#endif
33#endif
plugins/Utils/qsortfilterproxymodelqml.cpp+32
@@ -29,6 +29,17 @@ QSortFilterProxyModelQML::QSortFilterProxyModelQML(QObject *parent)
29 connect(this, SIGNAL(rowsRemoved(QModelIndex,int,int)), SIGNAL(countChanged()));
29 connect(this, SIGNAL(rowsRemoved(QModelIndex,int,int)), SIGNAL(countChanged()));
30}
30}
31
31
32+/*
33+ * Enter row index of filtered/sorted model, returns row index of source model
34+ */
35+int QSortFilterProxyModelQML::mapRowToSource(int row)
36+{
37+ if (sourceModel() == NULL)
38+ return -1;
39+
40+ return QSortFilterProxyModel::mapToSource(index(row, 0)).row();
41+}
42+
32QHash<int, QByteArray> QSortFilterProxyModelQML::roleNames() const
43QHash<int, QByteArray> QSortFilterProxyModelQML::roleNames() const
33{
44{
34 return sourceModel() ? sourceModel()->roleNames() : QHash<int, QByteArray>();
45 return sourceModel() ? sourceModel()->roleNames() : QHash<int, QByteArray>();
@@ -51,6 +62,7 @@ QSortFilterProxyModelQML::setModel(QAbstractItemModel *itemModel)
51 connect(itemModel, SIGNAL(modelReset()), SIGNAL(totalCountChanged()));
62 connect(itemModel, SIGNAL(modelReset()), SIGNAL(totalCountChanged()));
52 connect(itemModel, SIGNAL(rowsInserted(QModelIndex,int,int)), SIGNAL(totalCountChanged()));
63 connect(itemModel, SIGNAL(rowsInserted(QModelIndex,int,int)), SIGNAL(totalCountChanged()));
53 connect(itemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), SIGNAL(totalCountChanged()));
64 connect(itemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), SIGNAL(totalCountChanged()));
65+
54 Q_EMIT totalCountChanged();
66 Q_EMIT totalCountChanged();
55 Q_EMIT modelChanged();
67 Q_EMIT modelChanged();
56 }
68 }
@@ -121,3 +133,23 @@ QSortFilterProxyModelQML::findFirst(int role, const QVariant& value) const
121 return -1;
133 return -1;
122 }
134 }
123}
135}
136+
137+int
138+QSortFilterProxyModelQML::mapFromSource(int row)
139+{
140+ if (sourceModel() != NULL) {
141+ return QSortFilterProxyModel::mapFromSource(sourceModel()->index(row, 0)).row();
142+ } else {
143+ return -1;
144+ }
145+}
146+
147+int
148+QSortFilterProxyModelQML::mapToSource(int row)
149+{
150+ if (sourceModel() != NULL) {
151+ return QSortFilterProxyModel::mapToSource(index(row, 0)).row();
152+ } else {
153+ return -1;
154+ }
155+}
plugins/Utils/qsortfilterproxymodelqml.h+4
@@ -34,6 +34,7 @@ public:
34 Q_INVOKABLE QVariant data(int row, int role);
34 Q_INVOKABLE QVariant data(int row, int role);
35 Q_INVOKABLE int count();
35 Q_INVOKABLE int count();
36 Q_INVOKABLE int findFirst(int role, const QVariant& value) const;
36 Q_INVOKABLE int findFirst(int role, const QVariant& value) const;
37+ Q_INVOKABLE int mapRowToSource(int row);
37 virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
38 virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
38
39
39 /* getters */
40 /* getters */
@@ -45,6 +46,9 @@ public:
45 void setModel(QAbstractItemModel *model);
46 void setModel(QAbstractItemModel *model);
46 void setInvertMatch(bool invertMatch);
47 void setInvertMatch(bool invertMatch);
47
48
49+ Q_INVOKABLE int mapFromSource(int row);
50+ Q_INVOKABLE int mapToSource(int row);
51+
48Q_SIGNALS:
52Q_SIGNALS:
49 void totalCountChanged();
53 void totalCountChanged();
50 void countChanged();
54 void countChanged();
po/ar.po+2−29
@@ -16,8 +16,8 @@ msgstr ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n % 100 >= "
17"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n % 100 >= "
18"3 && n % 100 <= 10 ? 3 : n % 100 >= 11 && n % 100 <= 99 ? 4 : 5;\n"
18"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"
19+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
20+"X-Generator: Launchpad (build 16750)\n"
21
21
22#: Applications/applications.js:23
22#: Applications/applications.js:23
23msgid "Phone"
23msgid "Phone"
@@ -254,30 +254,3 @@ msgstr "عذراً، لا يوجد ما يطابق بحثك."
254#, qt-format
254#, qt-format
255msgid "Please enter %1"
255msgid "Please enter %1"
256msgstr ""
256msgstr ""
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 ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16750)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "Bağışlayın, amma axtarışınıza heç bir nəticə uyğun gəlmir."
253#, qt-format
253#, qt-format
254msgid "Please enter %1"
254msgid "Please enter %1"
255msgstr ""
255msgstr ""
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 ""
16"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Type: text/plain; charset=UTF-8\n"
17"Content-Transfer-Encoding: 8bit\n"
17"Content-Transfer-Encoding: 8bit\n"
18"Plural-Forms: nplurals=2; plural=n != 1;\n"
18"Plural-Forms: nplurals=2; plural=n != 1;\n"
19−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
20+"X-Generator: Launchpad (build 16750)\n"
21
21
22#: Applications/applications.js:23
22#: Applications/applications.js:23
23msgid "Phone"
23msgid "Phone"
@@ -254,12 +254,3 @@ msgstr "Съжаляваме, няма нищо, което да отговар
254#, qt-format
254#, qt-format
255msgid "Please enter %1"
255msgid "Please enter %1"
256msgstr ""
256msgstr ""
257−
258−#~ msgid "Installed"
259−#~ msgstr "Инсталирани"
260−
261−#~ msgid "Apps"
262−#~ msgstr "Приложения"
263−
264−#~ msgid "Home"
265−#~ msgstr "Начало"
po/ca.po+52−73
@@ -8,123 +8,129 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2013-08-27 13:36-0400\n"
10"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-06-27 00:24+0000\n"
11+"PO-Revision-Date: 2013-09-28 07:38+0000\n"
12−"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
12+"Last-Translator: David Planella <david.planella@ubuntu.com>\n"
13"Language-Team: Catalan <ca@li.org>\n"
13"Language-Team: Catalan <ca@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-09-29 06:18+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16774)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
23−msgstr ""
23+msgstr "Telèfon"
24
24
25#: Applications/applications.js:29
25#: Applications/applications.js:29
26msgid "Camera"
26msgid "Camera"
27−msgstr ""
27+msgstr "Càmera"
28
28
29#: Applications/applications.js:35
29#: Applications/applications.js:35
30msgid "Gallery"
30msgid "Gallery"
31−msgstr ""
31+msgstr "Galeria"
32
32
33#: Applications/applications.js:40
33#: Applications/applications.js:40
34msgid "Facebook"
34msgid "Facebook"
35−msgstr ""
35+msgstr "Facebook"
36
36
37#: Applications/applications.js:46
37#: Applications/applications.js:46
38msgid "Browser"
38msgid "Browser"
39−msgstr ""
39+msgstr "Navegador"
40
40
41#: Applications/applications.js:51
41#: Applications/applications.js:51
42msgid "Twitter"
42msgid "Twitter"
43−msgstr ""
43+msgstr "Twitter"
44
44
45#: Applications/applications.js:57
45#: Applications/applications.js:57
46msgid "GMail"
46msgid "GMail"
47−msgstr ""
47+msgstr "GMail"
48
48
49#: Applications/applications.js:62
49#: Applications/applications.js:62
50msgid "Weather"
50msgid "Weather"
51−msgstr ""
51+msgstr "El temps"
52
52
53#: Applications/applications.js:68
53#: Applications/applications.js:68
54msgid "Notepad"
54msgid "Notepad"
55−msgstr ""
55+msgstr "Bloc de notes"
56
56
57#: Applications/applications.js:74
57#: Applications/applications.js:74
58msgid "Calendar"
58msgid "Calendar"
59−msgstr ""
59+msgstr "Calendari"
60
60
61#: Applications/applications.js:80
61#: Applications/applications.js:80
62msgid "Media Player"
62msgid "Media Player"
63−msgstr ""
63+msgstr "Reproductor multimèdia"
64
64
65#: Applications/applications.js:86
65#: Applications/applications.js:86
66msgid "Evernote"
66msgid "Evernote"
67−msgstr ""
67+msgstr "Evernote"
68
68
69#: Applications/applications.js:91
69#: Applications/applications.js:91
70msgid "Map"
70msgid "Map"
71−msgstr ""
71+msgstr "Mapa"
72
72
73#: Applications/applications.js:96
73#: Applications/applications.js:96
74msgid "Pinterest"
74msgid "Pinterest"
75−msgstr ""
75+msgstr "Pinterest"
76
76
77#: Applications/applications.js:101
77#: Applications/applications.js:101
78msgid "SoundCloud"
78msgid "SoundCloud"
79−msgstr ""
79+msgstr "SoundCloud"
80
80
81#: Applications/applications.js:106
81#: Applications/applications.js:106
82msgid "Wikipedia"
82msgid "Wikipedia"
83−msgstr ""
83+msgstr "Viquipèdia"
84
84
85#: Applications/applications.js:111
85#: Applications/applications.js:111
86msgid "YouTube"
86msgid "YouTube"
87−msgstr ""
87+msgstr "YouTube"
88
88
89#: Components/EdgeDemoOverlay.qml:145
89#: Components/EdgeDemoOverlay.qml:145
90msgid "Skip intro"
90msgid "Skip intro"
91−msgstr ""
91+msgstr "Omet la introducció"
92
92
93#: Components/EdgeDemo.qml:98
93#: Components/EdgeDemo.qml:98
94msgid "Right edge"
94msgid "Right edge"
95−msgstr ""
95+msgstr "Vora dreta"
96
96
97#: Components/EdgeDemo.qml:99
97#: Components/EdgeDemo.qml:99
98msgid "Try swiping from the right edge to unlock the phone"
98msgid "Try swiping from the right edge to unlock the phone"
99msgstr ""
99msgstr ""
100+"Proveu de lliscar el dit des de la vora dreta per desblocar el telèfon"
100
101
101#: Components/EdgeDemo.qml:135
102#: Components/EdgeDemo.qml:135
102msgid "Top edge"
103msgid "Top edge"
103−msgstr ""
104+msgstr "Vora superior"
104
105
105#: Components/EdgeDemo.qml:136
106#: Components/EdgeDemo.qml:136
106msgid "Try swiping from the top edge to access the indicators"
107msgid "Try swiping from the top edge to access the indicators"
107msgstr ""
108msgstr ""
109+"Proveu de lliscar el dit des de la vora superior per accedir als indicadors"
108
110
109#: Components/EdgeDemo.qml:161
111#: Components/EdgeDemo.qml:161
110msgid "Close"
112msgid "Close"
111−msgstr ""
113+msgstr "Tanca"
112
114
113#: Components/EdgeDemo.qml:162
115#: Components/EdgeDemo.qml:162
114msgid "Swipe up again to close the settings screen"
116msgid "Swipe up again to close the settings screen"
115msgstr ""
117msgstr ""
118+"Llisqueu el dit cap amunt una altra vegada per tancar la pantalla de "
119+"configuració"
116
120
117#: Components/EdgeDemo.qml:189
121#: Components/EdgeDemo.qml:189
118msgid "Left edge"
122msgid "Left edge"
119−msgstr ""
123+msgstr "Vora esquerra"
120
124
121#: Components/EdgeDemo.qml:190
125#: Components/EdgeDemo.qml:190
122msgid "Swipe from the left to reveal the launcher for quick access to apps"
126msgid "Swipe from the left to reveal the launcher for quick access to apps"
123msgstr ""
127msgstr ""
128+"Llisqueu el dit des de la vora esquerra per mostrar el llançador i accedir "
129+"ràpidament a les aplicacions"
124
130
125#: Components/EdgeDemo.qml:217
131#: Components/EdgeDemo.qml:217
126msgid "Well done"
132msgid "Well done"
127−msgstr ""
133+msgstr "Enhorabona!"
128
134
129#: Components/EdgeDemo.qml:218
135#: Components/EdgeDemo.qml:218
130msgid "You have now mastered the edge gestures and can start using the phone"
136msgid "You have now mastered the edge gestures and can start using the phone"
@@ -138,15 +144,15 @@ msgstr "Cerques recents"
138#: Dash/Apps/AppInfo.qml:73
144#: Dash/Apps/AppInfo.qml:73
139#, qt-format
145#, qt-format
140msgid "(%1)"
146msgid "(%1)"
141−msgstr ""
147+msgstr "(%1)"
142
148
143#. TRANSLATORS: Number of persons who wrote reviews for this app
149#. TRANSLATORS: Number of persons who wrote reviews for this app
144#: Dash/Apps/AppInfo.qml:85
150#: Dash/Apps/AppInfo.qml:85
145#, qt-format
151#, qt-format
146msgid "%1 review"
152msgid "%1 review"
147msgid_plural "%1 reviews"
153msgid_plural "%1 reviews"
148−msgstr[0] ""
154+msgstr[0] "%1 ressenya"
149−msgstr[1] ""
155+msgstr[1] "%1 ressenyes"
150
156
151#: Dash/Apps/AppPreview.qml:175
157#: Dash/Apps/AppPreview.qml:175
152msgid "Rate this"
158msgid "Rate this"
@@ -154,35 +160,35 @@ msgstr ""
154
160
155#: Dash/Apps/AppReviews.qml:72
161#: Dash/Apps/AppReviews.qml:72
156msgid "Add a review"
162msgid "Add a review"
157−msgstr ""
163+msgstr "Afegiu una ressenya"
158
164
159#: Dash/Apps/AppReviews.qml:84
165#: Dash/Apps/AppReviews.qml:84
160msgid "Review"
166msgid "Review"
161−msgstr ""
167+msgstr "Ressenya"
162
168
163#: Dash/Apps/AppReviews.qml:118
169#: Dash/Apps/AppReviews.qml:118
164msgid "Send"
170msgid "Send"
165−msgstr ""
171+msgstr "Envia"
166
172
167#: Dash/Apps/AppReviews.qml:136
173#: Dash/Apps/AppReviews.qml:136
168msgid "Comments:"
174msgid "Comments:"
169−msgstr ""
175+msgstr "Comentaris:"
170
176
171#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
177#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
172msgid "Featured"
178msgid "Featured"
173−msgstr ""
179+msgstr "Destacats"
174
180
175#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
181#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
176msgid "Recent"
182msgid "Recent"
177−msgstr ""
183+msgstr "Recents"
178
184
179#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
185#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
180msgid "New Releases"
186msgid "New Releases"
181−msgstr ""
187+msgstr "Novetats"
182
188
183#: Dash/DashMusic.qml:30
189#: Dash/DashMusic.qml:30
184msgid "Top Charting"
190msgid "Top Charting"
185−msgstr ""
191+msgstr "El millor de les llistes"
186
192
187#: Dash/DashMusic.qml:91
193#: Dash/DashMusic.qml:91
188msgid "Music"
194msgid "Music"
@@ -190,7 +196,7 @@ msgstr "Música"
190
196
191#: Dash/DashVideos.qml:31
197#: Dash/DashVideos.qml:31
192msgid "Popular Online"
198msgid "Popular Online"
193−msgstr ""
199+msgstr "Popular a la xarxa"
194
200
195#: Dash/DashVideos.qml:146
201#: Dash/DashVideos.qml:146
196msgid "Videos"
202msgid "Videos"
@@ -198,28 +204,28 @@ msgstr "Vídeos"
198
204
199#: Dash/Video/VideoPreview.qml:130
205#: Dash/Video/VideoPreview.qml:130
200msgid "Directed by:"
206msgid "Directed by:"
201−msgstr ""
207+msgstr "Dirigit per:"
202
208
203#: Dash/Video/VideoPreview.qml:153
209#: Dash/Video/VideoPreview.qml:153
204msgid "Starring:"
210msgid "Starring:"
205−msgstr ""
211+msgstr "Protagonistes:"
206
212
207#: Dash/Video/VideoPreview.qml:176
213#: Dash/Video/VideoPreview.qml:176
208msgid "Author:"
214msgid "Author:"
209−msgstr ""
215+msgstr "Autor:"
210
216
211#: Greeter/Lockscreen.qml:134
217#: Greeter/Lockscreen.qml:134
212msgid "Emergency Call"
218msgid "Emergency Call"
213−msgstr ""
219+msgstr "Trucada d'emergència"
214
220
215#: Greeter/PassphraseLockscreen.qml:59
221#: Greeter/PassphraseLockscreen.qml:59
216#, qt-format
222#, qt-format
217msgid "Hello %1"
223msgid "Hello %1"
218−msgstr ""
224+msgstr "Hola %1"
219
225
220#: Greeter/PassphraseLockscreen.qml:59
226#: Greeter/PassphraseLockscreen.qml:59
221msgid "Hello"
227msgid "Hello"
222−msgstr ""
228+msgstr "Hola"
223
229
224#: Hud/HudParametrizedActionsPage.qml:132
230#: Hud/HudParametrizedActionsPage.qml:132
225msgid "Confirm"
231msgid "Confirm"
@@ -252,31 +258,4 @@ msgstr "No hi ha res que coincideixi amb la cerca"
252#: Shell.qml:429
258#: Shell.qml:429
253#, qt-format
259#, qt-format
254msgid "Please enter %1"
260msgid "Please enter %1"
255−msgstr ""
261+msgstr "Introduïu %1"
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 ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16750)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -253,30 +253,3 @@ msgstr "Entschuldigung, es wurden keine Treffer erzielt."
253#, qt-format
253#, qt-format
254msgid "Please enter %1"
254msgid "Please enter %1"
255msgstr ""
255msgstr ""
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 ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16750)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "Λυπούμαστε, δεν υπάρχει τίποτα που να τ
253#, qt-format
253#, qt-format
254msgid "Please enter %1"
254msgid "Please enter %1"
255msgstr ""
255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "Εφαρμογές"
259−
260−#~ msgid "Home"
261−#~ msgstr "Αρχή"
po/en_AU.po+27−53
@@ -8,15 +8,15 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2013-08-27 13:36-0400\n"
10"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-06-27 01:13+0000\n"
11+"PO-Revision-Date: 2013-09-28 07:46+0000\n"
12−"Last-Translator: Jackson Doak <Doak.jackson@gmail.com>\n"
12+"Last-Translator: Jared Norris <jarednorris@ubuntu.com>\n"
13"Language-Team: English (Australia) <en_AU@li.org>\n"
13"Language-Team: English (Australia) <en_AU@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-09-29 06:18+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16774)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -88,47 +88,48 @@ msgstr "YouTube"
88
88
89#: Components/EdgeDemoOverlay.qml:145
89#: Components/EdgeDemoOverlay.qml:145
90msgid "Skip intro"
90msgid "Skip intro"
91−msgstr ""
91+msgstr "Skip intro"
92
92
93#: Components/EdgeDemo.qml:98
93#: Components/EdgeDemo.qml:98
94msgid "Right edge"
94msgid "Right edge"
95−msgstr ""
95+msgstr "Right edge"
96
96
97#: Components/EdgeDemo.qml:99
97#: Components/EdgeDemo.qml:99
98msgid "Try swiping from the right edge to unlock the phone"
98msgid "Try swiping from the right edge to unlock the phone"
99−msgstr ""
99+msgstr "Try swiping from the right edge to unlock the phone"
100
100
101#: Components/EdgeDemo.qml:135
101#: Components/EdgeDemo.qml:135
102msgid "Top edge"
102msgid "Top edge"
103−msgstr ""
103+msgstr "Top edge"
104
104
105#: Components/EdgeDemo.qml:136
105#: Components/EdgeDemo.qml:136
106msgid "Try swiping from the top edge to access the indicators"
106msgid "Try swiping from the top edge to access the indicators"
107−msgstr ""
107+msgstr "Try swiping from the top edge to access the indicators"
108
108
109#: Components/EdgeDemo.qml:161
109#: Components/EdgeDemo.qml:161
110msgid "Close"
110msgid "Close"
111−msgstr ""
111+msgstr "Close"
112
112
113#: Components/EdgeDemo.qml:162
113#: Components/EdgeDemo.qml:162
114msgid "Swipe up again to close the settings screen"
114msgid "Swipe up again to close the settings screen"
115−msgstr ""
115+msgstr "Swipe up again to close the settings screen"
116
116
117#: Components/EdgeDemo.qml:189
117#: Components/EdgeDemo.qml:189
118msgid "Left edge"
118msgid "Left edge"
119−msgstr ""
119+msgstr "Left edge"
120
120
121#: Components/EdgeDemo.qml:190
121#: Components/EdgeDemo.qml:190
122msgid "Swipe from the left to reveal the launcher for quick access to apps"
122msgid "Swipe from the left to reveal the launcher for quick access to apps"
123−msgstr ""
123+msgstr "Swipe from the left to reveal the launcher for quick access to apps"
124
124
125#: Components/EdgeDemo.qml:217
125#: Components/EdgeDemo.qml:217
126msgid "Well done"
126msgid "Well done"
127−msgstr ""
127+msgstr "Well done"
128
128
129#: Components/EdgeDemo.qml:218
129#: Components/EdgeDemo.qml:218
130msgid "You have now mastered the edge gestures and can start using the phone"
130msgid "You have now mastered the edge gestures and can start using the phone"
131msgstr ""
131msgstr ""
132+"You have now mastered the edge gestures and can start using the phone"
132
133
133#: Components/PageHeader.qml:298
134#: Components/PageHeader.qml:298
134msgid "Recent searches"
135msgid "Recent searches"
@@ -138,35 +139,35 @@ msgstr "Recent searches"
138#: Dash/Apps/AppInfo.qml:73
139#: Dash/Apps/AppInfo.qml:73
139#, qt-format
140#, qt-format
140msgid "(%1)"
141msgid "(%1)"
141−msgstr ""
142+msgstr "(%1)"
142
143
143#. TRANSLATORS: Number of persons who wrote reviews for this app
144#. TRANSLATORS: Number of persons who wrote reviews for this app
144#: Dash/Apps/AppInfo.qml:85
145#: Dash/Apps/AppInfo.qml:85
145#, qt-format
146#, qt-format
146msgid "%1 review"
147msgid "%1 review"
147msgid_plural "%1 reviews"
148msgid_plural "%1 reviews"
148−msgstr[0] ""
149+msgstr[0] "%1 review"
149−msgstr[1] ""
150+msgstr[1] "%1 reviews"
150
151
151#: Dash/Apps/AppPreview.qml:175
152#: Dash/Apps/AppPreview.qml:175
152msgid "Rate this"
153msgid "Rate this"
153−msgstr ""
154+msgstr "Rate this"
154
155
155#: Dash/Apps/AppReviews.qml:72
156#: Dash/Apps/AppReviews.qml:72
156msgid "Add a review"
157msgid "Add a review"
157−msgstr ""
158+msgstr "Add a review"
158
159
159#: Dash/Apps/AppReviews.qml:84
160#: Dash/Apps/AppReviews.qml:84
160msgid "Review"
161msgid "Review"
161−msgstr ""
162+msgstr "Review"
162
163
163#: Dash/Apps/AppReviews.qml:118
164#: Dash/Apps/AppReviews.qml:118
164msgid "Send"
165msgid "Send"
165−msgstr ""
166+msgstr "Send"
166
167
167#: Dash/Apps/AppReviews.qml:136
168#: Dash/Apps/AppReviews.qml:136
168msgid "Comments:"
169msgid "Comments:"
169−msgstr ""
170+msgstr "Comments:"
170
171
171#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
172#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
172msgid "Featured"
173msgid "Featured"
@@ -210,16 +211,16 @@ msgstr "Author:"
210
211
211#: Greeter/Lockscreen.qml:134
212#: Greeter/Lockscreen.qml:134
212msgid "Emergency Call"
213msgid "Emergency Call"
213−msgstr ""
214+msgstr "Emergency Call"
214
215
215#: Greeter/PassphraseLockscreen.qml:59
216#: Greeter/PassphraseLockscreen.qml:59
216#, qt-format
217#, qt-format
217msgid "Hello %1"
218msgid "Hello %1"
218−msgstr ""
219+msgstr "Hello %1"
219
220
220#: Greeter/PassphraseLockscreen.qml:59
221#: Greeter/PassphraseLockscreen.qml:59
221msgid "Hello"
222msgid "Hello"
222−msgstr ""
223+msgstr "Hello"
223
224
224#: Hud/HudParametrizedActionsPage.qml:132
225#: Hud/HudParametrizedActionsPage.qml:132
225msgid "Confirm"
226msgid "Confirm"
@@ -252,31 +253,4 @@ msgstr "Sorry, there is nothing that matches your search."
252#: Shell.qml:429
253#: Shell.qml:429
253#, qt-format
254#, qt-format
254msgid "Please enter %1"
255msgid "Please enter %1"
255−msgstr ""
256+msgstr "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/en_GB.po+2−29
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16750)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -253,30 +253,3 @@ msgstr "Sorry, there is nothing that matches your search."
253#, qt-format
253#, qt-format
254msgid "Please enter %1"
254msgid "Please enter %1"
255msgstr "Please enter %1"
255msgstr "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 ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16750)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
po/es.po+26−51
@@ -8,15 +8,15 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2013-08-27 13:36-0400\n"
10"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-28 07:35+0000\n"
12−"Last-Translator: Adolfo Jayme Barrientos <fitoschido@gmail.com>\n"
12+"Last-Translator: Paco Molinero <paco@byasl.com>\n"
13"Language-Team: Spanish <es@li.org>\n"
13"Language-Team: Spanish <es@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-09-29 06:18+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16774)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -48,7 +48,7 @@ msgstr "GMail"
48
48
49#: Applications/applications.js:62
49#: Applications/applications.js:62
50msgid "Weather"
50msgid "Weather"
51−msgstr "Metereología"
51+msgstr "Meteorología"
52
52
53#: Applications/applications.js:68
53#: Applications/applications.js:68
54msgid "Notepad"
54msgid "Notepad"
@@ -88,47 +88,49 @@ msgstr "YouTube"
88
88
89#: Components/EdgeDemoOverlay.qml:145
89#: Components/EdgeDemoOverlay.qml:145
90msgid "Skip intro"
90msgid "Skip intro"
91−msgstr ""
91+msgstr "Omitir la introducción"
92
92
93#: Components/EdgeDemo.qml:98
93#: Components/EdgeDemo.qml:98
94msgid "Right edge"
94msgid "Right edge"
95−msgstr ""
95+msgstr "Borde derecho"
96
96
97#: Components/EdgeDemo.qml:99
97#: Components/EdgeDemo.qml:99
98msgid "Try swiping from the right edge to unlock the phone"
98msgid "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"
100
100
101#: Components/EdgeDemo.qml:135
101#: Components/EdgeDemo.qml:135
102msgid "Top edge"
102msgid "Top edge"
103−msgstr ""
103+msgstr "Borde superior"
104
104
105#: Components/EdgeDemo.qml:136
105#: Components/EdgeDemo.qml:136
106msgid "Try swiping from the top edge to access the indicators"
106msgid "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"
108
108
109#: Components/EdgeDemo.qml:161
109#: Components/EdgeDemo.qml:161
110msgid "Close"
110msgid "Close"
111−msgstr ""
111+msgstr "Cerrar"
112
112
113#: Components/EdgeDemo.qml:162
113#: Components/EdgeDemo.qml:162
114msgid "Swipe up again to close the settings screen"
114msgid "Swipe up again to close the settings screen"
115−msgstr ""
115+msgstr "Deslice hacia arriba para cerrar la pantalla de configuración"
116
116
117#: Components/EdgeDemo.qml:189
117#: Components/EdgeDemo.qml:189
118msgid "Left edge"
118msgid "Left edge"
119−msgstr ""
119+msgstr "Borde izquierdo"
120
120
121#: Components/EdgeDemo.qml:190
121#: Components/EdgeDemo.qml:190
122msgid "Swipe from the left to reveal the launcher for quick access to apps"
122msgid "Swipe from the left to reveal the launcher for quick access to apps"
123msgstr ""
123msgstr ""
124+"Deslice el dedo desde la izquierda para mostrar el lanzador y acceder "
125+"rápidamente a las aplicaciones"
124
126
125#: Components/EdgeDemo.qml:217
127#: Components/EdgeDemo.qml:217
126msgid "Well done"
128msgid "Well done"
127−msgstr ""
129+msgstr "Bien hecho"
128
130
129#: Components/EdgeDemo.qml:218
131#: Components/EdgeDemo.qml:218
130msgid "You have now mastered the edge gestures and can start using the phone"
132msgid "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"
132
134
133#: Components/PageHeader.qml:298
135#: Components/PageHeader.qml:298
134msgid "Recent searches"
136msgid "Recent searches"
@@ -138,35 +140,35 @@ msgstr "Búsquedas recientes"
138#: Dash/Apps/AppInfo.qml:73
140#: Dash/Apps/AppInfo.qml:73
139#, qt-format
141#, qt-format
140msgid "(%1)"
142msgid "(%1)"
141−msgstr ""
143+msgstr "(%1)"
142
144
143#. TRANSLATORS: Number of persons who wrote reviews for this app
145#. TRANSLATORS: Number of persons who wrote reviews for this app
144#: Dash/Apps/AppInfo.qml:85
146#: Dash/Apps/AppInfo.qml:85
145#, qt-format
147#, qt-format
146msgid "%1 review"
148msgid "%1 review"
147msgid_plural "%1 reviews"
149msgid_plural "%1 reviews"
148−msgstr[0] ""
150+msgstr[0] "%1 reseña"
149−msgstr[1] ""
151+msgstr[1] "%1 reseñas"
150
152
151#: Dash/Apps/AppPreview.qml:175
153#: Dash/Apps/AppPreview.qml:175
152msgid "Rate this"
154msgid "Rate this"
153−msgstr ""
155+msgstr "Valorar esto"
154
156
155#: Dash/Apps/AppReviews.qml:72
157#: Dash/Apps/AppReviews.qml:72
156msgid "Add a review"
158msgid "Add a review"
157−msgstr ""
159+msgstr "Añadir una reseña"
158
160
159#: Dash/Apps/AppReviews.qml:84
161#: Dash/Apps/AppReviews.qml:84
160msgid "Review"
162msgid "Review"
161−msgstr ""
163+msgstr "Reseñar"
162
164
163#: Dash/Apps/AppReviews.qml:118
165#: Dash/Apps/AppReviews.qml:118
164msgid "Send"
166msgid "Send"
165−msgstr ""
167+msgstr "Enviar"
166
168
167#: Dash/Apps/AppReviews.qml:136
169#: Dash/Apps/AppReviews.qml:136
168msgid "Comments:"
170msgid "Comments:"
169−msgstr ""
171+msgstr "Comentarios:"
170
172
171#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
173#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
172msgid "Featured"
174msgid "Featured"
@@ -210,7 +212,7 @@ msgstr "Autor:"
210
212
211#: Greeter/Lockscreen.qml:134
213#: Greeter/Lockscreen.qml:134
212msgid "Emergency Call"
214msgid "Emergency Call"
213−msgstr ""
215+msgstr "Llamada de emergencia"
214
216
215#: Greeter/PassphraseLockscreen.qml:59
217#: Greeter/PassphraseLockscreen.qml:59
216#, qt-format
218#, qt-format
@@ -253,30 +255,3 @@ msgstr "No hay nada que coincida con su búsqueda."
253#, qt-format
255#, qt-format
254msgid "Please enter %1"
256msgid "Please enter %1"
255msgstr "Introduzca %1"
257msgstr "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+15−42
@@ -8,15 +8,15 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2013-08-27 13:36-0400\n"
10"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-08-23 16:15+0000\n"
11+"PO-Revision-Date: 2013-09-26 09:25+0000\n"
12−"Last-Translator: Timo Jyrinki <timo.jyrinki@canonical.com>\n"
12+"Last-Translator: Jiri Grönroos <Unknown>\n"
13"Language-Team: Finnish <fi@li.org>\n"
13"Language-Team: Finnish <fi@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-09-27 06:43+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16774)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -88,47 +88,47 @@ msgstr "YouTube"
88
88
89#: Components/EdgeDemoOverlay.qml:145
89#: Components/EdgeDemoOverlay.qml:145
90msgid "Skip intro"
90msgid "Skip intro"
91−msgstr ""
91+msgstr "Ohita esittely"
92
92
93#: Components/EdgeDemo.qml:98
93#: Components/EdgeDemo.qml:98
94msgid "Right edge"
94msgid "Right edge"
95−msgstr ""
95+msgstr "Oikea reuna"
96
96
97#: Components/EdgeDemo.qml:99
97#: Components/EdgeDemo.qml:99
98msgid "Try swiping from the right edge to unlock the phone"
98msgid "Try swiping from the right edge to unlock the phone"
99−msgstr ""
99+msgstr "Vedä oikealta avataksesi puhelimen lukituksen"
100
100
101#: Components/EdgeDemo.qml:135
101#: Components/EdgeDemo.qml:135
102msgid "Top edge"
102msgid "Top edge"
103−msgstr ""
103+msgstr "Yläreuna"
104
104
105#: Components/EdgeDemo.qml:136
105#: Components/EdgeDemo.qml:136
106msgid "Try swiping from the top edge to access the indicators"
106msgid "Try swiping from the top edge to access the indicators"
107−msgstr ""
107+msgstr "Vedä yläreunasta käyttääksesi ilmaisimia"
108
108
109#: Components/EdgeDemo.qml:161
109#: Components/EdgeDemo.qml:161
110msgid "Close"
110msgid "Close"
111−msgstr ""
111+msgstr "Sulje"
112
112
113#: Components/EdgeDemo.qml:162
113#: Components/EdgeDemo.qml:162
114msgid "Swipe up again to close the settings screen"
114msgid "Swipe up again to close the settings screen"
115−msgstr ""
115+msgstr "Vedä uudestaan sulkeaksesi asetusnäkymän"
116
116
117#: Components/EdgeDemo.qml:189
117#: Components/EdgeDemo.qml:189
118msgid "Left edge"
118msgid "Left edge"
119−msgstr ""
119+msgstr "Vasen reuna"
120
120
121#: Components/EdgeDemo.qml:190
121#: Components/EdgeDemo.qml:190
122msgid "Swipe from the left to reveal the launcher for quick access to apps"
122msgid "Swipe from the left to reveal the launcher for quick access to apps"
123−msgstr ""
123+msgstr "Vedä vasemmalta saattaaksesi sovellusten käynnistimen esiin"
124
124
125#: Components/EdgeDemo.qml:217
125#: Components/EdgeDemo.qml:217
126msgid "Well done"
126msgid "Well done"
127−msgstr ""
127+msgstr "Hyvin tehty"
128
128
129#: Components/EdgeDemo.qml:218
129#: Components/EdgeDemo.qml:218
130msgid "You have now mastered the edge gestures and can start using the phone"
130msgid "You have now mastered the edge gestures and can start using the phone"
131−msgstr ""
131+msgstr "Hallitset nyt reunaeleet, joten voit aloittaa puhelimen käytön"
132
132
133#: Components/PageHeader.qml:298
133#: Components/PageHeader.qml:298
134msgid "Recent searches"
134msgid "Recent searches"
@@ -253,30 +253,3 @@ msgstr "Hakuun täsmääviä tuloksia ei löydy."
253#, qt-format
253#, qt-format
254msgid "Please enter %1"
254msgid "Please enter %1"
255msgstr "Kirjoita %1"
255msgstr "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 ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16750)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "Tíanverri er tað einki sum hóskar til tína leiting."
253#, qt-format
253#, qt-format
254msgid "Please enter %1"
254msgid "Please enter %1"
255msgstr ""
255msgstr ""
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 ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n > 1;\n"
17"Plural-Forms: nplurals=2; plural=n > 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16750)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -253,6 +253,3 @@ msgstr ""
253#, qt-format
253#, qt-format
254msgid "Please enter %1"
254msgid "Please enter %1"
255msgstr ""
255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "Applications"
po/gd.ponew file+266
@@ -0,0 +1,266 @@
1+# Gaelic; Scottish translation for unity8
2+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
3+# This file is distributed under the same license as the unity8 package.
4+# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
5+#
6+msgid ""
7+msgstr ""
8+"Project-Id-Version: unity8\n"
9+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10+"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11+"PO-Revision-Date: 2013-09-30 10:34+0000\n"
12+"Last-Translator: Akerbeltz <fios@akerbeltz.org>\n"
13+"Language-Team: Gaelic; Scottish <gd@li.org>\n"
14+"MIME-Version: 1.0\n"
15+"Content-Type: text/plain; charset=UTF-8\n"
16+"Content-Transfer-Encoding: 8bit\n"
17+"Plural-Forms: nplurals=4; plural=(n==1 || n==11) ? 0 : (n==2 || n==12) ? 1 : "
18+"(n > 2 && n < 20) ? 2 : 3;\n"
19+"X-Launchpad-Export-Date: 2013-10-01 05:53+0000\n"
20+"X-Generator: Launchpad (build 16774)\n"
21+
22+#: Applications/applications.js:23
23+msgid "Phone"
24+msgstr "Fòn"
25+
26+#: Applications/applications.js:29
27+msgid "Camera"
28+msgstr "Camara"
29+
30+#: Applications/applications.js:35
31+msgid "Gallery"
32+msgstr "Gailearaidh"
33+
34+#: Applications/applications.js:40
35+msgid "Facebook"
36+msgstr "Facebook"
37+
38+#: Applications/applications.js:46
39+msgid "Browser"
40+msgstr "Brabhsair"
41+
42+#: Applications/applications.js:51
43+msgid "Twitter"
44+msgstr "Twitter"
45+
46+#: Applications/applications.js:57
47+msgid "GMail"
48+msgstr "GMail"
49+
50+#: Applications/applications.js:62
51+msgid "Weather"
52+msgstr "An aimsir"
53+
54+#: Applications/applications.js:68
55+msgid "Notepad"
56+msgstr "Pada nan nòtaichean"
57+
58+#: Applications/applications.js:74
59+msgid "Calendar"
60+msgstr "Am mìosachan"
61+
62+#: Applications/applications.js:80
63+msgid "Media Player"
64+msgstr "Cluicheadair mheadhanan"
65+
66+#: Applications/applications.js:86
67+msgid "Evernote"
68+msgstr "Evernote"
69+
70+#: Applications/applications.js:91
71+msgid "Map"
72+msgstr "Mapa"
73+
74+#: Applications/applications.js:96
75+msgid "Pinterest"
76+msgstr "Pinterest"
77+
78+#: Applications/applications.js:101
79+msgid "SoundCloud"
80+msgstr "SoundCloud"
81+
82+#: Applications/applications.js:106
83+msgid "Wikipedia"
84+msgstr "An Uicipeid"
85+
86+#: Applications/applications.js:111
87+msgid "YouTube"
88+msgstr "YouTube"
89+
90+#: Components/EdgeDemoOverlay.qml:145
91+msgid "Skip intro"
92+msgstr "Gearr leum thairis air an ro-ràdh"
93+
94+#: Components/EdgeDemo.qml:98
95+msgid "Right edge"
96+msgstr "An oir dheas"
97+
98+#: Components/EdgeDemo.qml:99
99+msgid "Try swiping from the right edge to unlock the phone"
100+msgstr ""
101+"Feuch is dèan grad-shlaighdeadh a-steach on oir dheas gus a' ghlas a thoirt "
102+"far an fhòn"
103+
104+#: Components/EdgeDemo.qml:135
105+msgid "Top edge"
106+msgstr "An oir aig a' bharr"
107+
108+#: Components/EdgeDemo.qml:136
109+msgid "Try swiping from the top edge to access the indicators"
110+msgstr ""
111+"Feuch is dèan grad-shlaighdeadh a-steach on oir aig a' bharr gus greim "
112+"fhaighinn air na taisbeanairean"
113+
114+#: Components/EdgeDemo.qml:161
115+msgid "Close"
116+msgstr "Dùin"
117+
118+#: Components/EdgeDemo.qml:162
119+msgid "Swipe up again to close the settings screen"
120+msgstr "Dèan grad-shlaighdeadh a-nìos gus sgrìn nan roghainnean a dhùnadh"
121+
122+#: Components/EdgeDemo.qml:189
123+msgid "Left edge"
124+msgstr "An oir chlì"
125+
126+#: Components/EdgeDemo.qml:190
127+msgid "Swipe from the left to reveal the launcher for quick access to apps"
128+msgstr ""
129+"Dèan grad-shlaighdeadh on oir chlì air an lòinseir a bheir dhut cothrom "
130+"luath air na h-aplacaidean"
131+
132+#: Components/EdgeDemo.qml:217
133+msgid "Well done"
134+msgstr "Gasta!"
135+
136+#: Components/EdgeDemo.qml:218
137+msgid "You have now mastered the edge gestures and can start using the phone"
138+msgstr ""
139+"Dh'ionnsaich thu mar a dh'obraicheas na gluasadan air an oir agus is urrainn "
140+"dhut am fòn a chleachdadh a-nis"
141+
142+#: Components/PageHeader.qml:298
143+msgid "Recent searches"
144+msgstr "Na lorg thu o chionn goirid"
145+
146+#. TRANSLATORS: Number of persons who rated this app
147+#: Dash/Apps/AppInfo.qml:73
148+#, qt-format
149+msgid "(%1)"
150+msgstr "(%1)"
151+
152+#. TRANSLATORS: Number of persons who wrote reviews for this app
153+#: Dash/Apps/AppInfo.qml:85
154+#, qt-format
155+msgid "%1 review"
156+msgid_plural "%1 reviews"
157+msgstr[0] "%1 lèirmheas"
158+msgstr[1] "%1 lèirmheas"
159+msgstr[2] "%1 lèirmheasan"
160+msgstr[3] "%1 lèirmheas"
161+
162+#: Dash/Apps/AppPreview.qml:175
163+msgid "Rate this"
164+msgstr "Rangaich seo"
165+
166+#: Dash/Apps/AppReviews.qml:72
167+msgid "Add a review"
168+msgstr "Cuir lèirmheas ris"
169+
170+#: Dash/Apps/AppReviews.qml:84
171+msgid "Review"
172+msgstr "Lèirmheas"
173+
174+#: Dash/Apps/AppReviews.qml:118
175+msgid "Send"
176+msgstr "Cuir"
177+
178+#: Dash/Apps/AppReviews.qml:136
179+msgid "Comments:"
180+msgstr "Beachdan"
181+
182+#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
183+msgid "Featured"
184+msgstr "Brosnaichte"
185+
186+#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
187+msgid "Recent"
188+msgstr "O chionn goirid"
189+
190+#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
191+msgid "New Releases"
192+msgstr "Air ùr-sgaoileadh"
193+
194+#: Dash/DashMusic.qml:30
195+msgid "Top Charting"
196+msgstr "Gràinnean-mullaich nan cairt"
197+
198+#: Dash/DashMusic.qml:91
199+msgid "Music"
200+msgstr "Ceòl"
201+
202+#: Dash/DashVideos.qml:31
203+msgid "Popular Online"
204+msgstr "Fèill mhòr air air loidhne"
205+
206+#: Dash/DashVideos.qml:146
207+msgid "Videos"
208+msgstr "Videothan"
209+
210+#: Dash/Video/VideoPreview.qml:130
211+msgid "Directed by:"
212+msgstr "Air a stiùireadh le:"
213+
214+#: Dash/Video/VideoPreview.qml:153
215+msgid "Starring:"
216+msgstr "Leis na daoine a leanas:"
217+
218+#: Dash/Video/VideoPreview.qml:176
219+msgid "Author:"
220+msgstr "Ùghdar:"
221+
222+#: Greeter/Lockscreen.qml:134
223+msgid "Emergency Call"
224+msgstr "Gairm èiginn"
225+
226+#: Greeter/PassphraseLockscreen.qml:59
227+#, qt-format
228+msgid "Hello %1"
229+msgstr "Shin thu, %1"
230+
231+#: Greeter/PassphraseLockscreen.qml:59
232+msgid "Hello"
233+msgstr "Shin thu"
234+
235+#: Hud/HudParametrizedActionsPage.qml:132
236+msgid "Confirm"
237+msgstr "Dearbhaich"
238+
239+#: Hud/Hud.qml:61 Hud/Hud.qml:99 Hud/Hud.qml:372
240+msgid "Type or say a command"
241+msgstr "Sgrìobh no can àithne"
242+
243+#: Hud/Hud.qml:84
244+msgid "Loading. Please Wait..."
245+msgstr "'Ga luchdadh, fuirich ort..."
246+
247+#: Hud/Hud.qml:89
248+msgid "Speak Now..."
249+msgstr "Can rud a-nis..."
250+
251+#: Hud/Hud.qml:94
252+msgid "Speaking..."
253+msgstr "A' bruidhinn..."
254+
255+#: Panel/SearchIndicator.qml:27
256+msgid "Search"
257+msgstr "Lorg"
258+
259+#: plugins/Unity/scope.cpp:317
260+msgid "Sorry, there is nothing that matches your search."
261+msgstr "Tha sinn duilich ach chan eil dad a' freagairt ris na lorg thu."
262+
263+#: Shell.qml:429
264+#, qt-format
265+msgid "Please enter %1"
266+msgstr "Cuir a-steach %1"
po/gl.po+29−56
@@ -8,99 +8,99 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2013-08-27 13:36-0400\n"
10"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-06-27 03:38+0000\n"
11+"PO-Revision-Date: 2013-09-29 11:14+0000\n"
12−"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
12+"Last-Translator: Marcos Lans <Unknown>\n"
13"Language-Team: Galician <gl@li.org>\n"
13"Language-Team: Galician <gl@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-09-30 05:57+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16774)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
23−msgstr ""
23+msgstr "Teléfono"
24
24
25#: Applications/applications.js:29
25#: Applications/applications.js:29
26msgid "Camera"
26msgid "Camera"
27−msgstr ""
27+msgstr "Cámara"
28
28
29#: Applications/applications.js:35
29#: Applications/applications.js:35
30msgid "Gallery"
30msgid "Gallery"
31−msgstr ""
31+msgstr "Galería"
32
32
33#: Applications/applications.js:40
33#: Applications/applications.js:40
34msgid "Facebook"
34msgid "Facebook"
35−msgstr ""
35+msgstr "Facebook"
36
36
37#: Applications/applications.js:46
37#: Applications/applications.js:46
38msgid "Browser"
38msgid "Browser"
39−msgstr ""
39+msgstr "Navegador"
40
40
41#: Applications/applications.js:51
41#: Applications/applications.js:51
42msgid "Twitter"
42msgid "Twitter"
43−msgstr ""
43+msgstr "Twitter"
44
44
45#: Applications/applications.js:57
45#: Applications/applications.js:57
46msgid "GMail"
46msgid "GMail"
47−msgstr ""
47+msgstr "GMail"
48
48
49#: Applications/applications.js:62
49#: Applications/applications.js:62
50msgid "Weather"
50msgid "Weather"
51−msgstr ""
51+msgstr "O tempo"
52
52
53#: Applications/applications.js:68
53#: Applications/applications.js:68
54msgid "Notepad"
54msgid "Notepad"
55−msgstr ""
55+msgstr "Bloc de notas"
56
56
57#: Applications/applications.js:74
57#: Applications/applications.js:74
58msgid "Calendar"
58msgid "Calendar"
59−msgstr ""
59+msgstr "Calendario"
60
60
61#: Applications/applications.js:80
61#: Applications/applications.js:80
62msgid "Media Player"
62msgid "Media Player"
63−msgstr ""
63+msgstr "Reprodutor multimedia"
64
64
65#: Applications/applications.js:86
65#: Applications/applications.js:86
66msgid "Evernote"
66msgid "Evernote"
67−msgstr ""
67+msgstr "Evernote"
68
68
69#: Applications/applications.js:91
69#: Applications/applications.js:91
70msgid "Map"
70msgid "Map"
71−msgstr ""
71+msgstr "Mapa"
72
72
73#: Applications/applications.js:96
73#: Applications/applications.js:96
74msgid "Pinterest"
74msgid "Pinterest"
75−msgstr ""
75+msgstr "Pinterest"
76
76
77#: Applications/applications.js:101
77#: Applications/applications.js:101
78msgid "SoundCloud"
78msgid "SoundCloud"
79−msgstr ""
79+msgstr "SoundCloud"
80
80
81#: Applications/applications.js:106
81#: Applications/applications.js:106
82msgid "Wikipedia"
82msgid "Wikipedia"
83−msgstr ""
83+msgstr "Wikipedia"
84
84
85#: Applications/applications.js:111
85#: Applications/applications.js:111
86msgid "YouTube"
86msgid "YouTube"
87−msgstr ""
87+msgstr "YouTube"
88
88
89#: Components/EdgeDemoOverlay.qml:145
89#: Components/EdgeDemoOverlay.qml:145
90msgid "Skip intro"
90msgid "Skip intro"
91−msgstr ""
91+msgstr "Saltar introdución"
92
92
93#: Components/EdgeDemo.qml:98
93#: Components/EdgeDemo.qml:98
94msgid "Right edge"
94msgid "Right edge"
95−msgstr ""
95+msgstr "Bordo dereito"
96
96
97#: Components/EdgeDemo.qml:99
97#: Components/EdgeDemo.qml:99
98msgid "Try swiping from the right edge to unlock the phone"
98msgid "Try swiping from the right edge to unlock the phone"
99−msgstr ""
99+msgstr "Probe a arrastrar desde o bordo dereito para desbloquear o teléfono"
100
100
101#: Components/EdgeDemo.qml:135
101#: Components/EdgeDemo.qml:135
102msgid "Top edge"
102msgid "Top edge"
103−msgstr ""
103+msgstr "Bordo superior"
104
104
105#: Components/EdgeDemo.qml:136
105#: Components/EdgeDemo.qml:136
106msgid "Try swiping from the top edge to access the indicators"
106msgid "Try swiping from the top edge to access the indicators"
@@ -108,7 +108,7 @@ msgstr ""
108
108
109#: Components/EdgeDemo.qml:161
109#: Components/EdgeDemo.qml:161
110msgid "Close"
110msgid "Close"
111−msgstr ""
111+msgstr "Pechar"
112
112
113#: Components/EdgeDemo.qml:162
113#: Components/EdgeDemo.qml:162
114msgid "Swipe up again to close the settings screen"
114msgid "Swipe up again to close the settings screen"
@@ -116,7 +116,7 @@ msgstr ""
116
116
117#: Components/EdgeDemo.qml:189
117#: Components/EdgeDemo.qml:189
118msgid "Left edge"
118msgid "Left edge"
119−msgstr ""
119+msgstr "Bordo esquerdo"
120
120
121#: Components/EdgeDemo.qml:190
121#: Components/EdgeDemo.qml:190
122msgid "Swipe from the left to reveal the launcher for quick access to apps"
122msgid "Swipe from the left to reveal the launcher for quick access to apps"
@@ -124,7 +124,7 @@ msgstr ""
124
124
125#: Components/EdgeDemo.qml:217
125#: Components/EdgeDemo.qml:217
126msgid "Well done"
126msgid "Well done"
127−msgstr ""
127+msgstr "Ben feito"
128
128
129#: Components/EdgeDemo.qml:218
129#: Components/EdgeDemo.qml:218
130msgid "You have now mastered the edge gestures and can start using the phone"
130msgid "You have now mastered the edge gestures and can start using the phone"
@@ -138,7 +138,7 @@ msgstr "Buscas recentes"
138#: Dash/Apps/AppInfo.qml:73
138#: Dash/Apps/AppInfo.qml:73
139#, qt-format
139#, qt-format
140msgid "(%1)"
140msgid "(%1)"
141−msgstr ""
141+msgstr "(%1)"
142
142
143#. TRANSLATORS: Number of persons who wrote reviews for this app
143#. TRANSLATORS: Number of persons who wrote reviews for this app
144#: Dash/Apps/AppInfo.qml:85
144#: Dash/Apps/AppInfo.qml:85
@@ -253,30 +253,3 @@ msgstr "Sentímolo, non hai nada que coincida con esta busca."
253#, qt-format
253#, qt-format
254msgid "Please enter %1"
254msgid "Please enter %1"
255msgstr ""
255msgstr ""
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 ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16750)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "שום דבר אינו תואם לחיפוש שלך, עמך הסליחה
253#, qt-format
253#, qt-format
254msgid "Please enter %1"
254msgid "Please enter %1"
255msgstr ""
255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "יישומים"
259−
260−#~ msgid "Home"
261−#~ msgstr "בית"
po/hr.po+2−8
@@ -16,8 +16,8 @@ msgstr ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
18"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
18"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
20+"X-Generator: Launchpad (build 16750)\n"
21
21
22#: Applications/applications.js:23
22#: Applications/applications.js:23
23msgid "Phone"
23msgid "Phone"
@@ -254,9 +254,3 @@ msgstr "Nažalost, ne postoji ništa što odgovara vašoj pretrazi."
254#, qt-format
254#, qt-format
255msgid "Please enter %1"
255msgid "Please enter %1"
256msgstr ""
256msgstr ""
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 ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16750)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -253,18 +253,3 @@ msgstr "Elnézést, nincs találat a keresésre."
253#, qt-format
253#, qt-format
254msgid "Please enter %1"
254msgid "Please enter %1"
255msgstr ""
255msgstr ""
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 ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16750)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -253,30 +253,3 @@ msgstr "Կներերք, բայց Ձեր հարցումով ոչինչ չկար"
253#, qt-format
253#, qt-format
254msgid "Please enter %1"
254msgid "Please enter %1"
255msgstr ""
255msgstr ""
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 ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16750)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
po/is.ponew file+256
@@ -0,0 +1,256 @@
1+# Icelandic translation for unity8
2+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
3+# This file is distributed under the same license as the unity8 package.
4+# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
5+#
6+msgid ""
7+msgstr ""
8+"Project-Id-Version: unity8\n"
9+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10+"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11+"PO-Revision-Date: 2013-09-18 16:22+0000\n"
12+"Last-Translator: Andri Thorlacius <Unknown>\n"
13+"Language-Team: Icelandic <is@li.org>\n"
14+"MIME-Version: 1.0\n"
15+"Content-Type: text/plain; charset=UTF-8\n"
16+"Content-Transfer-Encoding: 8bit\n"
17+"Plural-Forms: nplurals=2; plural=n != 1;\n"
18+"X-Launchpad-Export-Date: 2013-09-19 05:14+0000\n"
19+"X-Generator: Launchpad (build 16765)\n"
20+
21+#: Applications/applications.js:23
22+msgid "Phone"
23+msgstr "Sími"
24+
25+#: Applications/applications.js:29
26+msgid "Camera"
27+msgstr "Myndavél"
28+
29+#: Applications/applications.js:35
30+msgid "Gallery"
31+msgstr "Myndasafn"
32+
33+#: Applications/applications.js:40
34+msgid "Facebook"
35+msgstr "Facebook"
36+
37+#: Applications/applications.js:46
38+msgid "Browser"
39+msgstr "Vafri"
40+
41+#: Applications/applications.js:51
42+msgid "Twitter"
43+msgstr "Twitter"
44+
45+#: Applications/applications.js:57
46+msgid "GMail"
47+msgstr "GMail"
48+
49+#: Applications/applications.js:62
50+msgid "Weather"
51+msgstr "Veður"
52+
53+#: Applications/applications.js:68
54+msgid "Notepad"
55+msgstr "Skrifblokk"
56+
57+#: Applications/applications.js:74
58+msgid "Calendar"
59+msgstr "Dagatal"
60+
61+#: Applications/applications.js:80
62+msgid "Media Player"
63+msgstr "Margmiðlunarspilari"
64+
65+#: Applications/applications.js:86
66+msgid "Evernote"
67+msgstr "Evernote"
68+
69+#: Applications/applications.js:91
70+msgid "Map"
71+msgstr "Kort"
72+
73+#: Applications/applications.js:96
74+msgid "Pinterest"
75+msgstr "Pinterest"
76+
77+#: Applications/applications.js:101
78+msgid "SoundCloud"
79+msgstr "SoundCloud"
80+
81+#: Applications/applications.js:106
82+msgid "Wikipedia"
83+msgstr "Wikipedia"
84+
85+#: Applications/applications.js:111
86+msgid "YouTube"
87+msgstr "YouTube"
88+
89+#: Components/EdgeDemoOverlay.qml:145
90+msgid "Skip intro"
91+msgstr "Hoppa yfir kynningu"
92+
93+#: Components/EdgeDemo.qml:98
94+msgid "Right edge"
95+msgstr "Hægri brún"
96+
97+#: Components/EdgeDemo.qml:99
98+msgid "Try swiping from the right edge to unlock the phone"
99+msgstr ""
100+"Prufaðu að renna puttanum frá hægri brúninni til að aflæsa símanum þínum."
101+
102+#: Components/EdgeDemo.qml:135
103+msgid "Top edge"
104+msgstr "Efri brún"
105+
106+#: Components/EdgeDemo.qml:136
107+msgid "Try swiping from the top edge to access the indicators"
108+msgstr ""
109+
110+#: Components/EdgeDemo.qml:161
111+msgid "Close"
112+msgstr "Loka"
113+
114+#: Components/EdgeDemo.qml:162
115+msgid "Swipe up again to close the settings screen"
116+msgstr ""
117+
118+#: Components/EdgeDemo.qml:189
119+msgid "Left edge"
120+msgstr "Vinstri brún"
121+
122+#: Components/EdgeDemo.qml:190
123+msgid "Swipe from the left to reveal the launcher for quick access to apps"
124+msgstr ""
125+
126+#: Components/EdgeDemo.qml:217
127+msgid "Well done"
128+msgstr "Vel gert"
129+
130+#: Components/EdgeDemo.qml:218
131+msgid "You have now mastered the edge gestures and can start using the phone"
132+msgstr ""
133+
134+#: Components/PageHeader.qml:298
135+msgid "Recent searches"
136+msgstr "Nýlegar leitir"
137+
138+#. TRANSLATORS: Number of persons who rated this app
139+#: Dash/Apps/AppInfo.qml:73
140+#, qt-format
141+msgid "(%1)"
142+msgstr "(%1)"
143+
144+#. TRANSLATORS: Number of persons who wrote reviews for this app
145+#: Dash/Apps/AppInfo.qml:85
146+#, qt-format
147+msgid "%1 review"
148+msgid_plural "%1 reviews"
149+msgstr[0] "%1 ummæli"
150+msgstr[1] "%1 ummæli"
151+
152+#: Dash/Apps/AppPreview.qml:175
153+msgid "Rate this"
154+msgstr "Gefa þessu einkunn"
155+
156+#: Dash/Apps/AppReviews.qml:72
157+msgid "Add a review"
158+msgstr "Gefa umsögn"
159+
160+#: Dash/Apps/AppReviews.qml:84
161+msgid "Review"
162+msgstr "Umsögn"
163+
164+#: Dash/Apps/AppReviews.qml:118
165+msgid "Send"
166+msgstr "Senda"
167+
168+#: Dash/Apps/AppReviews.qml:136
169+msgid "Comments:"
170+msgstr "Athugasemdir:"
171+
172+#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
173+msgid "Featured"
174+msgstr "Efst á baugi"
175+
176+#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
177+msgid "Recent"
178+msgstr "Nýlegt"
179+
180+#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
181+msgid "New Releases"
182+msgstr "Nýjar Útgáfur"
183+
184+#: Dash/DashMusic.qml:30
185+msgid "Top Charting"
186+msgstr "Topp Listi"
187+
188+#: Dash/DashMusic.qml:91
189+msgid "Music"
190+msgstr "Tónlist"
191+
192+#: Dash/DashVideos.qml:31
193+msgid "Popular Online"
194+msgstr "Vinsælt á Netinu"
195+
196+#: Dash/DashVideos.qml:146
197+msgid "Videos"
198+msgstr "Myndbönd"
199+
200+#: Dash/Video/VideoPreview.qml:130
201+msgid "Directed by:"
202+msgstr "Leikstýrt af:"
203+
204+#: Dash/Video/VideoPreview.qml:153
205+msgid "Starring:"
206+msgstr "Meðal leikara eru:"
207+
208+#: Dash/Video/VideoPreview.qml:176
209+msgid "Author:"
210+msgstr "Höfundur:"
211+
212+#: Greeter/Lockscreen.qml:134
213+msgid "Emergency Call"
214+msgstr "Neyðarsímtal"
215+
216+#: Greeter/PassphraseLockscreen.qml:59
217+#, qt-format
218+msgid "Hello %1"
219+msgstr "Hæ %1"
220+
221+#: Greeter/PassphraseLockscreen.qml:59
222+msgid "Hello"
223+msgstr "Hæ"
224+
225+#: Hud/HudParametrizedActionsPage.qml:132
226+msgid "Confirm"
227+msgstr "Staðfesta"
228+
229+#: Hud/Hud.qml:61 Hud/Hud.qml:99 Hud/Hud.qml:372
230+msgid "Type or say a command"
231+msgstr "Skrifaðu eða segðu eitthvað"
232+
233+#: Hud/Hud.qml:84
234+msgid "Loading. Please Wait..."
235+msgstr "Hleð. Vinsamlegast Bíðið..."
236+
237+#: Hud/Hud.qml:89
238+msgid "Speak Now..."
239+msgstr "Talaðu Núna..."
240+
241+#: Hud/Hud.qml:94
242+msgid "Speaking..."
243+msgstr "Tala..."
244+
245+#: Panel/SearchIndicator.qml:27
246+msgid "Search"
247+msgstr "Leita"
248+
249+#: plugins/Unity/scope.cpp:317
250+msgid "Sorry, there is nothing that matches your search."
251+msgstr "Því miður, það var ekkert sem passaði við leitarorðið þitt."
252+
253+#: Shell.qml:429
254+#, qt-format
255+msgid "Please enter %1"
256+msgstr ""
po/it.po+55−54
@@ -8,127 +8,134 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2013-08-27 13:36-0400\n"
10"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-06-27 05:14+0000\n"
11+"PO-Revision-Date: 2013-09-28 10:05+0000\n"
12−"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
12+"Last-Translator: Claudio Arseni <claudio.arseni@gmail.com>\n"
13"Language-Team: Italian <it@li.org>\n"
13"Language-Team: Italian <it@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-09-29 06:18+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16774)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
23−msgstr ""
23+msgstr "Telefono"
24
24
25#: Applications/applications.js:29
25#: Applications/applications.js:29
26msgid "Camera"
26msgid "Camera"
27−msgstr ""
27+msgstr "Fotocamera"
28
28
29#: Applications/applications.js:35
29#: Applications/applications.js:35
30msgid "Gallery"
30msgid "Gallery"
31−msgstr ""
31+msgstr "Galleria"
32
32
33#: Applications/applications.js:40
33#: Applications/applications.js:40
34msgid "Facebook"
34msgid "Facebook"
35−msgstr ""
35+msgstr "Facebook"
36
36
37#: Applications/applications.js:46
37#: Applications/applications.js:46
38msgid "Browser"
38msgid "Browser"
39−msgstr ""
39+msgstr "Browser"
40
40
41#: Applications/applications.js:51
41#: Applications/applications.js:51
42msgid "Twitter"
42msgid "Twitter"
43−msgstr ""
43+msgstr "Twitter"
44
44
45#: Applications/applications.js:57
45#: Applications/applications.js:57
46msgid "GMail"
46msgid "GMail"
47−msgstr ""
47+msgstr "GMail"
48
48
49#: Applications/applications.js:62
49#: Applications/applications.js:62
50msgid "Weather"
50msgid "Weather"
51−msgstr ""
51+msgstr "Meteo"
52
52
53#: Applications/applications.js:68
53#: Applications/applications.js:68
54msgid "Notepad"
54msgid "Notepad"
55−msgstr ""
55+msgstr "Blocco note"
56
56
57#: Applications/applications.js:74
57#: Applications/applications.js:74
58msgid "Calendar"
58msgid "Calendar"
59−msgstr ""
59+msgstr "Calendario"
60
60
61#: Applications/applications.js:80
61#: Applications/applications.js:80
62msgid "Media Player"
62msgid "Media Player"
63−msgstr ""
63+msgstr "Riproduttore multimediale"
64
64
65#: Applications/applications.js:86
65#: Applications/applications.js:86
66msgid "Evernote"
66msgid "Evernote"
67−msgstr ""
67+msgstr "Evernote"
68
68
69#: Applications/applications.js:91
69#: Applications/applications.js:91
70msgid "Map"
70msgid "Map"
71−msgstr ""
71+msgstr "Mappa"
72
72
73#: Applications/applications.js:96
73#: Applications/applications.js:96
74msgid "Pinterest"
74msgid "Pinterest"
75−msgstr ""
75+msgstr "Pinterest"
76
76
77#: Applications/applications.js:101
77#: Applications/applications.js:101
78msgid "SoundCloud"
78msgid "SoundCloud"
79−msgstr ""
79+msgstr "SoundCloud"
80
80
81#: Applications/applications.js:106
81#: Applications/applications.js:106
82msgid "Wikipedia"
82msgid "Wikipedia"
83−msgstr ""
83+msgstr "Wikipedia"
84
84
85#: Applications/applications.js:111
85#: Applications/applications.js:111
86msgid "YouTube"
86msgid "YouTube"
87−msgstr ""
87+msgstr "YouTube"
88
88
89#: Components/EdgeDemoOverlay.qml:145
89#: Components/EdgeDemoOverlay.qml:145
90msgid "Skip intro"
90msgid "Skip intro"
91−msgstr ""
91+msgstr "Salta introduzione"
92
92
93#: Components/EdgeDemo.qml:98
93#: Components/EdgeDemo.qml:98
94msgid "Right edge"
94msgid "Right edge"
95−msgstr ""
95+msgstr "Bordo destro"
96
96
97#: Components/EdgeDemo.qml:99
97#: Components/EdgeDemo.qml:99
98msgid "Try swiping from the right edge to unlock the phone"
98msgid "Try swiping from the right edge to unlock the phone"
99−msgstr ""
99+msgstr "Provare a far scorrere dal bordo destro per sbloccare il telefono"
100
100
101#: Components/EdgeDemo.qml:135
101#: Components/EdgeDemo.qml:135
102msgid "Top edge"
102msgid "Top edge"
103−msgstr ""
103+msgstr "Bordo superiore"
104
104
105#: Components/EdgeDemo.qml:136
105#: Components/EdgeDemo.qml:136
106msgid "Try swiping from the top edge to access the indicators"
106msgid "Try swiping from the top edge to access the indicators"
107msgstr ""
107msgstr ""
108+"Provare a far scorrere dal bordo in alto per accedere agli indicatori"
108
109
109#: Components/EdgeDemo.qml:161
110#: Components/EdgeDemo.qml:161
110msgid "Close"
111msgid "Close"
111−msgstr ""
112+msgstr "Chiudi"
112
113
113#: Components/EdgeDemo.qml:162
114#: Components/EdgeDemo.qml:162
114msgid "Swipe up again to close the settings screen"
115msgid "Swipe up again to close the settings screen"
115msgstr ""
116msgstr ""
117+"Far scorrere verso l'alto nuovamente per chiudere la schermata delle "
118+"impostazioni"
116
119
117#: Components/EdgeDemo.qml:189
120#: Components/EdgeDemo.qml:189
118msgid "Left edge"
121msgid "Left edge"
119−msgstr ""
122+msgstr "Bordo sinistro"
120
123
121#: Components/EdgeDemo.qml:190
124#: Components/EdgeDemo.qml:190
122msgid "Swipe from the left to reveal the launcher for quick access to apps"
125msgid "Swipe from the left to reveal the launcher for quick access to apps"
123msgstr ""
126msgstr ""
127+"Far scorrere il bordo sinistro per mostrare il Launcher e avere un rapido "
128+"accesso alle applicazioni"
124
129
125#: Components/EdgeDemo.qml:217
130#: Components/EdgeDemo.qml:217
126msgid "Well done"
131msgid "Well done"
127−msgstr ""
132+msgstr "Ben fatto"
128
133
129#: Components/EdgeDemo.qml:218
134#: Components/EdgeDemo.qml:218
130msgid "You have now mastered the edge gestures and can start using the phone"
135msgid "You have now mastered the edge gestures and can start using the phone"
131msgstr ""
136msgstr ""
137+"I gesti sui bordi dello schermo sono ora configurato ed è possibile usare il "
138+"telefono"
132
139
133#: Components/PageHeader.qml:298
140#: Components/PageHeader.qml:298
134msgid "Recent searches"
141msgid "Recent searches"
@@ -138,51 +145,51 @@ msgstr "Ricerche recenti"
138#: Dash/Apps/AppInfo.qml:73
145#: Dash/Apps/AppInfo.qml:73
139#, qt-format
146#, qt-format
140msgid "(%1)"
147msgid "(%1)"
141−msgstr ""
148+msgstr "(%1)"
142
149
143#. TRANSLATORS: Number of persons who wrote reviews for this app
150#. TRANSLATORS: Number of persons who wrote reviews for this app
144#: Dash/Apps/AppInfo.qml:85
151#: Dash/Apps/AppInfo.qml:85
145#, qt-format
152#, qt-format
146msgid "%1 review"
153msgid "%1 review"
147msgid_plural "%1 reviews"
154msgid_plural "%1 reviews"
148−msgstr[0] ""
155+msgstr[0] "%1 recensione"
149−msgstr[1] ""
156+msgstr[1] "%1 recensioni"
150
157
151#: Dash/Apps/AppPreview.qml:175
158#: Dash/Apps/AppPreview.qml:175
152msgid "Rate this"
159msgid "Rate this"
153−msgstr ""
160+msgstr "Valuta"
154
161
155#: Dash/Apps/AppReviews.qml:72
162#: Dash/Apps/AppReviews.qml:72
156msgid "Add a review"
163msgid "Add a review"
157−msgstr ""
164+msgstr "Aggiungi una recensione"
158
165
159#: Dash/Apps/AppReviews.qml:84
166#: Dash/Apps/AppReviews.qml:84
160msgid "Review"
167msgid "Review"
161−msgstr ""
168+msgstr "Recensisci"
162
169
163#: Dash/Apps/AppReviews.qml:118
170#: Dash/Apps/AppReviews.qml:118
164msgid "Send"
171msgid "Send"
165−msgstr ""
172+msgstr "Invia"
166
173
167#: Dash/Apps/AppReviews.qml:136
174#: Dash/Apps/AppReviews.qml:136
168msgid "Comments:"
175msgid "Comments:"
169−msgstr ""
176+msgstr "Commenti:"
170
177
171#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
178#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
172msgid "Featured"
179msgid "Featured"
173−msgstr ""
180+msgstr "In evidenza"
174
181
175#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
182#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
176msgid "Recent"
183msgid "Recent"
177−msgstr ""
184+msgstr "Recenti"
178
185
179#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
186#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
180msgid "New Releases"
187msgid "New Releases"
181−msgstr ""
188+msgstr "Nuovi rilasci"
182
189
183#: Dash/DashMusic.qml:30
190#: Dash/DashMusic.qml:30
184msgid "Top Charting"
191msgid "Top Charting"
185−msgstr ""
192+msgstr "Più votate"
186
193
187#: Dash/DashMusic.qml:91
194#: Dash/DashMusic.qml:91
188msgid "Music"
195msgid "Music"
@@ -190,7 +197,7 @@ msgstr "Musica"
190
197
191#: Dash/DashVideos.qml:31
198#: Dash/DashVideos.qml:31
192msgid "Popular Online"
199msgid "Popular Online"
193−msgstr ""
200+msgstr "Popolari online"
194
201
195#: Dash/DashVideos.qml:146
202#: Dash/DashVideos.qml:146
196msgid "Videos"
203msgid "Videos"
@@ -198,28 +205,28 @@ msgstr "Video"
198
205
199#: Dash/Video/VideoPreview.qml:130
206#: Dash/Video/VideoPreview.qml:130
200msgid "Directed by:"
207msgid "Directed by:"
201−msgstr ""
208+msgstr "Diretto da:"
202
209
203#: Dash/Video/VideoPreview.qml:153
210#: Dash/Video/VideoPreview.qml:153
204msgid "Starring:"
211msgid "Starring:"
205−msgstr ""
212+msgstr "Valutazioni:"
206
213
207#: Dash/Video/VideoPreview.qml:176
214#: Dash/Video/VideoPreview.qml:176
208msgid "Author:"
215msgid "Author:"
209−msgstr ""
216+msgstr "Autore:"
210
217
211#: Greeter/Lockscreen.qml:134
218#: Greeter/Lockscreen.qml:134
212msgid "Emergency Call"
219msgid "Emergency Call"
213−msgstr ""
220+msgstr "Chiamata di emergenza"
214
221
215#: Greeter/PassphraseLockscreen.qml:59
222#: Greeter/PassphraseLockscreen.qml:59
216#, qt-format
223#, qt-format
217msgid "Hello %1"
224msgid "Hello %1"
218−msgstr ""
225+msgstr "Ciao %1"
219
226
220#: Greeter/PassphraseLockscreen.qml:59
227#: Greeter/PassphraseLockscreen.qml:59
221msgid "Hello"
228msgid "Hello"
222−msgstr ""
229+msgstr "Ciao"
223
230
224#: Hud/HudParametrizedActionsPage.qml:132
231#: Hud/HudParametrizedActionsPage.qml:132
225msgid "Confirm"
232msgid "Confirm"
@@ -252,10 +259,4 @@ msgstr "Nessun risultato corrispondente alla ricerca."
252#: Shell.qml:429
259#: Shell.qml:429
253#, qt-format
260#, qt-format
254msgid "Please enter %1"
261msgid "Please enter %1"
255−msgstr ""
262+msgstr "Inserire %1"
256−
257−#~ msgid "Apps"
258−#~ msgstr "Applicazioni"
259−
260−#~ msgid "Home"
261−#~ msgstr "Home"
po/ja.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16750)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
po/kn.po+2−8
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16750)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "ಕ್ಷಮಿಸಿ ನಿಮ್ಮ ಶೋಧನೆಗೆ ಸರಿಯ
253#, qt-format
253#, qt-format
254msgid "Please enter %1"
254msgid "Please enter %1"
255msgstr ""
255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "ಅಪ್ಲಿಕೇಶನ್‌ಗಳು"
259−
260−#~ msgid "Home"
261−#~ msgstr "ಮನೆ (Home)"
po/ko.po+2−23
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16750)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -253,24 +253,3 @@ msgstr ""
253#, qt-format
253#, qt-format
254msgid "Please enter %1"
254msgid "Please enter %1"
255msgstr ""
255msgstr ""
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 ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16750)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "Тилекке каршы, сиздин издөөңүзгө эч нер
253#, qt-format
253#, qt-format
254msgid "Please enter %1"
254msgid "Please enter %1"
255msgstr ""
255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "Тиркемелер"
259−
260−#~ msgid "Home"
261−#~ msgstr "Үй папкасы"
po/lv.po+21−27
@@ -8,59 +8,59 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2013-08-27 13:36-0400\n"
10"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-06-27 06:31+0000\n"
11+"PO-Revision-Date: 2013-09-28 16:29+0000\n"
12−"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
12+"Last-Translator: Jānis-Marks Gailis <jeanmarc.gailis@gmail.com>\n"
13"Language-Team: Latvian <lv@li.org>\n"
13"Language-Team: Latvian <lv@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;\n"
17"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"
18+"X-Launchpad-Export-Date: 2013-09-29 06:18+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16774)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
23−msgstr ""
23+msgstr "Tālrunis"
24
24
25#: Applications/applications.js:29
25#: Applications/applications.js:29
26msgid "Camera"
26msgid "Camera"
27−msgstr ""
27+msgstr "Fotokamera"
28
28
29#: Applications/applications.js:35
29#: Applications/applications.js:35
30msgid "Gallery"
30msgid "Gallery"
31−msgstr ""
31+msgstr "Galerija"
32
32
33#: Applications/applications.js:40
33#: Applications/applications.js:40
34msgid "Facebook"
34msgid "Facebook"
35−msgstr ""
35+msgstr "Facebook"
36
36
37#: Applications/applications.js:46
37#: Applications/applications.js:46
38msgid "Browser"
38msgid "Browser"
39−msgstr ""
39+msgstr "Pārlūkprogramma"
40
40
41#: Applications/applications.js:51
41#: Applications/applications.js:51
42msgid "Twitter"
42msgid "Twitter"
43−msgstr ""
43+msgstr "Twitter"
44
44
45#: Applications/applications.js:57
45#: Applications/applications.js:57
46msgid "GMail"
46msgid "GMail"
47−msgstr ""
47+msgstr "GMail"
48
48
49#: Applications/applications.js:62
49#: Applications/applications.js:62
50msgid "Weather"
50msgid "Weather"
51−msgstr ""
51+msgstr "Laikapstākļi"
52
52
53#: Applications/applications.js:68
53#: Applications/applications.js:68
54msgid "Notepad"
54msgid "Notepad"
55−msgstr ""
55+msgstr "Bloknots"
56
56
57#: Applications/applications.js:74
57#: Applications/applications.js:74
58msgid "Calendar"
58msgid "Calendar"
59−msgstr ""
59+msgstr "Kalendārs"
60
60
61#: Applications/applications.js:80
61#: Applications/applications.js:80
62msgid "Media Player"
62msgid "Media Player"
63−msgstr ""
63+msgstr "Mēdiju Atskaņotājs"
64
64
65#: Applications/applications.js:86
65#: Applications/applications.js:86
66msgid "Evernote"
66msgid "Evernote"
@@ -68,23 +68,23 @@ msgstr ""
68
68
69#: Applications/applications.js:91
69#: Applications/applications.js:91
70msgid "Map"
70msgid "Map"
71−msgstr ""
71+msgstr "Karte"
72
72
73#: Applications/applications.js:96
73#: Applications/applications.js:96
74msgid "Pinterest"
74msgid "Pinterest"
75−msgstr ""
75+msgstr "Pinterest"
76
76
77#: Applications/applications.js:101
77#: Applications/applications.js:101
78msgid "SoundCloud"
78msgid "SoundCloud"
79−msgstr ""
79+msgstr "SoundCloud"
80
80
81#: Applications/applications.js:106
81#: Applications/applications.js:106
82msgid "Wikipedia"
82msgid "Wikipedia"
83−msgstr ""
83+msgstr "Vikipēdija"
84
84
85#: Applications/applications.js:111
85#: Applications/applications.js:111
86msgid "YouTube"
86msgid "YouTube"
87−msgstr ""
87+msgstr "YouTube"
88
88
89#: Components/EdgeDemoOverlay.qml:145
89#: Components/EdgeDemoOverlay.qml:145
90msgid "Skip intro"
90msgid "Skip intro"
@@ -92,7 +92,7 @@ msgstr ""
92
92
93#: Components/EdgeDemo.qml:98
93#: Components/EdgeDemo.qml:98
94msgid "Right edge"
94msgid "Right edge"
95−msgstr ""
95+msgstr "Labā mala"
96
96
97#: Components/EdgeDemo.qml:99
97#: Components/EdgeDemo.qml:99
98msgid "Try swiping from the right edge to unlock the phone"
98msgid "Try swiping from the right edge to unlock the phone"
@@ -253,9 +253,3 @@ msgstr "Diemžēl nekas neatbilst jūsu meklētajam."
253#, qt-format
253#, qt-format
254msgid "Please enter %1"
254msgid "Please enter %1"
255msgstr ""
255msgstr ""
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 ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16750)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "ဆောရီး၊ သင်၏ရှာဖွေမူနှင့
253#, qt-format
253#, qt-format
254msgid "Please enter %1"
254msgid "Please enter %1"
255msgstr ""
255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "Apps"
259−
260−#~ msgid "Home"
261−#~ msgstr "ပင်မ"
po/nb.po+2−17
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16750)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -253,18 +253,3 @@ msgstr "Søket ga ingen treff."
253#, qt-format
253#, qt-format
254msgid "Please enter %1"
254msgid "Please enter %1"
255msgstr ""
255msgstr ""
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 ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16750)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -253,9 +253,3 @@ msgstr "Er is helaas niets dat met uw zoekopdracht overeenkomt."
253#, qt-format
253#, qt-format
254msgid "Please enter %1"
254msgid "Please enter %1"
255msgstr ""
255msgstr ""
256−
257−#~ msgid "Apps"
258−#~ msgstr "Apps"
259−
260−#~ msgid "Home"
261−#~ msgstr "Hoofdvenster"
po/pl.po+2−29
@@ -16,8 +16,8 @@ msgstr ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
17"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
18"|| n%100>=20) ? 1 : 2;\n"
18"|| n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
20+"X-Generator: Launchpad (build 16750)\n"
21
21
22#: Applications/applications.js:23
22#: Applications/applications.js:23
23msgid "Phone"
23msgid "Phone"
@@ -254,30 +254,3 @@ msgstr "Nie znaleziono pasujących wyników."
254#, qt-format
254#, qt-format
255msgid "Please enter %1"
255msgid "Please enter %1"
256msgstr "Wprowadź %1"
256msgstr "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+49−53
@@ -8,119 +8,121 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2013-08-27 13:36-0400\n"
10"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-06-27 07:39+0000\n"
11+"PO-Revision-Date: 2013-09-30 13:01+0000\n"
12−"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
12+"Last-Translator: Rafael Neri <Unknown>\n"
13"Language-Team: Brazilian Portuguese <pt_BR@li.org>\n"
13"Language-Team: Brazilian Portuguese <pt_BR@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n > 1;\n"
17"Plural-Forms: nplurals=2; plural=n > 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-10-01 05:53+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16774)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
23−msgstr ""
23+msgstr "Telefone"
24
24
25#: Applications/applications.js:29
25#: Applications/applications.js:29
26msgid "Camera"
26msgid "Camera"
27−msgstr ""
27+msgstr "Câmera"
28
28
29#: Applications/applications.js:35
29#: Applications/applications.js:35
30msgid "Gallery"
30msgid "Gallery"
31−msgstr ""
31+msgstr "Galeria"
32
32
33#: Applications/applications.js:40
33#: Applications/applications.js:40
34msgid "Facebook"
34msgid "Facebook"
35−msgstr ""
35+msgstr "Facebook"
36
36
37#: Applications/applications.js:46
37#: Applications/applications.js:46
38msgid "Browser"
38msgid "Browser"
39−msgstr ""
39+msgstr "Navegador"
40
40
41#: Applications/applications.js:51
41#: Applications/applications.js:51
42msgid "Twitter"
42msgid "Twitter"
43−msgstr ""
43+msgstr "Twitter"
44
44
45#: Applications/applications.js:57
45#: Applications/applications.js:57
46msgid "GMail"
46msgid "GMail"
47−msgstr ""
47+msgstr "GMail"
48
48
49#: Applications/applications.js:62
49#: Applications/applications.js:62
50msgid "Weather"
50msgid "Weather"
51−msgstr ""
51+msgstr "Clima"
52
52
53#: Applications/applications.js:68
53#: Applications/applications.js:68
54msgid "Notepad"
54msgid "Notepad"
55−msgstr ""
55+msgstr "Bloco de notas"
56
56
57#: Applications/applications.js:74
57#: Applications/applications.js:74
58msgid "Calendar"
58msgid "Calendar"
59−msgstr ""
59+msgstr "Calendário"
60
60
61#: Applications/applications.js:80
61#: Applications/applications.js:80
62msgid "Media Player"
62msgid "Media Player"
63−msgstr ""
63+msgstr "Media Player"
64
64
65#: Applications/applications.js:86
65#: Applications/applications.js:86
66msgid "Evernote"
66msgid "Evernote"
67−msgstr ""
67+msgstr "Evernote"
68
68
69#: Applications/applications.js:91
69#: Applications/applications.js:91
70msgid "Map"
70msgid "Map"
71−msgstr ""
71+msgstr "Mapa"
72
72
73#: Applications/applications.js:96
73#: Applications/applications.js:96
74msgid "Pinterest"
74msgid "Pinterest"
75−msgstr ""
75+msgstr "Pinterest"
76
76
77#: Applications/applications.js:101
77#: Applications/applications.js:101
78msgid "SoundCloud"
78msgid "SoundCloud"
79−msgstr ""
79+msgstr "SoundCloud"
80
80
81#: Applications/applications.js:106
81#: Applications/applications.js:106
82msgid "Wikipedia"
82msgid "Wikipedia"
83−msgstr ""
83+msgstr "Wikipédia"
84
84
85#: Applications/applications.js:111
85#: Applications/applications.js:111
86msgid "YouTube"
86msgid "YouTube"
87−msgstr ""
87+msgstr "YouTube"
88
88
89#: Components/EdgeDemoOverlay.qml:145
89#: Components/EdgeDemoOverlay.qml:145
90msgid "Skip intro"
90msgid "Skip intro"
91−msgstr ""
91+msgstr "Pular introdução"
92
92
93#: Components/EdgeDemo.qml:98
93#: Components/EdgeDemo.qml:98
94msgid "Right edge"
94msgid "Right edge"
95−msgstr ""
95+msgstr "Borda direita"
96
96
97#: Components/EdgeDemo.qml:99
97#: Components/EdgeDemo.qml:99
98msgid "Try swiping from the right edge to unlock the phone"
98msgid "Try swiping from the right edge to unlock the phone"
99−msgstr ""
99+msgstr "Tente deslizar da borda direita para desbloquear o telefone"
100
100
101#: Components/EdgeDemo.qml:135
101#: Components/EdgeDemo.qml:135
102msgid "Top edge"
102msgid "Top edge"
103−msgstr ""
103+msgstr "Borda superior"
104
104
105#: Components/EdgeDemo.qml:136
105#: Components/EdgeDemo.qml:136
106msgid "Try swiping from the top edge to access the indicators"
106msgid "Try swiping from the top edge to access the indicators"
107−msgstr ""
107+msgstr "Tente deslizar da borda superior para acessar os indicadores"
108
108
109#: Components/EdgeDemo.qml:161
109#: Components/EdgeDemo.qml:161
110msgid "Close"
110msgid "Close"
111−msgstr ""
111+msgstr "Fechar"
112
112
113#: Components/EdgeDemo.qml:162
113#: Components/EdgeDemo.qml:162
114msgid "Swipe up again to close the settings screen"
114msgid "Swipe up again to close the settings screen"
115−msgstr ""
115+msgstr "Deslize novamente para cima para fechar a tela de configurações"
116
116
117#: Components/EdgeDemo.qml:189
117#: Components/EdgeDemo.qml:189
118msgid "Left edge"
118msgid "Left edge"
119−msgstr ""
119+msgstr "Borda esquerda"
120
120
121#: Components/EdgeDemo.qml:190
121#: Components/EdgeDemo.qml:190
122msgid "Swipe from the left to reveal the launcher for quick access to apps"
122msgid "Swipe from the left to reveal the launcher for quick access to apps"
123msgstr ""
123msgstr ""
124+"Deslize da esquerda para revelar o lançador para acesso rápido aos "
125+"aplicativos"
124
126
125#: Components/EdgeDemo.qml:217
127#: Components/EdgeDemo.qml:217
126msgid "Well done"
128msgid "Well done"
@@ -138,47 +140,47 @@ msgstr "Pesquisas recentes"
138#: Dash/Apps/AppInfo.qml:73
140#: Dash/Apps/AppInfo.qml:73
139#, qt-format
141#, qt-format
140msgid "(%1)"
142msgid "(%1)"
141−msgstr ""
143+msgstr "(%1)"
142
144
143#. TRANSLATORS: Number of persons who wrote reviews for this app
145#. TRANSLATORS: Number of persons who wrote reviews for this app
144#: Dash/Apps/AppInfo.qml:85
146#: Dash/Apps/AppInfo.qml:85
145#, qt-format
147#, qt-format
146msgid "%1 review"
148msgid "%1 review"
147msgid_plural "%1 reviews"
149msgid_plural "%1 reviews"
148−msgstr[0] ""
150+msgstr[0] "%1 análise"
149−msgstr[1] ""
151+msgstr[1] "%1 análises"
150
152
151#: Dash/Apps/AppPreview.qml:175
153#: Dash/Apps/AppPreview.qml:175
152msgid "Rate this"
154msgid "Rate this"
153−msgstr ""
155+msgstr "Avaliar isto"
154
156
155#: Dash/Apps/AppReviews.qml:72
157#: Dash/Apps/AppReviews.qml:72
156msgid "Add a review"
158msgid "Add a review"
157−msgstr ""
159+msgstr "Adicionar uma análise"
158
160
159#: Dash/Apps/AppReviews.qml:84
161#: Dash/Apps/AppReviews.qml:84
160msgid "Review"
162msgid "Review"
161−msgstr ""
163+msgstr "Revisão"
162
164
163#: Dash/Apps/AppReviews.qml:118
165#: Dash/Apps/AppReviews.qml:118
164msgid "Send"
166msgid "Send"
165−msgstr ""
167+msgstr "Enviar"
166
168
167#: Dash/Apps/AppReviews.qml:136
169#: Dash/Apps/AppReviews.qml:136
168msgid "Comments:"
170msgid "Comments:"
169−msgstr ""
171+msgstr "Comentários:"
170
172
171#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
173#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
172msgid "Featured"
174msgid "Featured"
173−msgstr ""
175+msgstr "Em destaque"
174
176
175#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
177#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
176msgid "Recent"
178msgid "Recent"
177−msgstr ""
179+msgstr "Recente"
178
180
179#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
181#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
180msgid "New Releases"
182msgid "New Releases"
181−msgstr ""
183+msgstr "Lançamentos"
182
184
183#: Dash/DashMusic.qml:30
185#: Dash/DashMusic.qml:30
184msgid "Top Charting"
186msgid "Top Charting"
@@ -198,28 +200,28 @@ msgstr "Vídeos"
198
200
199#: Dash/Video/VideoPreview.qml:130
201#: Dash/Video/VideoPreview.qml:130
200msgid "Directed by:"
202msgid "Directed by:"
201−msgstr ""
203+msgstr "Realizado por:"
202
204
203#: Dash/Video/VideoPreview.qml:153
205#: Dash/Video/VideoPreview.qml:153
204msgid "Starring:"
206msgid "Starring:"
205−msgstr ""
207+msgstr "Estrelando:"
206
208
207#: Dash/Video/VideoPreview.qml:176
209#: Dash/Video/VideoPreview.qml:176
208msgid "Author:"
210msgid "Author:"
209−msgstr ""
211+msgstr "Autor:"
210
212
211#: Greeter/Lockscreen.qml:134
213#: Greeter/Lockscreen.qml:134
212msgid "Emergency Call"
214msgid "Emergency Call"
213−msgstr ""
215+msgstr "Chamada de emergência"
214
216
215#: Greeter/PassphraseLockscreen.qml:59
217#: Greeter/PassphraseLockscreen.qml:59
216#, qt-format
218#, qt-format
217msgid "Hello %1"
219msgid "Hello %1"
218−msgstr ""
220+msgstr "Olá %1"
219
221
220#: Greeter/PassphraseLockscreen.qml:59
222#: Greeter/PassphraseLockscreen.qml:59
221msgid "Hello"
223msgid "Hello"
222−msgstr ""
224+msgstr "Olá"
223
225
224#: Hud/HudParametrizedActionsPage.qml:132
226#: Hud/HudParametrizedActionsPage.qml:132
225msgid "Confirm"
227msgid "Confirm"
@@ -252,10 +254,4 @@ msgstr "Desculpe, não há nada que corresponda à sua pesquisa."
252#: Shell.qml:429
254#: Shell.qml:429
253#, qt-format
255#, qt-format
254msgid "Please enter %1"
256msgid "Please enter %1"
255−msgstr ""
257+msgstr "Por favor, digite %1"
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 ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=3; plural=(n == 1 ? 0: (((n % 100 > 19) || ((n % 100 "
17"Plural-Forms: nplurals=3; plural=(n == 1 ? 0: (((n % 100 > 19) || ((n % 100 "
18"== 0) && (n != 0))) ? 2: 1));\n"
18"== 0) && (n != 0))) ? 2: 1));\n"
19−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
20+"X-Generator: Launchpad (build 16750)\n"
21
21
22#: Applications/applications.js:23
22#: Applications/applications.js:23
23msgid "Phone"
23msgid "Phone"
@@ -255,9 +255,3 @@ msgstr ""
255#, qt-format
255#, qt-format
256msgid "Please enter %1"
256msgid "Please enter %1"
257msgstr ""
257msgstr ""
258−
259−#~ msgid "Apps"
260−#~ msgstr "Aplicații"
261−
262−#~ msgid "Home"
263−#~ msgstr "Acasă"
po/ru.po+32−53
@@ -8,16 +8,16 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2013-08-27 13:36-0400\n"
10"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-06-28 06:40+0000\n"
11+"PO-Revision-Date: 2013-09-29 09:11+0000\n"
12−"Last-Translator: Eugene Marshal <Unknown>\n"
12+"Last-Translator: Устин <ustinershovskiy@yandex.ru>\n"
13"Language-Team: Russian <ru@li.org>\n"
13"Language-Team: Russian <ru@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
18"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
18"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19+"X-Launchpad-Export-Date: 2013-09-30 05:57+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
20+"X-Generator: Launchpad (build 16774)\n"
21
21
22#: Applications/applications.js:23
22#: Applications/applications.js:23
23msgid "Phone"
23msgid "Phone"
@@ -89,47 +89,54 @@ msgstr "YouTube"
89
89
90#: Components/EdgeDemoOverlay.qml:145
90#: Components/EdgeDemoOverlay.qml:145
91msgid "Skip intro"
91msgid "Skip intro"
92−msgstr ""
92+msgstr "Пропустить обучение"
93
93
94#: Components/EdgeDemo.qml:98
94#: Components/EdgeDemo.qml:98
95msgid "Right edge"
95msgid "Right edge"
96−msgstr ""
96+msgstr "Правый край"
97
97
98#: Components/EdgeDemo.qml:99
98#: Components/EdgeDemo.qml:99
99msgid "Try swiping from the right edge to unlock the phone"
99msgid "Try swiping from the right edge to unlock the phone"
100msgstr ""
100msgstr ""
101+"Попробуйте переместить палец от правого края к левому для разблокировки "
102+"устройства"
101
103
102#: Components/EdgeDemo.qml:135
104#: Components/EdgeDemo.qml:135
103msgid "Top edge"
105msgid "Top edge"
104−msgstr ""
106+msgstr "Верхний край"
105
107
106#: Components/EdgeDemo.qml:136
108#: Components/EdgeDemo.qml:136
107msgid "Try swiping from the top edge to access the indicators"
109msgid "Try swiping from the top edge to access the indicators"
108msgstr ""
110msgstr ""
111+"Попробуйте переместить палец от верхнего края вниз для доступа к индикаторам"
109
112
110#: Components/EdgeDemo.qml:161
113#: Components/EdgeDemo.qml:161
111msgid "Close"
114msgid "Close"
112−msgstr ""
115+msgstr "Закрыть"
113
116
114#: Components/EdgeDemo.qml:162
117#: Components/EdgeDemo.qml:162
115msgid "Swipe up again to close the settings screen"
118msgid "Swipe up again to close the settings screen"
116−msgstr ""
119+msgstr "Снова переместите палец вверх для закрытия экрана настроек"
117
120
118#: Components/EdgeDemo.qml:189
121#: Components/EdgeDemo.qml:189
119msgid "Left edge"
122msgid "Left edge"
120−msgstr ""
123+msgstr "Левый край"
121
124
122#: Components/EdgeDemo.qml:190
125#: Components/EdgeDemo.qml:190
123msgid "Swipe from the left to reveal the launcher for quick access to apps"
126msgid "Swipe from the left to reveal the launcher for quick access to apps"
124msgstr ""
127msgstr ""
128+"Переместите палец от левого края вправо для открытия лаунчера для быстрого "
129+"доступа к приложениям"
125
130
126#: Components/EdgeDemo.qml:217
131#: Components/EdgeDemo.qml:217
127msgid "Well done"
132msgid "Well done"
128−msgstr ""
133+msgstr "Великолепно"
129
134
130#: Components/EdgeDemo.qml:218
135#: Components/EdgeDemo.qml:218
131msgid "You have now mastered the edge gestures and can start using the phone"
136msgid "You have now mastered the edge gestures and can start using the phone"
132msgstr ""
137msgstr ""
138+"Теперь вы научились экранным жестам и можете приступить к использованию "
139+"устройства"
133
140
134#: Components/PageHeader.qml:298
141#: Components/PageHeader.qml:298
135msgid "Recent searches"
142msgid "Recent searches"
@@ -139,39 +146,38 @@ msgstr "Последние поисковые запросы"
139#: Dash/Apps/AppInfo.qml:73
146#: Dash/Apps/AppInfo.qml:73
140#, qt-format
147#, qt-format
141msgid "(%1)"
148msgid "(%1)"
142−msgstr ""
149+msgstr "(%1)"
143
150
144#. TRANSLATORS: Number of persons who wrote reviews for this app
151#. TRANSLATORS: Number of persons who wrote reviews for this app
145#: Dash/Apps/AppInfo.qml:85
152#: Dash/Apps/AppInfo.qml:85
146#, qt-format
153#, qt-format
147msgid "%1 review"
154msgid "%1 review"
148msgid_plural "%1 reviews"
155msgid_plural "%1 reviews"
149−msgstr[0] ""
156+msgstr[0] "%1 отзыв"
150−msgstr[1] ""
151
157
152#: Dash/Apps/AppPreview.qml:175
158#: Dash/Apps/AppPreview.qml:175
153msgid "Rate this"
159msgid "Rate this"
154−msgstr ""
160+msgstr "Оцените это"
155
161
156#: Dash/Apps/AppReviews.qml:72
162#: Dash/Apps/AppReviews.qml:72
157msgid "Add a review"
163msgid "Add a review"
158−msgstr ""
164+msgstr "Добавьте отзыв"
159
165
160#: Dash/Apps/AppReviews.qml:84
166#: Dash/Apps/AppReviews.qml:84
161msgid "Review"
167msgid "Review"
162−msgstr ""
168+msgstr "Отзыв"
163
169
164#: Dash/Apps/AppReviews.qml:118
170#: Dash/Apps/AppReviews.qml:118
165msgid "Send"
171msgid "Send"
166−msgstr ""
172+msgstr "Отправить"
167
173
168#: Dash/Apps/AppReviews.qml:136
174#: Dash/Apps/AppReviews.qml:136
169msgid "Comments:"
175msgid "Comments:"
170−msgstr ""
176+msgstr "Комментарии:"
171
177
172#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
178#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
173msgid "Featured"
179msgid "Featured"
174−msgstr ""
180+msgstr "Рекомендованное"
175
181
176#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
182#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
177msgid "Recent"
183msgid "Recent"
@@ -183,7 +189,7 @@ msgstr "Новые релизы"
183
189
184#: Dash/DashMusic.qml:30
190#: Dash/DashMusic.qml:30
185msgid "Top Charting"
191msgid "Top Charting"
186−msgstr ""
192+msgstr "Наиболее популярное"
187
193
188#: Dash/DashMusic.qml:91
194#: Dash/DashMusic.qml:91
189msgid "Music"
195msgid "Music"
@@ -191,7 +197,7 @@ msgstr "Музыка"
191
197
192#: Dash/DashVideos.qml:31
198#: Dash/DashVideos.qml:31
193msgid "Popular Online"
199msgid "Popular Online"
194−msgstr ""
200+msgstr "Популярное в Интернете"
195
201
196#: Dash/DashVideos.qml:146
202#: Dash/DashVideos.qml:146
197msgid "Videos"
203msgid "Videos"
@@ -211,20 +217,20 @@ msgstr "Автор:"
211
217
212#: Greeter/Lockscreen.qml:134
218#: Greeter/Lockscreen.qml:134
213msgid "Emergency Call"
219msgid "Emergency Call"
214−msgstr ""
220+msgstr "Экстренный вызов"
215
221
216#: Greeter/PassphraseLockscreen.qml:59
222#: Greeter/PassphraseLockscreen.qml:59
217#, qt-format
223#, qt-format
218msgid "Hello %1"
224msgid "Hello %1"
219−msgstr ""
225+msgstr "Привет, %1"
220
226
221#: Greeter/PassphraseLockscreen.qml:59
227#: Greeter/PassphraseLockscreen.qml:59
222msgid "Hello"
228msgid "Hello"
223−msgstr ""
229+msgstr "Привет"
224
230
225#: Hud/HudParametrizedActionsPage.qml:132
231#: Hud/HudParametrizedActionsPage.qml:132
226msgid "Confirm"
232msgid "Confirm"
227−msgstr "Подвердить"
233+msgstr "Подтвердить"
228
234
229#: Hud/Hud.qml:61 Hud/Hud.qml:99 Hud/Hud.qml:372
235#: Hud/Hud.qml:61 Hud/Hud.qml:99 Hud/Hud.qml:372
230msgid "Type or say a command"
236msgid "Type or say a command"
@@ -254,30 +260,3 @@ msgstr "Извините, поиск не дал результатов."
254#, qt-format
260#, qt-format
255msgid "Please enter %1"
261msgid "Please enter %1"
256msgstr "Пожалуйста, введите %1"
262msgstr "Пожалуйста, введите %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 ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16750)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
po/sl.po+32−48
@@ -8,7 +8,7 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2013-08-27 13:36-0400\n"
10"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-07-02 12:59+0000\n"
11+"PO-Revision-Date: 2013-09-28 09:53+0000\n"
12"Last-Translator: Damir Jerovšek <Unknown>\n"
12"Last-Translator: Damir Jerovšek <Unknown>\n"
13"Language-Team: Slovenian <sl@li.org>\n"
13"Language-Team: Slovenian <sl@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
@@ -16,8 +16,8 @@ msgstr ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || "
17"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || "
18"n%100==4 ? 3 : 0);\n"
18"n%100==4 ? 3 : 0);\n"
19−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19+"X-Launchpad-Export-Date: 2013-09-29 06:18+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
20+"X-Generator: Launchpad (build 16774)\n"
21
21
22#: Applications/applications.js:23
22#: Applications/applications.js:23
23msgid "Phone"
23msgid "Phone"
@@ -25,7 +25,7 @@ msgstr "Telefon"
25
25
26#: Applications/applications.js:29
26#: Applications/applications.js:29
27msgid "Camera"
27msgid "Camera"
28−msgstr ""
28+msgstr "Fotoaparat"
29
29
30#: Applications/applications.js:35
30#: Applications/applications.js:35
31msgid "Gallery"
31msgid "Gallery"
@@ -89,47 +89,50 @@ msgstr "YouTube"
89
89
90#: Components/EdgeDemoOverlay.qml:145
90#: Components/EdgeDemoOverlay.qml:145
91msgid "Skip intro"
91msgid "Skip intro"
92−msgstr ""
92+msgstr "Preskoči uvod"
93
93
94#: Components/EdgeDemo.qml:98
94#: Components/EdgeDemo.qml:98
95msgid "Right edge"
95msgid "Right edge"
96−msgstr ""
96+msgstr "Desni rob"
97
97
98#: Components/EdgeDemo.qml:99
98#: Components/EdgeDemo.qml:99
99msgid "Try swiping from the right edge to unlock the phone"
99msgid "Try swiping from the right edge to unlock the phone"
100−msgstr ""
100+msgstr "Poskusite povleči od desnega roba za odklep telefona"
101
101
102#: Components/EdgeDemo.qml:135
102#: Components/EdgeDemo.qml:135
103msgid "Top edge"
103msgid "Top edge"
104−msgstr ""
104+msgstr "Zgornji rob"
105
105
106#: Components/EdgeDemo.qml:136
106#: Components/EdgeDemo.qml:136
107msgid "Try swiping from the top edge to access the indicators"
107msgid "Try swiping from the top edge to access the indicators"
108−msgstr ""
108+msgstr "Poskusite povleči od zgornjega roba za dostop do kazalnikov"
109
109
110#: Components/EdgeDemo.qml:161
110#: Components/EdgeDemo.qml:161
111msgid "Close"
111msgid "Close"
112−msgstr ""
112+msgstr "Zapri"
113
113
114#: Components/EdgeDemo.qml:162
114#: Components/EdgeDemo.qml:162
115msgid "Swipe up again to close the settings screen"
115msgid "Swipe up again to close the settings screen"
116−msgstr ""
116+msgstr "Povlecite ponovno navzgor za zaprtje zaslona z nastavitvami"
117
117
118#: Components/EdgeDemo.qml:189
118#: Components/EdgeDemo.qml:189
119msgid "Left edge"
119msgid "Left edge"
120−msgstr ""
120+msgstr "Levi rob"
121
121
122#: Components/EdgeDemo.qml:190
122#: Components/EdgeDemo.qml:190
123msgid "Swipe from the left to reveal the launcher for quick access to apps"
123msgid "Swipe from the left to reveal the launcher for quick access to apps"
124msgstr ""
124msgstr ""
125+"Poskusite povleči od leve za razkritje zaganjalnika za hiter dostop do "
126+"programov"
125
127
126#: Components/EdgeDemo.qml:217
128#: Components/EdgeDemo.qml:217
127msgid "Well done"
129msgid "Well done"
128−msgstr ""
130+msgstr "Odlično"
129
131
130#: Components/EdgeDemo.qml:218
132#: Components/EdgeDemo.qml:218
131msgid "You have now mastered the edge gestures and can start using the phone"
133msgid "You have now mastered the edge gestures and can start using the phone"
132msgstr ""
134msgstr ""
135+"Zdaj, ko ste osvojili kretnje z robovi, lahko začnete uporabljati telefon"
133
136
134#: Components/PageHeader.qml:298
137#: Components/PageHeader.qml:298
135msgid "Recent searches"
138msgid "Recent searches"
@@ -139,35 +142,37 @@ msgstr "Nedavna iskanja"
139#: Dash/Apps/AppInfo.qml:73
142#: Dash/Apps/AppInfo.qml:73
140#, qt-format
143#, qt-format
141msgid "(%1)"
144msgid "(%1)"
142−msgstr ""
145+msgstr "(%1)"
143
146
144#. TRANSLATORS: Number of persons who wrote reviews for this app
147#. TRANSLATORS: Number of persons who wrote reviews for this app
145#: Dash/Apps/AppInfo.qml:85
148#: Dash/Apps/AppInfo.qml:85
146#, qt-format
149#, qt-format
147msgid "%1 review"
150msgid "%1 review"
148msgid_plural "%1 reviews"
151msgid_plural "%1 reviews"
149−msgstr[0] ""
152+msgstr[0] "%1 ocen"
153+msgstr[1] "%1 ocena"
150−msgstr[1] ""
154+msgstr[2] "%1 oceni"
155+msgstr[3] "%1 ocene"
151
156
152#: Dash/Apps/AppPreview.qml:175
157#: Dash/Apps/AppPreview.qml:175
153msgid "Rate this"
158msgid "Rate this"
154−msgstr ""
159+msgstr "Ocenite"
155
160
156#: Dash/Apps/AppReviews.qml:72
161#: Dash/Apps/AppReviews.qml:72
157msgid "Add a review"
162msgid "Add a review"
158−msgstr ""
163+msgstr "Dodaj oceno"
159
164
160#: Dash/Apps/AppReviews.qml:84
165#: Dash/Apps/AppReviews.qml:84
161msgid "Review"
166msgid "Review"
162−msgstr ""
167+msgstr "Ocena"
163
168
164#: Dash/Apps/AppReviews.qml:118
169#: Dash/Apps/AppReviews.qml:118
165msgid "Send"
170msgid "Send"
166−msgstr ""
171+msgstr "Pošlji"
167
172
168#: Dash/Apps/AppReviews.qml:136
173#: Dash/Apps/AppReviews.qml:136
169msgid "Comments:"
174msgid "Comments:"
170−msgstr ""
175+msgstr "Opombe:"
171
176
172#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
177#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
173msgid "Featured"
178msgid "Featured"
@@ -199,19 +204,19 @@ msgstr "Videi"
199
204
200#: Dash/Video/VideoPreview.qml:130
205#: Dash/Video/VideoPreview.qml:130
201msgid "Directed by:"
206msgid "Directed by:"
202−msgstr ""
207+msgstr "Režija:"
203
208
204#: Dash/Video/VideoPreview.qml:153
209#: Dash/Video/VideoPreview.qml:153
205msgid "Starring:"
210msgid "Starring:"
206−msgstr ""
211+msgstr "Igrajo:"
207
212
208#: Dash/Video/VideoPreview.qml:176
213#: Dash/Video/VideoPreview.qml:176
209msgid "Author:"
214msgid "Author:"
210−msgstr ""
215+msgstr "Avtor:"
211
216
212#: Greeter/Lockscreen.qml:134
217#: Greeter/Lockscreen.qml:134
213msgid "Emergency Call"
218msgid "Emergency Call"
214−msgstr ""
219+msgstr "Klic v sili"
215
220
216#: Greeter/PassphraseLockscreen.qml:59
221#: Greeter/PassphraseLockscreen.qml:59
217#, qt-format
222#, qt-format
@@ -220,7 +225,7 @@ msgstr "Pozdravljeni, %1"
220
225
221#: Greeter/PassphraseLockscreen.qml:59
226#: Greeter/PassphraseLockscreen.qml:59
222msgid "Hello"
227msgid "Hello"
223−msgstr ""
228+msgstr "Pozdravljeni"
224
229
225#: Hud/HudParametrizedActionsPage.qml:132
230#: Hud/HudParametrizedActionsPage.qml:132
226msgid "Confirm"
231msgid "Confirm"
@@ -253,25 +258,4 @@ msgstr "Nič se ne ujema z vašim iskalnim nizom."
253#: Shell.qml:429
258#: Shell.qml:429
254#, qt-format
259#, qt-format
255msgid "Please enter %1"
260msgid "Please enter %1"
256−msgstr ""
261+msgstr "Vnesite %1"
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 ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
18"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
18"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
20+"X-Generator: Launchpad (build 16750)\n"
21
21
22#: Applications/applications.js:23
22#: Applications/applications.js:23
23msgid "Phone"
23msgid "Phone"
@@ -254,9 +254,3 @@ msgstr "Нажалост, претрага није наишла на икакв
254#, qt-format
254#, qt-format
255msgid "Please enter %1"
255msgid "Please enter %1"
256msgstr ""
256msgstr ""
257−
258−#~ msgid "Apps"
259−#~ msgstr "Програми"
260−
261−#~ msgid "Home"
262−#~ msgstr "Почетна"
po/sv.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16750)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
po/te.po+2−5
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16750)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -253,6 +253,3 @@ msgstr ""
253#, qt-format
253#, qt-format
254msgid "Please enter %1"
254msgid "Please enter %1"
255msgstr ""
255msgstr ""
256−
257−#~ msgid "Home"
258−#~ msgstr "నివాసం"
po/tr.po+2−29
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16750)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -253,30 +253,3 @@ msgstr "Üzgünüz, aramanızla eşleşen hiçbir şey yok."
253#, qt-format
253#, qt-format
254msgid "Please enter %1"
254msgid "Please enter %1"
255msgstr ""
255msgstr ""
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 ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16750)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -253,30 +253,3 @@ msgstr "كەچۈرۈڭ، ئىزدىگىنىڭىزگە ماس نەتىجە تېپ
253#, qt-format
253#, qt-format
254msgid "Please enter %1"
254msgid "Please enter %1"
255msgstr ""
255msgstr ""
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+26−48
@@ -8,16 +8,16 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2013-08-27 13:36-0400\n"
10"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-07-21 05:47+0000\n"
11+"PO-Revision-Date: 2013-09-28 07:54+0000\n"
12−"Last-Translator: Ярослав Смук <Smuk.Slavko@yandex.ua>\n"
12+"Last-Translator: Yuri Chornoivan <yurchor@gmail.com>\n"
13"Language-Team: Ukrainian <uk@li.org>\n"
13"Language-Team: Ukrainian <uk@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
17"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
18"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
18"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
19+"X-Launchpad-Export-Date: 2013-09-29 06:18+0000\n"
20−"X-Generator: Launchpad (build 16738)\n"
20+"X-Generator: Launchpad (build 16774)\n"
21
21
22#: Applications/applications.js:23
22#: Applications/applications.js:23
23msgid "Phone"
23msgid "Phone"
@@ -89,47 +89,51 @@ msgstr "YouTube"
89
89
90#: Components/EdgeDemoOverlay.qml:145
90#: Components/EdgeDemoOverlay.qml:145
91msgid "Skip intro"
91msgid "Skip intro"
92−msgstr ""
92+msgstr "Пропустити вступ"
93
93
94#: Components/EdgeDemo.qml:98
94#: Components/EdgeDemo.qml:98
95msgid "Right edge"
95msgid "Right edge"
96−msgstr ""
96+msgstr "Правий край"
97
97
98#: Components/EdgeDemo.qml:99
98#: Components/EdgeDemo.qml:99
99msgid "Try swiping from the right edge to unlock the phone"
99msgid "Try swiping from the right edge to unlock the phone"
100−msgstr ""
100+msgstr "Спробуйте провести пальцем від правою краю, щоб розблокувати телефон"
101
101
102#: Components/EdgeDemo.qml:135
102#: Components/EdgeDemo.qml:135
103msgid "Top edge"
103msgid "Top edge"
104−msgstr ""
104+msgstr "Верхній край"
105
105
106#: Components/EdgeDemo.qml:136
106#: Components/EdgeDemo.qml:136
107msgid "Try swiping from the top edge to access the indicators"
107msgid "Try swiping from the top edge to access the indicators"
108msgstr ""
108msgstr ""
109+"Спробуйте провести пальцем від верхнього краю, щоб розблокувати телефон"
109
110
110#: Components/EdgeDemo.qml:161
111#: Components/EdgeDemo.qml:161
111msgid "Close"
112msgid "Close"
112−msgstr ""
113+msgstr "Закрити"
113
114
114#: Components/EdgeDemo.qml:162
115#: Components/EdgeDemo.qml:162
115msgid "Swipe up again to close the settings screen"
116msgid "Swipe up again to close the settings screen"
116−msgstr ""
117+msgstr "Проведіть пальцем ще раз, щоб закрити вікно параметрів"
117
118
118#: Components/EdgeDemo.qml:189
119#: Components/EdgeDemo.qml:189
119msgid "Left edge"
120msgid "Left edge"
120−msgstr ""
121+msgstr "Лівий край"
121
122
122#: Components/EdgeDemo.qml:190
123#: Components/EdgeDemo.qml:190
123msgid "Swipe from the left to reveal the launcher for quick access to apps"
124msgid "Swipe from the left to reveal the launcher for quick access to apps"
124msgstr ""
125msgstr ""
126+"Проведіть пальцем від лівого краю, щоб відкрити панель запуску для "
127+"пришвидшення доступу до програм"
125
128
126#: Components/EdgeDemo.qml:217
129#: Components/EdgeDemo.qml:217
127msgid "Well done"
130msgid "Well done"
128−msgstr ""
131+msgstr "Добре"
129
132
130#: Components/EdgeDemo.qml:218
133#: Components/EdgeDemo.qml:218
131msgid "You have now mastered the edge gestures and can start using the phone"
134msgid "You have now mastered the edge gestures and can start using the phone"
132msgstr ""
135msgstr ""
136+"Вами налаштовано жести від країв, ви можете почати користуватися телефоном"
133
137
134#: Components/PageHeader.qml:298
138#: Components/PageHeader.qml:298
135msgid "Recent searches"
139msgid "Recent searches"
@@ -139,35 +143,36 @@ msgstr "Нещодавні пошуки"
139#: Dash/Apps/AppInfo.qml:73
143#: Dash/Apps/AppInfo.qml:73
140#, qt-format
144#, qt-format
141msgid "(%1)"
145msgid "(%1)"
142−msgstr ""
146+msgstr "(%1)"
143
147
144#. TRANSLATORS: Number of persons who wrote reviews for this app
148#. TRANSLATORS: Number of persons who wrote reviews for this app
145#: Dash/Apps/AppInfo.qml:85
149#: Dash/Apps/AppInfo.qml:85
146#, qt-format
150#, qt-format
147msgid "%1 review"
151msgid "%1 review"
148msgid_plural "%1 reviews"
152msgid_plural "%1 reviews"
149−msgstr[0] ""
153+msgstr[0] "%1 рецензія"
150−msgstr[1] ""
154+msgstr[1] "%1 рецензії"
155+msgstr[2] "%1 рецензій"
151
156
152#: Dash/Apps/AppPreview.qml:175
157#: Dash/Apps/AppPreview.qml:175
153msgid "Rate this"
158msgid "Rate this"
154−msgstr ""
159+msgstr "Оцінити"
155
160
156#: Dash/Apps/AppReviews.qml:72
161#: Dash/Apps/AppReviews.qml:72
157msgid "Add a review"
162msgid "Add a review"
158−msgstr ""
163+msgstr "Додати рецензію"
159
164
160#: Dash/Apps/AppReviews.qml:84
165#: Dash/Apps/AppReviews.qml:84
161msgid "Review"
166msgid "Review"
162−msgstr ""
167+msgstr "Рецензія"
163
168
164#: Dash/Apps/AppReviews.qml:118
169#: Dash/Apps/AppReviews.qml:118
165msgid "Send"
170msgid "Send"
166−msgstr ""
171+msgstr "Надіслати"
167
172
168#: Dash/Apps/AppReviews.qml:136
173#: Dash/Apps/AppReviews.qml:136
169msgid "Comments:"
174msgid "Comments:"
170−msgstr ""
175+msgstr "Коментарі:"
171
176
172#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
177#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
173msgid "Featured"
178msgid "Featured"
@@ -211,7 +216,7 @@ msgstr "Автор:"
211
216
212#: Greeter/Lockscreen.qml:134
217#: Greeter/Lockscreen.qml:134
213msgid "Emergency Call"
218msgid "Emergency Call"
214−msgstr ""
219+msgstr "Терміновий виклик"
215
220
216#: Greeter/PassphraseLockscreen.qml:59
221#: Greeter/PassphraseLockscreen.qml:59
217#, qt-format
222#, qt-format
@@ -254,30 +259,3 @@ msgstr "Вибачте, для вказаних вами ключових слі
254#, qt-format
259#, qt-format
255msgid "Please enter %1"
260msgid "Please enter %1"
256msgstr "Будь ласка, введіть %1"
261msgstr "Будь ласка, введіть %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/xh.ponew file+255
@@ -0,0 +1,255 @@
1+# Xhosa translation for unity8
2+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
3+# This file is distributed under the same license as the unity8 package.
4+# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
5+#
6+msgid ""
7+msgstr ""
8+"Project-Id-Version: unity8\n"
9+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10+"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11+"PO-Revision-Date: 2013-09-28 13:20+0000\n"
12+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13+"Language-Team: Xhosa <xh@li.org>\n"
14+"MIME-Version: 1.0\n"
15+"Content-Type: text/plain; charset=UTF-8\n"
16+"Content-Transfer-Encoding: 8bit\n"
17+"Plural-Forms: nplurals=2; plural=n != 1;\n"
18+"X-Launchpad-Export-Date: 2013-09-29 06:18+0000\n"
19+"X-Generator: Launchpad (build 16774)\n"
20+
21+#: Applications/applications.js:23
22+msgid "Phone"
23+msgstr ""
24+
25+#: Applications/applications.js:29
26+msgid "Camera"
27+msgstr ""
28+
29+#: Applications/applications.js:35
30+msgid "Gallery"
31+msgstr ""
32+
33+#: Applications/applications.js:40
34+msgid "Facebook"
35+msgstr ""
36+
37+#: Applications/applications.js:46
38+msgid "Browser"
39+msgstr ""
40+
41+#: Applications/applications.js:51
42+msgid "Twitter"
43+msgstr ""
44+
45+#: Applications/applications.js:57
46+msgid "GMail"
47+msgstr ""
48+
49+#: Applications/applications.js:62
50+msgid "Weather"
51+msgstr ""
52+
53+#: Applications/applications.js:68
54+msgid "Notepad"
55+msgstr ""
56+
57+#: Applications/applications.js:74
58+msgid "Calendar"
59+msgstr ""
60+
61+#: Applications/applications.js:80
62+msgid "Media Player"
63+msgstr ""
64+
65+#: Applications/applications.js:86
66+msgid "Evernote"
67+msgstr ""
68+
69+#: Applications/applications.js:91
70+msgid "Map"
71+msgstr ""
72+
73+#: Applications/applications.js:96
74+msgid "Pinterest"
75+msgstr ""
76+
77+#: Applications/applications.js:101
78+msgid "SoundCloud"
79+msgstr ""
80+
81+#: Applications/applications.js:106
82+msgid "Wikipedia"
83+msgstr ""
84+
85+#: Applications/applications.js:111
86+msgid "YouTube"
87+msgstr ""
88+
89+#: Components/EdgeDemoOverlay.qml:145
90+msgid "Skip intro"
91+msgstr ""
92+
93+#: Components/EdgeDemo.qml:98
94+msgid "Right edge"
95+msgstr ""
96+
97+#: Components/EdgeDemo.qml:99
98+msgid "Try swiping from the right edge to unlock the phone"
99+msgstr ""
100+
101+#: Components/EdgeDemo.qml:135
102+msgid "Top edge"
103+msgstr ""
104+
105+#: Components/EdgeDemo.qml:136
106+msgid "Try swiping from the top edge to access the indicators"
107+msgstr ""
108+
109+#: Components/EdgeDemo.qml:161
110+msgid "Close"
111+msgstr ""
112+
113+#: Components/EdgeDemo.qml:162
114+msgid "Swipe up again to close the settings screen"
115+msgstr ""
116+
117+#: Components/EdgeDemo.qml:189
118+msgid "Left edge"
119+msgstr ""
120+
121+#: Components/EdgeDemo.qml:190
122+msgid "Swipe from the left to reveal the launcher for quick access to apps"
123+msgstr ""
124+
125+#: Components/EdgeDemo.qml:217
126+msgid "Well done"
127+msgstr ""
128+
129+#: Components/EdgeDemo.qml:218
130+msgid "You have now mastered the edge gestures and can start using the phone"
131+msgstr ""
132+
133+#: Components/PageHeader.qml:298
134+msgid "Recent searches"
135+msgstr ""
136+
137+#. TRANSLATORS: Number of persons who rated this app
138+#: Dash/Apps/AppInfo.qml:73
139+#, qt-format
140+msgid "(%1)"
141+msgstr ""
142+
143+#. TRANSLATORS: Number of persons who wrote reviews for this app
144+#: Dash/Apps/AppInfo.qml:85
145+#, qt-format
146+msgid "%1 review"
147+msgid_plural "%1 reviews"
148+msgstr[0] ""
149+msgstr[1] ""
150+
151+#: Dash/Apps/AppPreview.qml:175
152+msgid "Rate this"
153+msgstr ""
154+
155+#: Dash/Apps/AppReviews.qml:72
156+msgid "Add a review"
157+msgstr ""
158+
159+#: Dash/Apps/AppReviews.qml:84
160+msgid "Review"
161+msgstr ""
162+
163+#: Dash/Apps/AppReviews.qml:118
164+msgid "Send"
165+msgstr ""
166+
167+#: Dash/Apps/AppReviews.qml:136
168+msgid "Comments:"
169+msgstr ""
170+
171+#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
172+msgid "Featured"
173+msgstr ""
174+
175+#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
176+msgid "Recent"
177+msgstr ""
178+
179+#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
180+msgid "New Releases"
181+msgstr ""
182+
183+#: Dash/DashMusic.qml:30
184+msgid "Top Charting"
185+msgstr ""
186+
187+#: Dash/DashMusic.qml:91
188+msgid "Music"
189+msgstr ""
190+
191+#: Dash/DashVideos.qml:31
192+msgid "Popular Online"
193+msgstr ""
194+
195+#: Dash/DashVideos.qml:146
196+msgid "Videos"
197+msgstr ""
198+
199+#: Dash/Video/VideoPreview.qml:130
200+msgid "Directed by:"
201+msgstr ""
202+
203+#: Dash/Video/VideoPreview.qml:153
204+msgid "Starring:"
205+msgstr ""
206+
207+#: Dash/Video/VideoPreview.qml:176
208+msgid "Author:"
209+msgstr ""
210+
211+#: Greeter/Lockscreen.qml:134
212+msgid "Emergency Call"
213+msgstr ""
214+
215+#: Greeter/PassphraseLockscreen.qml:59
216+#, qt-format
217+msgid "Hello %1"
218+msgstr ""
219+
220+#: Greeter/PassphraseLockscreen.qml:59
221+msgid "Hello"
222+msgstr ""
223+
224+#: Hud/HudParametrizedActionsPage.qml:132
225+msgid "Confirm"
226+msgstr ""
227+
228+#: Hud/Hud.qml:61 Hud/Hud.qml:99 Hud/Hud.qml:372
229+msgid "Type or say a command"
230+msgstr ""
231+
232+#: Hud/Hud.qml:84
233+msgid "Loading. Please Wait..."
234+msgstr ""
235+
236+#: Hud/Hud.qml:89
237+msgid "Speak Now..."
238+msgstr ""
239+
240+#: Hud/Hud.qml:94
241+msgid "Speaking..."
242+msgstr ""
243+
244+#: Panel/SearchIndicator.qml:27
245+msgid "Search"
246+msgstr ""
247+
248+#: plugins/Unity/scope.cpp:317
249+msgid "Sorry, there is nothing that matches your search."
250+msgstr ""
251+
252+#: Shell.qml:429
253+#, qt-format
254+msgid "Please enter %1"
255+msgstr ""
po/zh_CN.po+2−29
@@ -15,8 +15,8 @@ msgstr ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16750)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -253,30 +253,3 @@ msgstr "对不起,没有找到您想要的结果。"
253#, qt-format
253#, qt-format
254msgid "Please enter %1"
254msgid "Please enter %1"
255msgstr ""
255msgstr ""
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 ""
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-29 05:41+0000\n"
18+"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19−"X-Generator: Launchpad (build 16738)\n"
19+"X-Generator: Launchpad (build 16750)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -253,30 +253,3 @@ msgstr "很抱歉,找不到符合您想搜尋的結果。"
253#, qt-format
253#, qt-format
254msgid "Please enter %1"
254msgid "Please enter %1"
255msgstr ""
255msgstr ""
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 "家屋"
run_on_device+2−1
@@ -65,8 +65,9 @@ setup_adb_forwarding() {
65}
65}
66
66
67install_dependencies() {
67install_dependencies() {
68+ exec_with_adb rm /etc/init/ssh.override
69+ exec_with_adb service ssh start
68 exec_with_adb apt-get update
70 exec_with_adb apt-get update
69− exec_with_adb apt-get -y install openssh-server
70 exec_with_ssh $SUDO apt-get -y install build-essential rsync bzr ccache gdb ninja-build devscripts equivs
71 exec_with_ssh $SUDO apt-get -y install build-essential rsync bzr ccache gdb ninja-build devscripts equivs
71}
72}
72
73
src/Panel/Indicators/CMakeLists.txt−1
@@ -1,2 +1 @@
1add_subdirectory(client)
1add_subdirectory(client)
2−add_subdirectory(servicefiles)
src/Panel/Indicators/servicefiles/CMakeLists.txtdeleted−14
@@ -1,14 +0,0 @@
1−file(GLOB INDICATOR_SERVICE_FILES
2− ${CMAKE_CURRENT_SOURCE_DIR}/com.canonical.indicator.messages
3−)
4−
5−# copy indicators files into build directory for shadow builds
6−add_custom_target(IndicatorsServiceFiles ALL
7− COMMAND mkdir -p ${CMAKE_BINARY_DIR}/share/unity/indicators
8− COMMAND cp ${INDICATOR_SERVICE_FILES} ${CMAKE_BINARY_DIR}/share/unity/indicators
9− DEPENDS ${INDICATOR_SERVICE_FILES}
10−)
11−
12−install(FILES ${INDICATOR_SERVICE_FILES}
13− DESTINATION ${SHELL_APP_DIR}/unity/indicators
14−)
src/Panel/Indicators/servicefiles/com.canonical.indicator.messagesdeleted−10
@@ -1,10 +0,0 @@
1−[Indicator Service]
2−Name=indicator-messages
3−ObjectPath=/com/canonical/indicator/messages
4−Position=50
5−
6−[phone]
7−ObjectPath=/com/canonical/indicator/messages/phone
8−
9−[desktop]
10−ObjectPath=/com/canonical/indicator/messages/menu
tests/autopilot/unity8/application_lifecycle/__init__.pynew file+20
@@ -0,0 +1,20 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2013 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
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+"""Tests for the application lifecycle base package."""
tests/autopilot/unity8/application_lifecycle/tests/__init__.pynew file

No changes to the content.

tests/autopilot/unity8/application_lifecycle/tests/test_application_lifecycle.pynew file+136
@@ -0,0 +1,136 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2013 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
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+"""Tests for the application lifecycle."""
21+
22+from __future__ import absolute_import
23+
24+from unity8.shell import disable_qml_mocking
25+from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
26+
27+from autopilot.matchers import Eventually
28+from autopilot.platform import model
29+from testtools.matchers import Equals, NotEquals
30+
31+import logging
32+
33+logger = logging.getLogger(__name__)
34+
35+
36+class ApplicationLifecycleTests(UnityTestCase):
37+
38+ scenarios = _get_device_emulation_scenarios()
39+
40+ def setUp(self):
41+ super(ApplicationLifecycleTests, self).setUp()
42+ if model() == "Desktop":
43+ self.skipTest("Test cannot be run on the desktop.")
44+
45+ def swipe_screen_from_right(self):
46+ qml_view = self.main_window.get_qml_view()
47+ width = qml_view.width
48+ height = qml_view.height
49+ start_x = width
50+ start_y = int(height/2)
51+ end_x = int(width/2)
52+ end_y = start_y
53+
54+ logger.info("Swiping screen from the right edge")
55+ self.touch.drag(start_x, start_y, end_x, end_y)
56+
57+ def _get_current_focused_app_id(self):
58+ return self._proxy.select_single("Shell").currentFocusedAppId
59+
60+ def _launch_app(self, app_name):
61+ """Launches the application *app_name*
62+
63+ Assumes that the desktop file resides at:
64+ /usr/share/applications/{app_name}.desktop
65+
66+ """
67+ desktop_file = "--desktop_file_hint="\
68+ "/usr/share/applications/{app_name}.desktop".format(
69+ app_name=app_name
70+ )
71+ return self.launch_test_application(
72+ app_name,
73+ desktop_file,
74+ "--stage_hint=main_stage",
75+ app_type='qt'
76+ )
77+
78+ @disable_qml_mocking
79+ def test_can_launch_application(self):
80+ """Must be able to launch an application."""
81+ self.launch_unity()
82+ self.main_window.get_greeter().swipe()
83+
84+ app = self._launch_app("messaging-app")
85+
86+ self.assertThat(app, NotEquals(None))
87+ self.assertThat(
88+ self._get_current_focused_app_id(),
89+ Eventually(Equals("messaging-app"))
90+ )
91+
92+ @disable_qml_mocking
93+ def test_can_launch_multiple_applications(self):
94+ """A second application launched must be focused."""
95+ self.launch_unity()
96+ self.main_window.get_greeter().swipe()
97+
98+ self._launch_app("messaging-app")
99+ self.assertThat(
100+ self._get_current_focused_app_id(),
101+ Eventually(Equals("messaging-app"))
102+ )
103+
104+ self._launch_app("address-book-app")
105+ self.assertThat(
106+ self._get_current_focused_app_id(),
107+ Eventually(Equals("address-book-app"))
108+ )
109+
110+ @disable_qml_mocking
111+ def test_app_moves_from_unfocused_to_focused(self):
112+ """An application that is in the unfocused state must be able to be
113+ brought back to the focused state.
114+
115+ """
116+ self.launch_unity()
117+ self.main_window.get_greeter().swipe()
118+
119+ self._launch_app("messaging-app")
120+ self.assertThat(
121+ self._get_current_focused_app_id(),
122+ Eventually(Equals("messaging-app"))
123+ )
124+
125+ self._launch_app("address-book-app")
126+ self.assertThat(
127+ self._get_current_focused_app_id(),
128+ Eventually(Equals("address-book-app"))
129+ )
130+
131+ self.swipe_screen_from_right()
132+
133+ self.assertThat(
134+ self._get_current_focused_app_id(),
135+ Eventually(Equals("messaging-app"))
136+ )
tests/autopilot/unity8/shell/__init__.py+10
@@ -36,3 +36,13 @@ def with_lightdm_mock(mock_type):
36 return fn(*args, **kwargs)
36 return fn(*args, **kwargs)
37 return wrapper
37 return wrapper
38 return with_lightdm_mock_internal
38 return with_lightdm_mock_internal
39+
40+
41+def disable_qml_mocking(fn):
42+ """Simple decorator that disables the QML mocks from being loaded."""
43+ @wraps(fn)
44+ def wrapper(*args, **kwargs):
45+ tests_self = args[0]
46+ tests_self._qml_mock_enabled = False
47+ return fn(*args, **kwargs)
48+ return wrapper
tests/autopilot/unity8/shell/tests/__init__.py+4−1
@@ -86,6 +86,7 @@ class UnityTestCase(AutopilotTestCase):
86
86
87 self._proxy = None
87 self._proxy = None
88 self._lightdm_mock_type = None
88 self._lightdm_mock_type = None
89+ self._qml_mock_enabled = True
89 self.touch = Touch.create()
90 self.touch = Touch.create()
90 self._setup_display_details()
91 self._setup_display_details()
91
92
@@ -160,7 +161,9 @@ class UnityTestCase(AutopilotTestCase):
160
161
161 if self._lightdm_mock_type is None:
162 if self._lightdm_mock_type is None:
162 self.patch_lightdm_mock()
163 self.patch_lightdm_mock()
164+
165+ if self._qml_mock_enabled:
163− self._setup_extra_mock_environment_patch()
166+ self._setup_extra_mock_environment_patch()
164
167
165 app_proxy = self.launch_test_application(
168 app_proxy = self.launch_test_application(
166 binary_path,
169 binary_path,
tests/autopilot/unity8/shell/tests/test_hud.py+7−2
@@ -34,6 +34,8 @@ class TestHud(UnityTestCase):
34
34
35 def test_show_hud_button_appears(self):
35 def test_show_hud_button_appears(self):
36 """Swiping up while an app is active must show the 'show hud' button.
36 """Swiping up while an app is active must show the 'show hud' button.
37+ The button must disappear not opening the HUD when releasing the
38+ mouse again somewhere on the screen except on the button itself.
37
39
38 """
40 """
39 self.launch_unity()
41 self.launch_unity()
@@ -49,9 +51,12 @@ class TestHud(UnityTestCase):
49 hud_show_button
51 hud_show_button
50 )
52 )
51 self.touch.press(swipe_coords.start_x, swipe_coords.start_y)
53 self.touch.press(swipe_coords.start_x, swipe_coords.start_y)
52− self.addCleanup(self.touch.release)
54+ self.addCleanup(self._maybe_release_finger)
53− self.touch._finger_move(swipe_coords.end_x, swipe_coords.end_y)
55+ self.touch._finger_move(swipe_coords.end_x, swipe_coords.end_y + hud_show_button.height);
54 self.assertThat(hud_show_button.opacity, Eventually(Equals(1.0)))
56 self.assertThat(hud_show_button.opacity, Eventually(Equals(1.0)))
57+ self.touch.release();
58+ self.assertThat(hud_show_button.opacity, Eventually(Equals(0.0)))
59+ self.assertThat(hud.shown, Equals(False))
55
60
56 def test_show_hud_appears(self):
61 def test_show_hud_appears(self):
57 """Releasing the touch on the 'show hud' button must display the hud.
62 """Releasing the touch on the 'show hud' button must display the hud.
tests/mocks/AccountsService/AccountsService.cpp+27−4
@@ -19,15 +19,38 @@
19#include "AccountsService.h"
19#include "AccountsService.h"
20
20
21AccountsService::AccountsService(QObject* parent)
21AccountsService::AccountsService(QObject* parent)
22− : QObject(parent)
22+ : QObject(parent),
23+ m_backgroundFile(TOP_SRCDIR "/graphics/phone_background.jpg")
23{
24{
24}
25}
25
26
26−QVariant AccountsService::getUserProperty(const QString &, const QString &)
27+QString AccountsService::user() const
27{
28{
28− return QVariant(false);
29+ return "testuser";
29}
30}
30
31
31−void AccountsService::setUserProperty(const QString &, const QString &, const QVariant &)
32+void AccountsService::setUser(const QString &user)
32{
33{
34+ Q_UNUSED(user)
35+}
36+
37+bool AccountsService::demoEdges() const
38+{
39+ return false;
40+}
41+
42+void AccountsService::setDemoEdges(bool demoEdges)
43+{
44+ Q_UNUSED(demoEdges)
45+}
46+
47+QString AccountsService::backgroundFile() const
48+{
49+ return m_backgroundFile;
50+}
51+
52+void AccountsService::setBackgroundFile(const QString &backgroundFile)
53+{
54+ m_backgroundFile = backgroundFile;
55+ backgroundFileChanged();
33}
56}
tests/mocks/AccountsService/AccountsService.h+27−3
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2012,2013 Canonical, Ltd.
2+ * Copyright (C) 2013 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -27,12 +27,36 @@
27class AccountsService: public QObject
27class AccountsService: public QObject
28{
28{
29 Q_OBJECT
29 Q_OBJECT
30+ Q_PROPERTY (QString user
31+ READ user
32+ WRITE setUser
33+ NOTIFY userChanged)
34+ Q_PROPERTY (bool demoEdges
35+ READ demoEdges
36+ WRITE setDemoEdges
37+ NOTIFY demoEdgesChanged)
38+ Q_PROPERTY (QString backgroundFile
39+ READ backgroundFile
40+ WRITE setBackgroundFile // only available in mock
41+ NOTIFY backgroundFileChanged)
30
42
31public:
43public:
32 explicit AccountsService(QObject *parent = 0);
44 explicit AccountsService(QObject *parent = 0);
33
45
34− Q_INVOKABLE QVariant getUserProperty(const QString &user, const QString &property);
46+ QString user() const;
35− Q_INVOKABLE void setUserProperty(const QString &user, const QString &property, const QVariant &value);
47+ void setUser(const QString &user);
48+ bool demoEdges() const;
49+ void setDemoEdges(bool demoEdges);
50+ QString backgroundFile() const;
51+ void setBackgroundFile(const QString &backgroundFile);
52+
53+Q_SIGNALS:
54+ void userChanged();
55+ void demoEdgesChanged();
56+ void backgroundFileChanged();
57+
58+private:
59+ QString m_backgroundFile;
36};
60};
37
61
38#endif
62#endif
tests/mocks/AccountsService/CMakeLists.txt+2
@@ -1,3 +1,5 @@
1+add_definitions(-DTOP_SRCDIR="${CMAKE_SOURCE_DIR}")
2+
1add_library(MockAccountsService-qml MODULE
3add_library(MockAccountsService-qml MODULE
2 AccountsService.cpp
4 AccountsService.cpp
3 plugin.cpp
5 plugin.cpp
tests/mocks/LightDM/demo/GreeterPrivate.cpp+4−2
@@ -55,11 +55,13 @@ void GreeterPrivate::handleRespond(const QString &response)
55 QSettings settings(QDir::homePath() + "/.unity8-greeter-demo", QSettings::NativeFormat);
55 QSettings settings(QDir::homePath() + "/.unity8-greeter-demo", QSettings::NativeFormat);
56 QVariant password = settings.value("password", "none");
56 QVariant password = settings.value("password", "none");
57
57
58+ QString passwordValue;
58 if (password == "pin") {
59 if (password == "pin") {
59− authenticated = (response == "1234");
60+ passwordValue = settings.value("passwordValue", "1234").toString();
60 } else {
61 } else {
61− authenticated = (response == "password");
62+ passwordValue = settings.value("passwordValue", "password").toString();
62 }
63 }
64+ authenticated = (response == passwordValue);
63 Q_EMIT q->authenticationComplete();
65 Q_EMIT q->authenticationComplete();
64}
66}
65
67
tests/mocks/Ubuntu/Application/CMakeLists.txtdeleted−29
@@ -1,29 +0,0 @@
1−set(FakeUbuntuApplicationQml_SOURCES
2− plugin.cpp
3− ApplicationInfo.cpp
4− ApplicationImage.cpp
5− ApplicationListModel.cpp
6− ApplicationManager.cpp
7−)
8−
9−add_library(FakeUbuntuApplicationQml MODULE ${FakeUbuntuApplicationQml_SOURCES})
10−
11−qt5_use_modules(FakeUbuntuApplicationQml Core Quick)
12−
13−# copy files into build directory for shadow builds
14−add_custom_target(UbuntuAppQmlDirFile ALL
15− COMMAND cp "${CMAKE_CURRENT_SOURCE_DIR}/qmldir" ${CMAKE_CURRENT_BINARY_DIR}
16− DEPENDS qmldir
17−)
18−add_custom_target(InputFilterAreaQmlFile ALL
19− COMMAND cp "${CMAKE_CURRENT_SOURCE_DIR}/InputFilterArea.qml" ${CMAKE_CURRENT_BINARY_DIR}
20− DEPENDS InputFilterArea.qml
21−)
22−
23−install(TARGETS FakeUbuntuApplicationQml
24− DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/mocks/Ubuntu/Application
25− )
26−
27−install(FILES qmldir InputFilterArea.qml
28− DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/mocks/Ubuntu/Application
29− )
tests/mocks/Ubuntu/Application/qmldirdeleted−3
@@ -1,3 +0,0 @@
1−module Ubuntu.Application
2−plugin FakeUbuntuApplicationQml
3−InputFilterArea 0.1 InputFilterArea.qml
tests/mocks/Ubuntu/CMakeLists.txt−1
@@ -1,2 +1 @@
1−add_subdirectory(Application)
2add_subdirectory(DownloadDaemonListener)
1add_subdirectory(DownloadDaemonListener)
tests/mocks/Ubuntu/DownloadDaemonListener/MockDownloadTracker.cpp+5
@@ -63,5 +63,10 @@ void MockDownloadTracker::startService()
63 if(!m_service.isEmpty() && !m_dbusPath.isEmpty()) {
63 if(!m_service.isEmpty() && !m_dbusPath.isEmpty()) {
64 m_active = true;
64 m_active = true;
65 Q_EMIT serviceReadyChanged(m_active);
65 Q_EMIT serviceReadyChanged(m_active);
66+ if(m_dbusPath == "finish") {
67+ Q_EMIT finished("downloadComplete");
68+ }else if(m_dbusPath == "error") {
69+ Q_EMIT error("DOWNLOAD ERROR");
70+ }
66 }
71 }
67}
72}
tests/mocks/Ubuntu/Application/ApplicationImage.cpp → tests/mocks/Unity/Application/ApplicationImage.cpprenamed

The content is the same.

tests/mocks/Ubuntu/Application/ApplicationImage.h → tests/mocks/Unity/Application/ApplicationImage.hrenamed

The content is the same.

tests/mocks/Ubuntu/Application/ApplicationInfo.cpp → tests/mocks/Unity/Application/ApplicationInfo.cpprenamed+15−2
@@ -21,11 +21,24 @@
21#include <QQuickView>
21#include <QQuickView>
22#include <QQmlComponent>
22#include <QQmlComponent>
23
23
24+ApplicationInfo::ApplicationInfo(const QString &appId, QObject *parent)
25+ : ApplicationInfoInterface(appId, parent)
26+ ,m_appId(appId)
27+ ,m_stage(MainStage)
28+ ,m_state(Starting)
29+ ,m_focused(false)
30+ ,m_fullscreen(false)
31+ ,m_windowItem(0)
32+ ,m_windowComponent(0)
33+ ,m_parentItem(0)
34+{
35+}
36+
24ApplicationInfo::ApplicationInfo(QObject *parent)
37ApplicationInfo::ApplicationInfo(QObject *parent)
25− : QObject(parent)
38+ : ApplicationInfoInterface(QString(), parent)
26− ,m_handle(0)
27 ,m_stage(MainStage)
39 ,m_stage(MainStage)
28 ,m_state(Starting)
40 ,m_state(Starting)
41+ ,m_focused(false)
29 ,m_fullscreen(false)
42 ,m_fullscreen(false)
30 ,m_windowItem(0)
43 ,m_windowItem(0)
31 ,m_windowComponent(0)
44 ,m_windowComponent(0)
tests/mocks/Ubuntu/Application/ApplicationInfo.h → tests/mocks/Unity/Application/ApplicationInfo.hrenamed+12−18
@@ -22,21 +22,18 @@
22
22
23class QQuickItem;
23class QQuickItem;
24
24
25+// unity-api
26+#include <unity/shell/application/ApplicationInfoInterface.h>
27+
25// A pretty dumb file. Just a container for properties.
28// A pretty dumb file. Just a container for properties.
26// Implemented in C++ instead of QML just because of the enumerations
29// Implemented in C++ instead of QML just because of the enumerations
27// See QTBUG-14861
30// See QTBUG-14861
31+
32+using namespace unity::shell::application;
33+
28−class ApplicationInfo : public QObject {
34+class ApplicationInfo : public ApplicationInfoInterface {
29 Q_OBJECT
35 Q_OBJECT
30− Q_ENUMS(Stage)
36+
31− Q_ENUMS(State)
32− Q_PROPERTY(QString desktopFile READ desktopFile WRITE setDesktopFile NOTIFY desktopFileChanged)
33− Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
34− Q_PROPERTY(QString comment READ comment WRITE setComment NOTIFY commentChanged)
35− Q_PROPERTY(QString icon READ icon WRITE setIcon NOTIFY iconChanged)
36− Q_PROPERTY(QString exec READ exec WRITE setExec NOTIFY execChanged)
37− Q_PROPERTY(qint64 handle READ handle WRITE setHandle NOTIFY handleChanged)
38− Q_PROPERTY(Stage stage READ stage WRITE setStage NOTIFY stageChanged)
39− Q_PROPERTY(State state READ state WRITE setState NOTIFY stateChanged)
40 Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged)
37 Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged)
41
38
42 // Only exists in this fake implementation
39 // Only exists in this fake implementation
@@ -48,10 +45,8 @@ class ApplicationInfo : public QObject {
48 Q_PROPERTY(QString windowQml READ windowQml WRITE setWindowQml NOTIFY windowQmlChanged)
45 Q_PROPERTY(QString windowQml READ windowQml WRITE setWindowQml NOTIFY windowQmlChanged)
49
46
50 public:
47 public:
51− enum Stage { MainStage, SideStage };
52− enum State { Starting, Running };
53−
54 ApplicationInfo(QObject *parent = NULL);
48 ApplicationInfo(QObject *parent = NULL);
49+ ApplicationInfo(const QString &appId, QObject *parent = NULL);
55
50
56 #define IMPLEMENT_PROPERTY(name, Name, type) \
51 #define IMPLEMENT_PROPERTY(name, Name, type) \
57 public: \
52 public: \
@@ -68,14 +63,13 @@ class ApplicationInfo : public QObject {
68 private: \
63 private: \
69 type m_##name;
64 type m_##name;
70
65
71− IMPLEMENT_PROPERTY(desktopFile, DesktopFile, QString)
66+ IMPLEMENT_PROPERTY(appId, AppId, QString)
72 IMPLEMENT_PROPERTY(name, Name, QString)
67 IMPLEMENT_PROPERTY(name, Name, QString)
73 IMPLEMENT_PROPERTY(comment, Comment, QString)
68 IMPLEMENT_PROPERTY(comment, Comment, QString)
74− IMPLEMENT_PROPERTY(icon, Icon, QString)
69+ IMPLEMENT_PROPERTY(icon, Icon, QUrl)
75− IMPLEMENT_PROPERTY(exec, Exec, QString)
76− IMPLEMENT_PROPERTY(handle, Handle, qint64)
77 IMPLEMENT_PROPERTY(stage, Stage, Stage)
70 IMPLEMENT_PROPERTY(stage, Stage, Stage)
78 IMPLEMENT_PROPERTY(state, State, State)
71 IMPLEMENT_PROPERTY(state, State, State)
72+ IMPLEMENT_PROPERTY(focused, Focused, bool)
79 IMPLEMENT_PROPERTY(fullscreen, Fullscreen, bool)
73 IMPLEMENT_PROPERTY(fullscreen, Fullscreen, bool)
80 IMPLEMENT_PROPERTY(imageQml, ImageQml, QString)
74 IMPLEMENT_PROPERTY(imageQml, ImageQml, QString)
81 IMPLEMENT_PROPERTY(windowQml, WindowQml, QString)
75 IMPLEMENT_PROPERTY(windowQml, WindowQml, QString)
tests/mocks/Ubuntu/Application/ApplicationListModel.cpp → tests/mocks/Unity/Application/ApplicationListModel.cpprenamed

The content is the same.

tests/mocks/Ubuntu/Application/ApplicationListModel.h → tests/mocks/Unity/Application/ApplicationListModel.hrenamed

The content is the same.

tests/mocks/Ubuntu/Application/ApplicationManager.cpp → tests/mocks/Unity/Application/ApplicationManager.cpprenamed+185−153
@@ -16,7 +16,6 @@
16
16
17#include "ApplicationManager.h"
17#include "ApplicationManager.h"
18#include "ApplicationInfo.h"
18#include "ApplicationInfo.h"
19−#include "ApplicationListModel.h"
20#include "paths.h"
19#include "paths.h"
21
20
22#include <QDir>
21#include <QDir>
@@ -26,11 +25,7 @@
26#include <QQmlComponent>
25#include <QQmlComponent>
27
26
28ApplicationManager::ApplicationManager(QObject *parent)
27ApplicationManager::ApplicationManager(QObject *parent)
29− : QObject(parent)
28+ : ApplicationManagerInterface(parent)
30− , m_mainStageApplications(new ApplicationListModel())
31− , m_sideStageApplications(new ApplicationListModel())
32− , m_mainStageFocusedApplication(0)
33− , m_sideStageFocusedApplication(0)
34 , m_mainStageComponent(0)
29 , m_mainStageComponent(0)
35 , m_mainStage(0)
30 , m_mainStage(0)
36 , m_sideStageComponent(0)
31 , m_sideStageComponent(0)
@@ -41,8 +36,84 @@ ApplicationManager::ApplicationManager(QObject *parent)
41
36
42ApplicationManager::~ApplicationManager()
37ApplicationManager::~ApplicationManager()
43{
38{
44− delete m_mainStageApplications;
39+}
45− delete m_sideStageApplications;
40+
41+int ApplicationManager::rowCount(const QModelIndex& parent) const {
42+ return !parent.isValid() ? m_runningApplications.size() : 0;
43+}
44+
45+QVariant ApplicationManager::data(const QModelIndex& index, int role) const {
46+ if (index.row() < 0 || index.row() >= m_runningApplications.size())
47+ return QVariant();
48+
49+ auto app = m_runningApplications.at(index.row());
50+ switch(role) {
51+ case RoleAppId:
52+ return app->appId();
53+ case RoleName:
54+ return app->name();
55+ case RoleComment:
56+ return app->comment();
57+ case RoleIcon:
58+ return app->icon();
59+ case RoleStage:
60+ return app->stage();
61+ case RoleState:
62+ return app->state();
63+ case RoleFocused:
64+ return app->focused();
65+ default:
66+ return QVariant();
67+ }
68+}
69+
70+ApplicationInfo *ApplicationManager::get(int row) const {
71+ if (row < 0 || row >= m_runningApplications.size())
72+ return nullptr;
73+ return m_runningApplications.at(row);
74+}
75+
76+ApplicationInfo *ApplicationManager::findApplication(const QString &appId) const {
77+ for (ApplicationInfo *app : m_runningApplications) {
78+ if (app->appId() == appId) {
79+ return app;
80+ }
81+ }
82+ return nullptr;
83+}
84+
85+void ApplicationManager::add(ApplicationInfo *application) {
86+ if (!application)
87+ return;
88+
89+ beginInsertRows(QModelIndex(), m_runningApplications.size(), m_runningApplications.size());
90+ m_runningApplications.append(application);
91+ endInsertRows();
92+ Q_EMIT countChanged();
93+}
94+
95+void ApplicationManager::remove(ApplicationInfo *application) {
96+ int i = m_runningApplications.indexOf(application);
97+ if (i != -1) {
98+ beginRemoveRows(QModelIndex(), i, i);
99+ m_runningApplications.removeAt(i);
100+ endRemoveRows();
101+ Q_EMIT countChanged();
102+ }
103+}
104+
105+void ApplicationManager::move(int from, int to) {
106+ if (from == to) return;
107+
108+ if (from >= 0 && from < m_runningApplications.size() && to >= 0 && to < m_runningApplications.size()) {
109+ QModelIndex parent;
110+ /* When moving an item down, the destination index needs to be incremented
111+ * by one, as explained in the documentation:
112+ * http://qt-project.org/doc/qt-5.0/qtcore/qabstractitemmodel.html#beginMoveRows */
113+ beginMoveRows(parent, from, from, parent, to + (to > from ? 1 : 0));
114+ m_runningApplications.move(from, to);
115+ endMoveRows();
116+ }
46}
117}
47
118
48int ApplicationManager::keyboardHeight() const
119int ApplicationManager::keyboardHeight() const
@@ -70,36 +141,21 @@ ApplicationManager::FormFactorHint ApplicationManager::formFactorHint() const
70 return PhoneFormFactor;
141 return PhoneFormFactor;
71}
142}
72
143
73−ApplicationListModel* ApplicationManager::mainStageApplications() const
144+ApplicationInfo* ApplicationManager::startApplication(const QString &appId,
74−{
145+ const QStringList &arguments)
75− return m_mainStageApplications;
76−}
77−
78−ApplicationListModel* ApplicationManager::sideStageApplications() const
79{
146{
80− return m_sideStageApplications;
147+ return startApplication(appId, NoFlag, arguments);
81}
148}
82
149
83−ApplicationInfo* ApplicationManager::mainStageFocusedApplication() const
150+ApplicationInfo* ApplicationManager::startApplication(const QString &appId,
84−{
85− return m_mainStageFocusedApplication;
86−}
87−
88−ApplicationInfo* ApplicationManager::sideStageFocusedApplication() const
89−{
90− return m_sideStageFocusedApplication;
91−}
92−
93−ApplicationInfo* ApplicationManager::startProcess(QString desktopFile,
94 ExecFlags flags,
151 ExecFlags flags,
95− QStringList arguments)
152+ const QStringList &arguments)
96{
153{
97 Q_UNUSED(arguments)
154 Q_UNUSED(arguments)
98 ApplicationInfo *application = 0;
155 ApplicationInfo *application = 0;
99
156
100− for (int i = 0; i < m_availableApplications.count(); ++i) {
101− ApplicationInfo *availableApp = m_availableApplications[i];
157+ for (ApplicationInfo *availableApp : m_availableApplications) {
102− if (availableApp->desktopFile() == desktopFile) {
158+ if (availableApp->appId() == appId) {
103 application = availableApp;
159 application = availableApp;
104 break;
160 break;
105 }
161 }
@@ -109,86 +165,91 @@ ApplicationInfo* ApplicationManager::startProcess(QString desktopFile,
109 return 0;
165 return 0;
110
166
111 if (flags.testFlag(ApplicationManager::ForceMainStage)
167 if (flags.testFlag(ApplicationManager::ForceMainStage)
112− || application->stage() == ApplicationInfo::MainStage) {
168+ && application->stage() == ApplicationInfo::SideStage) {
113− m_mainStageApplications->add(application);
169+ application->setStage(ApplicationInfo::MainStage);
114− } else {
115− m_sideStageApplications->add(application);
116 }
170 }
171+ add(application);
117
172
118 return application;
173 return application;
119}
174}
120
175
121−void ApplicationManager::stopProcess(ApplicationInfo* application)
176+bool ApplicationManager::stopApplication(const QString &appId)
122{
177{
178+ ApplicationInfo *application = findApplication(appId);
123− if (m_mainStageApplications->contains(application)) {
179+ if (application == nullptr)
124− m_mainStageApplications->remove(application);
180+ return false;
125
181
126− if (m_mainStageFocusedApplication == application) {
182+ remove(application);
127− m_mainStageFocusedApplication = 0;
183+ Q_EMIT focusedApplicationIdChanged();
128− Q_EMIT mainStageFocusedApplicationChanged();
184+ return true;
129− }
185+}
130− } else if (m_sideStageApplications->contains(application)){
131− m_sideStageApplications->remove(application);
132
186
133− if (m_sideStageFocusedApplication == application) {
187+QString ApplicationManager::focusedApplicationId() const {
134− m_sideStageFocusedApplication = 0;
188+ for (ApplicationInfo *app : m_runningApplications) {
135− Q_EMIT sideStageFocusedApplicationChanged();
189+ if (app->focused()) {
190+ return app->appId();
136 }
191 }
137 }
192 }
193+ return QString();
138}
194}
139
195
140−void ApplicationManager::focusApplication(int handle)
196+bool ApplicationManager::focusApplication(const QString &appId)
141{
197{
142− for (int i = 0; i < m_mainStageApplications->m_applications.count(); ++i) {
198+ ApplicationInfo *application = findApplication(appId);
143− ApplicationInfo *application = m_mainStageApplications->m_applications[i];
199+ if (application == nullptr)
144− if (application->handle() == handle) {
200+ return false;
145− if (m_mainStageFocusedApplication)
201+
146− m_mainStageFocusedApplication->hideWindow();
202+ if (application->stage() == ApplicationInfo::MainStage) {
147− m_mainStageFocusedApplication = application;
203+ // unfocus currently focused mainstage app
148− if (!m_mainStage)
204+ for (ApplicationInfo *app : m_runningApplications) {
149− createMainStage();
205+ if (app->focused() && app->stage() == ApplicationInfo::MainStage) {
150− application->showWindow(m_mainStage);
206+ app->setFocused(false);
151− m_mainStage->setZ(-1000);
207+ app->hideWindow();
152− if (m_sideStage)
208+ }
153− m_sideStage->setZ(-2000);
154− Q_EMIT mainStageFocusedApplicationChanged();
155− return;
156 }
209 }
157− }
158
210
159− for (int i = 0; i < m_sideStageApplications->m_applications.count(); ++i) {
211+ // focus this app
160− ApplicationInfo *application = m_sideStageApplications->m_applications[i];
212+ application->setFocused(true);
161− if (application->handle() == handle) {
213+ if (!m_mainStage)
162− if (m_sideStageFocusedApplication)
214+ createMainStage();
163− m_sideStageFocusedApplication->hideWindow();
215+ application->showWindow(m_mainStage);
164− m_sideStageFocusedApplication = application;
216+ m_mainStage->setZ(-1000);
165− if (!m_sideStage)
217+ if (m_sideStage)
166− createSideStage();
218+ m_sideStage->setZ(-2000);
167− application->showWindow(m_sideStage);
219+ } else if (application->stage() == ApplicationInfo::SideStage) {
168− m_sideStage->setZ(-1000);
220+ // unfocus currently focused sidestage app
169− if (m_mainStage)
221+ for (ApplicationInfo *app : m_runningApplications) {
170− m_mainStage->setZ(-2000);
222+ if (app->focused() && app->stage() == ApplicationInfo::SideStage) {
171− Q_EMIT sideStageFocusedApplicationChanged();
223+ app->setFocused(false);
172− return;
224+ app->hideWindow();
225+ }
173 }
226 }
227+
228+ // focus this app
229+ application->setFocused(true);
230+ if (!m_sideStage)
231+ createSideStage();
232+ application->showWindow(m_sideStage);
233+ m_sideStage->setZ(-1000);
234+ if (m_mainStage)
235+ m_mainStage->setZ(-2000);
174 }
236 }
237+
238+ // move app to top of stack
239+ move(m_runningApplications.indexOf(application), 0);
240+ Q_EMIT focusedApplicationIdChanged();
241+ return true;
175}
242}
176
243
177−void ApplicationManager::unfocusCurrentApplication(StageHint stageHint)
244+void ApplicationManager::unfocusCurrentApplication()
178{
245{
179− if (stageHint == SideStage) {
246+ for (ApplicationInfo *app : m_runningApplications) {
180− if (m_sideStageFocusedApplication) {
247+ if (app->focused()) {
181− m_sideStageFocusedApplication->hideWindow();
248+ app->hideWindow();
182− m_sideStageFocusedApplication = 0;
249+ app->setFocused(false);
183− Q_EMIT sideStageFocusedApplicationChanged();
184− }
185− } else {
186− if (m_mainStageFocusedApplication) {
187− m_mainStageFocusedApplication->hideWindow();
188− m_mainStageFocusedApplication = 0;
189− Q_EMIT mainStageFocusedApplicationChanged();
190 }
250 }
191 }
251 }
252+ Q_EMIT focusedApplicationIdChanged();
192}
253}
193
254
194void ApplicationManager::generateQmlStrings(ApplicationInfo *application)
255void ApplicationManager::generateQmlStrings(ApplicationInfo *application)
@@ -213,7 +274,7 @@ void ApplicationManager::generateQmlStrings(ApplicationInfo *application)
213 " fillMode: Image.PreserveAspectCrop\n"
274 " fillMode: Image.PreserveAspectCrop\n"
214 "}").arg(topMargin)
275 "}").arg(topMargin)
215 .arg(shellAppDirectory())
276 .arg(shellAppDirectory())
216− .arg(application->icon());
277+ .arg(application->icon().toString());
217 application->setWindowQml(windowQml);
278 application->setWindowQml(windowQml);
218
279
219 QString imageQml = QString(
280 QString imageQml = QString(
@@ -224,159 +285,130 @@ void ApplicationManager::generateQmlStrings(ApplicationInfo *application)
224 " smooth: true\n"
285 " smooth: true\n"
225 " fillMode: Image.PreserveAspectCrop\n"
286 " fillMode: Image.PreserveAspectCrop\n"
226 "}").arg(shellAppDirectory())
287 "}").arg(shellAppDirectory())
227− .arg(application->icon());
288+ .arg(application->icon().toString());
228 application->setImageQml(imageQml);
289 application->setImageQml(imageQml);
229}
290}
230
291
231void ApplicationManager::buildListOfAvailableApplications()
292void ApplicationManager::buildListOfAvailableApplications()
232{
293{
233 ApplicationInfo *application;
294 ApplicationInfo *application;
234− qint64 nextHandle = 1;
235
295
236 application = new ApplicationInfo(this);
296 application = new ApplicationInfo(this);
237− application->setDesktopFile("/usr/share/applications/phone-app.desktop");
297+ application->setAppId("phone-app");
238 application->setName("Phone");
298 application->setName("Phone");
239− application->setIcon("phone");
299+ application->setIcon(QUrl("phone"));
240− application->setExec("/usr/bin/phone-app");
241 application->setStage(ApplicationInfo::SideStage);
300 application->setStage(ApplicationInfo::SideStage);
242− application->setHandle(nextHandle++);
243 generateQmlStrings(application);
301 generateQmlStrings(application);
244 m_availableApplications.append(application);
302 m_availableApplications.append(application);
245
303
246 application = new ApplicationInfo(this);
304 application = new ApplicationInfo(this);
247− application->setDesktopFile("/usr/share/applications/camera-app.desktop");
305+ application->setAppId("camera-app");
248 application->setName("Camera");
306 application->setName("Camera");
249− application->setIcon("camera");
307+ application->setIcon(QUrl("camera"));
250 application->setFullscreen(true);
308 application->setFullscreen(true);
251− application->setExec("/usr/bin/camera-app --fullscreen");
252− application->setHandle(nextHandle++);
253 generateQmlStrings(application);
309 generateQmlStrings(application);
254 m_availableApplications.append(application);
310 m_availableApplications.append(application);
255
311
256 application = new ApplicationInfo(this);
312 application = new ApplicationInfo(this);
257− application->setDesktopFile("/usr/share/applications/gallery-app.desktop");
313+ application->setAppId("gallery-app");
258 application->setName("Gallery");
314 application->setName("Gallery");
259− application->setIcon("gallery");
315+ application->setIcon(QUrl("gallery"));
260− application->setExec("/usr/bin/gallery-app");
261− application->setHandle(nextHandle++);
262 generateQmlStrings(application);
316 generateQmlStrings(application);
263 m_availableApplications.append(application);
317 m_availableApplications.append(application);
264
318
265 application = new ApplicationInfo(this);
319 application = new ApplicationInfo(this);
266− application->setDesktopFile("/usr/share/applications/facebook-webapp.desktop");
320+ application->setAppId("facebook-webapp");
267 application->setName("Facebook");
321 application->setName("Facebook");
268− application->setIcon("facebook");
322+ application->setIcon(QUrl("facebook"));
269− application->setExec("/usr/bin/webbrowser-app --chromeless http://m.facebook.com");
270 application->setStage(ApplicationInfo::SideStage);
323 application->setStage(ApplicationInfo::SideStage);
271− application->setHandle(nextHandle++);
272 generateQmlStrings(application);
324 generateQmlStrings(application);
273 m_availableApplications.append(application);
325 m_availableApplications.append(application);
274
326
275 application = new ApplicationInfo(this);
327 application = new ApplicationInfo(this);
276− application->setDesktopFile("/usr/share/applications/webbrowser-app.desktop");
328+ application->setAppId("webbrowser-app");
277 application->setName("Browser");
329 application->setName("Browser");
278− application->setIcon("browser");
330+ application->setIcon(QUrl("browser"));
279− application->setExec("/usr/bin/webbrowser-app");
280− application->setHandle(nextHandle++);
281 generateQmlStrings(application);
331 generateQmlStrings(application);
282 m_availableApplications.append(application);
332 m_availableApplications.append(application);
283
333
284 application = new ApplicationInfo(this);
334 application = new ApplicationInfo(this);
285− application->setDesktopFile("/usr/share/applications/twitter-webapp.desktop");
335+ application->setAppId("twitter-webapp");
286 application->setName("Twitter");
336 application->setName("Twitter");
287− application->setIcon("twitter");
337+ application->setIcon(QUrl("twitter"));
288− application->setExec("/usr/bin/webbrowser-app --chromeless http://www.twitter.com");
289 application->setStage(ApplicationInfo::SideStage);
338 application->setStage(ApplicationInfo::SideStage);
290− application->setHandle(nextHandle++);
291 generateQmlStrings(application);
339 generateQmlStrings(application);
292 m_availableApplications.append(application);
340 m_availableApplications.append(application);
293
341
294 application = new ApplicationInfo(this);
342 application = new ApplicationInfo(this);
295− application->setDesktopFile("/usr/share/applications/gmail-webapp.desktop");
343+ application->setAppId("gmail-webapp");
296 application->setName("GMail");
344 application->setName("GMail");
297− application->setIcon("gmail");
345+ application->setIcon(QUrl("gmail"));
298− application->setExec("/usr/bin/webbrowser-app --chromeless http://m.gmail.com");
299− application->setHandle(nextHandle++);
300 m_availableApplications.append(application);
346 m_availableApplications.append(application);
301
347
302 application = new ApplicationInfo(this);
348 application = new ApplicationInfo(this);
303− application->setDesktopFile("/usr/share/applications/ubuntu-weather-app.desktop");
349+ application->setAppId("ubuntu-weather-app");
304 application->setName("Weather");
350 application->setName("Weather");
305− application->setIcon("weather");
351+ application->setIcon(QUrl("weather"));
306− application->setExec("/usr/bin/qmlscene /usr/share/ubuntu-weather-app/ubuntu-weather-app.qml");
307 application->setStage(ApplicationInfo::SideStage);
352 application->setStage(ApplicationInfo::SideStage);
308− application->setHandle(nextHandle++);
309 generateQmlStrings(application);
353 generateQmlStrings(application);
310 m_availableApplications.append(application);
354 m_availableApplications.append(application);
311
355
312 application = new ApplicationInfo(this);
356 application = new ApplicationInfo(this);
313− application->setDesktopFile("/usr/share/applications/notes-app.desktop");
357+ application->setAppId("notes-app");
314 application->setName("Notepad");
358 application->setName("Notepad");
315− application->setIcon("notepad");
359+ application->setIcon(QUrl("notepad"));
316− application->setExec("/usr/bin/qmlscene /usr/share/notes-app/NotesApp.qml");
317 application->setStage(ApplicationInfo::SideStage);
360 application->setStage(ApplicationInfo::SideStage);
318− application->setHandle(nextHandle++);
319 m_availableApplications.append(application);
361 m_availableApplications.append(application);
320
362
321 application = new ApplicationInfo(this);
363 application = new ApplicationInfo(this);
322− application->setDesktopFile("/usr/share/applications/calendar-app.desktop");
364+ application->setAppId("calendar-app");
323 application->setName("Calendar");
365 application->setName("Calendar");
324− application->setIcon("calendar");
366+ application->setIcon(QUrl("calendar"));
325− application->setExec("/usr/bin/qmlscene /usr/share/calendar-app/calendar.qml");
326 application->setStage(ApplicationInfo::SideStage);
367 application->setStage(ApplicationInfo::SideStage);
327− application->setHandle(nextHandle++);
328 m_availableApplications.append(application);
368 m_availableApplications.append(application);
329
369
330 application = new ApplicationInfo(this);
370 application = new ApplicationInfo(this);
331− application->setDesktopFile("/usr/share/applications/mediaplayer-app.desktop");
371+ application->setAppId("mediaplayer-app");
332 application->setName("Media Player");
372 application->setName("Media Player");
333− application->setIcon("mediaplayer-app");
373+ application->setIcon(QUrl("mediaplayer-app"));
334 application->setFullscreen(true);
374 application->setFullscreen(true);
335− application->setExec("/usr/bin/mediaplayer-app");
336− application->setHandle(nextHandle++);
337 m_availableApplications.append(application);
375 m_availableApplications.append(application);
338
376
339 application = new ApplicationInfo(this);
377 application = new ApplicationInfo(this);
340− application->setDesktopFile("/usr/share/applications/evernote.desktop");
378+ application->setAppId("evernote");
341 application->setName("Evernote");
379 application->setName("Evernote");
342− application->setIcon("evernote");
380+ application->setIcon(QUrl("evernote"));
343− application->setHandle(nextHandle++);
344 m_availableApplications.append(application);
381 m_availableApplications.append(application);
345
382
346 application = new ApplicationInfo(this);
383 application = new ApplicationInfo(this);
347− application->setDesktopFile("/usr/share/applications/map.desktop");
384+ application->setAppId("map");
348 application->setName("Map");
385 application->setName("Map");
349− application->setIcon("map");
386+ application->setIcon(QUrl("map"));
350− application->setHandle(nextHandle++);
351 generateQmlStrings(application);
387 generateQmlStrings(application);
352 m_availableApplications.append(application);
388 m_availableApplications.append(application);
353
389
354 application = new ApplicationInfo(this);
390 application = new ApplicationInfo(this);
355− application->setDesktopFile("/usr/share/applications/pinterest.desktop");
391+ application->setAppId("pinterest");
356 application->setName("Pinterest");
392 application->setName("Pinterest");
357− application->setIcon("pinterest");
393+ application->setIcon(QUrl("pinterest"));
358− application->setHandle(nextHandle++);
359 m_availableApplications.append(application);
394 m_availableApplications.append(application);
360
395
361 application = new ApplicationInfo(this);
396 application = new ApplicationInfo(this);
362− application->setDesktopFile("/usr/share/applications/soundcloud.desktop");
397+ application->setAppId("soundcloud");
363 application->setName("SoundCloud");
398 application->setName("SoundCloud");
364− application->setIcon("soundcloud");
399+ application->setIcon(QUrl("soundcloud"));
365− application->setHandle(nextHandle++);
366 m_availableApplications.append(application);
400 m_availableApplications.append(application);
367
401
368 application = new ApplicationInfo(this);
402 application = new ApplicationInfo(this);
369− application->setDesktopFile("/usr/share/applications/wikipedia.desktop");
403+ application->setAppId("wikipedia");
370 application->setName("Wikipedia");
404 application->setName("Wikipedia");
371− application->setIcon("wikipedia");
405+ application->setIcon(QUrl("wikipedia"));
372− application->setHandle(nextHandle++);
373 m_availableApplications.append(application);
406 m_availableApplications.append(application);
374
407
375 application = new ApplicationInfo(this);
408 application = new ApplicationInfo(this);
376− application->setDesktopFile("/usr/share/applications/youtube.desktop");
409+ application->setAppId("youtube");
377 application->setName("YouTube");
410 application->setName("YouTube");
378− application->setIcon("youtube");
411+ application->setIcon(QUrl("youtube"));
379− application->setHandle(nextHandle++);
380 m_availableApplications.append(application);
412 m_availableApplications.append(application);
381}
413}
382
414
tests/mocks/Ubuntu/Application/ApplicationManager.h → tests/mocks/Unity/Application/ApplicationManager.hrenamed+26−26
@@ -20,12 +20,15 @@
20#include <QObject>
20#include <QObject>
21#include <QList>
21#include <QList>
22#include <QStringList>
22#include <QStringList>
23−#include "ApplicationListModel.h"
24#include "ApplicationInfo.h"
23#include "ApplicationInfo.h"
25
24
25+// unity-api
26+#include <unity/shell/application/ApplicationManagerInterface.h>
27+
26class QQuickItem;
28class QQuickItem;
29+using namespace unity::shell::application;
27
30
28−class ApplicationManager : public QObject {
31+class ApplicationManager : public ApplicationManagerInterface {
29 Q_OBJECT
32 Q_OBJECT
30 Q_ENUMS(Role)
33 Q_ENUMS(Role)
31 Q_ENUMS(StageHint)
34 Q_ENUMS(StageHint)
@@ -39,12 +42,6 @@ class ApplicationManager : public QObject {
39 Q_PROPERTY(int sideStageWidth READ sideStageWidth)
42 Q_PROPERTY(int sideStageWidth READ sideStageWidth)
40 Q_PROPERTY(StageHint stageHint READ stageHint)
43 Q_PROPERTY(StageHint stageHint READ stageHint)
41 Q_PROPERTY(FormFactorHint formFactorHint READ formFactorHint)
44 Q_PROPERTY(FormFactorHint formFactorHint READ formFactorHint)
42− Q_PROPERTY(ApplicationListModel* mainStageApplications READ mainStageApplications)
43− Q_PROPERTY(ApplicationListModel* sideStageApplications READ sideStageApplications)
44− Q_PROPERTY(ApplicationInfo* mainStageFocusedApplication READ mainStageFocusedApplication
45− NOTIFY mainStageFocusedApplicationChanged)
46− Q_PROPERTY(ApplicationInfo* sideStageFocusedApplication READ sideStageFocusedApplication
47− NOTIFY sideStageFocusedApplicationChanged)
48
45
49 Q_PROPERTY(bool fake READ fake CONSTANT)
46 Q_PROPERTY(bool fake READ fake CONSTANT)
50
47
@@ -64,7 +61,8 @@ class ApplicationManager : public QObject {
64 DesktopFormFactor, PhoneFormFactor, TabletFormFactor
61 DesktopFormFactor, PhoneFormFactor, TabletFormFactor
65 };
62 };
66 enum FavoriteApplication {
63 enum FavoriteApplication {
67− CameraApplication, GalleryApplication, BrowserApplication, ShareApplication
64+ CameraApplication, GalleryApplication, BrowserApplication, ShareApplication,
65+ PhoneApplication, DialerApplication, MessagingApplication, AddressbookApplication
68 };
66 };
69 enum Flag {
67 enum Flag {
70 NoFlag = 0x0,
68 NoFlag = 0x0,
@@ -77,29 +75,34 @@ class ApplicationManager : public QObject {
77 int sideStageWidth() const;
75 int sideStageWidth() const;
78 StageHint stageHint() const;
76 StageHint stageHint() const;
79 FormFactorHint formFactorHint() const;
77 FormFactorHint formFactorHint() const;
80− ApplicationListModel* mainStageApplications() const;
81− ApplicationListModel* sideStageApplications() const;
82− ApplicationInfo* mainStageFocusedApplication() const;
83− ApplicationInfo* sideStageFocusedApplication() const;
84
78
85 bool fake() { return true; }
79 bool fake() { return true; }
86
80
87− Q_INVOKABLE void focusApplication(int handle);
81+ // QAbstractItemModel methods.
82+ int rowCount(const QModelIndex& parent = QModelIndex()) const override;
83+ QVariant data(const QModelIndex& index, int role) const override;
84+ Q_INVOKABLE ApplicationInfo *get(int index) const override;
85+ Q_INVOKABLE ApplicationInfo *findApplication(const QString &appId) const override;
86+
87+ Q_INVOKABLE void move(int from, int to);
88+
89+ // Application control methods
90+ Q_INVOKABLE bool focusApplication(const QString &appId) override;
88− Q_INVOKABLE void unfocusCurrentApplication(StageHint stageHint);
91+ Q_INVOKABLE void unfocusCurrentApplication() override;
89− Q_INVOKABLE ApplicationInfo* startProcess(QString desktopFile,
92+ Q_INVOKABLE ApplicationInfo *startApplication(const QString &appId, const QStringList &arguments = QStringList()) override;
90− ExecFlags flags,
91− QStringList arguments = QStringList());
93+ Q_INVOKABLE ApplicationInfo *startApplication(const QString &appId, ExecFlags flags, const QStringList &arguments = QStringList());
92− Q_INVOKABLE void stopProcess(ApplicationInfo* application);
94+ Q_INVOKABLE bool stopApplication(const QString &appId) override;
93− Q_INVOKABLE void startWatcher() {}
95+
96+ QString focusedApplicationId() const override;
94
97
95 Q_SIGNALS:
98 Q_SIGNALS:
96 void keyboardHeightChanged();
99 void keyboardHeightChanged();
97 void keyboardVisibleChanged();
100 void keyboardVisibleChanged();
98− void mainStageFocusedApplicationChanged();
99− void sideStageFocusedApplicationChanged();
100 void focusRequested(FavoriteApplication favoriteApplication);
101 void focusRequested(FavoriteApplication favoriteApplication);
101
102
102 private:
103 private:
104+ void add(ApplicationInfo *application);
105+ void remove(ApplicationInfo* application);
103 void showApplicationWindow(ApplicationInfo *application);
106 void showApplicationWindow(ApplicationInfo *application);
104 void buildListOfAvailableApplications();
107 void buildListOfAvailableApplications();
105 void generateQmlStrings(ApplicationInfo *application);
108 void generateQmlStrings(ApplicationInfo *application);
@@ -109,10 +112,7 @@ class ApplicationManager : public QObject {
109 void createSideStage();
112 void createSideStage();
110 int m_keyboardHeight;
113 int m_keyboardHeight;
111 bool m_keyboardVisible;
114 bool m_keyboardVisible;
112− ApplicationListModel* m_mainStageApplications;
115+ QList<ApplicationInfo*> m_runningApplications;
113− ApplicationListModel* m_sideStageApplications;
114− ApplicationInfo* m_mainStageFocusedApplication;
115− ApplicationInfo* m_sideStageFocusedApplication;
116 QList<ApplicationInfo*> m_availableApplications;
116 QList<ApplicationInfo*> m_availableApplications;
117 QQmlComponent *m_mainStageComponent;
117 QQmlComponent *m_mainStageComponent;
118 QQuickItem *m_mainStage;
118 QQuickItem *m_mainStage;
tests/mocks/Unity/Application/CMakeLists.txtnew file+37
@@ -0,0 +1,37 @@
1+include(FindPkgConfig)
2+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application)
3+
4+set(FakeUnityApplicationQml_SOURCES
5+ plugin.cpp
6+ ApplicationInfo.cpp
7+ ApplicationImage.cpp
8+ ApplicationManager.cpp
9+ ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
10+ ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
11+)
12+
13+add_library(FakeUnityApplicationQml MODULE ${FakeUnityApplicationQml_SOURCES})
14+
15+qt5_use_modules(FakeUnityApplicationQml Core Quick)
16+
17+# copy files into build directory for shadow builds
18+add_custom_target(UnityAppQmlDirFile ALL
19+ COMMAND cp "${CMAKE_CURRENT_SOURCE_DIR}/qmldir" ${CMAKE_CURRENT_BINARY_DIR}
20+ DEPENDS qmldir
21+)
22+add_custom_target(InputFilterAreaQmlFile ALL
23+ COMMAND cp "${CMAKE_CURRENT_SOURCE_DIR}/InputFilterArea.qml" ${CMAKE_CURRENT_BINARY_DIR}
24+ DEPENDS InputFilterArea.qml
25+)
26+add_custom_target(OSKControllerQmlFile ALL
27+ COMMAND cp "${CMAKE_CURRENT_SOURCE_DIR}/OSKController.qml" ${CMAKE_CURRENT_BINARY_DIR}
28+ DEPENDS OSKController.qml
29+)
30+
31+install(TARGETS FakeUnityApplicationQml
32+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/mocks/Unity/Application
33+ )
34+
35+install(FILES qmldir InputFilterArea.qml OSKController.qml
36+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/mocks/Unity/Application
37+ )
tests/mocks/Ubuntu/Application/InputFilterArea.qml → tests/mocks/Unity/Application/InputFilterArea.qmlrenamed

The content is the same.

tests/mocks/Unity/Application/OSKController.qmlnew file+20
@@ -0,0 +1,20 @@
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+import QtQuick 2.0;
18+
19+Item {
20+}
tests/mocks/Ubuntu/Application/plugin.cpp → tests/mocks/Unity/Application/plugin.cpprenamed+6−5
@@ -17,7 +17,6 @@
17#include "plugin.h"
17#include "plugin.h"
18#include "ApplicationInfo.h"
18#include "ApplicationInfo.h"
19#include "ApplicationImage.h"
19#include "ApplicationImage.h"
20−#include "ApplicationListModel.h"
21#include "ApplicationManager.h"
20#include "ApplicationManager.h"
22
21
23#include <qqml.h>
22#include <qqml.h>
@@ -28,11 +27,13 @@ static QObject* applicationManagerSingleton(QQmlEngine* engine, QJSEngine* scrip
28 return new ApplicationManager();
27 return new ApplicationManager();
29}
28}
30
29
31−void FakeUbuntuApplicationQmlPlugin::registerTypes(const char *uri)
30+void FakeUnityApplicationQmlPlugin::registerTypes(const char *uri)
32{
31{
33− qmlRegisterSingletonType<ApplicationManager>(
32+ qmlRegisterUncreatableType<unity::shell::application::ApplicationManagerInterface>(uri, 0, 1, "ApplicationManagerInterface", "Abstract interface. Cannot be created in QML");
34− uri, 0, 1, "ApplicationManager", applicationManagerSingleton);
33+ qmlRegisterSingletonType<ApplicationManager>(uri, 0, 1, "ApplicationManager", applicationManagerSingleton);
34+
35+ qmlRegisterUncreatableType<unity::shell::application::ApplicationInfoInterface>(uri, 0, 1, "ApplicationInfoInterface", "Abstract interface. Cannot be created in QML");
35 qmlRegisterType<ApplicationInfo>(uri, 0, 1, "ApplicationInfo");
36 qmlRegisterType<ApplicationInfo>(uri, 0, 1, "ApplicationInfo");
37+
36 qmlRegisterType<ApplicationImage>(uri, 0, 1, "ApplicationImage");
38 qmlRegisterType<ApplicationImage>(uri, 0, 1, "ApplicationImage");
37− qmlRegisterType<ApplicationListModel>(uri, 0, 1, "ApplicationListModel");
38}
39}
tests/mocks/Ubuntu/Application/plugin.h → tests/mocks/Unity/Application/plugin.hrenamed+1−1
@@ -19,7 +19,7 @@
19
19
20#include <QQmlExtensionPlugin>
20#include <QQmlExtensionPlugin>
21
21
22−class FakeUbuntuApplicationQmlPlugin : public QQmlExtensionPlugin
22+class FakeUnityApplicationQmlPlugin : public QQmlExtensionPlugin
23{
23{
24 Q_OBJECT
24 Q_OBJECT
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
25 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
tests/mocks/Unity/Application/qmldirnew file+4
@@ -0,0 +1,4 @@
1+module Unity.Application
2+plugin FakeUnityApplicationQml
3+InputFilterArea 0.1 InputFilterArea.qml
4+OSKController 0.1 OSKController.qml
tests/mocks/Unity/CMakeLists.txt+4
@@ -1,3 +1,4 @@
1+add_subdirectory(Application)
1add_subdirectory(Indicators)
2add_subdirectory(Indicators)
2
3
3pkg_search_module(DEE dee-1.0 REQUIRED)
4pkg_search_module(DEE dee-1.0 REQUIRED)
@@ -17,6 +18,9 @@ add_definitions(-DQT_NO_KEYWORDS)
17
18
18set(UnityQML_SOURCES
19set(UnityQML_SOURCES
19 ${CMAKE_SOURCE_DIR}/plugins/Unity/categoryresults.cpp
20 ${CMAKE_SOURCE_DIR}/plugins/Unity/categoryresults.cpp
21+ ${CMAKE_SOURCE_DIR}/plugins/Unity/iconutils.cpp
22+ fake_applications_scope.cpp
23+ fake_preview.cpp
20 fake_scope.cpp
24 fake_scope.cpp
21 fake_scopes.cpp
25 fake_scopes.cpp
22 fake_categories.cpp
26 fake_categories.cpp
tests/mocks/Unity/Indicators/CMakeLists.txt+1
@@ -13,6 +13,7 @@ set(IndicatorsFakeQml_SOURCES
13 fakeplugin.cpp
13 fakeplugin.cpp
14 ${CMAKE_SOURCE_DIR}/plugins/Unity/Indicators/indicators.h
14 ${CMAKE_SOURCE_DIR}/plugins/Unity/Indicators/indicators.h
15 ${CMAKE_SOURCE_DIR}/plugins/Unity/Indicators/menucontentactivator.cpp
15 ${CMAKE_SOURCE_DIR}/plugins/Unity/Indicators/menucontentactivator.cpp
16+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Indicators/visibleindicatorsmodel.cpp
16)
17)
17
18
18set(IndicatorsFakeQml_RESOURCES
19set(IndicatorsFakeQml_RESOURCES
tests/mocks/Unity/Indicators/IndicatorsModel.qml+47−76
@@ -23,82 +23,53 @@ ListModel {
23
23
24 function load() {}
24 function load() {}
25
25
26− ListElement {
26+ // Need to do this dynamically.
27+ // Apparently ListModels dont order roles visually when using ListElement
28+ // which throws off the filter for non-visible indicators.
29+ Component.onCompleted: {
27− identifier: "indicator-fake1";
30+ append({ "identifier": "indicator-fake1",
28− priority: 0
31+ "priority": 0,
29− title: "Menu1";
32+ "title": "Menu1",
30− description: "";
33+ "description": "",
31− widgetSource: "qrc:/tests/indciators/qml/fake_menu_widget1.qml";
34+ "widgetSource": "qrc:/tests/indciators/qml/fake_menu_widget1.qml",
32− pageSource: "qrc:/tests/indciators/qml/fake_menu_page1.qml";
35+ "pageSource": "qrc:/tests/indciators/qml/fake_menu_page1.qml",
33− indicatorProperties: "";
34− isValid: "";
35− }
36− ListElement {
37− identifier: "indicator-fake2";
38− priority: 1
39− title: "Menu2";
40− description: "";
41− widgetSource: "qrc:/tests/indciators/qml/fake_menu_widget2.qml";
42− pageSource: "qrc:/tests/indciators/qml/fake_menu_page2.qml";
43− indicatorProperties: "";
36+ "indicatorProperties": ""
44− isValid: "";
45− }
46− ListElement {
47− identifier: "indicator-fake3";
48− priority: 2
49− title: "Menu3";
50− description: "";
51− widgetSource: "qrc:/tests/indciators/qml/fake_menu_widget3.qml";
52− pageSource: "qrc:/tests/indciators/qml/fake_menu_page3.qml";
53− indicatorProperties: "";
54− isValid: "";
55− }
37+ });
56− ListElement {
57− identifier: "indicator-fake4";
58− priority: 3
59− title: "Menu4";
60− description: "";
61− widgetSource: "qrc:/tests/indciators/qml/fake_menu_widget4.qml";
62− pageSource: "qrc:/tests/indciators/qml/fake_menu_page4.qml";
63− indicatorProperties: "";
64− isValid: "";
65− }
66− ListElement {
67− identifier: "indicator-fake5";
68− priority: 4
69− title: "Menu5";
70− description: "";
71− widgetSource: "qrc:/tests/indciators/qml/fake_menu_widget5.qml";
72− pageSource: "qrc:/tests/indciators/qml/fake_menu_page5.qml";
73− indicatorProperties: "";
74− isValid: "";
75− }
76
38
77− function data(row, role) {
39+ append({ "identifier": "indicator-fake2",
78− if (role == Indicators.IndicatorsModelRole.Identifier) {
40+ "priority": 1,
79− return get(row).identifier;
41+ "title": "Menu2",
80− }
42+ "description": "",
81− else if (role == Indicators.IndicatorsModelRole.Priority) {
43+ "widgetSource": "qrc:/tests/indciators/qml/fake_menu_widget2.qml",
82− return get(row).priority
44+ "pageSource": "qrc:/tests/indciators/qml/fake_menu_page2.qml",
83− }
45+ "indicatorProperties": ""
84− else if (role == Indicators.IndicatorsModelRole.Title) {
85− return get(row).title
86− }
46+ });
87− else if (role == Indicators.IndicatorsModelRole.Description) {
47+
88− return get(row).description
48+ append({ "identifier": "indicator-fake3",
89− }
49+ "priority": 2,
90− else if (role == Indicators.IndicatorsModelRole.WidgetSource) {
50+ "title": "Menu3",
91− return get(row).widgetSource
51+ "description": "",
92− }
52+ "widgetSource": "qrc:/tests/indciators/qml/fake_menu_widget3.qml",
93− else if (role == Indicators.IndicatorsModelRole.PageSource) {
53+ "pageSource": "qrc:/tests/indciators/qml/fake_menu_page3.qml",
94− return get(row).pageSource
54+ "indicatorProperties": ""
95− }
96− else if (role == Indicators.IndicatorsModelRole.IndicatorProperties) {
97− return get(row).indicatorProperties
98− }
99− else if (role == Indicators.IndicatorsModelRole.IsValid) {
100− return get(row).isValid
101− }
102− }
55+ });
103
56
57+ append({ "identifier": "indicator-fake4",
58+ "priority": 3,
59+ "title": "Menu4",
60+ "description": "",
61+ "widgetSource": "qrc:/tests/indciators/qml/fake_menu_widget4.qml",
62+ "pageSource": "qrc:/tests/indciators/qml/fake_menu_page4.qml",
63+ "indicatorProperties": ""
64+ });
65+
66+ append({ "identifier": "indicator-fake5",
67+ "priority": 4,
68+ "title": "Menu5",
69+ "description": "",
70+ "widgetSource": "qrc:/tests/indciators/qml/fake_menu_widget5.qml",
71+ "pageSource": "qrc:/tests/indciators/qml/fake_menu_page5.qml",
72+ "indicatorProperties": ""
73+ });
74+ }
104}
75}
tests/mocks/Unity/Indicators/fakeplugin.cpp+2
@@ -25,12 +25,14 @@
25// local
25// local
26#include "indicators.h"
26#include "indicators.h"
27#include "menucontentactivator.h"
27#include "menucontentactivator.h"
28+#include "visibleindicatorsmodel.h"
28
29
29void IndicatorsFakePlugin::registerTypes(const char * uri)
30void IndicatorsFakePlugin::registerTypes(const char * uri)
30{
31{
31 Q_INIT_RESOURCE(indicators_fake);
32 Q_INIT_RESOURCE(indicators_fake);
32
33
33 qmlRegisterType<MenuContentActivator>(uri, 0, 1, "MenuContentActivator");
34 qmlRegisterType<MenuContentActivator>(uri, 0, 1, "MenuContentActivator");
35+ qmlRegisterType<VisibleIndicatorsModel>(uri, 0, 1, "VisibleIndicatorsModel");
34
36
35 qmlRegisterUncreatableType<MenuContentState>(uri, 0, 1, "MenuContentState", "Can't create MenuContentState class");
37 qmlRegisterUncreatableType<MenuContentState>(uri, 0, 1, "MenuContentState", "Can't create MenuContentState class");
36 qmlRegisterUncreatableType<ActionState>(uri, 0, 1, "ActionState", "Can't create ActionState class");
38 qmlRegisterUncreatableType<ActionState>(uri, 0, 1, "ActionState", "Can't create ActionState class");
tests/mocks/Unity/Indicators/qml/fake_menu_widget2.qml+2
@@ -20,4 +20,6 @@ Rectangle {
20 width: 40
20 width: 40
21 height: 40
21 height: 40
22 color : "yellow"
22 color : "yellow"
23+
24+ enabled: false
23}
25}
tests/mocks/Unity/Launcher/CMakeLists.txt+3−1
@@ -1,5 +1,7 @@
1include(FindPkgConfig)
1include(FindPkgConfig)
2−pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=2)
2+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=3)
3+
4+add_definitions(-DTOP_SRCDIR="${CMAKE_SOURCE_DIR}")
3
5
4include_directories(
6include_directories(
5 ${CMAKE_CURRENT_SOURCE_DIR}
7 ${CMAKE_CURRENT_SOURCE_DIR}
tests/mocks/Unity/Launcher/MockLauncherItem.cpp+17−1
@@ -27,12 +27,13 @@ MockLauncherItem::MockLauncherItem(const QString &appId, const QString& desktopF
27 m_appId(appId),
27 m_appId(appId),
28 m_desktopFile(desktopFile),
28 m_desktopFile(desktopFile),
29 m_name(name),
29 m_name(name),
30− m_icon(icon),
30+ m_icon(TOP_SRCDIR "/graphics/applicationIcons/" + icon + ".png"),
31 m_pinned(false),
31 m_pinned(false),
32 m_running(false),
32 m_running(false),
33 m_recent(false),
33 m_recent(false),
34 m_progress(-1),
34 m_progress(-1),
35 m_count(0),
35 m_count(0),
36+ m_focused(false),
36 m_quickList(new MockQuickListModel(this))
37 m_quickList(new MockQuickListModel(this))
37{
38{
38
39
@@ -128,6 +129,21 @@ void MockLauncherItem::setCount(int count)
128 }
129 }
129}
130}
130
131
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+
131unity::shell::launcher::QuickListModelInterface *MockLauncherItem::quickList() const
147unity::shell::launcher::QuickListModelInterface *MockLauncherItem::quickList() const
132{
148{
133 return m_quickList;
149 return m_quickList;
tests/mocks/Unity/Launcher/MockLauncherItem.h+4
@@ -52,6 +52,9 @@ public:
52 int count() const;
52 int count() const;
53 void setCount(int count);
53 void setCount(int count);
54
54
55+ bool focused() const;
56+ void setFocused(bool focused);
57+
55 unity::shell::launcher::QuickListModelInterface *quickList() const;
58 unity::shell::launcher::QuickListModelInterface *quickList() const;
56
59
57private:
60private:
@@ -64,6 +67,7 @@ private:
64 bool m_recent;
67 bool m_recent;
65 int m_progress;
68 int m_progress;
66 int m_count;
69 int m_count;
70+ bool m_focused;
67 MockQuickListModel *m_quickList;
71 MockQuickListModel *m_quickList;
68};
72};
69
73
tests/mocks/Unity/Launcher/MockLauncherModel.cpp+14−2
@@ -25,6 +25,7 @@ MockLauncherModel::MockLauncherModel(QObject* parent): LauncherModelInterface(pa
25 MockLauncherItem *item = new MockLauncherItem("phone-app", "/usr/share/applications/phone-app.desktop", "Phone", "phone-app", this);
25 MockLauncherItem *item = new MockLauncherItem("phone-app", "/usr/share/applications/phone-app.desktop", "Phone", "phone-app", this);
26 item->setProgress(0);
26 item->setProgress(0);
27 m_list.append(item);
27 m_list.append(item);
28+ item->setFocused(true);
28 item = new MockLauncherItem("camera-app", "/usr/share/applications/camera-app.desktop", "Camera", "camera", this);
29 item = new MockLauncherItem("camera-app", "/usr/share/applications/camera-app.desktop", "Camera", "camera", this);
29 item->setProgress(10);
30 item->setProgress(10);
30 m_list.append(item);
31 m_list.append(item);
@@ -49,6 +50,7 @@ MockLauncherModel::MockLauncherModel(QObject* parent): LauncherModelInterface(pa
49 item = new MockLauncherItem("notes-app", "/usr/share/applications/notes-app.desktop", "Notepad", "notepad", this);
50 item = new MockLauncherItem("notes-app", "/usr/share/applications/notes-app.desktop", "Notepad", "notepad", this);
50 item->setProgress(50);
51 item->setProgress(50);
51 item->setCount(5);
52 item->setCount(5);
53+ item->setFocused(true);
52 m_list.append(item);
54 m_list.append(item);
53 item = new MockLauncherItem("calendar-app", "/usr/share/applications/calendar-app.desktop","Calendar", "calendar", this);
55 item = new MockLauncherItem("calendar-app", "/usr/share/applications/calendar-app.desktop","Calendar", "calendar", this);
54 m_list.append(item);
56 m_list.append(item);
@@ -69,8 +71,6 @@ QVariant MockLauncherModel::data(const QModelIndex& index, int role) const
69 LauncherItemInterface *item = m_list.at(index.row());
71 LauncherItemInterface *item = m_list.at(index.row());
70 switch(role)
72 switch(role)
71 {
73 {
72− case RoleDesktopFile:
73− return item->desktopFile();
74 case RoleName:
74 case RoleName:
75 return item->name();
75 return item->name();
76 case RoleIcon:
76 case RoleIcon:
@@ -85,6 +85,8 @@ QVariant MockLauncherModel::data(const QModelIndex& index, int role) const
85 return item->progress();
85 return item->progress();
86 case RoleCount:
86 case RoleCount:
87 return item->count();
87 return item->count();
88+ case RoleFocused:
89+ return item->focused();
88 }
90 }
89
91
90 return QVariant();
92 return QVariant();
@@ -180,3 +182,13 @@ void MockLauncherModel::setUser(const QString &username)
180 Q_UNUSED(username)
182 Q_UNUSED(username)
181 // TODO: implement this...
183 // TODO: implement this...
182}
184}
185+
186+void MockLauncherModel::setApplicationManager(unity::shell::application::ApplicationManagerInterface *applicationManager)
187+{
188+ Q_UNUSED(applicationManager)
189+}
190+
191+unity::shell::application::ApplicationManagerInterface *MockLauncherModel::applicationManager() const
192+{
193+ return nullptr;
194+}
tests/mocks/Unity/Launcher/MockLauncherModel.h+3
@@ -45,6 +45,9 @@ public:
45 Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex);
45 Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex);
46 Q_INVOKABLE void setUser(const QString &username);
46 Q_INVOKABLE void setUser(const QString &username);
47
47
48+ unity::shell::application::ApplicationManagerInterface *applicationManager() const;
49+ void setApplicationManager(unity::shell::application::ApplicationManagerInterface *applicationManager);
50+
48Q_SIGNALS:
51Q_SIGNALS:
49 void quickListTriggered(const QString &appId, int index);
52 void quickListTriggered(const QString &appId, int index);
50
53
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 @@
24
24
25#define CATEGORY_COLUMN 2
25#define CATEGORY_COLUMN 2
26
26
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+
27Categories::Categories(QObject* parent)
36Categories::Categories(QObject* parent)
28 : DeeListModel(parent)
37 : DeeListModel(parent)
29{
38{
30 // FIXME: need to clean up unused filters on countChanged
39 // FIXME: need to clean up unused filters on countChanged
31− m_roles[Categories::RoleId] = "id";
40+ m_roles[Categories::RoleCategoryId] = "categoryId";
32 m_roles[Categories::RoleName] = "name";
41 m_roles[Categories::RoleName] = "name";
33 m_roles[Categories::RoleIcon] = "icon";
42 m_roles[Categories::RoleIcon] = "icon";
34 m_roles[Categories::RoleRenderer] = "renderer";
43 m_roles[Categories::RoleRenderer] = "renderer";
@@ -36,7 +45,6 @@ Categories::Categories(QObject* parent)
36 m_roles[Categories::RoleHints] = "hints";
45 m_roles[Categories::RoleHints] = "hints";
37 m_roles[Categories::RoleResults] = "results";
46 m_roles[Categories::RoleResults] = "results";
38 m_roles[Categories::RoleCount] = "count";
47 m_roles[Categories::RoleCount] = "count";
39− m_roles[Categories::RoleCategoryIndex] = "categoryIndex";
40
48
41 // TODO This should not be needed but accumulatting the count changes
49 // TODO This should not be needed but accumulatting the count changes
42 // makes the visualization more stable and also makes crashes on fast
50 // makes the visualization more stable and also makes crashes on fast
@@ -74,6 +82,25 @@ Categories::onCountChanged()
74 }
82 }
75}
83}
76
84
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+
77void
104void
78Categories::onEmitCountChanged()
105Categories::onEmitCountChanged()
79{
106{
@@ -93,6 +120,41 @@ Categories::roleNames() const
93 return m_roles;
120 return m_roles;
94}
121}
95
122
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+
96void Categories::setResultModel(DeeModel* model)
158void Categories::setResultModel(DeeModel* model)
97{
159{
98 // FIXME: should ref it
160 // FIXME: should ref it
@@ -154,27 +216,37 @@ Categories::data(const QModelIndex& index, int role) const
154 }
216 }
155
217
156 switch (role) {
218 switch (role) {
157− case RoleId:
219+ case RoleCategoryId:
158− return DeeListModel::data(index, 0); //ID
220+ return DeeListModel::data(index, CategoryColumn::ID);
159 case RoleName:
221 case RoleName:
160− return DeeListModel::data(index, 1); //DISPLAY_NAME
222+ return DeeListModel::data(index, CategoryColumn::DISPLAY_NAME);
161 case RoleIcon:
223 case RoleIcon:
162− return DeeListModel::data(index, 2); //ICON_HINT
224+ return DeeListModel::data(index, CategoryColumn::ICON_HINT);
163 case RoleRenderer:
225 case RoleRenderer:
164− return DeeListModel::data(index, 3); //RENDERER_NAME
226+ return DeeListModel::data(index, CategoryColumn::RENDERER_NAME);
165 case RoleContentType:
227 case RoleContentType:
166 {
228 {
167− auto hints = DeeListModel::data(index, 4).toHash();
229+ auto hints = DeeListModel::data(index, CategoryColumn::HINTS).toHash();
168− return hints.contains("content-type") ? hints["content-type"] : QVariant(QString("default"));
230+ return hints.contains("content-type") ? hints["content-type"] : QVariant(QString("default"));
169 }
231 }
170 case RoleHints:
232 case RoleHints:
171− return DeeListModel::data(index, 4); //HINTS
233+ return DeeListModel::data(index, CategoryColumn::HINTS);
172 case RoleResults:
234 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+ }
173 return QVariant::fromValue(getFilter(index.row()));
241 return QVariant::fromValue(getFilter(index.row()));
174 case RoleCount:
242 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+ }
175 return QVariant::fromValue(getFilter(index.row())->rowCount());
249 return QVariant::fromValue(getFilter(index.row())->rowCount());
176− case RoleCategoryIndex:
177− return QVariant::fromValue(index.row());
178 default:
250 default:
179 return QVariant();
251 return QVariant();
180 }
252 }
tests/mocks/Unity/fake_categories.h+7−3
@@ -34,17 +34,18 @@ class Categories : public DeeListModel
34public:
34public:
35 Categories(QObject* parent = 0);
35 Categories(QObject* parent = 0);
36 enum Roles {
36 enum Roles {
37− RoleId,
37+ RoleCategoryId,
38 RoleName,
38 RoleName,
39 RoleIcon,
39 RoleIcon,
40 RoleRenderer,
40 RoleRenderer,
41 RoleContentType,
41 RoleContentType,
42 RoleHints,
42 RoleHints,
43 RoleResults,
43 RoleResults,
44− RoleCount,
44+ RoleCount
45− RoleCategoryIndex
46 };
45 };
47
46
47+ Q_INVOKABLE void overrideResults(const QString& categoryId, QAbstractItemModel* model);
48+
48 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
49 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
49
50
50 QHash<int, QByteArray> roleNames() const;
51 QHash<int, QByteArray> roleNames() const;
@@ -54,7 +55,9 @@ public:
54
55
55private Q_SLOTS:
56private Q_SLOTS:
56 void onCountChanged();
57 void onCountChanged();
58+ void onRowCountChanged();
57 void onEmitCountChanged();
59 void onEmitCountChanged();
60+ void onOverrideModelDestroyed();
58
61
59private:
62private:
60 DeeModel* getResultsForCategory(unsigned index) const;
63 DeeModel* getResultsForCategory(unsigned index) const;
@@ -64,6 +67,7 @@ private:
64 QTimer m_timer;
67 QTimer m_timer;
65 QSet<DeeListModel*> m_timerFilters;
68 QSet<DeeListModel*> m_timerFilters;
66 QHash<int, QByteArray> m_roles;
69 QHash<int, QByteArray> m_roles;
70+ QMap<QString, QAbstractItemModel*> m_overriddenCategories;
67 mutable QMap<int, DeeListModel*> m_filters;
71 mutable QMap<int, DeeListModel*> m_filters;
68};
72};
69
73
tests/mocks/Unity/fake_preview.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_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+ Q_UNUSED(actionId);
67+ Q_UNUSED(hints);
68+}
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 @@
20#include <dee.h>
20#include <dee.h>
21#include "paths.h"
21#include "paths.h"
22
22
23+#include "fake_preview.h"
24+
23static DeeModel* create_categories_model(unsigned category_count);
25static DeeModel* create_categories_model(unsigned category_count);
24static DeeModel* create_results_model(unsigned category_count, unsigned result_count);
26static DeeModel* create_results_model(unsigned category_count, unsigned result_count);
25
27
@@ -127,6 +129,36 @@ void Scope::setNoResultsHint(const QString& str) {
127 }
129 }
128}
130}
129
131
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+
130static const gchar * categories_model_schema[] = {
162static const gchar * categories_model_schema[] = {
131 "s", //ID
163 "s", //ID
132 "s", // DISPLAY_NAME
164 "s", // DISPLAY_NAME
@@ -168,14 +200,6 @@ static const gchar * results_model_schema[] = {
168 "a{sv}" // METADATA
200 "a{sv}" // METADATA
169};
201};
170
202
171−static const gchar * icons[] = {
172− "Applications.png",
173− "Home.png",
174− "Music.png",
175− "People.png",
176− "Videos.png",
177−};
178−
179DeeModel* create_results_model(unsigned category_count, unsigned result_count) {
203DeeModel* create_results_model(unsigned category_count, unsigned result_count) {
180 DeeModel* results_model = dee_sequence_model_new();
204 DeeModel* results_model = dee_sequence_model_new();
181 dee_model_set_schema_full(results_model, results_model_schema, G_N_ELEMENTS(results_model_schema));
205 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) {
187
211
188 dee_model_append(results_model,
212 dee_model_append(results_model,
189 ("uri://result."+std::to_string(i)).c_str(),
213 ("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(),
191 category,
215 category,
192 0,
216 0,
193 "application/x-desktop",
217 "application/x-desktop",
tests/mocks/Unity/fake_scope.h+17−1
@@ -21,6 +21,8 @@
21#include <QObject>
21#include <QObject>
22#include "fake_categories.h"
22#include "fake_categories.h"
23
23
24+class Preview;
25+
24class Scope : public QObject
26class Scope : public QObject
25{
27{
26 Q_OBJECT
28 Q_OBJECT
@@ -63,6 +65,13 @@ public:
63 void setNoResultsHint(const QString& hint);
65 void setNoResultsHint(const QString& hint);
64 void setFormFactor(const QString& form_factor);
66 void setFormFactor(const QString& form_factor);
65
67
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+
66Q_SIGNALS:
75Q_SIGNALS:
67 void idChanged(const QString&);
76 void idChanged(const QString&);
68 void nameChanged(const QString&);
77 void nameChanged(const QString&);
@@ -78,7 +87,14 @@ Q_SIGNALS:
78 void noResultsHintChanged();
87 void noResultsHintChanged();
79 void formFactorChanged();
88 void formFactorChanged();
80
89
81−private:
90+ // signals triggered by activate(..) or preview(..) requests.
91+ void previewReady(Preview *preview);
92+ void activateApplication(const QString &desktop);
93+ void showDash();
94+ void hideDash();
95+
96+protected:
97+
82 QString m_id;
98 QString m_id;
83 QString m_iconHint;
99 QString m_iconHint;
84 QString m_description;
100 QString m_description;
tests/mocks/Unity/fake_scopes.cpp+4−1
@@ -19,6 +19,9 @@
19// Self
19// Self
20#include "fake_scopes.h"
20#include "fake_scopes.h"
21
21
22+// Local
23+#include "fake_applications_scope.h"
24+
22// TODO: Implement remaining pieces, like Categories (i.e. LensView now gives warnings)
25// TODO: Implement remaining pieces, like Categories (i.e. LensView now gives warnings)
23
26
24// Qt
27// Qt
@@ -53,7 +56,7 @@ void Scopes::updateScopes()
53 addScope(new Scope("MockScope1", "People", true, this));
56 addScope(new Scope("MockScope1", "People", true, this));
54 addScope(new Scope("MockScope2", "Music", false, this));
57 addScope(new Scope("MockScope2", "Music", false, this));
55 addScope(new Scope("home.scope", "Home", true, this));
58 addScope(new Scope("home.scope", "Home", true, this));
56− addScope(new Scope("applications.scope", "Applications", true, this));
59+ addScope(new ApplicationsScope(true, this));
57 addScope(new Scope("MockScope5", "Videos", true, this));
60 addScope(new Scope("MockScope5", "Videos", true, this));
58
61
59 if (!m_loaded) {
62 if (!m_loaded) {
tests/plugins/AccountsService/CMakeLists.txt+1
@@ -25,6 +25,7 @@ qt5_use_modules(mock-server Core DBus)
25
25
26add_executable(test-accountsservice
26add_executable(test-accountsservice
27 ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsService.cpp
27 ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsService.cpp
28+ ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
28 client.cpp
29 client.cpp
29 )
30 )
30qt5_use_modules(test-accountsservice Core DBus Test)
31qt5_use_modules(test-accountsservice Core DBus Test)
tests/plugins/AccountsService/client.cpp+19−7
@@ -18,6 +18,7 @@
18 */
18 */
19
19
20#include "AccountsService.h"
20#include "AccountsService.h"
21+#include "AccountsServiceDBusAdaptor.h"
21#include <QSignalSpy>
22#include <QSignalSpy>
22#include <QTest>
23#include <QTest>
23
24
@@ -30,17 +31,28 @@ private Q_SLOTS:
30 void testInvalids()
31 void testInvalids()
31 {
32 {
32 // Test various invalid calls
33 // Test various invalid calls
33− AccountsService session;
34+ AccountsServiceDBusAdaptor session;
34− QCOMPARE(session.getUserProperty("NOPE", "demo-edges"), QVariant());
35+ QCOMPARE(session.getUserProperty("NOPE", "com.canonical.unity.AccountsService", "demo-edges"), QVariant());
35− QCOMPARE(session.getUserProperty("testuser", "NOPE"), QVariant());
36+ QCOMPARE(session.getUserProperty("testuser", "com.canonical.unity.AccountsService", "NOPE"), QVariant());
37+ }
38+
39+ void testGetSetServiceDBusAdaptor()
40+ {
41+ AccountsServiceDBusAdaptor session;
42+ session.setUserProperty("testuser", "com.canonical.unity.AccountsService", "demo-edges", QVariant(true));
43+ QCOMPARE(session.getUserProperty("testuser", "com.canonical.unity.AccountsService", "demo-edges"), QVariant(true));
44+ session.setUserProperty("testuser", "com.canonical.unity.AccountsService", "demo-edges", QVariant(false));
45+ QCOMPARE(session.getUserProperty("testuser", "com.canonical.unity.AccountsService", "demo-edges"), QVariant(false));
36 }
46 }
37
47
38− void testGetSet()
48+ void testGetSetService()
39 {
49 {
40 AccountsService session;
50 AccountsService session;
41− QCOMPARE(session.getUserProperty("testuser", "demo-edges"), QVariant(true));
51+ session.setUser("testuser");
42− session.setUserProperty("testuser", "demo-edges", QVariant(false));
52+ session.setDemoEdges(true);
53+ QCOMPARE(session.demoEdges(), true);
54+ session.setDemoEdges(false);
43− QCOMPARE(session.getUserProperty("testuser", "demo-edges"), QVariant(false));
55+ QCOMPARE(session.demoEdges(), false);
44 }
56 }
45};
57};
46
58
tests/plugins/ListViewWithPageHeader/CMakeLists.txt+6
@@ -32,5 +32,11 @@ qt5_use_modules(listviewwithpageheadertestsectionExec Test Core Qml)
32target_link_libraries(listviewwithpageheadertestsectionExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
32target_link_libraries(listviewwithpageheadertestsectionExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
33add_custom_target(testlistviewwithpageheadersection ${CMAKE_CURRENT_BINARY_DIR}/listviewwithpageheadertestsectionExec -o ${CMAKE_BINARY_DIR}/testlistviewwithpageheadersection.xml,xunitxml -o -,txt)
33add_custom_target(testlistviewwithpageheadersection ${CMAKE_CURRENT_BINARY_DIR}/listviewwithpageheadertestsectionExec -o ${CMAKE_BINARY_DIR}/testlistviewwithpageheadersection.xml,xunitxml -o -,txt)
34
34
35+add_executable(listviewwithpageheadertestsectionexternalmodelExec listviewwithpageheadertestsectionexternalmodel.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/ListViewWithPageHeader/listviewwithpageheader.cpp)
36+qt5_use_modules(listviewwithpageheadertestsectionexternalmodelExec Test Core Qml)
37+target_link_libraries(listviewwithpageheadertestsectionexternalmodelExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
38+add_custom_target(testlistviewwithpageheadersectionexternalmodel ${CMAKE_CURRENT_BINARY_DIR}/listviewwithpageheadertestsectionexternalmodelExec -o ${CMAKE_BINARY_DIR}/testlistviewwithpageheadersectionexternalmodel.xml,xunitxml -o -,txt)
39+
35add_dependencies(qmluitests testlistviewwithpageheader)
40add_dependencies(qmluitests testlistviewwithpageheader)
36add_dependencies(qmluitests testlistviewwithpageheadersection)
41add_dependencies(qmluitests testlistviewwithpageheadersection)
42+add_dependencies(qmluitests testlistviewwithpageheadersectionexternalmodel)
tests/plugins/ListViewWithPageHeader/listviewwithpageheadertest.cpp+161
@@ -1655,6 +1655,167 @@ private Q_SLOTS:
1655 QCOMPARE(spy.count(), 0);
1655 QCOMPARE(spy.count(), 0);
1656 }
1656 }
1657
1657
1658+ void testOvershootOnSameSize()
1659+ {
1660+ QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 0), Q_ARG(QVariant, 6));
1661+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 0);
1662+ QCOMPARE(lvwph->m_minYExtent, 0.);
1663+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
1664+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1665+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1666+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1667+ QCOMPARE(lvwph->contentY(), 0.);
1668+
1669+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 100));
1670+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 392));
1671+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1672+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1673+ verifyItem(0, 50., 392., false);
1674+ verifyItem(1, 442., 100., false);
1675+
1676+ QCOMPARE(lvwph->contentHeight(), lvwph->height());
1677+
1678+ QTest::mousePress(view, Qt::LeftButton, Qt::NoModifier, QPoint(0, 0));
1679+ QTest::qWait(100);
1680+ QTest::mouseMove(view, QPoint(0, 5));
1681+ QTest::qWait(100);
1682+ QTest::mouseMove(view, QPoint(0, 10));
1683+ QTest::qWait(100);
1684+ QTest::mouseMove(view, QPoint(0, 15));
1685+ QTest::qWait(100);
1686+ QTest::mouseMove(view, QPoint(0, 20));
1687+ QTest::qWait(100);
1688+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1689+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1690+ verifyItem(0, 55., 392., false);
1691+ verifyItem(1, 447., 100., false);
1692+ QCOMPARE(lvwph->m_minYExtent, 0.);
1693+ QCOMPARE(lvwph->m_clipItem->y(), -5.);
1694+
1695+ QTest::mouseRelease(view, Qt::LeftButton, Qt::NoModifier, QPoint(0, 15));
1696+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1697+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1698+ verifyItem(0, 50., 392., false);
1699+ verifyItem(1, 442., 100., false);
1700+ }
1701+
1702+ void testMaximizeVisibleAreaMoveDownAndShowHeader()
1703+ {
1704+ model->setProperty(0, "size", 800);
1705+ verifyItem(0, 50., 800., false);
1706+
1707+ lvwph->maximizeVisibleArea(0);
1708+ QTRY_COMPARE(lvwph->contentY(), 50.);
1709+
1710+ changeContentY(10);
1711+ QTRY_COMPARE(lvwph->contentY(), 60.);
1712+
1713+ lvwph->showHeader();
1714+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1715+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1716+ QCOMPARE(lvwph->m_minYExtent, 50.);
1717+ QCOMPARE(lvwph->m_clipItem->y(), 60.);
1718+ QCOMPARE(lvwph->m_clipItem->clip(), true);
1719+ QCOMPARE(lvwph->m_headerItem->y(), 10.);
1720+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1721+ QCOMPARE(lvwph->contentY(), 10.);
1722+ verifyItem(0, -60., 800., false);
1723+ }
1724+
1725+ void testMaximizeVisibleAreaMoveUpAndShowHeader()
1726+ {
1727+ model->setProperty(0, "size", 800);
1728+ verifyItem(0, 50., 800., false);
1729+
1730+ lvwph->maximizeVisibleArea(0);
1731+ QTRY_COMPARE(lvwph->contentY(), 50.);
1732+
1733+ changeContentY(-10);
1734+ QTRY_COMPARE(lvwph->contentY(), 40.);
1735+
1736+ lvwph->showHeader();
1737+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1738+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1739+ QCOMPARE(lvwph->m_minYExtent, 40.);
1740+ QCOMPARE(lvwph->m_clipItem->y(), 50.);
1741+ QCOMPARE(lvwph->m_clipItem->clip(), true);
1742+ QTRY_COMPARE(lvwph->m_headerItem->y(), 0.);
1743+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1744+ QCOMPARE(lvwph->contentY(), 0.);
1745+ verifyItem(0, -40., 800., false);
1746+ }
1747+
1748+ void testMaximizeVisibleAreaMoveDownAndUpAndShowHeader()
1749+ {
1750+ model->setProperty(0, "size", 800);
1751+ verifyItem(0, 50., 800., false);
1752+
1753+ lvwph->maximizeVisibleArea(0);
1754+ QTRY_COMPARE(lvwph->contentY(), 50.);
1755+
1756+ changeContentY(-10);
1757+ QTRY_COMPARE(lvwph->contentY(), 40.);
1758+ changeContentY(10);
1759+ QTRY_COMPARE(lvwph->contentY(), 50.);
1760+
1761+ lvwph->showHeader();
1762+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1763+
1764+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1765+ QCOMPARE(lvwph->m_minYExtent, 50.);
1766+ QCOMPARE(lvwph->m_clipItem->y(), 50.);
1767+ QCOMPARE(lvwph->m_clipItem->clip(), true);
1768+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1769+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1770+ QCOMPARE(lvwph->contentY(), 0.);
1771+ verifyItem(0, -50., 800., false);
1772+ }
1773+
1774+ void testMaximizeVisibleAreaMoveUpAndDownAndShowHeader()
1775+ {
1776+ model->setProperty(0, "size", 800);
1777+ verifyItem(0, 50., 800., false);
1778+
1779+ lvwph->maximizeVisibleArea(0);
1780+ QTRY_COMPARE(lvwph->contentY(), 50.);
1781+
1782+ changeContentY(10);
1783+ QTRY_COMPARE(lvwph->contentY(), 60.);
1784+ changeContentY(-10);
1785+ QTRY_COMPARE(lvwph->contentY(), 50.);
1786+
1787+ lvwph->showHeader();
1788+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1789+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1790+ QCOMPARE(lvwph->m_minYExtent, 40.);
1791+ QCOMPARE(lvwph->m_clipItem->y(), 60.);
1792+ QCOMPARE(lvwph->m_clipItem->clip(), true);
1793+ QCOMPARE(lvwph->m_headerItem->y(), 10.);
1794+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1795+ QCOMPARE(lvwph->contentY(), 10.);
1796+ verifyItem(0, -50., 800., false);
1797+ }
1798+
1799+ void testMaximizeVisibleAreaAndShowHeader()
1800+ {
1801+ model->setProperty(0, "size", 800);
1802+ verifyItem(0, 50., 800., false);
1803+
1804+ lvwph->maximizeVisibleArea(0);
1805+ QTRY_COMPARE(lvwph->contentY(), 50.);
1806+
1807+ lvwph->showHeader();
1808+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1809+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1810+ QCOMPARE(lvwph->m_minYExtent, 50.);
1811+ QCOMPARE(lvwph->m_clipItem->y(), 50.);
1812+ QCOMPARE(lvwph->m_clipItem->clip(), true);
1813+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1814+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1815+ QCOMPARE(lvwph->contentY(), 0.);
1816+ verifyItem(0, -50., 800., false);
1817+ }
1818+
1658private:
1819private:
1659 QQuickView *view;
1820 QQuickView *view;
1660 ListViewWithPageHeader *lvwph;
1821 ListViewWithPageHeader *lvwph;
tests/plugins/ListViewWithPageHeader/listviewwithpageheadertestsectionexternalmodel.cppnew file+251
@@ -0,0 +1,251 @@
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 "listviewwithpageheader.h"
18+
19+#include <QAbstractItemModel>
20+#include <QQmlEngine>
21+#include <QQuickView>
22+#include <QSignalSpy>
23+#include <QSortFilterProxyModel>
24+#include <QtTestGui>
25+#pragma GCC diagnostic push
26+#pragma GCC diagnostic ignored "-pedantic"
27+#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
28+#include <private/qquicklistmodel_p.h>
29+#else
30+#include <private/qqmllistmodel_p.h>
31+#endif
32+#include <private/qquickanimation_p.h>
33+#include <private/qquickitem_p.h>
34+#pragma GCC diagnostic pop
35+
36+class StringListModel : public QAbstractListModel
37+{
38+public:
39+ StringListModel()
40+ {
41+ list << "A" << "B" << "C" << "D" << "E" << "F" << "G" << "H";
42+ }
43+
44+ int rowCount(const QModelIndex &parent) const
45+ {
46+ if (parent.isValid())
47+ return 0;
48+ else
49+ return list.count();
50+ }
51+
52+ QVariant data(const QModelIndex &index, int role) const
53+ {
54+ if (role == Qt::SizeHintRole) return 50;
55+ else if (role == Qt::DisplayRole) return list[index.row()];
56+ return QVariant();
57+ }
58+
59+ QHash<int, QByteArray> roleNames() const
60+ {
61+ QHash<int, QByteArray> hash;
62+ hash.insert(Qt::DisplayRole, "type");
63+ hash.insert(Qt::SizeHintRole, "size");
64+ return hash;
65+ }
66+
67+ void moveLastToFirst()
68+ {
69+ const int last = list.count() - 1;
70+ beginMoveRows(QModelIndex(), last, last, QModelIndex(), 0);
71+ list.move(last, 0);
72+ endMoveRows();
73+ }
74+
75+ QStringList list;
76+};
77+
78+class ListViewWithPageHeaderTestSection : public QObject
79+{
80+ Q_OBJECT
81+
82+private:
83+ void verifyItem(int visibleIndex, qreal pos, qreal height, bool culled, const QString &sectionHeader, bool sectionHeaderCulled)
84+ {
85+ QTRY_VERIFY(visibleIndex < lvwph->m_visibleItems.count());
86+ QTRY_COMPARE(lvwph->m_visibleItems[visibleIndex]->y(), pos);
87+ QTRY_COMPARE(lvwph->m_visibleItems[visibleIndex]->height(), height);
88+ QCOMPARE(QQuickItemPrivate::get(lvwph->m_visibleItems[visibleIndex]->m_item)->culled, culled);
89+ QCOMPARE(section(lvwph->m_visibleItems[visibleIndex]->m_sectionItem), sectionHeader);
90+ if (!sectionHeader.isNull()) {
91+ QCOMPARE(QQuickItemPrivate::get(lvwph->m_visibleItems[visibleIndex]->m_sectionItem)->culled, sectionHeaderCulled);
92+ QCOMPARE(sectionDelegateIndex(lvwph->m_visibleItems[visibleIndex]->m_sectionItem), lvwph->m_firstVisibleIndex + visibleIndex);
93+ }
94+ }
95+
96+ void changeContentY(qreal change)
97+ {
98+ const qreal dest = lvwph->contentY() + change;
99+ if (dest > lvwph->contentY()) {
100+ const qreal jump = 25;
101+ while (lvwph->contentY() + jump < dest) {
102+ lvwph->setContentY(lvwph->contentY() + jump);
103+ QTest::qWait(1);
104+ }
105+ } else {
106+ const qreal jump = -25;
107+ while (lvwph->contentY() + jump > dest) {
108+ lvwph->setContentY(lvwph->contentY() + jump);
109+ QTest::qWait(1);
110+ }
111+ }
112+ lvwph->setContentY(dest);
113+ QTest::qWait(1);
114+ }
115+
116+ void scrollToTop()
117+ {
118+ const qreal jump = -25;
119+ while (!lvwph->isAtYBeginning()) {
120+ if (lvwph->contentY() + jump > -lvwph->minYExtent()) {
121+ lvwph->setContentY(lvwph->contentY() + jump);
122+ } else {
123+ lvwph->setContentY(lvwph->contentY() - 1);
124+ }
125+ QTest::qWait(1);
126+ }
127+ }
128+
129+ void scrollToBottom()
130+ {
131+ const qreal jump = 25;
132+ while (!lvwph->isAtYEnd()) {
133+ if (lvwph->contentY() + lvwph->height() + jump < lvwph->contentHeight()) {
134+ lvwph->setContentY(lvwph->contentY() + jump);
135+ } else {
136+ lvwph->setContentY(lvwph->contentY() + 1);
137+ }
138+ QTest::qWait(1);
139+ }
140+ }
141+
142+ void verifyInitialTopPosition()
143+ {
144+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 0);
145+ QCOMPARE(lvwph->m_firstVisibleIndex, -1);
146+ QCOMPARE(lvwph->m_minYExtent, 0.);
147+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
148+ QCOMPARE(lvwph->m_clipItem->clip(), false);
149+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
150+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
151+ QCOMPARE(lvwph->contentY(), 0.);
152+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
153+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
154+ }
155+
156+ QString section(QQuickItem *item)
157+ {
158+ return item ? QQmlEngine::contextForObject(item)->parentContext()->contextProperty(QLatin1String("section")).toString() : QString();
159+ }
160+
161+ int sectionDelegateIndex(QQuickItem *item)
162+ {
163+ return item ? QQmlEngine::contextForObject(item)->parentContext()->contextProperty(QLatin1String("delegateIndex")).toInt() : -1;
164+ }
165+
166+private Q_SLOTS:
167+
168+ void initTestCase()
169+ {
170+ }
171+
172+ void init()
173+ {
174+ view = new QQuickView();
175+ view->engine()->addImportPath(BUILT_PLUGINS_DIR);
176+ view->setSource(QUrl::fromLocalFile(LISTVIEWWITHPAGEHEADER_FOLDER "/test_sectionexternalmodel.qml"));
177+ lvwph = dynamic_cast<ListViewWithPageHeader*>(view->rootObject()->findChild<QQuickFlickable*>());
178+ QVERIFY(lvwph);
179+ view->show();
180+ QTest::qWaitForWindowExposed(view);
181+
182+ verifyInitialTopPosition();
183+ }
184+
185+ void cleanup()
186+ {
187+ delete view;
188+ }
189+
190+ void testCreationDeletion()
191+ {
192+ // Nothing, init/cleanup already tests this
193+ }
194+
195+ void testMoveWithProxy()
196+ {
197+ StringListModel m;
198+ QSortFilterProxyModel proxy;
199+ proxy.setSourceModel(&m);
200+
201+ lvwph->setModel(&proxy);
202+
203+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 8);
204+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
205+ verifyItem(0, 50., 90., false, "A", false);
206+ verifyItem(1, 140., 90., false, "B", false);
207+ verifyItem(2, 230., 90., false, "C", false);
208+ verifyItem(3, 320., 90., false, "D", false);
209+ verifyItem(4, 410., 90., false, "E", false);
210+ verifyItem(5, 500., 90., false, "F", false);
211+ verifyItem(6, 590., 90., true, "G", true);
212+ verifyItem(7, 680., 90., true, "H", true);
213+ QCOMPARE(lvwph->m_minYExtent, 0.);
214+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
215+ QCOMPARE(lvwph->m_clipItem->clip(), false);
216+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
217+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
218+ QCOMPARE(lvwph->contentY(), 0.);
219+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
220+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
221+
222+ m.moveLastToFirst();
223+
224+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 8);
225+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
226+ verifyItem(0, 50., 90., false, "H", false);
227+ verifyItem(1, 140., 90., false, "A", false);
228+ verifyItem(2, 230., 90., false, "B", false);
229+ verifyItem(3, 320., 90., false, "C", false);
230+ verifyItem(4, 410., 90., false, "D", false);
231+ verifyItem(5, 500., 90., false, "E", false);
232+ verifyItem(6, 590., 90., true, "F", true);
233+ verifyItem(7, 680., 90., true, "G", true);
234+ QCOMPARE(lvwph->m_minYExtent, 0.);
235+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
236+ QCOMPARE(lvwph->m_clipItem->clip(), false);
237+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
238+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
239+ QCOMPARE(lvwph->contentY(), 0.);
240+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
241+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
242+ }
243+
244+private:
245+ QQuickView *view;
246+ ListViewWithPageHeader *lvwph;
247+};
248+
249+QTEST_MAIN(ListViewWithPageHeaderTestSection)
250+
251+#include "listviewwithpageheadertestsectionexternalmodel.moc"
tests/plugins/ListViewWithPageHeader/test_sectionexternalmodel.qmlnew file+74
@@ -0,0 +1,74 @@
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+import QtQuick 2.0
18+import ListViewWithPageHeader 0.1
19+
20+Rectangle {
21+ width: 300
22+ height: 542
23+ color: "lightblue"
24+
25+ ListViewWithPageHeader {
26+ id: listView
27+ width: parent.width
28+ anchors.top: parent.top
29+ anchors.bottom: parent.bottom
30+ model: model
31+ delegate: Rectangle {
32+ property bool timerDone: false
33+ width: parent.width - 20
34+ x: 10
35+ color: index % 2 == 0 ? "red" : "blue"
36+ height: timerDone ? size : 350
37+ Text {
38+ text: index
39+ }
40+ Timer {
41+ id: sizeTimer
42+ interval: 10;
43+ onTriggered: {
44+ timerDone = true
45+ }
46+ }
47+ Component.onCompleted: {
48+ sizeTimer.start()
49+ }
50+ }
51+
52+ pageHeader: Rectangle {
53+ color: "transparent"
54+ width: parent.width
55+ height: 50
56+ implicitHeight: 50
57+ Text {
58+ anchors.fill: parent
59+ text: "APPS"
60+ font.pixelSize: 40
61+ }
62+ }
63+
64+ sectionProperty: "type"
65+ sectionDelegate: Component {
66+ Rectangle {
67+ color: "green"
68+ height: 40
69+ Text { text: section; font.pixelSize: 34 }
70+ anchors { left: parent.left; right: parent.right }
71+ }
72+ }
73+ }
74+}
tests/plugins/Unity/CMakeLists.txt+5
@@ -1,9 +1,11 @@
1add_subdirectory(Indicators)
1add_subdirectory(Indicators)
2+add_subdirectory(Launcher)
2
3
3pkg_check_modules(UNITYCORE REQUIRED unity-core-6.0)
4pkg_check_modules(UNITYCORE REQUIRED unity-core-6.0)
4pkg_check_modules(LIBUNITYPROTO REQUIRED unity-protocol-private)
5pkg_check_modules(LIBUNITYPROTO REQUIRED unity-protocol-private)
5pkg_check_modules(LIBUNITY REQUIRED unity)
6pkg_check_modules(LIBUNITY REQUIRED unity)
6pkg_check_modules(LIBSIGCPP REQUIRED sigc++-2.0)
7pkg_check_modules(LIBSIGCPP REQUIRED sigc++-2.0)
8+pkg_check_modules(QTDEE REQUIRED libdee-qt5>=3.2)
7
9
8include_directories(
10include_directories(
9 ${Unity-qml_SOURCE_DIR}
11 ${Unity-qml_SOURCE_DIR}
@@ -13,6 +15,7 @@ include_directories(
13 ${LIBUNITY_INCLUDE_DIRS}
15 ${LIBUNITY_INCLUDE_DIRS}
14 ${LIBSIGCPP_INCLUDE_DIRS}
16 ${LIBSIGCPP_INCLUDE_DIRS}
15 ${UNITYCORE_INCLUDE_DIRS}
17 ${UNITYCORE_INCLUDE_DIRS}
18+ ${QTDEE_INCLUDE_DIRS}
16 )
19 )
17
20
18macro(run_tests)
21macro(run_tests)
@@ -35,6 +38,7 @@ macro(run_tests)
35 ${LIBUNITY_LDFLAGS}
38 ${LIBUNITY_LDFLAGS}
36 ${LIBUNITYPROTO_LDFLAGS}
39 ${LIBUNITYPROTO_LDFLAGS}
37 ${LIBSIGCPP_LDFLAGS}
40 ${LIBSIGCPP_LDFLAGS}
41+ ${QTDEE_LDFLAGS}
38 )
42 )
39
43
40 set(_test_list "${_test_list};${_test}")
44 set(_test_list "${_test_list};${_test}")
@@ -45,4 +49,5 @@ run_tests(
45 signalslisttest
49 signalslisttest
46 previewbindingstest
50 previewbindingstest
47 filtersbindingstest
51 filtersbindingstest
52+ resultstest
48 )
53 )
tests/plugins/Unity/Launcher/CMakeLists.txtnew file+71
@@ -0,0 +1,71 @@
1+pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
2+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=3)
3+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=1)
4+
5+include_directories(
6+ ${CMAKE_CURRENT_BINARY_DIR}
7+ ${CMAKE_SOURCE_DIR}/plugins/AccountsService
8+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher
9+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/backend
10+ ${GSETTINGS_QT_INCLUDE_DIRS}
11+ )
12+
13+add_definitions(-DSM_BUSNAME=sessionBus)
14+add_definitions(-DSRCDIR="${CMAKE_CURRENT_SOURCE_DIR}")
15+add_definitions(-DLAUNCHER_TESTING)
16+
17+### LauncherBackendTest
18+set(testBackendCommand ${CMAKE_CURRENT_BINARY_DIR}/launcherbackendtestExec
19+ -o ${CMAKE_BINARY_DIR}/launcherbackendtest.xml,xunitxml
20+ -o -,txt)
21+add_test(NAME launcherbackendtest COMMAND ${testBackendCommand})
22+add_custom_target(launcherbackendtest ${testBackendCommand})
23+add_executable(launcherbackendtestExec
24+ launcherbackendtest.cpp
25+ ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
26+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/backend/launcherbackend.cpp
27+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/common/quicklistentry.cpp
28+ )
29+target_link_libraries(launcherbackendtestExec ${GSETTINGS_QT_LDFLAGS})
30+qt5_use_modules(launcherbackendtestExec Test Core DBus)
31+
32+### LauncherModelTest
33+set(testModelCommand ${CMAKE_CURRENT_BINARY_DIR}/launchermodeltestExec
34+ -o ${CMAKE_BINARY_DIR}/launchermodeltest.xml,xunitxml
35+ -o -,txt)
36+add_test(NAME launchermodeltest COMMAND ${testModelCommand})
37+add_custom_target(launchermodeltest ${testModelCommand})
38+add_executable(launchermodeltestExec
39+ launchermodeltest.cpp
40+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/launchermodel.cpp
41+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/launcheritem.cpp
42+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/quicklistmodel.cpp
43+ ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
44+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/backend/launcherbackend.cpp
45+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/common/quicklistentry.cpp
46+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
47+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
48+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
49+ ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
50+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
51+ )
52+target_link_libraries(launchermodeltestExec ${GSETTINGS_QT_LDFLAGS} )
53+qt5_use_modules(launchermodeltestExec Test Core DBus)
54+
55+# copy .desktop files into build directory for shadow builds
56+file(GLOB DESKTOP_FILES *.desktop)
57+
58+foreach(DESKTOP_FILE ${DESKTOP_FILES})
59+ file(COPY "${DESKTOP_FILE}"
60+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
61+ )
62+endforeach()
63+
64+# copy .svg files into build directory for shadow builds
65+file(GLOB DESKTOP_FILES *.svg)
66+
67+foreach(DESKTOP_FILE ${DESKTOP_FILES})
68+ file(COPY "${DESKTOP_FILE}"
69+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
70+ )
71+endforeach()
tests/plugins/Unity/Launcher/abs-icon.desktopnew file+3
@@ -0,0 +1,3 @@
1+[Desktop Entry]
2+Name=Absolute Icon
3+Icon=/path/to/icon.png
tests/plugins/Unity/Launcher/click-icon.desktopnew file+4
@@ -0,0 +1,4 @@
1+[Desktop Entry]
2+Name=Click Package Icon
3+Icon=click-icon.svg
4+Path=/path/to/some/click/app
tests/plugins/Unity/Launcher/click-icon.svgnew file

No changes to the content.

tests/plugins/Unity/Launcher/launcherbackendtest.cppnew file+93
@@ -0,0 +1,93 @@
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 Terry <michael.terry@canonical.com>
18+ */
19+
20+#include "launcherbackend.h"
21+
22+#include <QtTest>
23+
24+class LauncherBackendTest : public QObject
25+{
26+ Q_OBJECT
27+
28+private Q_SLOTS:
29+
30+ void initTestCase()
31+ {
32+ // As we want to test absolute file paths in the .desktop file, we need to modify the
33+ // sample file and replace the path in there with the current build dir.
34+ QSettings settings(QDir::currentPath() + "/click-icon.desktop", QSettings::IniFormat);
35+ settings.setValue("Desktop Entry/Path", QDir::currentPath());
36+ }
37+
38+ void testFileNames()
39+ {
40+ LauncherBackend backend(false);
41+
42+ backend.setStoredApplications(QStringList() << "rel-icon" << "abs-icon" << "invalid");
43+ QCOMPARE(backend.storedApplications(), QStringList() << "rel-icon" << "abs-icon");
44+ }
45+
46+ void testPinning()
47+ {
48+ LauncherBackend backend(false);
49+
50+ backend.setStoredApplications(QStringList() << "rel-icon" << "abs-icon");
51+ QCOMPARE(backend.isPinned("rel-icon"), false);
52+ QCOMPARE(backend.isPinned("abs-icon"), false);
53+
54+ backend.setPinned("rel-icon", true);
55+ QCOMPARE(backend.isPinned("rel-icon"), true);
56+
57+ backend.setStoredApplications(QStringList() << "rel-icon" << "abs-icon" << "no-name");
58+ QCOMPARE(backend.isPinned("rel-icon"), true);
59+ QCOMPARE(backend.isPinned("no-name"), false);
60+
61+ backend.setPinned("no-name", true);
62+ backend.setStoredApplications(QStringList() << "rel-icon" << "abs-icon");
63+ QCOMPARE(backend.isPinned("rel-icon"), true);
64+ QCOMPARE(backend.isPinned("no-name"), false); // doesn't exist anymore!
65+ }
66+
67+ void testIcon_data() {
68+ QTest::addColumn<QString>("appId");
69+ QTest::addColumn<QString>("expectedIcon");
70+
71+ // Needs to expand a relative icon to the absolute path
72+ QTest::newRow("relative icon path") << "rel-icon" << QDir::currentPath() + "/rel-icon.svg";
73+
74+ // In case an icon is not found on disk, it needs to fallback on image://theme/ for it
75+ QTest::newRow("fallback on theme") << "abs-icon" << "image://theme//path/to/icon.png";
76+
77+ // Click packages have a relative icon path but an absolute path as a separate entry
78+ QTest::newRow("click package icon") << "click-icon" << QDir::currentPath() + "/click-icon.svg";
79+ }
80+
81+ void testIcon() {
82+ QFETCH(QString, appId);
83+ QFETCH(QString, expectedIcon);
84+
85+ LauncherBackend backend(false);
86+ backend.setStoredApplications(QStringList() << appId);
87+
88+ QCOMPARE(backend.icon(appId), expectedIcon);
89+ }
90+};
91+
92+QTEST_GUILESS_MAIN(LauncherBackendTest)
93+#include "launcherbackendtest.moc"
tests/plugins/Unity/Launcher/launchermodeltest.cppnew file+275
@@ -0,0 +1,275 @@
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+#include <unity/shell/application/ApplicationInfoInterface.h>
23+
24+#include "launcheritem.h"
25+#include "launchermodel.h"
26+
27+#include <QtTest>
28+
29+// This is a mock, specifically to test the LauncherModel
30+class MockApp: public unity::shell::application::ApplicationInfoInterface
31+{
32+ Q_OBJECT
33+public:
34+ MockApp(const QString &appId, QObject *parent = 0): ApplicationInfoInterface(appId, parent), m_appId(appId), m_focused(false) { }
35+ QString appId() const { return m_appId; }
36+ QString name() const { return "mock"; }
37+ QString comment() const { return "this is a mock"; }
38+ QUrl icon() const { return QUrl(); }
39+ ApplicationInfoInterface::Stage stage() const { return ApplicationInfoInterface::MainStage; }
40+ ApplicationInfoInterface::State state() const { return ApplicationInfoInterface::Running; }
41+ bool focused() const { return m_focused; }
42+
43+ // Methods used for mocking (not in the interface)
44+ void setFocused(bool focused) { m_focused = focused; Q_EMIT focusedChanged(focused); }
45+private:
46+ QString m_appId;
47+ bool m_focused;
48+};
49+
50+// This is a mock, specifically to test the LauncherModel
51+class MockAppManager: public unity::shell::application::ApplicationManagerInterface
52+{
53+ Q_OBJECT
54+public:
55+ MockAppManager(QObject *parent = 0): ApplicationManagerInterface(parent) {}
56+ int rowCount(const QModelIndex &) const { return m_list.count(); }
57+ QVariant data(const QModelIndex &, int ) const { return QVariant(); }
58+ QString focusedApplicationId() const {
59+ Q_FOREACH(MockApp *app, m_list) {
60+ if (app->focused()) return app->appId();
61+ }
62+ return QString();
63+ }
64+ unity::shell::application::ApplicationInfoInterface *get(int index) const { return m_list.at(index); }
65+ unity::shell::application::ApplicationInfoInterface *findApplication(const QString &appId) const {
66+ Q_FOREACH(MockApp* app, m_list) {
67+ if (app->appId() == appId) {
68+ return app;
69+ }
70+ }
71+ return nullptr;
72+ }
73+ unity::shell::application::ApplicationInfoInterface *startApplication(const QString &, const QStringList &) { return nullptr; }
74+ bool stopApplication(const QString &) { return false; }
75+ bool focusApplication(const QString &appId) {
76+ Q_FOREACH(MockApp* app, m_list) {
77+ app->setFocused(app->appId() == appId);
78+ }
79+ Q_EMIT focusedApplicationIdChanged();
80+ return true;
81+ }
82+
83+ void unfocusCurrentApplication() { }
84+
85+ void addApplication(MockApp *app) {
86+ beginInsertRows(QModelIndex(), count(), count());
87+ m_list.append(app);
88+ endInsertRows();
89+ }
90+ void removeApplication(int index) {
91+ beginRemoveRows(QModelIndex(), index, index);
92+ m_list.takeAt(index)->deleteLater();
93+ endRemoveRows();
94+ }
95+
96+private:
97+ QList<MockApp*> m_list;
98+};
99+
100+class LauncherModelTest : public QObject
101+{
102+ Q_OBJECT
103+
104+private:
105+ LauncherModel *launcherModel;
106+ MockAppManager *appManager;
107+
108+private Q_SLOTS:
109+
110+ void initTestCase() {
111+ launcherModel = new LauncherModel(this);
112+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 0);
113+
114+ appManager = new MockAppManager(this);
115+ launcherModel->setApplicationManager(appManager);
116+ }
117+
118+ // Adding 2 apps to the mock appmanager. Both should appear in the launcher.
119+ void init() {
120+ appManager->addApplication(new MockApp("abs-icon"));
121+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
122+
123+ appManager->addApplication(new MockApp("no-icon"));
124+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
125+ }
126+
127+ // Removing apps from appmanager and launcher as pinned ones would stick
128+ void cleanup() {
129+ while (appManager->count() > 0) {
130+ appManager->removeApplication(0);
131+ }
132+ while (launcherModel->rowCount(QModelIndex()) > 0) {
133+ launcherModel->requestRemove(launcherModel->get(0)->appId());
134+ }
135+ }
136+
137+ void testMove() {
138+ QCOMPARE(launcherModel->get(0)->pinned(), false);
139+ QCOMPARE(launcherModel->get(1)->pinned(), false);
140+
141+ LauncherItemInterface *item0BeforeMove = launcherModel->get(0);
142+ LauncherItemInterface *item1BeforeMove = launcherModel->get(1);
143+ launcherModel->move(1, 0);
144+
145+ QCOMPARE(item0BeforeMove, launcherModel->get(1));
146+ QCOMPARE(item1BeforeMove, launcherModel->get(0));
147+
148+ // moved item must be pinned now
149+ QCOMPARE(item0BeforeMove->pinned(), false);
150+ QCOMPARE(item1BeforeMove->pinned(), true);
151+ }
152+
153+ void testPinning() {
154+ QCOMPARE(launcherModel->get(0)->pinned(), false);
155+ QCOMPARE(launcherModel->get(1)->pinned(), false);
156+ launcherModel->pin(launcherModel->get(0)->appId());
157+ QCOMPARE(launcherModel->get(0)->pinned(), true);
158+ QCOMPARE(launcherModel->get(1)->pinned(), false);
159+ }
160+
161+ void testRemove_data() {
162+
163+ QTest::addColumn<bool>("pinned");
164+ QTest::addColumn<bool>("running");
165+
166+ QTest::newRow("non-pinned, running") << false << true;
167+ QTest::newRow("pinned, running") << true << false;
168+ QTest::newRow("pinned, non-running") << true << false;
169+ }
170+
171+ void testRemove() {
172+ QFETCH(bool, pinned);
173+ QFETCH(bool, running);
174+
175+ // In the beginning we always have two items
176+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
177+
178+ // pin one if required
179+ if (pinned) {
180+ launcherModel->pin(launcherModel->get(1)->appId());
181+ }
182+
183+ // stop it if required
184+ if (!running) {
185+ appManager->removeApplication(1);
186+ }
187+
188+ // Now remove it
189+ launcherModel->requestRemove(launcherModel->get(1)->appId());
190+
191+ if (running) {
192+ // both apps are running, both apps must still be here
193+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
194+
195+ // Item must be unpinned now
196+ QCOMPARE(launcherModel->get(1)->pinned(), false);
197+
198+ } else if (pinned) {
199+ // Item 1 must go away, item 0 is here to stay
200+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
201+ }
202+
203+ // done our checks. now stop the app if was still running
204+ if (running) {
205+ appManager->removeApplication(1);
206+ }
207+
208+ // It needs to go away in any case now
209+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
210+ }
211+
212+ void testQuickListPinningRemoving() {
213+ // we start with 2 unpinned items
214+ QCOMPARE(launcherModel->get(0)->pinned(), false);
215+ QCOMPARE(launcherModel->get(1)->pinned(), false);
216+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
217+
218+ // find the Pin item in the quicklist
219+ QuickListModel *model = qobject_cast<QuickListModel*>(launcherModel->get(0)->quickList());
220+ int pinActionIndex = -1;
221+ for (int i = 0; i < model->rowCount(QModelIndex()); ++i) {
222+ if (model->get(i).actionId() == "pin_item") {
223+ pinActionIndex = i;
224+ break;
225+ }
226+ }
227+ QVERIFY(pinActionIndex >= 0);
228+
229+ // trigger pin item quicklist action => Item must be pinned now.
230+ launcherModel->quickListActionInvoked(launcherModel->get(0)->appId(), pinActionIndex);
231+ QCOMPARE(launcherModel->get(0)->pinned(), true);
232+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
233+
234+ // quicklist needs to transform to remove item. trigger it and check it item goes away
235+ launcherModel->quickListActionInvoked(launcherModel->get(0)->appId(), pinActionIndex);
236+ QCOMPARE(launcherModel->get(0)->pinned(), false);
237+
238+ // still needs to be here as the app is still here
239+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
240+ // close the app
241+ appManager->removeApplication(0);
242+ // Now it needs to go away
243+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
244+ }
245+
246+ void testApplicationFocused() {
247+ // all apps unfocused at beginning...
248+ QCOMPARE(launcherModel->get(0)->focused(), false);
249+ QCOMPARE(launcherModel->get(1)->focused(), false);
250+
251+ appManager->focusApplication("abs-icon");
252+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
253+ QCOMPARE(launcherModel->get(0)->focused(), true);
254+ QCOMPARE(launcherModel->get(1)->focused(), false);
255+
256+ appManager->focusApplication("no-icon");
257+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
258+ QCOMPARE(launcherModel->get(0)->focused(), false);
259+ QCOMPARE(launcherModel->get(1)->focused(), true);
260+ }
261+
262+ void testClosingApps() {
263+ // At the start there are 2 items. Let's pin one.
264+ launcherModel->pin("abs-icon");
265+ while (appManager->count() > 0) {
266+ appManager->removeApplication(0);
267+ }
268+ // The pinned one needs to stay, the other needs to disappear
269+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
270+ QCOMPARE(launcherModel->get(0)->appId(), QLatin1String("abs-icon"));
271+ }
272+};
273+
274+QTEST_GUILESS_MAIN(LauncherModelTest)
275+#include "launchermodeltest.moc"
tests/plugins/Unity/Launcher/no-icon.desktopnew file+2
@@ -0,0 +1,2 @@
1+[Desktop Entry]
2+Name=No Icon
tests/plugins/Unity/Launcher/no-name.desktopnew file+2
@@ -0,0 +1,2 @@
1+[Desktop Entry]
2+Icon=no-name
tests/plugins/Unity/Launcher/rel-icon.desktopnew file+3
@@ -0,0 +1,3 @@
1+[Desktop Entry]
2+Name=Relative Icon
3+Icon=rel-icon.svg
tests/plugins/Unity/Launcher/rel-icon.svgnew file

No changes to the content.

tests/plugins/Unity/filtersbindingstest.cpp+61−30
@@ -65,17 +65,17 @@ DeeModel* FiltersBindingsTest::createFilterModel()
65
65
66void FiltersBindingsTest::createMultiRangeFilter(DeeModel *model, const std::string &id, const std::string &name, int optionCount)
66void FiltersBindingsTest::createMultiRangeFilter(DeeModel *model, const std::string &id, const std::string &name, int optionCount)
67{
67{
68− createFilter(model, "filter-multirange", id, name, optionCount);
68+ createFilter(model, "filter-multirange", id, name, optionCount, true);
69}
69}
70
70
71void FiltersBindingsTest::createRadioOptionFilter(DeeModel *model, const std::string &id, const std::string &name, int optionCount)
71void FiltersBindingsTest::createRadioOptionFilter(DeeModel *model, const std::string &id, const std::string &name, int optionCount)
72{
72{
73− createFilter(model, "filter-radiooption", id, name, optionCount);
73+ createFilter(model, "filter-radiooption", id, name, optionCount, true);
74}
74}
75
75
76void FiltersBindingsTest::createCheckOptionFilter(DeeModel *model, const std::string &id, const std::string &name, int optionCount)
76void FiltersBindingsTest::createCheckOptionFilter(DeeModel *model, const std::string &id, const std::string &name, int optionCount)
77{
77{
78− createFilter(model, "filter-checkoption", id, name, optionCount);
78+ createFilter(model, "filter-checkoption", id, name, optionCount, true);
79}
79}
80
80
81void FiltersBindingsTest::createRatingsFilter(DeeModel *model, const std::string &id, const std::string &name)
81void FiltersBindingsTest::createRatingsFilter(DeeModel *model, const std::string &id, const std::string &name)
@@ -90,7 +90,7 @@ void FiltersBindingsTest::createRatingsFilter(DeeModel *model, const std::string
90 GVariant *children[2];
90 GVariant *children[2];
91 GVariant *key1 = g_variant_new_string("show-all-button");
91 GVariant *key1 = g_variant_new_string("show-all-button");
92 GVariant *key2 = g_variant_new_string("rating");
92 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)));
94 children[1] = g_variant_new_dict_entry(key2, g_variant_new_variant(g_variant_new_double(0.0f)));
94 children[1] = g_variant_new_dict_entry(key2, g_variant_new_variant(g_variant_new_double(0.0f)));
95 auto fhints = g_variant_new_array(G_VARIANT_TYPE("{sv}"), children, 2);
95 auto fhints = g_variant_new_array(G_VARIANT_TYPE("{sv}"), children, 2);
96
96
@@ -102,7 +102,7 @@ void FiltersBindingsTest::createRatingsFilter(DeeModel *model, const std::string
102 dee_model_append_row(model, row);
102 dee_model_append_row(model, row);
103}
103}
104
104
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)
106{
106{
107 GVariant* row[8];
107 GVariant* row[8];
108
108
@@ -114,7 +114,7 @@ void FiltersBindingsTest::createFilter(DeeModel *model, const std::string &rende
114 GVariant *children[2];
114 GVariant *children[2];
115 GVariant *key1 = g_variant_new_string("show-all-button");
115 GVariant *key1 = g_variant_new_string("show-all-button");
116 GVariant *key2 = g_variant_new_string("options");
116 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)));
118 children[1] = g_variant_new_dict_entry(key2, g_variant_new_variant(createOptions(optionCount)));
118 children[1] = g_variant_new_dict_entry(key2, g_variant_new_variant(createOptions(optionCount)));
119 auto fhints = g_variant_new_array(G_VARIANT_TYPE("{sv}"), children, 2);
119 auto fhints = g_variant_new_array(G_VARIANT_TYPE("{sv}"), children, 2);
120
120
@@ -143,9 +143,9 @@ void FiltersBindingsTest::testMultiRangeFilter()
143 auto multi_filter = dynamic_cast<MultiRangeFilter*>(bind_filter);
143 auto multi_filter = dynamic_cast<MultiRangeFilter*>(bind_filter);
144 QVERIFY(multi_filter != nullptr);
144 QVERIFY(multi_filter != nullptr);
145 auto options = multi_filter->options();
145 auto options = multi_filter->options();
146− QCOMPARE(options->rowCount(), 1);
146+ QCOMPARE(options->rowCount(), 2);
147
147
148− auto idx = options->index(0);
148+ auto idx = options->index(1);
149 QVariant id_var = options->data(idx, GenericOptionsModel::RoleId);
149 QVariant id_var = options->data(idx, GenericOptionsModel::RoleId);
150 QVariant name_var = options->data(idx, GenericOptionsModel::RoleName);
150 QVariant name_var = options->data(idx, GenericOptionsModel::RoleName);
151 QVariant icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
151 QVariant icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
@@ -168,9 +168,9 @@ void FiltersBindingsTest::testMultiRangeFilter()
168 auto multi_filter = dynamic_cast<MultiRangeFilter*>(bind_filter);
168 auto multi_filter = dynamic_cast<MultiRangeFilter*>(bind_filter);
169 QVERIFY(multi_filter != nullptr);
169 QVERIFY(multi_filter != nullptr);
170 auto options = multi_filter->options();
170 auto options = multi_filter->options();
171− QCOMPARE(options->rowCount(), 2);
171+ QCOMPARE(options->rowCount(), 3);
172
172
173− auto idx = options->index(0);
173+ auto idx = options->index(1);
174 QVariant id_var = options->data(idx, GenericOptionsModel::RoleId);
174 QVariant id_var = options->data(idx, GenericOptionsModel::RoleId);
175 QVariant name_var = options->data(idx, GenericOptionsModel::RoleName);
175 QVariant name_var = options->data(idx, GenericOptionsModel::RoleName);
176 QVariant icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
176 QVariant icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
@@ -181,10 +181,10 @@ void FiltersBindingsTest::testMultiRangeFilter()
181 QCOMPARE(icon_var.toString(), QString(""));
181 QCOMPARE(icon_var.toString(), QString(""));
182 QCOMPARE(active_var.toBool(), false);
182 QCOMPARE(active_var.toBool(), false);
183
183
184− AbstractFilterOption* opt1 = options->getRawOption(0);
184+ AbstractFilterOption* opt1 = options->getRawOption(1);
185 QCOMPARE(opt1->id(), QString("opt0"));
185 QCOMPARE(opt1->id(), QString("opt0"));
186
186
187− AbstractFilterOption* opt2 = options->getRawOption(1);
187+ AbstractFilterOption* opt2 = options->getRawOption(2);
188 QCOMPARE(opt2->id(), QString("opt1"));
188 QCOMPARE(opt2->id(), QString("opt1"));
189
189
190 delete multi_filter;
190 delete multi_filter;
@@ -199,18 +199,21 @@ void FiltersBindingsTest::testMultiRangeFilter()
199 auto multi_filter = dynamic_cast<MultiRangeFilter*>(bind_filter);
199 auto multi_filter = dynamic_cast<MultiRangeFilter*>(bind_filter);
200 QVERIFY(multi_filter != nullptr);
200 QVERIFY(multi_filter != nullptr);
201 auto options = multi_filter->options();
201 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::"));
203
206
204− AbstractFilterOption* opt0 = options->getRawOption(0);
207+ AbstractFilterOption* opt0 = options->getRawOption(1);
205 QCOMPARE(opt0->id(), QString("opt0"));
208 QCOMPARE(opt0->id(), QString("opt0"));
206
209
207− AbstractFilterOption* opt1 = options->getRawOption(1);
210+ AbstractFilterOption* opt1 = options->getRawOption(2);
208 QCOMPARE(opt1->id(), QString("opt1"));
211 QCOMPARE(opt1->id(), QString("opt1"));
209
212
210− AbstractFilterOption* opt2 = options->getRawOption(2);
213+ AbstractFilterOption* opt2 = options->getRawOption(3);
211 QCOMPARE(opt2->id(), QString("opt2"));
214 QCOMPARE(opt2->id(), QString("opt2"));
212
215
213− // verify combined filter options are bound to correct underlying unity options
216+ // verify filter options are bound to correct underlying unity options
214 auto core_multi_filter = std::dynamic_pointer_cast<unity::dash::MultiRangeFilter>(core_filter);
217 auto core_multi_filter = std::dynamic_pointer_cast<unity::dash::MultiRangeFilter>(core_filter);
215 QCOMPARE(QString::fromStdString(core_multi_filter->options()[0]->id()), QString("opt0"));
218 QCOMPARE(QString::fromStdString(core_multi_filter->options()[0]->id()), QString("opt0"));
216 QCOMPARE(QString::fromStdString(core_multi_filter->options()[1]->id()), QString("opt1"));
219 QCOMPARE(QString::fromStdString(core_multi_filter->options()[1]->id()), QString("opt1"));
@@ -274,7 +277,7 @@ void FiltersBindingsTest::testCheckOptionFilter()
274 auto check_filter = dynamic_cast<CheckOptionFilter*>(bind_filter);
277 auto check_filter = dynamic_cast<CheckOptionFilter*>(bind_filter);
275 QVERIFY(check_filter != nullptr);
278 QVERIFY(check_filter != nullptr);
276 auto options = check_filter->options();
279 auto options = check_filter->options();
277− QCOMPARE(options->rowCount(), 3);
280+ QCOMPARE(options->rowCount(), 4);
278
281
279 QCOMPARE(check_filter->id(), QString("f1"));
282 QCOMPARE(check_filter->id(), QString("f1"));
280 QCOMPARE(check_filter->name(), QString("Filter1"));
283 QCOMPARE(check_filter->name(), QString("Filter1"));
@@ -284,7 +287,7 @@ void FiltersBindingsTest::testCheckOptionFilter()
284 QCOMPARE(check_filter->collapsed(), false);
287 QCOMPARE(check_filter->collapsed(), false);
285 QCOMPARE(check_filter->filtering(), false);
288 QCOMPARE(check_filter->filtering(), false);
286
289
287− auto idx = options->index(0);
290+ auto idx = options->index(1);
288 QVariant id_var = options->data(idx, GenericOptionsModel::RoleId);
291 QVariant id_var = options->data(idx, GenericOptionsModel::RoleId);
289 QVariant name_var = options->data(idx, GenericOptionsModel::RoleName);
292 QVariant name_var = options->data(idx, GenericOptionsModel::RoleName);
290 QVariant icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
293 QVariant icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
@@ -295,7 +298,7 @@ void FiltersBindingsTest::testCheckOptionFilter()
295 QCOMPARE(icon_var.toString(), QString(""));
298 QCOMPARE(icon_var.toString(), QString(""));
296 QCOMPARE(active_var.toBool(), false);
299 QCOMPARE(active_var.toBool(), false);
297
300
298− idx = options->index(1);
301+ idx = options->index(2);
299 id_var = options->data(idx, GenericOptionsModel::RoleId);
302 id_var = options->data(idx, GenericOptionsModel::RoleId);
300 name_var = options->data(idx, GenericOptionsModel::RoleName);
303 name_var = options->data(idx, GenericOptionsModel::RoleName);
301 icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
304 icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
@@ -306,38 +309,55 @@ void FiltersBindingsTest::testCheckOptionFilter()
306 QCOMPARE(icon_var.toString(), QString(""));
309 QCOMPARE(icon_var.toString(), QString(""));
307 QCOMPARE(active_var.toBool(), false);
310 QCOMPARE(active_var.toBool(), false);
308
311
312+ AbstractFilterOption* showAll = options->getRawOption(0);
309− AbstractFilterOption* opt0 = options->getRawOption(0);
313+ AbstractFilterOption* opt0 = options->getRawOption(1);
310− AbstractFilterOption* opt1 = options->getRawOption(1);
314+ AbstractFilterOption* opt1 = options->getRawOption(2);
311− AbstractFilterOption* opt2 = options->getRawOption(2);
315+ AbstractFilterOption* opt2 = options->getRawOption(3);
312
316
317+ QSignalSpy showAllSpy(showAll, SIGNAL(activeChanged(bool)));
313 QSignalSpy opt0spy(opt0, SIGNAL(activeChanged(bool)));
318 QSignalSpy opt0spy(opt0, SIGNAL(activeChanged(bool)));
314 QSignalSpy opt1spy(opt1, SIGNAL(activeChanged(bool)));
319 QSignalSpy opt1spy(opt1, SIGNAL(activeChanged(bool)));
315 QSignalSpy opt2spy(opt2, SIGNAL(activeChanged(bool)));
320 QSignalSpy opt2spy(opt2, SIGNAL(activeChanged(bool)));
316 QSignalSpy dataChangedSpy(options, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&)));
321 QSignalSpy dataChangedSpy(options, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&)));
317
322
318 // test active property changes
323 // test active property changes
324+ QCOMPARE(showAll->active(), false);
319 QCOMPARE(opt0->active(), false);
325 QCOMPARE(opt0->active(), false);
320 QCOMPARE(opt1->active(), false);
326 QCOMPARE(opt1->active(), false);
321 QCOMPARE(opt2->active(), false);
327 QCOMPARE(opt2->active(), false);
322
328
323 opt0->setActive(true);
329 opt0->setActive(true);
330+ QCOMPARE(showAllSpy.count(), 0);
324 QCOMPARE(opt0spy.count(), 1);
331 QCOMPARE(opt0spy.count(), 1);
325 QCOMPARE(opt1spy.count(), 0);
332 QCOMPARE(opt1spy.count(), 0);
326 QCOMPARE(opt2spy.count(), 0);
333 QCOMPARE(opt2spy.count(), 0);
334+ QCOMPARE(showAll->active(), false);
327 QCOMPARE(opt0->active(), true);
335 QCOMPARE(opt0->active(), true);
328 QCOMPARE(opt1->active(), false);
336 QCOMPARE(opt1->active(), false);
329 QCOMPARE(opt2->active(), false);
337 QCOMPARE(opt2->active(), false);
330
338
331 opt1->setActive(true);
339 opt1->setActive(true);
340+ QCOMPARE(showAllSpy.count(), 0);
332 QCOMPARE(opt0spy.count(), 2);
341 QCOMPARE(opt0spy.count(), 2);
333 QCOMPARE(opt1spy.count(), 1);
342 QCOMPARE(opt1spy.count(), 1);
334 QCOMPARE(opt2spy.count(), 0);
343 QCOMPARE(opt2spy.count(), 0);
344+ QCOMPARE(showAll->active(), false);
335 QCOMPARE(opt0->active(), false);
345 QCOMPARE(opt0->active(), false);
336 QCOMPARE(opt1->active(), true);
346 QCOMPARE(opt1->active(), true);
337 QCOMPARE(opt2->active(), false);
347 QCOMPARE(opt2->active(), false);
338
348
339 QCOMPARE(dataChangedSpy.count(), 3);
349 QCOMPARE(dataChangedSpy.count(), 3);
340
350
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+
341 delete check_filter;
361 delete check_filter;
342 }
362 }
343}
363}
@@ -357,7 +377,7 @@ void FiltersBindingsTest::testRadioOptionFilter()
357 auto radio_filter = dynamic_cast<RadioOptionFilter*>(bind_filter);
377 auto radio_filter = dynamic_cast<RadioOptionFilter*>(bind_filter);
358 QVERIFY(radio_filter != nullptr);
378 QVERIFY(radio_filter != nullptr);
359 auto options = radio_filter->options();
379 auto options = radio_filter->options();
360− QCOMPARE(options->rowCount(), 3);
380+ QCOMPARE(options->rowCount(), 4);
361
381
362 auto idx = options->index(0);
382 auto idx = options->index(0);
363 QVariant id_var = options->data(idx, GenericOptionsModel::RoleId);
383 QVariant id_var = options->data(idx, GenericOptionsModel::RoleId);
@@ -365,12 +385,23 @@ void FiltersBindingsTest::testRadioOptionFilter()
365 QVariant icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
385 QVariant icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
366 QVariant active_var = options->data(idx, GenericOptionsModel::RoleActive);
386 QVariant active_var = options->data(idx, GenericOptionsModel::RoleActive);
367
387
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+
368 QCOMPARE(id_var.toString(), QString("opt0"));
399 QCOMPARE(id_var.toString(), QString("opt0"));
369 QCOMPARE(name_var.toString(), QString("Option 0"));
400 QCOMPARE(name_var.toString(), QString("Option 0"));
370 QCOMPARE(icon_var.toString(), QString(""));
401 QCOMPARE(icon_var.toString(), QString(""));
371 QCOMPARE(active_var.toBool(), false);
402 QCOMPARE(active_var.toBool(), false);
372
403
373− idx = options->index(1);
404+ idx = options->index(2);
374 id_var = options->data(idx, GenericOptionsModel::RoleId);
405 id_var = options->data(idx, GenericOptionsModel::RoleId);
375 name_var = options->data(idx, GenericOptionsModel::RoleName);
406 name_var = options->data(idx, GenericOptionsModel::RoleName);
376 icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
407 icon_var = options->data(idx, GenericOptionsModel::RoleIconHint);
@@ -381,9 +412,9 @@ void FiltersBindingsTest::testRadioOptionFilter()
381 QCOMPARE(icon_var.toString(), QString(""));
412 QCOMPARE(icon_var.toString(), QString(""));
382 QCOMPARE(active_var.toBool(), false);
413 QCOMPARE(active_var.toBool(), false);
383
414
384− AbstractFilterOption* opt0 = options->getRawOption(0);
415+ AbstractFilterOption* opt0 = options->getRawOption(1);
385− AbstractFilterOption* opt1 = options->getRawOption(1);
416+ AbstractFilterOption* opt1 = options->getRawOption(2);
386− AbstractFilterOption* opt2 = options->getRawOption(2);
417+ AbstractFilterOption* opt2 = options->getRawOption(3);
387
418
388 QSignalSpy opt0spy(opt0, SIGNAL(activeChanged(bool)));
419 QSignalSpy opt0spy(opt0, SIGNAL(activeChanged(bool)));
389 QSignalSpy opt1spy(opt1, SIGNAL(activeChanged(bool)));
420 QSignalSpy opt1spy(opt1, SIGNAL(activeChanged(bool)));
@@ -432,11 +463,11 @@ void FiltersBindingsTest::testRatingsFilter()
432 auto rating_filter = dynamic_cast<RatingsFilter*>(bind_filter);
463 auto rating_filter = dynamic_cast<RatingsFilter*>(bind_filter);
433 QVERIFY(rating_filter != nullptr);
464 QVERIFY(rating_filter != nullptr);
434 auto options = rating_filter->options();
465 auto options = rating_filter->options();
435− QCOMPARE(options->rowCount(), 5);
466+ QCOMPARE(options->rowCount(), 6);
436
467
437 RatingFilterOption* opt[5];
468 RatingFilterOption* opt[5];
438 for (int i = 0; i<5; i++) {
469 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));
440 }
471 }
441
472
442 QSignalSpy opt0spy(opt[0], SIGNAL(activeChanged(bool)));
473 QSignalSpy opt0spy(opt[0], SIGNAL(activeChanged(bool)));
tests/plugins/Unity/filtersbindingstest.h+1−1
@@ -41,7 +41,7 @@ class FiltersBindingsTest : public QObject
41 void createCheckOptionFilter(DeeModel *model, const std::string &id, const std::string &name, int optionCount);
41 void createCheckOptionFilter(DeeModel *model, const std::string &id, const std::string &name, int optionCount);
42 void createRadioOptionFilter(DeeModel *model, const std::string &id, const std::string &name, int optionCount);
42 void createRadioOptionFilter(DeeModel *model, const std::string &id, const std::string &name, int optionCount);
43 void createRatingsFilter(DeeModel *model, const std::string &id, const std::string &name);
43 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);
45};
45};
46
46
47#endif // FILTERSBINDINGSTEST_H
47#endif // FILTERSBINDINGSTEST_H
tests/plugins/Unity/previewbindingstest.cpp+27
@@ -19,6 +19,7 @@
19
19
20#include <UnityCore/Preview.h>
20#include <UnityCore/Preview.h>
21#include <UnityCore/GLibWrapper.h>
21#include <UnityCore/GLibWrapper.h>
22+#include <UnityCore/Variant.h>
22#include <unity-protocol.h>
23#include <unity-protocol.h>
23
24
24#include "genericpreview.h"
25#include "genericpreview.h"
@@ -48,7 +49,23 @@ void PreviewBindingsTest::testGenericPreview()
48 UNITY_PROTOCOL_LAYOUT_HINT_LEFT);
49 UNITY_PROTOCOL_LAYOUT_HINT_LEFT);
49 unity::glib::Object<GObject> genPrv(rawPreview);
50 unity::glib::Object<GObject> genPrv(rawPreview);
50
51
52+ // create local result
53+ unity::glib::HintsMap hints;
54+ hints["a"] = unity::glib::Variant(g_variant_new_string("b"));
55+ unity::dash::LocalResult localResult;
56+ localResult.uri = "http://foo";
57+ localResult.icon_hint = "xyz";
58+ localResult.category_index = 1;
59+ localResult.result_type = 2;
60+ localResult.mimetype = "abc";
61+ localResult.name = "baz";
62+ localResult.comment = "qwerty";
63+ localResult.dnd_uri = "zzz";
64+ localResult.hints = hints;
65+
51 auto corePrv = unity::dash::Preview::PreviewForProtocolObject(genPrv);
66 auto corePrv = unity::dash::Preview::PreviewForProtocolObject(genPrv);
67+ corePrv->preview_result = localResult;
68+
52 auto prv = Preview::newFromUnityPreview(corePrv);
69 auto prv = Preview::newFromUnityPreview(corePrv);
53
70
54 QCOMPARE(prv != nullptr, true);
71 QCOMPARE(prv != nullptr, true);
@@ -64,6 +81,16 @@ void PreviewBindingsTest::testGenericPreview()
64 QCOMPARE(act->displayName(), QString("Action1"));
81 QCOMPARE(act->displayName(), QString("Action1"));
65 QCOMPARE(act->iconHint(), QString("/foo.png"));
82 QCOMPARE(act->iconHint(), QString("/foo.png"));
66
83
84+ Result* res = prv->result().value<Result*>();
85+ QCOMPARE(res->uri(), QString("http://foo"));
86+ QCOMPARE(res->iconHint(), QString("xyz"));
87+ QCOMPARE(res->categoryIndex(), 1u);
88+ QCOMPARE(res->resultType(), 2u);
89+ QCOMPARE(res->mimeType(), QString("abc"));
90+ QCOMPARE(res->title(), QString("baz"));
91+ QCOMPARE(res->dndUri(), QString("zzz"));
92+ QCOMPARE(res->metadata().toHash()["a"].toString(), QString("b"));
93+
67 g_object_unref(icon);
94 g_object_unref(icon);
68 g_object_unref(iconFile);
95 g_object_unref(iconFile);
69}
96}
tests/plugins/Unity/resultstest.cppnew file+105
@@ -0,0 +1,105 @@
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:
17+ * Michal Hruby <michal.hruby@canonical.com>
18+ */
19+
20+#include <QTest>
21+#include <dee.h>
22+
23+#include "resultstest.h"
24+#include "categoryresults.h"
25+
26+static DeeModel* createBackendModel()
27+{
28+ auto model = dee_sequence_model_new();
29+ dee_model_set_schema(model, "s", "s", "u", "u", "s", "s", "s", "s", "a{sv}", NULL);
30+
31+ return model;
32+}
33+
34+void ResultsTest::testAllColumns()
35+{
36+ auto deeModel = createBackendModel();
37+ GVariantBuilder builder;
38+ g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
39+ g_variant_builder_add(&builder, "{sv}", "metadata-field", g_variant_new_string("foo"));
40+ dee_model_append (deeModel,
41+ "test:uri",
42+ "themed-icon",
43+ 4,
44+ 0,
45+ "application/octet-stream",
46+ "Test",
47+ "Comment",
48+ "test:dnd-uri",
49+ g_variant_builder_end(&builder));
50+
51+ CategoryResults* results = new CategoryResults(this);
52+ results->setModel(deeModel);
53+
54+ auto index = results->index(0, 0); // there's just one result
55+ QCOMPARE(index.data(CategoryResults::Roles::RoleUri).toString(), QString("test:uri"));
56+ QCOMPARE(index.data(CategoryResults::Roles::RoleIconHint).toString(), QString("image://theme/themed-icon"));
57+ QCOMPARE(index.data(CategoryResults::Roles::RoleCategory).toInt(), 4);
58+ QCOMPARE(index.data(CategoryResults::Roles::RoleMimetype).toString(), QString("application/octet-stream"));
59+ QCOMPARE(index.data(CategoryResults::Roles::RoleTitle).toString(), QString("Test"));
60+ QCOMPARE(index.data(CategoryResults::Roles::RoleComment).toString(), QString("Comment"));
61+ QCOMPARE(index.data(CategoryResults::Roles::RoleDndUri).toString(), QString("test:dnd-uri"));
62+ auto metadata = index.data(CategoryResults::Roles::RoleMetadata).toHash();
63+ QCOMPARE(metadata["metadata-field"].toString(), QString("foo"));
64+}
65+
66+void ResultsTest::testIconColumn_data()
67+{
68+ QTest::addColumn<QString>("giconString");
69+ QTest::addColumn<QString>("result");
70+
71+ QTest::newRow("absolute path") << "/usr/share/icons/example.png" << "/usr/share/icons/example.png";
72+ QTest::newRow("file uri") << "file:///usr/share/icons/example.png" << "file:///usr/share/icons/example.png";
73+ QTest::newRow("http uri") << "http://images.ubuntu.com/example.jpg" << "http://images.ubuntu.com/example.jpg";
74+ QTest::newRow("image uri") << "image://thumbnail/with/arguments?passed_to=ImageProvider" << "image://thumbnail/with/arguments?passed_to=ImageProvider";
75+ QTest::newRow("themed icon") << "accessories-other" << "image://theme/accessories-other";
76+ QTest::newRow("fileicon") << ". GFileIcon http://example.org/resource.gif" << "http://example.org/resource.gif";
77+ QTest::newRow("themedicon") << ". GThemedIcon accessories-other accessories generic" << "image://theme/accessories-other,accessories,generic";
78+ QTest::newRow("annotatedicon") << ". UnityProtocolAnnotatedIcon %7B'base-icon':%20%3C'.%20GThemedIcon%20accessories-other%20accessories%20generic'%3E%7D" << "image://theme/accessories-other,accessories,generic";
79+}
80+
81+void ResultsTest::testIconColumn()
82+{
83+ QFETCH(QString, giconString);
84+ QFETCH(QString, result);
85+ auto deeModel = createBackendModel();
86+ dee_model_append (deeModel,
87+ "test:uri",
88+ giconString.toLocal8Bit().constData(),
89+ 0,
90+ 0,
91+ "application/octet-stream",
92+ "Test",
93+ "",
94+ "test:dnd-uri",
95+ g_variant_new_array(g_variant_type_element(G_VARIANT_TYPE_VARDICT), NULL, 0));
96+
97+ CategoryResults* results = new CategoryResults(this);
98+ results->setModel(deeModel);
99+
100+ auto index = results->index(0, 0); // there's just one result
101+ auto transformedIcon = index.data(CategoryResults::Roles::RoleIconHint).toString();
102+ QCOMPARE(transformedIcon, result);
103+}
104+
105+QTEST_MAIN(ResultsTest)
tests/plugins/Unity/resultstest.hnew file+35
@@ -0,0 +1,35 @@
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:
17+ * Michal Hruby <michal.hruby@canonical.com>
18+ */
19+
20+#ifndef RESULTSTEST_H
21+#define RESULTSTEST_H
22+
23+#include <QObject>
24+
25+class ResultsTest : public QObject
26+{
27+ Q_OBJECT
28+
29+ private Q_SLOTS:
30+ void testAllColumns();
31+ void testIconColumn_data();
32+ void testIconColumn();
33+};
34+
35+#endif
tests/qmltests/CMakeLists.txt+2−2
@@ -13,7 +13,6 @@ set(qmltest_DEFAULT_NO_ADD_TEST FALSE)
13set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
13set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
14add_qml_test(Components AnimationControllerWithSignals)
14add_qml_test(Components AnimationControllerWithSignals)
15add_qml_test(Components Carousel)
15add_qml_test(Components Carousel)
16−add_qml_test(Components CrossFadeImage)
17add_qml_test(Components MathLocal)
16add_qml_test(Components MathLocal)
18add_qml_test(Components OpenEffect)
17add_qml_test(Components OpenEffect)
19add_qml_test(Components RatingStars)
18add_qml_test(Components RatingStars)
@@ -32,6 +31,7 @@ add_manual_qml_test(Components DragHandle IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugi
32add_qml_test(Components DraggingArea)
31add_qml_test(Components DraggingArea)
33add_qml_test(Components EdgeDemoOverlay)
32add_qml_test(Components EdgeDemoOverlay)
34add_qml_test(Components FilterGrid IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins)
33add_qml_test(Components FilterGrid IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins)
34+add_qml_test(Components LazyImage)
35add_qml_test(Components ResponsiveFlowView)
35add_qml_test(Components ResponsiveFlowView)
36add_qml_test(Components ResponsiveGridView)
36add_qml_test(Components ResponsiveGridView)
37add_qml_test(Components Revealer)
37add_qml_test(Components Revealer)
@@ -66,7 +66,7 @@ add_qml_test(Launcher Launcher IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltes
66add_qml_test(Notifications Notifications IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_SOURCE_DIR}/tests/mocks)
66add_qml_test(Notifications Notifications IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_SOURCE_DIR}/tests/mocks)
67add_qml_test(Panel IndicatorRow)
67add_qml_test(Panel IndicatorRow)
68add_qml_test(Panel Indicators IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
68add_qml_test(Panel Indicators IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
69−add_qml_test(Panel MenuContent)
69+add_qml_test(Panel MenuContent IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
70add_qml_test(Panel Panel IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
70add_qml_test(Panel Panel IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
71add_qml_test(Panel SearchIndicator)
71add_qml_test(Panel SearchIndicator)
72add_qml_test(SideStage SideStage IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS}
72add_qml_test(SideStage SideStage IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS}
tests/qmltests/Components/tst_CrossFadeImage.qmldeleted−125
@@ -1,125 +0,0 @@
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 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−import QtQuick 2.0
18−import QtTest 1.0
19−import "../../../Components"
20−
21−TestCase {
22− name: "CrossFadeImage"
23−
24− property alias status: crossFadeImage.status
25− property alias source: crossFadeImage.source
26− property alias crossFade: crossFadeImage.crossFade
27− property alias fadeInFirst: crossFadeImage.fadeInFirst
28− property alias running: crossFadeImage.running
29−
30− CrossFadeImage {
31− id: crossFadeImage
32− }
33−
34− SignalSpy {
35− id: signalSpy
36− target: crossFadeImage
37− }
38−
39− function initTestFunction(argCrossFade, argFadeInFirst) {
40− source = ""
41− crossFade = argCrossFade
42− fadeInFirst = argFadeInFirst
43− compare(status, Image.Null, "Could not reset CrossFadeImage")
44− }
45−
46− function loadImage(url) {
47− console.log("Loading image...")
48− source = url
49−
50− signalSpy.signalName = "statusChanged"
51− signalSpy.wait()
52−
53− if (status == Image.Null) {
54− signalSpy.clear()
55− signalSpy.wait()
56− }
57−
58− if (status == Image.Loading) {
59− signalSpy.clear()
60− signalSpy.wait()
61− }
62−
63− compare(status, Image.Ready, "Image not ready")
64− console.log("Image loaded.")
65− }
66−
67− function waitForAnimation() {
68− signalSpy.signalName = "runningChanged"
69−
70− if (!running) {
71− signalSpy.clear()
72− signalSpy.wait()
73− compare(running, true, "Animation did not start")
74− }
75−
76− signalSpy.clear()
77− console.log("Waiting for animation to finish...")
78− signalSpy.wait()
79− compare(running, false, "Animation did not stop within 5 seconds.")
80− }
81−
82− function cleanupTest() {
83− compare(running, false, "Animation is running after testcase")
84− compare(crossFadeImage.__nextImage.source, "", "nextimage source is not reset")
85− }
86−
87− function test_fadeFirst() {
88− initTestFunction(true, true)
89−
90− loadImage("../../../graphics/phone_background.jpg")
91−
92− waitForAnimation()
93−
94− cleanupTest()
95− }
96−
97− function test_no_fadeFirst() {
98− initTestFunction(true, false)
99−
100− loadImage("../../../graphics/phone_background.jpg")
101−
102− cleanupTest()
103− }
104−
105− function test_crossFade() {
106− initTestFunction(true, false)
107−
108− loadImage("../../../graphics/phone_background.jpg")
109−
110− loadImage("../../../graphics/tablet_background.jpg")
111−
112− // Due to the internal implementation, __currentImage and __nextImage are swapped before the animation starts
113− // Make sure z order reflects that too.
114− compare(crossFadeImage.__currentImage.z > crossFadeImage.__nextImage.z, true, "new image should be above old image")
115− compare(crossFadeImage.__currentImage.opacity < 0.5, true)
116− compare(crossFadeImage.__nextImage.opacity > 0.5, true)
117−
118− waitForAnimation()
119−
120− compare(crossFadeImage.__currentImage.opacity > 0.5, true)
121− compare(crossFadeImage.__nextImage.opacity < 0.5, true)
122−
123− cleanupTest()
124− }
125−}
tests/qmltests/Components/tst_LazyImage.qmlnew file+156
@@ -0,0 +1,156 @@
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 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+import QtQuick 2.0
18+import QtTest 1.0
19+import "../../../Components"
20+import Ubuntu.Components 0.1
21+import Unity.Test 0.1 as UT
22+import "tst_LazyImage"
23+
24+Rectangle {
25+ width: units.gu(120)
26+ height: units.gu(70)
27+
28+ Rectangle {
29+ id: baseRect
30+ anchors {
31+ fill: parent
32+ rightMargin: 2 * parent.width / 3
33+ }
34+
35+ color: "grey"
36+
37+ Column {
38+ anchors { fill: parent; margins: units.gu(5) }
39+
40+ Label {
41+ height: units.gu(4)
42+ text: "Unbound"
43+ color: "white"
44+ verticalAlignment: Text.AlignBottom
45+ }
46+
47+ LazyImage {
48+ id: lazy1
49+ }
50+
51+ Label {
52+ height: units.gu(4)
53+ text: "Width-bound"
54+ color: "white"
55+ verticalAlignment: Text.AlignBottom
56+ }
57+
58+ LazyImage {
59+ id: lazy2
60+ width: units.gu(30)
61+ scaleTo: "width"
62+ }
63+
64+ Label {
65+ height: units.gu(4)
66+ text: "Height-bound"
67+ color: "white"
68+ verticalAlignment: Text.AlignBottom
69+ }
70+
71+ LazyImage {
72+ id: lazy3
73+ height: units.gu(10)
74+ scaleTo: "height"
75+ }
76+ }
77+ }
78+
79+ Rectangle {
80+ id: controlsRect
81+ anchors {
82+ fill: parent
83+ leftMargin: parent.width / 3
84+ }
85+
86+ color: "lightgrey"
87+
88+ Column {
89+ id: controls
90+ spacing: units.gu(1)
91+
92+ anchors { fill: parent; margins: units.gu(3) }
93+
94+ ImageControls { id: controls1; image: lazy1 }
95+ ImageControls { id: controls2; image: lazy2 }
96+ ImageControls { id: controls3; image: lazy3 }
97+ }
98+ }
99+
100+ UT.UnityTestCase {
101+ name: "Stage"
102+ when: windowShown
103+
104+ function cleanup() {
105+ controls1.blank();
106+ tryCompare(lazy1, "width", units.gu(10));
107+ controls2.blank();
108+ tryCompare(lazy2, "height", units.gu(10));
109+ controls3.blank();
110+ tryCompare(lazy3, "width", units.gu(10));
111+ }
112+
113+ function test_lazyimage_data() {
114+ return [
115+ {tag: "Unbound Blank", image: lazy1, func: controls1.blank, width: units.gu(10), height: units.gu(10), placeholder: true},
116+ {tag: "Unbound Wide", image: lazy1, func: controls1.wide, transition: "readyTransition", width: 160, height: 80},
117+ {tag: "Unbound Square", image: lazy1, func: controls1.square, transition: "readyTransition", width: 160, height: 160},
118+ {tag: "Unbound Portrait", image: lazy1, func: controls1.portrait, transition: "readyTransition", width: 80, height: 160},
119+ {tag: "Unbound Bad path", image: lazy1, func: controls1.badpath, transition: "genericTransition", width: units.gu(10), height: units.gu(10), placeholder: true, error: true},
120+ {tag: "Width-bound Blank", image: lazy2, func: controls2.blank, width: units.gu(30), height: units.gu(10), placeholder: true},
121+ {tag: "Width-bound Wide", image: lazy2, func: controls2.wide, transition: "readyTransition", width: units.gu(30), height: units.gu(15)},
122+ {tag: "Width-bound Square", image: lazy2, func: controls2.square, transition: "readyTransition", width: units.gu(30), height: units.gu(30)},
123+ {tag: "Width-bound Portrait", image: lazy2, func: controls2.portrait, transition: "readyTransition", width: units.gu(30), height: units.gu(60)},
124+ {tag: "Width-bound Bad path", image: lazy2, func: controls2.badpath, transition: "genericTransition", width: units.gu(30), height: units.gu(10), placeholder: true, error: true},
125+ {tag: "Height-bound Blank", image: lazy3, func: controls3.blank, width: units.gu(10), height: units.gu(10), placeholder: true},
126+ {tag: "Height-bound Wide", image: lazy3, func: controls3.wide, transition: "readyTransition", width: units.gu(20), height: units.gu(10)},
127+ {tag: "Height-bound Square", image: lazy3, func: controls3.square, transition: "readyTransition", width: units.gu(10), height: units.gu(10)},
128+ {tag: "Height-bound Portrait", image: lazy3, func: controls3.portrait, transition: "readyTransition", width: units.gu(5), height: units.gu(10)},
129+ {tag: "Height-bound Bad path", image: lazy3, func: controls3.badpath, transition: "genericTransition", width: units.gu(10), height: units.gu(10), placeholder: true, error: true},
130+ ]
131+ }
132+
133+ function test_lazyimage(data) {
134+ data.func();
135+
136+ if (data.transition) {
137+ // wait for the transition to complete
138+ var transition = findInvisibleChild(data.image, data.transition);
139+ tryCompare(transition, "running", true);
140+ tryCompare(transition, "running", false);
141+ }
142+
143+ // check the dimensions
144+ compare(data.image.width, data.width);
145+ compare(data.image.height, data.height);
146+
147+ // check the placeholder
148+ var placeholder = findChild(data.image, "placeholder");
149+ compare(placeholder.visible, data.placeholder ? true : false);
150+
151+ // check the error image
152+ var error = findChild(data.image, "errorImage");
153+ compare(error.visible, data.error ? true : false);
154+ }
155+ }
156+}
tests/qmltests/Components/tst_LazyImage/ImageControls.qmlnew file+67
@@ -0,0 +1,67 @@
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 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+import QtQuick 2.0
18+import Ubuntu.Components 0.1
19+import "../../../../Components"
20+
21+Row {
22+ property LazyImage image
23+
24+ anchors { left: parent.left; right: parent.right }
25+ spacing: units.gu(1)
26+
27+ function blank() { blankButton.clicked() }
28+ function wide() { wideButton.clicked() }
29+ function square() { squareButton.clicked() }
30+ function portrait() { portraitButton.clicked() }
31+ function badpath() { badpathButton.clicked() }
32+
33+ Button {
34+ id: blankButton
35+ width: parent / 5
36+ text: "Blank"
37+ onClicked: image.source = ""
38+ }
39+
40+ Button {
41+ id: wideButton
42+ width: parent / 5
43+ text: "Wide"
44+ onClicked: image.source = "wide.png"
45+ }
46+
47+ Button {
48+ id: squareButton
49+ width: parent / 5
50+ text: "Square"
51+ onClicked: image.source = "square.png"
52+ }
53+
54+ Button {
55+ id: portraitButton
56+ width: parent / 5
57+ text: "Portrait"
58+ onClicked: image.source = "portrait.png"
59+ }
60+
61+ Button {
62+ id: badpathButton
63+ width: parent / 5
64+ text: "Bad path"
65+ onClicked: image.source = "bad/path"
66+ }
67+}
tests/qmltests/Components/tst_LazyImage/portrait.pngnew file

Binary file not shown.

tests/qmltests/Components/tst_LazyImage/square.pngnew file

Binary file not shown.

tests/qmltests/Components/tst_LazyImage/wide.pngnew file

Binary file not shown.

tests/qmltests/Components/tst_Stage.qml+1−1
@@ -18,7 +18,7 @@ import QtQuick 2.0
18import QtTest 1.0
18import QtTest 1.0
19import ".."
19import ".."
20import "../../../Components"
20import "../../../Components"
21−import Ubuntu.Application 0.1
21+import Unity.Application 0.1
22import Ubuntu.Components 0.1
22import Ubuntu.Components 0.1
23import Unity.Test 0.1 as UT
23import Unity.Test 0.1 as UT
24import "tst_Stage"
24import "tst_Stage"
tests/qmltests/Dash/Apps/tst_AppPreview.qml+75−2
@@ -25,6 +25,9 @@ Item {
25 width: units.gu(60)
25 width: units.gu(60)
26 height: units.gu(80)
26 height: units.gu(80)
27
27
28+ // Fake shell
29+ QtObject { id: shell; property int height: appPreview.height }
30+
28 property var calls: []
31 property var calls: []
29
32
30 SignalSpy {
33 SignalSpy {
@@ -45,6 +48,8 @@ Item {
45 ["Unity User", 10, "10/02/2013", root.commentary],
48 ["Unity User", 10, "10/02/2013", root.commentary],
46 ]
49 ]
47 }
50 }
51+ QtObject { id: showProgress; property bool value: true }
52+ QtObject { id: progressSource; property string value: "service" }
48
53
49 QtObject {
54 QtObject {
50 id: data
55 id: data
@@ -66,8 +71,30 @@ Item {
66 ]
71 ]
67 }
72 }
68
73
74+ QtObject {
75+ id: dataProgress
76+ property string title: "Unity App"
77+ property string appIcon: "fake_image.png"
78+ property string description: "This is an Application description"
79+ property real rating: rating.value
80+ property int numRatings: reviews.value
81+ property var execute: root.fake_call
82+ property var infoMap: {
83+ "show_progressbar": showProgress,
84+ "more-screenshots": screenshots,
85+ "rated": rated,
86+ "comments": comments,
87+ "progressbar_source": progressSource
88+ }
89+ property var actions: [
90+ { "id": 123, "displayName": "action1" },
91+ { "id": 456, "displayName": "action2" },
92+ { "id": 789, "displayName": "action3" },
93+ ]
94+ }
95+
69 function fake_call(id, data){
96 function fake_call(id, data){
70− root.calls[root.calls.length] = id;
97+ root.calls[root.calls.length] = [id, data];
71 }
98 }
72
99
73 // The component under test
100 // The component under test
@@ -89,6 +116,10 @@ Item {
89 reviewField.focus = false;
116 reviewField.focus = false;
90 reviewField.text = "";
117 reviewField.text = "";
91 data.rating = rating.value;
118 data.rating = rating.value;
119+ dataProgress.infoMap["progressbar_source"].value = "service";
120+ var appReviews = findChild(appPreview, "appReviews");
121+ appReviews.visible = false;
122+ appPreview.keyboardSize = 0;
92 }
123 }
93
124
94 function test_actions() {
125 function test_actions() {
@@ -102,7 +133,7 @@ Item {
102
133
103 var actions = data.actions;
134 var actions = data.actions;
104 for(var i = 0; i < actions.length; i++) {
135 for(var i = 0; i < actions.length; i++) {
105− compare(root.calls[i], actions[i].id, "Id of action not found.");
136+ compare(root.calls[i][0], actions[i].id, "Id of action not found.");
106 }
137 }
107 }
138 }
108
139
@@ -124,6 +155,7 @@ Item {
124
155
125 function test_review_focus() {
156 function test_review_focus() {
126 var appReviews = findChild(appPreview, "appReviews");
157 var appReviews = findChild(appPreview, "appReviews");
158+ appReviews.visible = true;
127 var sendButton = findChild(appReviews, "sendButton");
159 var sendButton = findChild(appReviews, "sendButton");
128 var reviewField = findChild(appReviews, "reviewField");
160 var reviewField = findChild(appReviews, "reviewField");
129
161
@@ -162,5 +194,46 @@ Item {
162 verify(buttons.visible == true);
194 verify(buttons.visible == true);
163 }
195 }
164
196
197+ function test_progress_show() {
198+ appPreview.previewData = dataProgress;
199+ var progress = findChild(appPreview, "progressBar");
200+ verify(progress.visible == true);
201+ }
202+
203+ function test_progress_download_finish() {
204+ appPreview.previewData = dataProgress;
205+ var progress = findChild(appPreview, "progressBar");
206+ dataProgress.infoMap["progressbar_source"].value = "finish";
207+
208+ var actions = dataProgress.actions;
209+ compare(root.calls[0][0], actions[0].id, "Id of action not found.");
210+ compare(root.calls[0][1], {}, "Data of action not found.");
211+ }
212+
213+ function test_progress_download_error() {
214+ appPreview.previewData = dataProgress;
215+ var progress = findChild(appPreview, "progressBar");
216+ dataProgress.infoMap["progressbar_source"].value = "error";
217+
218+ var actions = dataProgress.actions;
219+ compare(root.calls[0][0], actions[1].id, "Id of action not found.");
220+ compare(root.calls[0][1], {"error": "DOWNLOAD ERROR"}, "Data of action not found.");
221+ }
222+
223+ function test_automatic_scroll_on_keyboard_shown() {
224+ waitForRendering(appPreview);
225+ var appReviews = findChild(appPreview, "appReviews");
226+ appReviews.visible = true;
227+
228+ var leftFlickable = findChild(appPreview, "leftFlickable");
229+ leftFlickable.contentY = leftFlickable.contentHeight;
230+ var reviewField = findChild(appReviews, "reviewField");
231+ appPreview.keyboardSize = 400;
232+ appReviews.editing(reviewField);
233+ var newFlickPos = leftFlickable.contentY;
234+ var keyboardY = shell.height - appPreview.keyboardSize;
235+ verify(newFlickPos < keyboardY);
236+ }
237+
165 }
238 }
166}
239}
tests/qmltests/Dash/Apps/tst_RunningApplicationsGrid.qml+55−37
@@ -16,7 +16,6 @@
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18import QtTest 1.0
18import QtTest 1.0
19−import Ubuntu.Application 0.1
20import "../../../../Dash/Apps"
19import "../../../../Dash/Apps"
21import Unity.Test 0.1 as UT
20import Unity.Test 0.1 as UT
22
21
@@ -29,8 +28,12 @@ Item {
29
28
30 property bool sideStageEnabled: false
29 property bool sideStageEnabled: false
31
30
32− function stopProcess(application) {
31+ function stopApplication(appId) {
32+ for (var i=0, len=fakeRunningAppsModel.count; i<len; i++) {
33+ if (appId == fakeRunningAppsModel.get(i).appId) {
33− fakeRunningAppsModel.remove(application)
34+ fakeRunningAppsModel.remove(i)
35+ }
36+ }
34 }
37 }
35 }
38 }
36
39
@@ -40,47 +43,62 @@ Item {
40 property bool stageScreenshotsReady: false
43 property bool stageScreenshotsReady: false
41 property var applicationManager: fakeApplicationManager
44 property var applicationManager: fakeApplicationManager
42
45
43− function activateApplication(desktopFile) {
46+ function activateApplication(appId) {
44 }
47 }
45 }
48 }
46
49
50+ ListModel {
47− ApplicationListModel { id: fakeRunningAppsModel }
51+ id: fakeRunningAppsModel
48−
52+
49− ApplicationInfo {
53+ function contains(appId) {
50− id: phoneApp
54+ for (var i=0, len=fakeRunningAppsModel.count; i<len; i++) {
51− name: "Phone"
55+ if (appId == fakeRunningAppsModel.get(i).appId) {
52− icon: "phone-app"
56+ return true;
53− exec: "/usr/bin/phone-app"
57+ }
54− stage: ApplicationInfo.MainStage
58+ }
55− desktopFile: "phone.desktop"
59+ return false;
56− imageQml: "import QtQuick 2.0\n" +
60+ }
57− "Rectangle { \n" +
61+
58− " anchors.fill:parent \n" +
62+ function rePopulate() {
59− " color:'darkgreen' \n" +
63+ for (var i=0, len=availableAppsModel.count; i<len; i++) {
60− " Text { anchors.centerIn: parent; text: 'PHONE' } \n" +
64+ fakeRunningAppsModel.append(availableAppsModel.get(i));
65+ }
61− "}"
66+ }
62 }
67 }
63
68
64− ApplicationInfo {
69+ ListModel {
65− id: calendarApp
70+ id: availableAppsModel
71+ ListElement {
72+ name: "Phone"
73+ icon: "phone-app"
74+ exec: "/usr/bin/phone-app"
75+ appId: "phone"
76+ imageQml: "import QtQuick 2.0\n \
77+ Rectangle { \n \
78+ anchors.fill:parent \n \
79+ color:'darkgreen' \n \
80+ Text { anchors.centerIn: parent; text: 'PHONE' } \n \
81+ }"
82+ }
83+
84+ ListElement {
66− name: "Calendar"
85+ name: "Calendar"
67− icon: "calendar-app"
86+ icon: "calendar-app"
68− exec: "/usr/bin/calendar-app"
87+ exec: "/usr/bin/calendar-app"
69− stage: ApplicationInfo.MainStage
70− desktopFile: "calendar.desktop"
88+ appId: "calendar"
71− imageQml: "import QtQuick 2.0\n" +
89+ imageQml: "import QtQuick 2.0\n \
72− "Rectangle { \n" +
90+ Rectangle { \n \
73− " anchors.fill:parent \n" +
91+ anchors.fill:parent \n \
74− " color:'darkblue' \n" +
92+ color:'darkblue' \n \
75− " Text { anchors.centerIn: parent; text: 'CALENDAR'\n" +
93+ Text { anchors.centerIn: parent; text: 'CALENDAR'\n \
76− " color:'white'} \n" +
94+ color:'white'} \n \
77− "}"
95+ }"
96+ }
78 }
97 }
79
98
80 function resetRunningApplications() {
99 function resetRunningApplications() {
81 fakeRunningAppsModel.clear()
100 fakeRunningAppsModel.clear()
82− fakeRunningAppsModel.add(phoneApp)
101+ fakeRunningAppsModel.rePopulate()
83− fakeRunningAppsModel.add(calendarApp)
84 }
102 }
85
103
86 Component.onCompleted: {
104 Component.onCompleted: {
@@ -185,11 +203,11 @@ Item {
185 var calendarTile = findChild(runningApplicationsGrid, "runningAppTile Calendar")
203 var calendarTile = findChild(runningApplicationsGrid, "runningAppTile Calendar")
186 verify(calendarTile != undefined)
204 verify(calendarTile != undefined)
187
205
188− verify(fakeRunningAppsModel.contains(calendarApp))
206+ verify(fakeRunningAppsModel.contains("calendar"))
189
207
190 mouseClick(calendarTile, calendarTile.width/2, calendarTile.height/2)
208 mouseClick(calendarTile, calendarTile.width/2, calendarTile.height/2)
191
209
192− verify(!fakeRunningAppsModel.contains(calendarApp))
210+ verify(!fakeRunningAppsModel.contains("calendar"))
193
211
194 // The tile for the Calendar app should eventually vanish since the
212 // The tile for the Calendar app should eventually vanish since the
195 // application has been terminated
213 // application has been terminated
tests/qmltests/Dash/tst_DashContent.qml+1−1
@@ -106,7 +106,7 @@ Item {
106 contentEndReachedSpy.clear()
106 contentEndReachedSpy.clear()
107 clear_scope_status();
107 clear_scope_status();
108
108
109− // clear, wait for dahs to empty and load scopes.
109+ // clear, wait for dash to empty and load scopes.
110 var dashContentList = findChild(dashContent, "dashContentList");
110 var dashContentList = findChild(dashContent, "dashContentList");
111 verify(dashContentList != undefined)
111 verify(dashContentList != undefined)
112 scopesModel.clear();
112 scopesModel.clear();
tests/qmltests/Dash/tst_GenericScopeView.qml+17
@@ -44,10 +44,27 @@ Item {
44
44
45 function test_isCurrent() {
45 function test_isCurrent() {
46 var pageHeader = findChild(genericScopeView, "pageHeader");
46 var pageHeader = findChild(genericScopeView, "pageHeader");
47+ var previewLoader = findChild(genericScopeView, "previewLoader");
47 genericScopeView.isCurrent = true
48 genericScopeView.isCurrent = true
48 pageHeader.searchQuery = "test"
49 pageHeader.searchQuery = "test"
50+ previewLoader.open = true
49 genericScopeView.isCurrent = false
51 genericScopeView.isCurrent = false
50 tryCompare(pageHeader, "searchQuery", "")
52 tryCompare(pageHeader, "searchQuery", "")
53+ tryCompare(genericScopeView, "previewShown", false);
54+ }
55+
56+ function test_showDash() {
57+ var previewLoader = findChild(genericScopeView, "previewLoader");
58+ previewLoader.open = true;
59+ scopes.get(0).showDash();
60+ tryCompare(genericScopeView, "previewShown", false);
61+ }
62+
63+ function test_hideDash() {
64+ var previewLoader = findChild(genericScopeView, "previewLoader");
65+ previewLoader.open = true;
66+ scopes.get(0).hideDash();
67+ tryCompare(genericScopeView, "previewShown", false);
51 }
68 }
52 }
69 }
53 }
70 }
tests/qmltests/Greeter/tst_Phone.qml+19−1
@@ -18,8 +18,8 @@ import QtQuick 2.0
18import QtTest 1.0
18import QtTest 1.0
19import ".."
19import ".."
20import "../../../Greeter"
20import "../../../Greeter"
21+import AccountsService 0.1
21import Ubuntu.Components 0.1
22import Ubuntu.Components 0.1
22−import LightDM 0.1 as LightDM
23import Unity.Test 0.1 as UT
23import Unity.Test 0.1 as UT
24
24
25Item {
25Item {
@@ -32,6 +32,8 @@ Item {
32 height: parent.height
32 height: parent.height
33 x: 0; y: 0
33 x: 0; y: 0
34
34
35+ defaultBackground: "../../../graphics/phone_background.jpg"
36+
35 property int minX: 0
37 property int minX: 0
36
38
37 onXChanged: {
39 onXChanged: {
@@ -102,5 +104,21 @@ Item {
102 // Wait until we're back to 0
104 // Wait until we're back to 0
103 tryCompareFunction(function() { return greeter.x;}, 0);
105 tryCompareFunction(function() { return greeter.x;}, 0);
104 }
106 }
107+
108+ function test_wallpaper_data() {
109+ return [
110+ {tag: "set", accounts: "../tests/data/unity/backgrounds/blue.png", expected: "blue.png"},
111+ {tag: "unset", accounts: "", expected: "background.jpg"},
112+ {tag: "invalid", accounts: "invalid", expected: "background.jpg"},
113+ ]
114+ }
115+
116+ function test_wallpaper(data) {
117+ var loader = findChild(greeter, "greeterContentLoader")
118+ var wallpaper = findChild(loader.item, "wallpaper")
119+ AccountsService.backgroundFile = data.accounts
120+ tryCompareFunction(function() { return wallpaper.source.toString().indexOf(data.expected) !== -1; }, true)
121+ tryCompare(wallpaper, "status", Image.Ready)
122+ }
105 }
123 }
106}
124}
tests/qmltests/Launcher/tst_Launcher.qml+10−2
@@ -38,7 +38,7 @@ Item {
38 property string lastSelectedApplication
38 property string lastSelectedApplication
39
39
40 onLauncherApplicationSelected: {
40 onLauncherApplicationSelected: {
41− lastSelectedApplication = desktopFile
41+ lastSelectedApplication = appId
42 }
42 }
43
43
44 property int dashItemSelected_count: 0
44 property int dashItemSelected_count: 0
@@ -131,7 +131,7 @@ Item {
131 mouseClick(appIcon, appIcon.width/2, appIcon.height/2)
131 mouseClick(appIcon, appIcon.width/2, appIcon.height/2)
132
132
133 tryCompare(launcher, "lastSelectedApplication",
133 tryCompare(launcher, "lastSelectedApplication",
134− "/usr/share/applications/phone-app.desktop")
134+ "phone-app")
135
135
136 // Tapping on an application icon also dismisses the launcher
136 // Tapping on an application icon also dismisses the launcher
137 revealer.waitUntilLauncherDisappears()
137 revealer.waitUntilLauncherDisappears()
@@ -198,6 +198,14 @@ Item {
198 compare(findChild(delegate, "progressOverlay").visible, LauncherModel.get(i).progress >= 0)
198 compare(findChild(delegate, "progressOverlay").visible, LauncherModel.get(i).progress >= 0)
199 }
199 }
200 }
200 }
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+ }
201 }
209 }
202
210
203 UT.UnityTestCase {
211 UT.UnityTestCase {
tests/qmltests/Panel/tst_IndicatorItem.qml+2−2
@@ -53,9 +53,9 @@ Rectangle {
53 }
53 }
54
54
55 function test_empty() {
55 function test_empty() {
56− compare(indicatorItem.visible, false, "IndicatorItem should not be visible.");
56+ compare(indicatorItem.indicatorVisible, false, "IndicatorItem should not be visible.");
57 indicatorItem.widgetSource = "qrc:/tests/indciators/qml/fake_menu_widget1.qml";
57 indicatorItem.widgetSource = "qrc:/tests/indciators/qml/fake_menu_widget1.qml";
58− tryCompare(indicatorItem, "visible", true);
58+ tryCompare(indicatorItem, "indicatorVisible", true);
59 }
59 }
60 }
60 }
61}
61}
tests/qmltests/Panel/tst_Indicators.qml+30−11
@@ -100,26 +100,29 @@ Item {
100 {
100 {
101 // tests changing the lateral position of the revealer activates the correct indicator items.
101 // tests changing the lateral position of the revealer activates the correct indicator items.
102
102
103− var indicator_row = findChild(indicators, "indicatorRow")
103+ var indicatorRow = findChild(indicators, "indicatorRow")
104− var row_repeater = findChild(indicators, "rowRepeater")
104+ var rowRepeater = findChild(indicators, "rowRepeater")
105
105
106− for (var i = 0; i < row_repeater.count; i++) {
106+ for (var i = 0; i < rowRepeater.count; i++) {
107− var indicator_item = row_repeater.itemAt(i);
107+ var indicatorItem = rowRepeater.itemAt(i);
108
108
109+ if (!indicatorItem.visible)
110+ continue;
111+
109− var indicator_position = indicators.mapFromItem(indicator_item,
112+ var indicatorPosition = indicators.mapFromItem(indicatorItem,
110− indicator_item.width/2, indicator_item.height/2)
113+ indicatorItem.width/2, indicatorItem.height/2)
111
114
112 touchFlick(indicators,
115 touchFlick(indicators,
113− indicator_position.x, indicator_position.y,
116+ indicatorPosition.x, indicatorPosition.y,
114− indicator_position.x, indicators.openedHeight * 0.4,
117+ indicatorPosition.x, indicators.openedHeight * 0.4,
115 true /* beginTouch */, false /* endTouch */)
118 true /* beginTouch */, false /* endTouch */)
116
119
117− compare(indicator_row.currentItem, indicator_item,
120+ compare(indicatorRow.currentItem, indicatorItem,
118 "Incorrect item activated at position " + i);
121 "Incorrect item activated at position " + i);
119
122
120 touchFlick(indicators,
123 touchFlick(indicators,
121− indicator_position.x, indicators.openedHeight * 0.4,
124+ indicatorPosition.x, indicators.openedHeight * 0.4,
122− indicator_position.x, indicator_position.y,
125+ indicatorPosition.x, indicatorPosition.y,
123 false /* beginTouch */, true /* endTouch */)
126 false /* beginTouch */, true /* endTouch */)
124
127
125 // wait until fully closed
128 // wait until fully closed
@@ -158,5 +161,21 @@ Item {
158 compare(indicators.fullyOpened, true);
161 compare(indicators.fullyOpened, true);
159 }
162 }
160
163
164+ function test_row_visible_menuContent_visible_data() { return [
165+ {tag: "visible", index: 0, name: "indicator-fake1", visible: true },
166+ {tag: "invisible", index: 1, name: "indicator-fake2", visible: false }]
167+ }
168+
169+ function test_row_visible_menuContent_visible(data) {
170+ var indicatorTabs = findChild(indicators, "tabs");
171+ var rowRepeater = findChild(indicators, "rowRepeater");
172+
173+ var indicatorItem = rowRepeater.itemAt(data.index);
174+ tryCompareFunction(function() { return indicatorItem.width > 0}, true);
175+ tryCompare(indicatorItem, "visible", data.visible);
176+
177+ var indicatorTab = findChild(indicatorTabs, data.name)
178+ tryCompareFunction(function() { return indicatorTab !== undefined }, data.visible);
179+ }
161 }
180 }
162}
181}
tests/qmltests/Panel/tst_MenuContent.qml+9−2
@@ -48,8 +48,15 @@ Item {
48 id: menuContent
48 id: menuContent
49 indicatorsModel: indicatorsModel
49 indicatorsModel: indicatorsModel
50 contentReleaseInterval: 50
50 contentReleaseInterval: 50
51−
52 height: parent.height - 50
51 height: parent.height - 50
52+
53+ visibleIndicators: {
54+ 'indicator-fake1': true,
55+ 'indicator-fake2': true,
56+ 'indicator-fake3': true,
57+ 'indicator-fake4': true,
58+ 'indicator-fake5': true
59+ }
53 }
60 }
54
61
55 Rectangle {
62 Rectangle {
@@ -134,7 +141,7 @@ Item {
134 var menuIndex = i%menuCount;
141 var menuIndex = i%menuCount;
135
142
136 activate_content(menuIndex);
143 activate_content(menuIndex);
137− testTabObjectName = indicatorsModel.data(menuIndex, Indicators.IndicatorsModelRole.Identifier);
144+ testTabObjectName = indicatorsModel.get(menuIndex).identifier;
138 compare(tabs.selectedTabIndex, menuIndex, "Current tab index does not match selected tab index");
145 compare(tabs.selectedTabIndex, menuIndex, "Current tab index does not match selected tab index");
139 tryCompareFunction(selected_tab_equals_test_tab, true);
146 tryCompareFunction(selected_tab_equals_test_tab, true);
140 }
147 }
tests/qmltests/Panel/tst_Panel.qml+3
@@ -159,6 +159,9 @@ Item {
159 var indicatorItem = get_indicator_item(i);
159 var indicatorItem = get_indicator_item(i);
160 verify(indicatorItem != undefined);
160 verify(indicatorItem != undefined);
161
161
162+ if (!indicatorItem.visible)
163+ continue;
164+
162 var indicatorItemCoord = get_indicator_item_position(i);
165 var indicatorItemCoord = get_indicator_item_position(i);
163
166
164 touchPress(panel,
167 touchPress(panel,
tests/qmltests/tst_Shell.qml+33−9
@@ -20,7 +20,7 @@
20import QtQuick 2.0
20import QtQuick 2.0
21import QtTest 1.0
21import QtTest 1.0
22import GSettings 1.0
22import GSettings 1.0
23−import Ubuntu.Application 0.1
23+import Unity.Application 0.1
24import Unity.Test 0.1 as UT
24import Unity.Test 0.1 as UT
25import Powerd 0.1
25import Powerd 0.1
26
26
@@ -66,16 +66,16 @@ Item {
66 }
66 }
67
67
68 // kill all (fake) running apps
68 // kill all (fake) running apps
69− killApps(ApplicationManager.mainStageApplications);
69+ killApps(ApplicationManager);
70− killApps(ApplicationManager.sideStageApplications);
71
70
72 var dashHome = findChild(shell, "DashHome");
71 var dashHome = findChild(shell, "DashHome");
73 swipeUntilScopeViewIsReached(dashHome);
72 swipeUntilScopeViewIsReached(dashHome);
74 }
73 }
75
74
76 function killApps(apps) {
75 function killApps(apps) {
76+ if (!apps) return;
77 while (apps.count > 0) {
77 while (apps.count > 0) {
78− ApplicationManager.stopProcess(apps.get(0));
78+ ApplicationManager.stopApplication(apps.get(0).appId);
79 }
79 }
80 }
80 }
81
81
@@ -114,6 +114,26 @@ Item {
114 checkRightEdgeDragWithNoRunningApps();
114 checkRightEdgeDragWithNoRunningApps();
115 }
115 }
116
116
117+ function test_leftEdgeDrag_data() {
118+ return [
119+ {tag: "without launcher", revealLauncher: false},
120+ {tag: "with launcher", revealLauncher: true},
121+ ];
122+ }
123+
124+ function test_leftEdgeDrag(data) {
125+ dragLauncherIntoView();
126+ tapOnAppIconInLauncher();
127+ waitUntilApplicationWindowIsFullyVisible();
128+
129+ if (data.revealLauncher) {
130+ dragLauncherIntoView();
131+ }
132+
133+ swipeFromLeftEdge();
134+ waitUntilApplicationWindowIsFullyHidden();
135+ }
136+
117 function test_suspend() {
137 function test_suspend() {
118 var greeter = findChild(shell, "greeter");
138 var greeter = findChild(shell, "greeter");
119
139
@@ -122,8 +142,8 @@ Item {
122 tapOnAppIconInLauncher();
142 tapOnAppIconInLauncher();
123 waitUntilApplicationWindowIsFullyVisible();
143 waitUntilApplicationWindowIsFullyVisible();
124
144
125− var mainApp = ApplicationManager.mainStageFocusedApplication;
145+ var mainApp = ApplicationManager.focusedApplicationId;
126− tryCompareFunction(function() { return mainApp != null; }, true);
146+ tryCompareFunction(function() { return mainApp != ""; }, true);
127
147
128 // Try to suspend while proximity is engaged...
148 // Try to suspend while proximity is engaged...
129 Powerd.displayPowerStateChange(Powerd.Off, Powerd.UseProximity);
149 Powerd.displayPowerStateChange(Powerd.Off, Powerd.UseProximity);
@@ -132,11 +152,11 @@ Item {
132 // Now really suspend
152 // Now really suspend
133 Powerd.displayPowerStateChange(Powerd.Off, 0);
153 Powerd.displayPowerStateChange(Powerd.Off, 0);
134 tryCompare(greeter, "showProgress", 1);
154 tryCompare(greeter, "showProgress", 1);
135− tryCompare(ApplicationManager, "mainStageFocusedApplication", null);
155+ tryCompare(ApplicationManager, "focusedApplicationId", "");
136
156
137 // And wake up
157 // And wake up
138 Powerd.displayPowerStateChange(Powerd.On, 0);
158 Powerd.displayPowerStateChange(Powerd.On, 0);
139− tryCompare(ApplicationManager, "mainStageFocusedApplication", mainApp);
159+ tryCompare(ApplicationManager, "focusedApplicationId", mainApp);
140 tryCompare(greeter, "showProgress", 1);
160 tryCompare(greeter, "showProgress", 1);
141 }
161 }
142
162
@@ -223,7 +243,11 @@ Item {
223 function dragLauncherIntoView() {
243 function dragLauncherIntoView() {
224 var launcherPanel = findChild(shell, "launcherPanel");
244 var launcherPanel = findChild(shell, "launcherPanel");
225 verify(launcherPanel.x = - launcherPanel.width);
245 verify(launcherPanel.x = - launcherPanel.width);
226− swipeFromLeftEdge();
246+
247+ var touchStartX = 2;
248+ var touchStartY = shell.height / 2;
249+ touchFlick(shell, touchStartX, touchStartY, launcherPanel.width + units.gu(1), touchStartY);
250+
227 tryCompare(launcherPanel, "x", 0);
251 tryCompare(launcherPanel, "x", 0);
228 }
252 }
229
253
tests/uqmlscene/main.cpp−2
@@ -497,8 +497,6 @@ int main(int argc, char ** argv)
497 }
497 }
498
498
499 if (window) {
499 if (window) {
500− mouseTouchAdaptor.setTargetWindow(window);
501−
502 QSurfaceFormat surfaceFormat = window->requestedFormat();
500 QSurfaceFormat surfaceFormat = window->requestedFormat();
503 if (options.multisample)
501 if (options.multisample)
504 surfaceFormat.setSamples(16);
502 surfaceFormat.setSamples(16);