on xenial help sign in
Merge from trunk
0cd9b5eMichael Terry
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")
@@ -133,6 +136,7 @@ target_link_libraries(${SHELL_APP}
133 ${Qt5Qml_LIBRARIES}
136 ${Qt5Qml_LIBRARIES}
134 ${Qt5Quick_LIBRARIES}
137 ${Qt5Quick_LIBRARIES}
135 ${XCB_LDFLAGS}
138 ${XCB_LDFLAGS}
139+ ${CMAKE_DL_LIBS}
136 )
140 )
137target_link_libraries(${GREETER_APP}
141target_link_libraries(${GREETER_APP}
138 ${Qt5Qml_LIBRARIES}
142 ${Qt5Qml_LIBRARIES}
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/BasicShell.qml+5
@@ -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.Application 0.1
19import "../Components"
20import "../Components"
20import "../Components/Math.js" as MathLocal
21import "../Components/Math.js" as MathLocal
21
22
@@ -61,6 +62,10 @@ FocusScope {
61 }
62 }
62 }
63 }
63
64
65+ OSKController {
66+ anchors.fill: parent // as needs to know the geometry of the shell
67+ }
68+
64 VolumeControl {
69 VolumeControl {
65 id: volumeControl
70 id: volumeControl
66 }
71 }
Components/EdgeDemo.qml+16−4
@@ -41,7 +41,6 @@ Item {
41
41
42 function hideEdgeDemoInShell() {
42 function hideEdgeDemoInShell() {
43 AccountsService.demoEdges = false;
43 AccountsService.demoEdges = false;
44− d.showEdgeDemo = false;
45 stopDemo();
44 stopDemo();
46 }
45 }
47
46
@@ -56,6 +55,19 @@ Item {
56 if (d.finalEdgeDemo) d.finalEdgeDemo.destroy()
55 if (d.finalEdgeDemo) d.finalEdgeDemo.destroy()
57 }
56 }
58
57
58+ function startDemo() {
59+ if (!d.overlay) {
60+ d.overlay = Qt.createComponent("EdgeDemoOverlay.qml")
61+ }
62+
63+ launcherEnabled = false;
64+ dashEnabled = false;
65+ panelEnabled = false;
66+ panelContentEnabled = false;
67+
68+ startTopEdgeDemo()
69+ }
70+
59 QtObject {
71 QtObject {
60 id: d
72 id: d
61 property Component overlay
73 property Component overlay
@@ -66,9 +78,9 @@ Item {
66 property bool showEdgeDemo: AccountsService.demoEdges
78 property bool showEdgeDemo: AccountsService.demoEdges
67
79
68 onShowEdgeDemoChanged: {
80 onShowEdgeDemoChanged: {
81+ stopDemo()
69− if (!d.overlay && d.showEdgeDemo) {
82+ if (d.showEdgeDemo) {
70− d.overlay = Qt.createComponent("EdgeDemoOverlay.qml")
83+ startDemo()
71− startTopEdgeDemo()
72 }
84 }
73 }
85 }
74 }
86 }
Components/EdgeDemoOverlay.qml+1−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 {
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/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
Dash/Apps/AppPreview.qml+1−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
@@ -137,7 +136,7 @@ DashPreview {
137 anchors { left: parent.left; right: parent.right }
136 anchors { left: parent.left; right: parent.right }
138
137
139 appName: root.previewData.title
138 appName: root.previewData.title
140− icon: IconUtil.from_gicon(root.previewData.appIcon)
139+ icon: root.previewData.appIcon
141 rating: Math.round(root.previewData.rating * 10)
140 rating: Math.round(root.previewData.rating * 10)
142 reviews: root.previewData.numRatings
141 reviews: root.previewData.numRatings
143 rated: root.previewData.infoMap["rated"] ? root.previewData.infoMap["rated"].value : 0
142 rated: root.previewData.infoMap["rated"] ? root.previewData.infoMap["rated"].value : 0
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/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−1
@@ -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
22
21
23ScopeView {
22ScopeView {
24 id: scopeView
23 id: scopeView
Greeter/GreeterEdgeDemo.qml+10−4
@@ -36,7 +36,6 @@ Item {
36
36
37 function hideEdgeDemoInGreeter() {
37 function hideEdgeDemoInGreeter() {
38 AccountsService.demoEdgesForCurrentUser = false;
38 AccountsService.demoEdgesForCurrentUser = false;
39− d.showEdgeDemoInGreeter = false;
40 stopDemo();
39 stopDemo();
41 }
40 }
42
41
@@ -45,6 +44,13 @@ Item {
45 hideEdgeDemoInShell();
44 hideEdgeDemoInShell();
46 }
45 }
47
46
47+ function startDemo() {
48+ if (!d.overlay) {
49+ d.overlay = Qt.createComponent("EdgeDemoOverlay.qml")
50+ }
51+ startRightEdgeDemo()
52+ }
53+
48 function stopDemo() {
54 function stopDemo() {
49 active = false
55 active = false
50 if (d.rightEdgeDemo) d.rightEdgeDemo.destroy()
56 if (d.rightEdgeDemo) d.rightEdgeDemo.destroy()
@@ -57,9 +63,9 @@ Item {
57 property bool showEdgeDemoInGreeter: AccountsService.demoEdgesForCurrentUser
63 property bool showEdgeDemoInGreeter: AccountsService.demoEdgesForCurrentUser
58
64
59 onShowEdgeDemoInGreeterChanged: {
65 onShowEdgeDemoInGreeterChanged: {
66+ stopDemo()
60− if (!d.overlay && d.showEdgeDemoInGreeter) {
67+ if (d.showEdgeDemoInGreeter) {
61− d.overlay = Qt.createComponent("EdgeDemoOverlay.qml")
68+ startDemo()
62− startRightEdgeDemo()
63 }
69 }
64 }
70 }
65 }
71 }
GreeterShell.qml+1−1
@@ -19,7 +19,7 @@ import LightDM 0.1 as LightDM
19import Powerd 0.1
19import Powerd 0.1
20import QtQuick 2.0
20import QtQuick 2.0
21import SessionBroadcast 0.1
21import SessionBroadcast 0.1
22−import Ubuntu.Application 0.1
22+import Unity.Application 0.1
23import Unity.Launcher 0.1
23import Unity.Launcher 0.1
24import "Components"
24import "Components"
25import "Components/Math.js" as MathLocal
25import "Components/Math.js" as MathLocal
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/LauncherPanel.qml+3−3
@@ -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 {
@@ -300,7 +300,7 @@ Item {
300 } else if (clickedItem.angle < -12) {
300 } else if (clickedItem.angle < -12) {
301 launcherListView.flick(0, launcherListView.clickFlickSpeed);
301 launcherListView.flick(0, launcherListView.clickFlickSpeed);
302 } else {
302 } else {
303− root.applicationSelected(LauncherModel.get(index).desktopFile);
303+ root.applicationSelected(LauncherModel.get(index).appId);
304 }
304 }
305 return;
305 return;
306 }
306 }
@@ -311,7 +311,7 @@ Item {
311 } else if (clickedItem.angle < -30) {
311 } else if (clickedItem.angle < -30) {
312 launcherListView.flick(0, launcherListView.clickFlickSpeed);
312 launcherListView.flick(0, launcherListView.clickFlickSpeed);
313 } else {
313 } else {
314− root.applicationSelected(LauncherModel.get(index).desktopFile);
314+ root.applicationSelected(LauncherModel.get(index).appId);
315 }
315 }
316 }
316 }
317
317
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+17−2
@@ -180,11 +180,19 @@ Showable {
180 clip: !indicators.fullyOpened
180 clip: !indicators.fullyOpened
181 activeHeader: indicators.state == "hint" || indicators.state == "reveal"
181 activeHeader: indicators.state == "hint" || indicators.state == "reveal"
182 enabled: contentEnabled
182 enabled: contentEnabled
183+ visibleIndicators: indicatorRow.visibleIndicators
183
184
184 Connections {
185 Connections {
186+ property bool enableIndexChangeSignal: true
187+
185− target: indicatorRow
188+ target: enableIndexChangeSignal ? indicatorRow : null
186 onCurrentItemIndexChanged: {
189 onCurrentItemIndexChanged: {
190+ var oldActive = enableIndexChangeSignal;
191+ enableIndexChangeSignal = false;
192+
187 menuContent.setCurrentMenuIndex(indicatorRow.currentItemIndex);
193 menuContent.setCurrentMenuIndex(indicatorRow.currentItemIndex);
194+
195+ enableIndexChangeSignal = oldActive;
188 }
196 }
189 }
197 }
190
198
@@ -256,9 +264,16 @@ Showable {
256 state: indicators.state
264 state: indicators.state
257
265
258 Connections {
266 Connections {
267+ property bool enableIndexChangeSignal: true
268+
259− target: menuContent
269+ target: enableIndexChangeSignal ? menuContent : null
260 onCurrentMenuIndexChanged: {
270 onCurrentMenuIndexChanged: {
271+ var oldActive = enableIndexChangeSignal;
272+ enableIndexChangeSignal = false;
273+
261 indicatorRow.setCurrentItem(menuContent.currentMenuIndex);
274 indicatorRow.setCurrentItem(menuContent.currentMenuIndex);
275+
276+ enableIndexChangeSignal = oldActive;
262 }
277 }
263 }
278 }
264 }
279 }
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+2−1
@@ -63,6 +63,7 @@ Indicators.IndicatorWidget {
63
63
64 onActionStateChanged: {
64 onActionStateChanged: {
65 if (action == undefined || !action.valid) {
65 if (action == undefined || !action.valid) {
66+ enabled = false;
66 return;
67 return;
67 }
68 }
68
69
@@ -74,7 +75,7 @@ Indicators.IndicatorWidget {
74 }
75 }
75
76
76 label = action.state[Indicators.ActionState.Label];
77 label = action.state[Indicators.ActionState.Label];
77− iconSource = "image://gicon/" + action.state[Indicators.ActionState.IconSource];
78+ iconSource = "image://theme/" + action.state[Indicators.ActionState.IconSource];
78 enabled = action.state[Indicators.ActionState.Visible];
79 enabled = action.state[Indicators.ActionState.Visible];
79 }
80 }
80}
81}
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+9−6
@@ -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/MenuContent.qml+25−7
@@ -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.
@@ -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 }
Shell.qml+23−25
@@ -15,8 +15,9 @@
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
22import Unity.Launcher 0.1
23import Unity.Launcher 0.1
@@ -55,6 +56,12 @@ BasicShell {
55
56
56 property var applicationManager: ApplicationManagerWrapper {}
57 property var applicationManager: ApplicationManagerWrapper {}
57
58
59+ Binding {
60+ target: LauncherModel
61+ property: "applicationManager"
62+ value: ApplicationManager
63+ }
64+
58 Component.onCompleted: {
65 Component.onCompleted: {
59 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
66 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
60
67
@@ -65,6 +72,9 @@ BasicShell {
65 applicationManager.unfocusCurrentApplication();
72 applicationManager.unfocusCurrentApplication();
66 }
73 }
67
74
75+ readonly property bool applicationFocused: !!applicationManager.mainStageFocusedApplication
76+ || !!applicationManager.sideStageFocusedApplication
77+
68 readonly property bool fullscreenMode: {
78 readonly property bool fullscreenMode: {
69 if (mainStage.usingScreenshots) { // Window Manager animating so want to re-evaluate fullscreen mode
79 if (mainStage.usingScreenshots) { // Window Manager animating so want to re-evaluate fullscreen mode
70 return mainStage.switchingFromFullscreenToFullscreen;
80 return mainStage.switchingFromFullscreenToFullscreen;
@@ -81,15 +91,6 @@ BasicShell {
81 onFocusRequested: {
91 onFocusRequested: {
82 shell.activateApplication(desktopFile);
92 shell.activateApplication(desktopFile);
83 }
93 }
84−
85− onMainStageFocusedApplicationChanged: {
86− var app = applicationManager.mainStageFocusedApplication
87− if (app != null) {
88− LauncherModel.applicationFocused(app.desktopFile);
89− } else {
90− LauncherModel.applicationFocused("");
91− }
92− }
93 }
94 }
94
95
95 function activateApplication(desktopFile, argument) {
96 function activateApplication(desktopFile, argument) {
@@ -201,7 +202,7 @@ BasicShell {
201
202
202 property bool fullyShown: shown && x == 0 && parent.x == 0
203 property bool fullyShown: shown && x == 0 && parent.x == 0
203 property bool fullyHidden: !shown && x == width
204 property bool fullyHidden: !shown && x == width
204− hides: [launcher, panel.indicators]
205+ hides: [panel.indicators]
205 shown: false
206 shown: false
206 opacity: 1.0
207 opacity: 1.0
207 showAnimation: StandardAnimation { property: "x"; duration: 350; to: 0; easing.type: Easing.OutCubic }
208 showAnimation: StandardAnimation { property: "x"; duration: 350; to: 0; easing.type: Easing.OutCubic }
@@ -362,10 +363,8 @@ BasicShell {
362
363
363 function setFocused(focused) {
364 function setFocused(focused) {
364 if (!focused) {
365 if (!focused) {
365− // FIXME: *FocusedApplication are not updated when unfocused, hence the need to check whether
366− // the stage was actually shown
367− if (mainStage.fullyShown) powerConnection.previousMainApp = applicationManager.mainStageFocusedApplication;
366+ powerConnection.previousMainApp = applicationManager.mainStageFocusedApplication;
368− if (sideStage.fullyShown) powerConnection.previousSideApp = applicationManager.sideStageFocusedApplication;
367+ powerConnection.previousSideApp = applicationManager.sideStageFocusedApplication;
369 applicationManager.unfocusCurrentApplication();
368 applicationManager.unfocusCurrentApplication();
370 } else {
369 } else {
371 if (powerConnection.previousMainApp) {
370 if (powerConnection.previousMainApp) {
@@ -415,8 +414,13 @@ BasicShell {
415 fullscreenMode: shell.fullscreenMode
414 fullscreenMode: shell.fullscreenMode
416
415
417 InputFilterArea {
416 InputFilterArea {
418− anchors.fill: parent
417+ anchors {
418+ top: parent.top
419+ left: parent.left
420+ right: parent.right
421+ }
422+ height: (panel.fullscreenMode) ? shell.edgeSize : panel.panelHeight
419− blockInput: panel.indicators.shown
423+ blockInput: true
420 }
424 }
421 }
425 }
422
426
@@ -436,11 +440,6 @@ BasicShell {
436 onMainStageFocusedApplicationChanged: hud.hide()
440 onMainStageFocusedApplicationChanged: hud.hide()
437 onSideStageFocusedApplicationChanged: hud.hide()
441 onSideStageFocusedApplicationChanged: hud.hide()
438 }
442 }
439−
440− InputFilterArea {
441− anchors.fill: parent
442− blockInput: hud.shown
443− }
444 }
443 }
445
444
446 Revealer {
445 Revealer {
@@ -463,8 +462,7 @@ BasicShell {
463 theHud: hud
462 theHud: hud
464 anchors.fill: parent
463 anchors.fill: parent
465 enabled: !panel.indicators.shown
464 enabled: !panel.indicators.shown
466− applicationIsOnForeground: applicationManager.mainStageFocusedApplication
465+ applicationIsOnForeground: applicationFocused
467− || applicationManager.sideStageFocusedApplication
468 }
466 }
469
467
470 InputFilterArea {
468 InputFilterArea {
@@ -502,7 +500,7 @@ BasicShell {
502 }
500 }
503 }
501 }
504 onLauncherApplicationSelected:{
502 onLauncherApplicationSelected:{
505− shell.activateApplication(desktopFile)
503+ shell.activateApplication(appId)
506 }
504 }
507 onShownChanged: {
505 onShownChanged: {
508 if (shown) {
506 if (shown) {
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
debian/changelog+88
@@ -1,3 +1,91 @@
1+unity8 (7.81.3+13.10.20130912-0ubuntu1) saucy; urgency=low
2+
3+ [ Michael Zanetti ]
4+ * add support for finding icons from click package apps in the
5+ launcher.
6+ * update to latest launcher API for better integration with the
7+ AppManager.
8+
9+ [ Ricardo Mendoza ]
10+ * Fixes problems related to image 20130912.0, amongst: * Fix autopilot
11+ tests by preventing blocking of input during HUD button animations,
12+ only when fully visible * Fix loading of unity-mir library, major
13+ version wasn't specified so unless the dev package was there it
14+ would fail.
15+
16+ [ Ubuntu daily release ]
17+ * Automatic snapshot from revision 316
18+
19+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 12 Sep 2013 13:47:59 +0000
20+
21+unity8 (7.81.3+13.10.20130911.1-0ubuntu1) saucy; urgency=low
22+
23+ [ Michael Terry ]
24+ * Switch from deprecated image://gicon/ to new image://theme/.
25+
26+ [ Gerry Boland ]
27+ * Add OSKController so shell can control OSK correctly on Mir.
28+ * Remove InputFilterArea for bottom edge swipes, as applications also
29+ listen for such swipes for Toolbar reveal.
30+
31+ [ Ricardo Mendoza ]
32+ * Select the backend to use dynamically on runtime according to the
33+ QPA selected by the system.
34+
35+ [ Ubuntu daily release ]
36+ * Automatic snapshot from revision 311
37+
38+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 11 Sep 2013 16:22:55 +0000
39+
40+unity8 (7.81.3+13.10.20130911-0ubuntu1) saucy; urgency=low
41+
42+ [ Michal Hruby ]
43+ * Hide all gicon strings from the shell and use the image://theme icon
44+ provider that was recently added to the SDK.
45+
46+ [ Gerry Boland ]
47+ * Convert to new ApplicationManager API.
48+
49+ [ Nick Dedekind ]
50+ * Updated access point design as per spec.
51+ * Indicator visibility based on connection with backend service.
52+
53+ [ Albert Astals ]
54+ * Dash: Make assignments bindings This way if the model changes the
55+ item value also changes.
56+
57+ [ Michael Zanetti ]
58+ * adds support for highlighting the currently focused application in
59+ the launcher, adds tests.
60+ * include ~/.local/share/applications in launcher's .desktop file
61+ search path.
62+ * shrink size of area for revealing the HUD button and make it
63+ disappear on release again. fixes 1219035. (LP: #1219035)
64+ * revert revision 304 as it makes the Shell crash.
65+
66+ [ Michael Terry ]
67+ * Allow testers to set custom password or pin in demo mode, rather
68+ than hardcoding them.
69+ * Have the greeter use AccountsService to determine its background.
70+ (LP: #1218402)
71+ * Listen to changes in the "show edge demo" AccountsService setting.
72+
73+ [ Daniel d'Andrada ]
74+ * Update fake/mock plugins so that "./run --fake" works well again -
75+ You can now see the thumbnails of the fake running applications once
76+ again. - You no longer get hundreds of warnings due to icons not
77+ found.
78+ * Reset apps scope when returning from app to dash (LP #1193419) If an
79+ app is on foreground and you perform a long left-edge swipe to
80+ minimize it, and therefore return to the dash, the dash should be in
81+ the Applications scope and showing the running/recents applications.
82+ (LP: #1193419)
83+
84+ [ Ubuntu daily release ]
85+ * Automatic snapshot from revision 306
86+
87+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 11 Sep 2013 00:54:31 +0000
88+
1unity8 (7.81.3+13.10.20130905.2-0ubuntu1) saucy; urgency=low
89unity8 (7.81.3+13.10.20130905.2-0ubuntu1) saucy; urgency=low
2
90
3 [ Michael Zanetti ]
91 [ Michael Zanetti ]
debian/control+9−7
@@ -24,6 +24,7 @@ Build-Depends: cmake,
24 libunity-api-dev (>= 7.80.3),
24 libunity-api-dev (>= 7.80.3),
25 libunity-core-6.0-dev (<< 7.80),
25 libunity-core-6.0-dev (<< 7.80),
26 libunity-dev (>= 7.0.12),
26 libunity-dev (>= 7.0.12),
27+ libunity-mir-dev,
27 libunity-scopes-json-def-phone,
28 libunity-scopes-json-def-phone,
28 libupstart-dev,
29 libupstart-dev,
29 libusermetricsoutput1-dev,
30 libusermetricsoutput1-dev,
@@ -55,7 +56,7 @@ Vcs-Browser: https://bazaar.launchpad.net/~unity-team/unity8/trunk
55Package: indicators-client
56Package: indicators-client
56Architecture: amd64 armhf i386
57Architecture: amd64 armhf i386
57Depends: qmenumodel-qml (>= 0.2.7),
58Depends: qmenumodel-qml (>= 0.2.7),
58− qtdeclarative5-ubuntu-ui-toolkit-plugin | qt-components-ubuntu,
59+ qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 0.1.46+13.10.20130829.1-0ubuntu1),
59 unity8 (= ${binary:Version}),
60 unity8 (= ${binary:Version}),
60 ${misc:Depends},
61 ${misc:Depends},
61 ${shlibs:Depends},
62 ${shlibs:Depends},
@@ -66,14 +67,15 @@ Package: unity8
66Architecture: any
67Architecture: any
67Provides: indicator-renderer,
68Provides: indicator-renderer,
68Depends: gsettings-desktop-schemas,
69Depends: gsettings-desktop-schemas,
70+ libunity-mir1,
69 qmenumodel-qml (>= 0.2.7),
71 qmenumodel-qml (>= 0.2.7),
70 qtdeclarative5-dee-plugin,
72 qtdeclarative5-dee-plugin,
71 qtdeclarative5-gsettings1.0,
73 qtdeclarative5-gsettings1.0,
72− qtdeclarative5-ubuntu-ui-toolkit-plugin,
74+ qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 0.1.46+13.10.20130829.1-0ubuntu1),
73 qtdeclarative5-unity-notifications-plugin | unity-notifications-impl,
75 qtdeclarative5-unity-notifications-plugin | unity-notifications-impl,
74 qtdeclarative5-xmllistmodel-plugin,
76 qtdeclarative5-xmllistmodel-plugin,
75 unity-greeter-session-broadcast,
77 unity-greeter-session-broadcast,
76− unity-launcher-impl-2,
78+ unity-launcher-impl-3,
77 unity-notifications-impl-1,
79 unity-notifications-impl-1,
78 unity8-fake-env | qtubuntu-shell,
80 unity8-fake-env | qtubuntu-shell,
79 unity8-private (= ${binary:Version}),
81 unity8-private (= ${binary:Version}),
@@ -98,19 +100,19 @@ Description: Ubuntu QML greeter
98
100
99Package: unity8-autopilot
101Package: unity8-autopilot
100Architecture: all
102Architecture: all
103+Depends: gir1.2-glib-2.0,
101−Depends: indicators-client (>= ${source:Version}),
104+ indicators-client (>= ${source:Version}),
102 libautopilot-qt,
105 libautopilot-qt,
103 libqt5test5,
106 libqt5test5,
104 libqt5widgets5,
107 libqt5widgets5,
105 python-evdev,
108 python-evdev,
109+ python-gi,
106 unity8 (>= ${source:Version}),
110 unity8 (>= ${source:Version}),
107 unity8-fake-env (>= ${source:Version}),
111 unity8-fake-env (>= ${source:Version}),
108 unity8-greeter (>= ${source:Version}),
112 unity8-greeter (>= ${source:Version}),
109 ${misc:Depends},
113 ${misc:Depends},
110 ${python:Depends},
114 ${python:Depends},
111 ${shlibs:Depends},
115 ${shlibs:Depends},
112−Recommends: gir1.2-glib-2.0,
113− python-gi,
114Description: Test package for Unity 8 shell
116Description: Test package for Unity 8 shell
115 Autopilot tests for the unity8 package
117 Autopilot tests for the unity8 package
116
118
@@ -132,7 +134,7 @@ Pre-Depends: ${misc:Pre-Depends},
132Depends: ${misc:Depends},
134Depends: ${misc:Depends},
133 ${shlibs:Depends},
135 ${shlibs:Depends},
134Provides: unity-launcher-impl,
136Provides: unity-launcher-impl,
135− unity-launcher-impl-2,
137+ unity-launcher-impl-3,
136Description: Unity 8 private libs
138Description: Unity 8 private libs
137 The Unity 8 shell is the primary user interface for Ubuntu devices.
139 The Unity 8 shell is the primary user interface for Ubuntu devices.
138 .
140 .
main.cpp+73−6
@@ -26,13 +26,17 @@
26#include <QtQml/QQmlContext>
26#include <QtQml/QQmlContext>
27#include <qpa/qplatformnativeinterface.h>
27#include <qpa/qplatformnativeinterface.h>
28#include <QLibrary>
28#include <QLibrary>
29+#include <QDebug>
29#include <libintl.h>
30#include <libintl.h>
31+#include <dlfcn.h>
30
32
31// local
33// local
32#include "paths.h"
34#include "paths.h"
33#include "MouseTouchAdaptor.h"
35#include "MouseTouchAdaptor.h"
34#include "ApplicationArguments.h"
36#include "ApplicationArguments.h"
35
37
38+#include <unity-mir/qmirserver.h>
39+
36namespace {
40namespace {
37
41
38void prependImportPaths(QQmlEngine *engine, const QStringList &paths)
42void prependImportPaths(QQmlEngine *engine, const QStringList &paths)
@@ -73,7 +77,7 @@ void resolveIconTheme() {
73}
77}
74} // namespace {
78} // namespace {
75
79
76−int main(int argc, char** argv)
80+int startShell(int argc, const char** argv, void* server)
77{
81{
78 /* Workaround Qt platform integration plugin not advertising itself
82 /* Workaround Qt platform integration plugin not advertising itself
79 as having the following capabilities:
83 as having the following capabilities:
@@ -83,12 +87,29 @@ int main(int argc, char** argv)
83 setenv("QML_FORCE_THREADED_RENDERER", "1", 1);
87 setenv("QML_FORCE_THREADED_RENDERER", "1", 1);
84 setenv("QML_FIXED_ANIMATION_STEP", "1", 1);
88 setenv("QML_FIXED_ANIMATION_STEP", "1", 1);
85
89
90+ const bool isUbuntuMirServer = qgetenv("QT_QPA_PLATFORM") == "ubuntumirserver";
91+
86 QGuiApplication::setApplicationName(APP_NAME);
92 QGuiApplication::setApplicationName(APP_NAME);
87− QGuiApplication application(argc, argv);
93+ QGuiApplication *application;
94+ if (isUbuntuMirServer) {
95+ QLibrary unityMir("unity-mir", 1);
96+ unityMir.load();
97+
98+ typedef QGuiApplication* (*createServerApplication_t)(int&, const char **, void*);
99+ createServerApplication_t createQMirServerApplication = (createServerApplication_t) unityMir.resolve("createQMirServerApplication");
100+ if (!createQMirServerApplication) {
101+ qDebug() << "unable to resolve symbol: createQMirServerApplication";
102+ return 4;
103+ }
104+
105+ application = createQMirServerApplication(argc, argv, server);
106+ } else {
107+ application = new QGuiApplication(argc, (char**)argv);
108+ }
88
109
89 resolveIconTheme();
110 resolveIconTheme();
90
111
91− QStringList args = application.arguments();
112+ QStringList args = application->arguments();
92 ApplicationArguments qmlArgs(args);
113 ApplicationArguments qmlArgs(args);
93
114
94 // The testability driver is only loaded by QApplication but not by QGuiApplication.
115 // The testability driver is only loaded by QApplication but not by QGuiApplication.
@@ -125,7 +146,7 @@ int main(int argc, char** argv)
125 if (args.contains(QLatin1String("-mousetouch"))) {
146 if (args.contains(QLatin1String("-mousetouch"))) {
126 mouseTouchAdaptor = new MouseTouchAdaptor;
147 mouseTouchAdaptor = new MouseTouchAdaptor;
127 mouseTouchAdaptor->setTargetWindow(view);
148 mouseTouchAdaptor->setTargetWindow(view);
128− application.installNativeEventFilter(mouseTouchAdaptor);
149+ application->installNativeEventFilter(mouseTouchAdaptor);
129 }
150 }
130
151
131 QPlatformNativeInterface* nativeInterface = QGuiApplication::platformNativeInterface();
152 QPlatformNativeInterface* nativeInterface = QGuiApplication::platformNativeInterface();
@@ -140,10 +161,17 @@ int main(int argc, char** argv)
140 QUrl source(QML_FILE);
161 QUrl source(QML_FILE);
141 prependImportPaths(view->engine(), ::overrideImportPaths());
162 prependImportPaths(view->engine(), ::overrideImportPaths());
142 appendImportPaths(view->engine(), ::fallbackImportPaths());
163 appendImportPaths(view->engine(), ::fallbackImportPaths());
164+
165+ QStringList importPath = view->engine()->importPathList().filter("qt5/imports");
166+ if (isUbuntuMirServer) {
167+ importPath.first().append("/Unity-Mir");
168+ view->engine()->addImportPath(importPath.first());
169+ }
170+
143 view->setSource(source);
171 view->setSource(source);
144 view->setColor("transparent");
172 view->setColor("transparent");
145
173
146− if (qgetenv("QT_QPA_PLATFORM") == "ubuntu" || args.contains(QLatin1String("-fullscreen"))) {
174+ if (qgetenv("QT_QPA_PLATFORM") == "ubuntu" || isUbuntuMirServer || args.contains(QLatin1String("-fullscreen"))) {
147 // First, size window equal to screen (fake a real WM fullscreen mode).
175 // First, size window equal to screen (fake a real WM fullscreen mode).
148 // Then, in case we are actually running inside a windowing system,
176 // Then, in case we are actually running inside a windowing system,
149 // nicely set actual WM fullscreen hint for its benefit.
177 // nicely set actual WM fullscreen hint for its benefit.
@@ -153,9 +181,48 @@ int main(int argc, char** argv)
153 view->show();
181 view->show();
154 }
182 }
155
183
156− int result = application.exec();
184+ int result = application->exec();
157
185
158 delete mouseTouchAdaptor;
186 delete mouseTouchAdaptor;
187+ delete application;
159
188
160 return result;
189 return result;
161}
190}
191+
192+int main(int argc, const char *argv[])
193+{
194+ // For ubuntumirserver/ubuntumirclient
195+ if (qgetenv("QT_QPA_PLATFORM").startsWith("ubuntumir")) {
196+ setenv("QT_QPA_PLATFORM", "ubuntumirserver", 1);
197+
198+ // If we use unity-mir directly, we automatically link to the Mir-server
199+ // platform-api bindings, which result in unexpected behaviour when
200+ // running the non-Mir scenario.
201+ QLibrary unityMir("unity-mir", 1);
202+ unityMir.load();
203+ if (!unityMir.isLoaded()) {
204+ qDebug() << "Library unity-mir not found/loaded";
205+ return 1;
206+ }
207+
208+ typedef QMirServer* (*createServer_t)(int, const char **);
209+ createServer_t createQMirServer = (createServer_t) unityMir.resolve("createQMirServer");
210+ if (!createQMirServer) {
211+ qDebug() << "unable to resolve symbol: createQMirServer";
212+ return 2;
213+ }
214+
215+ QMirServer* mirServer = createQMirServer(argc, argv);
216+
217+ typedef int (*runWithClient_t)(QMirServer*, std::function<int(int, const char**, void*)>);
218+ runWithClient_t runWithClient = (runWithClient_t) unityMir.resolve("runQMirServerWithClient");
219+ if (!runWithClient) {
220+ qDebug() << "unable to resolve symbol: runWithClient";
221+ return 3;
222+ }
223+
224+ return runWithClient(mirServer, startShell);
225+ } else {
226+ return startShell(argc, argv, nullptr);
227+ }
228+}
plugins/Unity/CMakeLists.txt+1
@@ -47,6 +47,7 @@ set(QMLPLUGIN_SRC
47 signalslist.cpp
47 signalslist.cpp
48 socialpreview.cpp
48 socialpreview.cpp
49 socialpreviewcomment.cpp
49 socialpreviewcomment.cpp
50+ iconutils.cpp
50 variantutils.cpp
51 variantutils.cpp
51)
52)
52
53
plugins/Unity/Indicators/CMakeLists.txt+9
@@ -34,11 +34,20 @@ set(IndicatorsQML_SOURCES
34 rootactionstate.cpp
34 rootactionstate.cpp
35 unitymenumodelcache.cpp
35 unitymenumodelcache.cpp
36 unitymenumodelstack.cpp
36 unitymenumodelstack.cpp
37+ visibleindicatorsmodel.cpp
37)
38)
38add_definitions(-DUNITYINDICATORS_LIBRARY)
39add_definitions(-DUNITYINDICATORS_LIBRARY)
39
40
41+set(IndicatorsQML_RESOURCES
42+ resources/indicators.qrc
43+)
44+
45+qt5_add_resources(IndicatorsQML_RESOURCES_RCC
46+ ${IndicatorsQML_RESOURCES}
47+)
40
48
41add_library(IndicatorsQml SHARED
49add_library(IndicatorsQml SHARED
50+ ${IndicatorsQML_RESOURCES_RCC}
42 ${IndicatorsQML_SOURCES}
51 ${IndicatorsQML_SOURCES}
43)
52)
44
53
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+2
@@ -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);
@@ -47,6 +48,7 @@ void Indicators2Plugin::registerTypes(const char *uri)
47 qmlRegisterType<UnityMenuModelStack>(uri, 0, 1, "UnityMenuModelStack");
48 qmlRegisterType<UnityMenuModelStack>(uri, 0, 1, "UnityMenuModelStack");
48 qmlRegisterType<RootActionState>(uri, 0, 1, "RootActionState");
49 qmlRegisterType<RootActionState>(uri, 0, 1, "RootActionState");
49 qmlRegisterType<ModelPrinter>(uri, 0, 1, "ModelPrinter");
50 qmlRegisterType<ModelPrinter>(uri, 0, 1, "ModelPrinter");
51+ qmlRegisterType<VisibleIndicatorsModel>(uri, 0, 1, "VisibleIndicatorsModel");
50
52
51 qmlRegisterSingletonType<UnityMenuModelCache>(uri, 0, 1, "UnityMenuModelCache", menuModelCacheSingleton);
53 qmlRegisterSingletonType<UnityMenuModelCache>(uri, 0, 1, "UnityMenuModelCache", menuModelCacheSingleton);
52
54
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/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+5−5
@@ -159,17 +159,17 @@ Item {
159 id: accessPoint;
159 id: accessPoint;
160 ICNetwork.AccessPoint {
160 ICNetwork.AccessPoint {
161 property QtObject menu: null
161 property QtObject menu: null
162−// property var strenthAction: QMenuModel.UnityMenuAction {
162+ property var strengthAction: QMenuModel.UnityMenuAction {
163−// model: menuFactory.model ? menuFactory.model : null
163+ model: menuFactory.model ? menuFactory.model : null
164−// name: menu ? menu.ext.xCanonicalWifiApStrengthAction : ""
164+ name: menu ? menu.ext.xCanonicalWifiApStrengthAction : ""
165−// }
165+ }
166
166
167 text: menu && menu.label ? menu.label : ""
167 text: menu && menu.label ? menu.label : ""
168 icon: menu ? menu.icon : ""
168 icon: menu ? menu.icon : ""
169 secure: menu ? menu.ext.xCanonicalWifiApIsSecure : false
169 secure: menu ? menu.ext.xCanonicalWifiApIsSecure : false
170 adHoc: menu ? menu.ext.xCanonicalWifiApIsAdhoc : false
170 adHoc: menu ? menu.ext.xCanonicalWifiApIsAdhoc : false
171 checked: menu ? menu.isToggled : false
171 checked: menu ? menu.isToggled : false
172−// signalStrength: strenthAction.valid ? strenthAction.state : 0
172+ signalStrength: strengthAction.valid ? strengthAction.state : 0
173 enabled: menu ? menu.sensitive : false
173 enabled: menu ? menu.sensitive : false
174
174
175 Component.onCompleted: {
175 Component.onCompleted: {
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+5
@@ -0,0 +1,5 @@
1+<RCC>
2+ <qresource prefix="/indicators">
3+ <file>artwork/network/secure.svg</file>
4+ </qresource>
5+</RCC>
plugins/Unity/Indicators/rootactionstate.cpp+8−8
@@ -148,15 +148,15 @@ static QString iconUri(GIcon *icon)
148 QString uri;
148 QString uri;
149
149
150 if (G_IS_THEMED_ICON (icon)) {
150 if (G_IS_THEMED_ICON (icon)) {
151−
152 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));
153− guint index = 0;
152+
153+ QStringList iconNameList;
154− while(iconNames[index] != NULL) {
154+ for (uint index = 0; iconNames[index] != NULL; index++) {
155− if (QIcon::hasThemeIcon(iconNames[index])) {
155+ iconNameList << iconNames[index];
156+ }
157+
158+ if (!iconNameList.empty()) {
156− uri = QString("image://theme/%1").arg(iconNames[index]);
159+ uri = QString("image://theme/%1").arg(iconNameList.join(","));
157− break;
158− }
159− index++;
160 }
160 }
161 }
161 }
162 else if (G_IS_FILE_ICON (icon)) {
162 else if (G_IS_FILE_ICON (icon)) {
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/Messaging/qml/GroupedMessage.qml+1−1
@@ -44,7 +44,7 @@ Indicators.BasicMenuItem {
44 height: units.gu(6)
44 height: units.gu(6)
45 width: units.gu(6)
45 width: units.gu(6)
46 image: Image {
46 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"
47+ source: menu && (menu.extra.canonical_icon.length > 0) ? "image://theme/" + encodeURI(menu.extra.canonical_icon) : "qrc:/indicators/artwork/messaging/default_app.svg"
48 fillMode: Image.PreserveAspectFit
48 fillMode: Image.PreserveAspectFit
49 }
49 }
50 }
50 }
plugins/Unity/IndicatorsLegacy/Messaging/qml/HeroMessage.qml+2−2
@@ -48,8 +48,8 @@ Indicators.BasicMenuItem {
48 anchors.left: parent.left
48 anchors.left: parent.left
49 anchors.right: parent.right
49 anchors.right: parent.right
50
50
51− avatar: menu && (menu.extra.canonical_icon.length > 0) ? "image://gicon/" + encodeURI(menu.extra.canonical_icon) : "qrc:/indicators/artwork/messaging/default_contact.png"
51+ avatar: menu && (menu.extra.canonical_icon.length > 0) ? "image://theme/" + encodeURI(menu.extra.canonical_icon) : "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) : ""
52+ icon: menu && (menu.extra.canonical_app_icon.length > 0) ? "image://theme/" + encodeURI(menu.extra.canonical_app_icon) : ""
53 appIcon: icon
53 appIcon: icon
54
54
55 state: heroMessage.state
55 state: heroMessage.state
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/Launcher/CMakeLists.txt+2−1
@@ -1,5 +1,6 @@
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)
3pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
4pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
4
5
5add_definitions(-DSM_BUSNAME=systemBus)
6add_definitions(-DSM_BUSNAME=systemBus)
plugins/Unity/Launcher/backend/launcherbackend.cpp+6−1
@@ -300,7 +300,12 @@ LauncherBackendItem* LauncherBackend::parseDesktopFile(const QString &desktopFil
300 LauncherBackendItem* item = new LauncherBackendItem();
300 LauncherBackendItem* item = new LauncherBackendItem();
301 item->desktopFile = desktopFile;
301 item->desktopFile = desktopFile;
302 item->displayName = settings.value("Desktop Entry/Name").toString();
302 item->displayName = settings.value("Desktop Entry/Name").toString();
303+
304+ if (settings.contains("Desktop Entry/Path")) {
303− item->icon = settings.value("Desktop Entry/Icon").toString();
305+ item->icon = settings.value("Desktop Entry/Path").toString() + "/" + settings.value("Desktop Entry/Icon").toString();
306+ } else {
307+ item->icon = settings.value("Desktop Entry/Icon").toString();
308+ }
304 item->pinned = false;
309 item->pinned = false;
305 return item;
310 return item;
306}
311}
plugins/Unity/Launcher/launcheritem.cpp+1−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),
@@ -48,11 +47,6 @@ QString LauncherItem::appId() const
48 return m_appId;
47 return m_appId;
49}
48}
50
49
51−QString LauncherItem::desktopFile() const
52−{
53− return m_desktopFile;
54−}
55−
56QString LauncherItem::name() const
50QString LauncherItem::name() const
57{
51{
58 return m_name;
52 return m_name;
plugins/Unity/Launcher/launcheritem.h+1−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
@@ -65,7 +64,6 @@ Q_SIGNALS:
65
64
66private:
65private:
67 QString m_appId;
66 QString m_appId;
68− QString m_desktopFile;
69 QString m_name;
67 QString m_name;
70 QString m_icon;
68 QString m_icon;
71 bool m_pinned;
69 bool m_pinned;
plugins/Unity/Launcher/launchermodel.cpp+94−46
@@ -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(true, 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:
@@ -137,7 +139,6 @@ void LauncherModel::pin(const QString &appId, int index)
137 }
139 }
138 beginInsertRows(QModelIndex(), index, index);
140 beginInsertRows(QModelIndex(), index, index);
139 LauncherItem *item = new LauncherItem(appId,
141 LauncherItem *item = new LauncherItem(appId,
140− m_backend->desktopFile(appId),
141 m_backend->displayName(appId),
142 m_backend->displayName(appId),
142 m_backend->icon(appId));
143 m_backend->icon(appId));
143 item->setPinned(true);
144 item->setPinned(true);
@@ -193,45 +194,21 @@ void LauncherModel::setUser(const QString &username)
193 m_backend->setUser(username);
194 m_backend->setUser(username);
194}
195}
195
196
196−void LauncherModel::applicationFocused(const QString &appId)
197+ApplicationManagerInterface *LauncherModel::applicationManager() const
197{
198{
198− // Unfocus all apps
199− for(int i = 0; i < m_list.count(); ++i) {
200− LauncherItem *item = m_list.at(i);
201− if (item->focused()) {
202− item->setFocused(false);
203− Q_EMIT dataChanged(this->index(i), this->index(i), QVector<int>() << RoleFocused);
204− }
205− }
206−
207− if (appId.isEmpty()) {
208− return;
199+ return m_appManager;
209− }
200+}
210−
211− // FIXME: drop this once we get real appIds from the AppManager
212− QString helper = appId.split('/').last();
213− if (helper.endsWith(".desktop")) {
214− helper.chop(8);
215− }
216−
217− int index = findApplication(helper);
218− if (index >= 0) {
219− m_list.at(index)->setFocused(true);
220− Q_EMIT dataChanged(this->index(index), this->index(index), QVector<int>() << RoleFocused);
221− } else {
222− // Add app to recent apps
223− QString desktopFile = m_backend->desktopFile(helper);
224− QString appName = m_backend->displayName(helper);
225− QString icon = m_backend->icon(helper);
226−
227− LauncherItem *item = new LauncherItem(helper, desktopFile, appName, icon);
228− item->setRecent(true);
229− item->setFocused(true);
230− beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
231− m_list.append(item);
232− endInsertRows();
233
201
234− // Clean up old recent apps
202+void LauncherModel::setApplicationManager(unity::shell::application::ApplicationManagerInterface *appManager)
203+{
204+ // Is there already another appmanager set?
205+ if (m_appManager) {
206+ // Disconnect any signals
207+ disconnect(this, SLOT(applicationAdded(QModelIndex,int)));
208+ disconnect(this, SLOT(applicationRemoved(QModelIndex,int)));
209+ disconnect(this, SLOT(focusedAppIdChanged()));
210+
211+ // remove any recent/running apps from the launcher
235 QList<int> recentAppIndices;
212 QList<int> recentAppIndices;
236 for (int i = 0; i < m_list.count(); ++i) {
213 for (int i = 0; i < m_list.count(); ++i) {
237 if (m_list.at(i)->recent()) {
214 if (m_list.at(i)->recent()) {
@@ -239,22 +216,33 @@ void LauncherModel::applicationFocused(const QString &appId)
239 }
216 }
240 }
217 }
241 int run = 0;
218 int run = 0;
242− while (recentAppIndices.count() > 5) {
219+ while (recentAppIndices.count() > 0) {
243 beginRemoveRows(QModelIndex(), recentAppIndices.first() - run, recentAppIndices.first() - run);
220 beginRemoveRows(QModelIndex(), recentAppIndices.first() - run, recentAppIndices.first() - run);
244 m_list.takeAt(recentAppIndices.first() - run)->deleteLater();
221 m_list.takeAt(recentAppIndices.first() - run)->deleteLater();
245 endRemoveRows();
222 endRemoveRows();
246 recentAppIndices.takeFirst();
223 recentAppIndices.takeFirst();
247 ++run;
224 ++run;
248 }
225 }
249− storeAppList();
226+ }
227+
228+ m_appManager = appManager;
229+ connect(m_appManager, SIGNAL(rowsInserted(QModelIndex, int, int)), SLOT(applicationAdded(QModelIndex,int)));
230+ connect(m_appManager, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), SLOT(applicationRemoved(QModelIndex,int)));
231+ connect(m_appManager, SIGNAL(focusedApplicationIdChanged()), SLOT(focusedAppIdChanged()));
232+
233+ Q_EMIT applicationManagerChanged();
234+
235+ for (int i = 0; i < appManager->count(); ++i) {
236+ applicationAdded(QModelIndex(), i);
250 }
237 }
251}
238}
252
239
240+
253void LauncherModel::storeAppList()
241void LauncherModel::storeAppList()
254{
242{
255 QStringList appIds;
243 QStringList appIds;
256 Q_FOREACH(LauncherItem *item, m_list) {
244 Q_FOREACH(LauncherItem *item, m_list) {
257− if (item->pinned() || item->recent()) {
245+ if (item->pinned()) {
258 appIds << item->appId();
246 appIds << item->appId();
259 }
247 }
260 }
248 }
@@ -292,3 +280,63 @@ void LauncherModel::countChanged(const QString &appId, int count)
292 Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleCount);
280 Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleCount);
293 }
281 }
294}
282}
283+
284+void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
285+{
286+ Q_UNUSED(parent);
287+
288+ ApplicationInfoInterface *app = m_appManager->get(row);
289+
290+ bool found = false;
291+ Q_FOREACH(LauncherItem *item, m_list) {
292+ if (app->appId() == item->appId()) {
293+ found = true;
294+ break;
295+ }
296+ }
297+ if (found) {
298+ // Shall we paint some running/recent app highlight? If yes, do it here.
299+ } else {
300+ LauncherItem *item = new LauncherItem(app->appId(), app->name(), app->icon().toString());
301+ item->setRecent(true);
302+ item->setFocused(app->focused());
303+
304+ beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
305+ m_list.append(item);
306+ endInsertRows();
307+ }
308+}
309+
310+void LauncherModel::applicationRemoved(const QModelIndex &parent, int row)
311+{
312+ Q_UNUSED(parent)
313+
314+ int appIndex = -1;
315+ for (int i = 0; i < m_list.count(); ++i) {
316+ if (m_list.at(i)->appId() == m_appManager->get(row)->appId()) {
317+ appIndex = i;
318+ break;
319+ }
320+ }
321+
322+ if (appIndex > -1 && !m_list.at(appIndex)->pinned()) {
323+ beginRemoveRows(QModelIndex(), appIndex, appIndex);
324+ m_list.takeAt(appIndex)->deleteLater();
325+ endRemoveRows();
326+ }
327+}
328+
329+void LauncherModel::focusedAppIdChanged()
330+{
331+ QString appId = m_appManager->focusedApplicationId();
332+ for (int i = 0; i < m_list.count(); ++i) {
333+ LauncherItem *item = m_list.at(i);
334+ if (!item->focused() && item->appId() == appId) {
335+ item->setFocused(true);
336+ Q_EMIT dataChanged(index(i), index(i), QVector<int>() << RoleFocused);
337+ } else if (item->focused() && item->appId() != appId) {
338+ item->setFocused(false);
339+ Q_EMIT dataChanged(index(i), index(i), QVector<int>() << RoleFocused);
340+ }
341+ }
342+}
plugins/Unity/Launcher/launchermodel.h+10−1
@@ -22,6 +22,7 @@
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{
@@ -49,7 +51,9 @@ public:
49 Q_INVOKABLE void requestRemove(const QString &appId);
51 Q_INVOKABLE void requestRemove(const QString &appId);
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− Q_INVOKABLE void applicationFocused(const QString &appId);
54+
55+ unity::shell::application::ApplicationManagerInterface* applicationManager() const;
56+ void setApplicationManager(unity::shell::application::ApplicationManagerInterface *appManager);
53
57
54private:
58private:
55 void storeAppList();
59 void storeAppList();
@@ -59,9 +63,14 @@ private Q_SLOTS:
59 void progressChanged(const QString &appId, int progress);
63 void progressChanged(const QString &appId, int progress);
60 void countChanged(const QString &appId, int count);
64 void countChanged(const QString &appId, int count);
61
65
66+ void applicationAdded(const QModelIndex &parent, int row);
67+ void applicationRemoved(const QModelIndex &parent, int row);
68+ void focusedAppIdChanged();
69+
62private:
70private:
63 QList<LauncherItem*> m_list;
71 QList<LauncherItem*> m_list;
64 LauncherBackend *m_backend;
72 LauncherBackend *m_backend;
73+ ApplicationManagerInterface *m_appManager;
65};
74};
66
75
67#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/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/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:"))) {
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/preview.cpp+5−1
@@ -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
@@ -102,7 +103,10 @@ QVariantMap Preview::infoHintsHash() const
102QString Preview::image() const
103QString Preview::image() const
103{
104{
104 if (m_unityPreview) {
105 if (m_unityPreview) {
105− return QString::fromUtf8(g_icon_to_string(m_unityPreview->image()));
106+ auto giconString = g_icon_to_string(m_unityPreview->image());
107+ QString result(gIconToDeclarativeImageProviderString(QString::fromUtf8(giconString)));
108+ g_free(giconString);
109+ return result;
106 } else {
110 } else {
107 qWarning() << "Preview not set";
111 qWarning() << "Preview not set";
108 }
112 }
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/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/ca.po+32−32
@@ -8,83 +8,83 @@ 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-11 10:30+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-30 05:37+0000\n"
18+"X-Launchpad-Export-Date: 2013-09-12 08:06+0000\n"
19−"X-Generator: Launchpad (build 16750)\n"
19+"X-Generator: Launchpad (build 16761)\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"
@@ -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 "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"
@@ -100,7 +100,7 @@ msgstr ""
100
100
101#: Components/EdgeDemo.qml:135
101#: Components/EdgeDemo.qml:135
102msgid "Top edge"
102msgid "Top edge"
103−msgstr ""
103+msgstr "Vora 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"
@@ -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 "Vora esquerra"
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 "Enhorabona!"
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 "Cerques recents"
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
@@ -158,7 +158,7 @@ msgstr ""
158
158
159#: Dash/Apps/AppReviews.qml:84
159#: Dash/Apps/AppReviews.qml:84
160msgid "Review"
160msgid "Review"
161−msgstr ""
161+msgstr "Ressenya"
162
162
163#: Dash/Apps/AppReviews.qml:118
163#: Dash/Apps/AppReviews.qml:118
164msgid "Send"
164msgid "Send"
@@ -166,15 +166,15 @@ msgstr ""
166
166
167#: Dash/Apps/AppReviews.qml:136
167#: Dash/Apps/AppReviews.qml:136
168msgid "Comments:"
168msgid "Comments:"
169−msgstr ""
169+msgstr "Comentaris:"
170
170
171#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
171#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
172msgid "Featured"
172msgid "Featured"
173−msgstr ""
173+msgstr "Destacats"
174
174
175#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
175#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
176msgid "Recent"
176msgid "Recent"
177−msgstr ""
177+msgstr "Recents"
178
178
179#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
179#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
180msgid "New Releases"
180msgid "New Releases"
@@ -206,7 +206,7 @@ msgstr ""
206
206
207#: Dash/Video/VideoPreview.qml:176
207#: Dash/Video/VideoPreview.qml:176
208msgid "Author:"
208msgid "Author:"
209−msgstr ""
209+msgstr "Autor:"
210
210
211#: Greeter/Lockscreen.qml:134
211#: Greeter/Lockscreen.qml:134
212msgid "Emergency Call"
212msgid "Emergency Call"
@@ -219,7 +219,7 @@ msgstr ""
219
219
220#: Greeter/PassphraseLockscreen.qml:59
220#: Greeter/PassphraseLockscreen.qml:59
221msgid "Hello"
221msgid "Hello"
222−msgstr ""
222+msgstr "Hola"
223
223
224#: Hud/HudParametrizedActionsPage.qml:132
224#: Hud/HudParametrizedActionsPage.qml:132
225msgid "Confirm"
225msgid "Confirm"
tests/autopilot/unity8/shell/tests/test_hud.py+7−2
@@ -33,6 +33,8 @@ class TestHud(UnityTestCase):
33
33
34 def test_show_hud_button_appears(self):
34 def test_show_hud_button_appears(self):
35 """Swiping up while an app is active must show the 'show hud' button.
35 """Swiping up while an app is active must show the 'show hud' button.
36+ The button must disappear not opening the HUD when releasing the
37+ mouse again somewhere on the screen except on the button itself.
36
38
37 """
39 """
38 self.launch_unity()
40 self.launch_unity()
@@ -47,9 +49,12 @@ class TestHud(UnityTestCase):
47 hud_show_button
49 hud_show_button
48 )
50 )
49 self.touch.press(swipe_coords.start_x, swipe_coords.start_y)
51 self.touch.press(swipe_coords.start_x, swipe_coords.start_y)
50− self.addCleanup(self.touch.release)
52+ self.addCleanup(self._maybe_release_finger)
51− self.touch._finger_move(swipe_coords.end_x, swipe_coords.end_y)
53+ self.touch._finger_move(swipe_coords.end_x, swipe_coords.end_y + hud_show_button.height);
52 self.assertThat(hud_show_button.opacity, Eventually(Equals(1.0)))
54 self.assertThat(hud_show_button.opacity, Eventually(Equals(1.0)))
55+ self.touch.release();
56+ self.assertThat(hud_show_button.opacity, Eventually(Equals(0.0)))
57+ self.assertThat(hud.shown, Equals(False))
53
58
54 def test_show_hud_appears(self):
59 def test_show_hud_appears(self):
55 """Releasing the touch on the 'show hud' button must display the hud.
60 """Releasing the touch on the 'show hud' button must display the hud.
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/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+2
@@ -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,7 @@ 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
20 fake_applications_scope.cpp
22 fake_applications_scope.cpp
21 fake_preview.cpp
23 fake_preview.cpp
22 fake_scope.cpp
24 fake_scope.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+1−1
@@ -1,5 +1,5 @@
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
3
4add_definitions(-DTOP_SRCDIR="${CMAKE_SOURCE_DIR}")
4add_definitions(-DTOP_SRCDIR="${CMAKE_SOURCE_DIR}")
5
5
tests/mocks/Unity/Launcher/MockLauncherModel.cpp+7−4
@@ -71,8 +71,6 @@ QVariant MockLauncherModel::data(const QModelIndex& index, int role) const
71 LauncherItemInterface *item = m_list.at(index.row());
71 LauncherItemInterface *item = m_list.at(index.row());
72 switch(role)
72 switch(role)
73 {
73 {
74− case RoleDesktopFile:
75− return item->desktopFile();
76 case RoleName:
74 case RoleName:
77 return item->name();
75 return item->name();
78 case RoleIcon:
76 case RoleIcon:
@@ -185,7 +183,12 @@ void MockLauncherModel::setUser(const QString &username)
185 // TODO: implement this...
183 // TODO: implement this...
186}
184}
187
185
188−void MockLauncherModel::applicationFocused(const QString &appId)
186+void MockLauncherModel::setApplicationManager(unity::shell::application::ApplicationManagerInterface *applicationManager)
189{
187{
190− Q_UNUSED(appId)
188+ Q_UNUSED(applicationManager)
189+}
190+
191+unity::shell::application::ApplicationManagerInterface *MockLauncherModel::applicationManager() const
192+{
193+ return nullptr;
191}
194}
tests/mocks/Unity/Launcher/MockLauncherModel.h+3−1
@@ -44,7 +44,9 @@ public:
44 Q_INVOKABLE void requestRemove(const QString &appId);
44 Q_INVOKABLE void requestRemove(const QString &appId);
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− Q_INVOKABLE void applicationFocused(const QString &appId);
47+
48+ unity::shell::application::ApplicationManagerInterface *applicationManager() const;
49+ void setApplicationManager(unity::shell::application::ApplicationManagerInterface *applicationManager);
48
50
49Q_SIGNALS:
51Q_SIGNALS:
50 void quickListTriggered(const QString &appId, int index);
52 void quickListTriggered(const QString &appId, int index);
tests/plugins/Unity/CMakeLists.txt+4
@@ -5,6 +5,7 @@ pkg_check_modules(UNITYCORE REQUIRED unity-core-6.0)
5pkg_check_modules(LIBUNITYPROTO REQUIRED unity-protocol-private)
5pkg_check_modules(LIBUNITYPROTO REQUIRED unity-protocol-private)
6pkg_check_modules(LIBUNITY REQUIRED unity)
6pkg_check_modules(LIBUNITY REQUIRED unity)
7pkg_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)
8
9
9include_directories(
10include_directories(
10 ${Unity-qml_SOURCE_DIR}
11 ${Unity-qml_SOURCE_DIR}
@@ -14,6 +15,7 @@ include_directories(
14 ${LIBUNITY_INCLUDE_DIRS}
15 ${LIBUNITY_INCLUDE_DIRS}
15 ${LIBSIGCPP_INCLUDE_DIRS}
16 ${LIBSIGCPP_INCLUDE_DIRS}
16 ${UNITYCORE_INCLUDE_DIRS}
17 ${UNITYCORE_INCLUDE_DIRS}
18+ ${QTDEE_INCLUDE_DIRS}
17 )
19 )
18
20
19macro(run_tests)
21macro(run_tests)
@@ -36,6 +38,7 @@ macro(run_tests)
36 ${LIBUNITY_LDFLAGS}
38 ${LIBUNITY_LDFLAGS}
37 ${LIBUNITYPROTO_LDFLAGS}
39 ${LIBUNITYPROTO_LDFLAGS}
38 ${LIBSIGCPP_LDFLAGS}
40 ${LIBSIGCPP_LDFLAGS}
41+ ${QTDEE_LDFLAGS}
39 )
42 )
40
43
41 set(_test_list "${_test_list};${_test}")
44 set(_test_list "${_test_list};${_test}")
@@ -46,4 +49,5 @@ run_tests(
46 signalslisttest
49 signalslisttest
47 previewbindingstest
50 previewbindingstest
48 filtersbindingstest
51 filtersbindingstest
52+ resultstest
49 )
53 )
tests/plugins/Unity/Launcher/CMakeLists.txt+13−1
@@ -1,5 +1,6 @@
1pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
1pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
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)
3
4
4include_directories(
5include_directories(
5 ${CMAKE_CURRENT_BINARY_DIR}
6 ${CMAKE_CURRENT_BINARY_DIR}
@@ -45,6 +46,8 @@ add_executable(launchermodeltestExec
45 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
46 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
46 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
47 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
47 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.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
48 )
51 )
49target_link_libraries(launchermodeltestExec ${GSETTINGS_QT_LDFLAGS} )
52target_link_libraries(launchermodeltestExec ${GSETTINGS_QT_LDFLAGS} )
50qt5_use_modules(launchermodeltestExec Test Core DBus)
53qt5_use_modules(launchermodeltestExec Test Core DBus)
@@ -57,3 +60,12 @@ foreach(DESKTOP_FILE ${DESKTOP_FILES})
57 DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
60 DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
58 )
61 )
59endforeach()
62endforeach()
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/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/launcherbackendtest.cpp+25
@@ -54,6 +54,31 @@ private Q_SLOTS:
54 QCOMPARE(backend.isPinned("rel-icon"), true);
54 QCOMPARE(backend.isPinned("rel-icon"), true);
55 QCOMPARE(backend.isPinned("no-name"), false); // doesn't exist anymore!
55 QCOMPARE(backend.isPinned("no-name"), false); // doesn't exist anymore!
56 }
56 }
57+
58+ void testIcon_data() {
59+ QTest::addColumn<QString>("appId");
60+ QTest::addColumn<QString>("expectedIcon");
61+
62+ // Needs to expand a relative icon to the absolute path
63+ QTest::newRow("relative icon path") << "rel-icon" << QDir::currentPath() + "/rel-icon.svg";
64+
65+ // In case an icon is not found on disk, it needs to fallback on image://theme/ for it
66+ QTest::newRow("fallback on theme") << "abs-icon" << "image://theme//path/to/icon.png";
67+
68+ // Click packages have a relative icon path but an absolute path as a separate entry
69+ // As we don't want to rely on a click app being installed for the test, accept it with the image://theme fallback
70+ QTest::newRow("click package icon") << "click-icon" << "image://theme//path/to/some/click/app/click-icon.svg";
71+ }
72+
73+ void testIcon() {
74+ QFETCH(QString, appId);
75+ QFETCH(QString, expectedIcon);
76+
77+ LauncherBackend backend(false);
78+ backend.setStoredApplications(QStringList() << appId);
79+
80+ QCOMPARE(backend.icon(appId), expectedIcon);
81+ }
57};
82};
58
83
59QTEST_GUILESS_MAIN(LauncherBackendTest)
84QTEST_GUILESS_MAIN(LauncherBackendTest)
tests/plugins/Unity/Launcher/launchermodeltest.cpp+88−18
@@ -19,38 +19,109 @@
19
19
20// unity-api
20// unity-api
21#include <unity/shell/launcher/LauncherModelInterface.h>
21#include <unity/shell/launcher/LauncherModelInterface.h>
22+#include <unity/shell/application/ApplicationInfoInterface.h>
22
23
23#include "launcheritem.h"
24#include "launcheritem.h"
24#include "launchermodel.h"
25#include "launchermodel.h"
25
26
26#include <QtTest>
27#include <QtTest>
27
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 &) const { return nullptr; }
66+ unity::shell::application::ApplicationInfoInterface *startApplication(const QString &, const QStringList &) { return nullptr; }
67+ bool stopApplication(const QString &) { return false; }
68+ bool focusApplication(const QString &appId) {
69+ Q_FOREACH(MockApp* app, m_list) {
70+ app->setFocused(app->appId() == appId);
71+ }
72+ Q_EMIT focusedApplicationIdChanged();
73+ return true;
74+ }
75+
76+ void unfocusCurrentApplication() { }
77+
78+ void addApplication(MockApp *app) {
79+ beginInsertRows(QModelIndex(), count(), count());
80+ m_list.append(app);
81+ endInsertRows();
82+ }
83+ void removeApplication(int index) {
84+ beginRemoveRows(QModelIndex(), index, index);
85+ m_list.takeAt(index)->deleteLater();
86+ endRemoveRows();
87+ }
88+
89+private:
90+ QList<MockApp*> m_list;
91+};
92+
28class LauncherModelTest : public QObject
93class LauncherModelTest : public QObject
29{
94{
30 Q_OBJECT
95 Q_OBJECT
31
96
32private:
97private:
33 LauncherModel *launcherModel;
98 LauncherModel *launcherModel;
99+ MockAppManager *appManager;
34
100
35private Q_SLOTS:
101private Q_SLOTS:
36
102
37 void initTestCase() {
103 void initTestCase() {
38 launcherModel = new LauncherModel(this);
104 launcherModel = new LauncherModel(this);
39 QCOMPARE(launcherModel->rowCount(QModelIndex()), 0);
105 QCOMPARE(launcherModel->rowCount(QModelIndex()), 0);
106+
107+ appManager = new MockAppManager(this);
108+ launcherModel->setApplicationManager(appManager);
40 }
109 }
41
110
111+ // Adding 2 apps to the mock appmanager. Both should appear in the launcher.
42 void init() {
112 void init() {
43− qDebug() << "init";
113+ appManager->addApplication(new MockApp("abs-icon"));
44− launcherModel->applicationFocused("abs-icon");
45 QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
114 QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
46
115
47− launcherModel->applicationFocused("no-icon.desktop");
116+ appManager->addApplication(new MockApp("no-icon"));
48 QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
117 QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
49−
50− launcherModel->applicationFocused(QString());
51 }
118 }
52
119
120+ // Removing apps from appmanager and launcher as pinned ones would stick
53 void cleanup() {
121 void cleanup() {
122+ while (appManager->count() > 0) {
123+ appManager->removeApplication(0);
124+ }
54 while (launcherModel->rowCount(QModelIndex()) > 0) {
125 while (launcherModel->rowCount(QModelIndex()) > 0) {
55 launcherModel->requestRemove(launcherModel->get(0)->appId());
126 launcherModel->requestRemove(launcherModel->get(0)->appId());
56 }
127 }
@@ -118,27 +189,26 @@ private Q_SLOTS:
118 QCOMPARE(launcherModel->get(0)->focused(), false);
189 QCOMPARE(launcherModel->get(0)->focused(), false);
119 QCOMPARE(launcherModel->get(1)->focused(), false);
190 QCOMPARE(launcherModel->get(1)->focused(), false);
120
191
121− launcherModel->applicationFocused("abs-icon");
192+ appManager->focusApplication("abs-icon");
122 QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
193 QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
123 QCOMPARE(launcherModel->get(0)->focused(), true);
194 QCOMPARE(launcherModel->get(0)->focused(), true);
124 QCOMPARE(launcherModel->get(1)->focused(), false);
195 QCOMPARE(launcherModel->get(1)->focused(), false);
125
196
126− launcherModel->applicationFocused("no-icon");
197+ appManager->focusApplication("no-icon");
127 QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
198 QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
128 QCOMPARE(launcherModel->get(0)->focused(), false);
199 QCOMPARE(launcherModel->get(0)->focused(), false);
129 QCOMPARE(launcherModel->get(1)->focused(), true);
200 QCOMPARE(launcherModel->get(1)->focused(), true);
201+ }
130
202
203+ void testClosingApps() {
204+ // At the start there are 2 items. Let's pin one.
131− launcherModel->applicationFocused("rel-icon");
205+ launcherModel->pin("abs-icon");
132− QCOMPARE(launcherModel->rowCount(QModelIndex()), 3);
206+ while (appManager->count() > 0) {
133− QCOMPARE(launcherModel->get(0)->focused(), false);
207+ appManager->removeApplication(0);
134− QCOMPARE(launcherModel->get(1)->focused(), false);
208+ }
135− QCOMPARE(launcherModel->get(2)->focused(), true);
209+ // The pinned one needs to stay, the other needs to disappear
136−
137− launcherModel->applicationFocused(QString());
138− QCOMPARE(launcherModel->rowCount(QModelIndex()), 3);
210+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
139− QCOMPARE(launcherModel->get(0)->focused(), false);
211+ QCOMPARE(launcherModel->get(0)->appId(), QLatin1String("abs-icon"));
140− QCOMPARE(launcherModel->get(1)->focused(), false);
141− QCOMPARE(launcherModel->get(2)->focused(), false);
142 }
212 }
143};
213};
144
214
tests/plugins/Unity/Launcher/rel-icon.desktop+1−1
@@ -1,3 +1,3 @@
1[Desktop Entry]
1[Desktop Entry]
2Name=Relative Icon
2Name=Relative Icon
3−Icon=rel-icon
3+Icon=rel-icon.svg
tests/plugins/Unity/Launcher/rel-icon.svgnew file

No changes to the content.

tests/plugins/Unity/resultstest.cppnew file+104
@@ -0,0 +1,104 @@
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("themed icon") << "accessories-other" << "image://theme/accessories-other";
75+ QTest::newRow("fileicon") << ". GFileIcon http://example.org/resource.gif" << "http://example.org/resource.gif";
76+ QTest::newRow("themedicon") << ". GThemedIcon accessories-other accessories generic" << "image://theme/accessories-other,accessories,generic";
77+ QTest::newRow("annotatedicon") << ". UnityProtocolAnnotatedIcon %7B'base-icon':%20%3C'.%20GThemedIcon%20accessories-other%20accessories%20generic'%3E%7D" << "image://theme/accessories-other,accessories,generic";
78+}
79+
80+void ResultsTest::testIconColumn()
81+{
82+ QFETCH(QString, giconString);
83+ QFETCH(QString, result);
84+ auto deeModel = createBackendModel();
85+ dee_model_append (deeModel,
86+ "test:uri",
87+ giconString.toLocal8Bit().constData(),
88+ 0,
89+ 0,
90+ "application/octet-stream",
91+ "Test",
92+ "",
93+ "test:dnd-uri",
94+ g_variant_new_array(g_variant_type_element(G_VARIANT_TYPE_VARDICT), NULL, 0));
95+
96+ CategoryResults* results = new CategoryResults(this);
97+ results->setModel(deeModel);
98+
99+ auto index = results->index(0, 0); // there's just one result
100+ auto transformedIcon = index.data(CategoryResults::Roles::RoleIconHint).toString();
101+ QCOMPARE(transformedIcon, result);
102+}
103+
104+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/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_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/Launcher/tst_Launcher.qml+2−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()
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
@@ -56,16 +56,16 @@ Item {
56
56
57 function cleanup() {
57 function cleanup() {
58 // kill all (fake) running apps
58 // kill all (fake) running apps
59− killApps(ApplicationManager.mainStageApplications);
59+ killApps(ApplicationManager);
60− killApps(ApplicationManager.sideStageApplications);
61
60
62 var dashHome = findChild(shell, "DashHome");
61 var dashHome = findChild(shell, "DashHome");
63 swipeUntilScopeViewIsReached(dashHome);
62 swipeUntilScopeViewIsReached(dashHome);
64 }
63 }
65
64
66 function killApps(apps) {
65 function killApps(apps) {
66+ if (!apps) return;
67 while (apps.count > 0) {
67 while (apps.count > 0) {
68− ApplicationManager.stopProcess(apps.get(0));
68+ ApplicationManager.stopApplication(apps.get(0).appId);
69 }
69 }
70 }
70 }
71
71
@@ -104,14 +104,34 @@ Item {
104 checkRightEdgeDragWithNoRunningApps();
104 checkRightEdgeDragWithNoRunningApps();
105 }
105 }
106
106
107+ function test_leftEdgeDrag_data() {
108+ return [
109+ {tag: "without launcher", revealLauncher: false},
110+ {tag: "with launcher", revealLauncher: true},
111+ ];
112+ }
113+
114+ function test_leftEdgeDrag(data) {
115+ dragLauncherIntoView();
116+ tapOnAppIconInLauncher();
117+ waitUntilApplicationWindowIsFullyVisible();
118+
119+ if (data.revealLauncher) {
120+ dragLauncherIntoView();
121+ }
122+
123+ swipeFromLeftEdge();
124+ waitUntilApplicationWindowIsFullyHidden();
125+ }
126+
107 function test_suspend() {
127 function test_suspend() {
108 // Launch an app from the launcher
128 // Launch an app from the launcher
109 dragLauncherIntoView();
129 dragLauncherIntoView();
110 tapOnAppIconInLauncher();
130 tapOnAppIconInLauncher();
111 waitUntilApplicationWindowIsFullyVisible();
131 waitUntilApplicationWindowIsFullyVisible();
112
132
113− var mainApp = ApplicationManager.mainStageFocusedApplication;
133+ var mainApp = ApplicationManager.focusedApplicationId;
114− tryCompareFunction(function() { return mainApp != null; }, true);
134+ tryCompareFunction(function() { return mainApp != ""; }, true);
115
135
116 // Try to suspend while proximity is engaged...
136 // Try to suspend while proximity is engaged...
117 Powerd.displayPowerStateChange(Powerd.Off, Powerd.UseProximity);
137 Powerd.displayPowerStateChange(Powerd.Off, Powerd.UseProximity);
@@ -119,11 +139,11 @@ Item {
119
139
120 // Now really suspend
140 // Now really suspend
121 Powerd.displayPowerStateChange(Powerd.Off, 0);
141 Powerd.displayPowerStateChange(Powerd.Off, 0);
122− tryCompare(ApplicationManager, "mainStageFocusedApplication", null);
142+ tryCompare(ApplicationManager, "focusedApplicationId", "");
123
143
124 // And wake up
144 // And wake up
125 Powerd.displayPowerStateChange(Powerd.On, 0);
145 Powerd.displayPowerStateChange(Powerd.On, 0);
126− tryCompare(ApplicationManager, "mainStageFocusedApplication", mainApp);
146+ tryCompare(ApplicationManager, "focusedApplicationId", mainApp);
127 }
147 }
128
148
129 /*
149 /*
@@ -197,7 +217,11 @@ Item {
197 function dragLauncherIntoView() {
217 function dragLauncherIntoView() {
198 var launcherPanel = findChild(shell, "launcherPanel");
218 var launcherPanel = findChild(shell, "launcherPanel");
199 verify(launcherPanel.x = - launcherPanel.width);
219 verify(launcherPanel.x = - launcherPanel.width);
200− swipeFromLeftEdge();
220+
221+ var touchStartX = 2;
222+ var touchStartY = shell.height / 2;
223+ touchFlick(shell, touchStartX, touchStartY, launcherPanel.width + units.gu(1), touchStartY);
224+
201 tryCompare(launcherPanel, "x", 0);
225 tryCompare(launcherPanel, "x", 0);
202 }
226 }
203
227