on xenial help sign in
Merged with trunk, fixed text-field width of extended snap-decisions, removed unused code from snap-decisions.
commitcc25fa3e7caf442b4d7484e75150f5238b480d43 authorMirco Müller <mirco.mueller@ubuntu.com> dateFri 20 Sep 2013, 15:50 (13 years ago) parent0bd68a76fe2f9b
103 files changed+1968−650
Applications/Application.qml+1−1 Bottombar/Bottombar.qml+2−2 CMakeLists.txt+4 Components/ApplicationManagerWrapper.qml+89−42 Components/ApplicationScreenshot.qml+2−2 Components/ApplicationsModelStageFiltered.qml+49 Components/EdgeDemoOverlay.qml+1−1 Components/Stage.qml+1−1 Components/VolumeControl.qml+5−20 Dash/Apps/RunningApplicationTile.qml+2−3 Dash/Apps/RunningApplicationsGrid.qml+4−4 Dash/GenericScopeView.qml+4−1 Dash/graphics/phone/home.png Dash/graphics/phone/music.png Dash/graphics/phone/videos.png Dash/graphics/tablet/apps.png Dash/graphics/tablet/home.png Dash/graphics/tablet/music.png Dash/graphics/tablet/people.png Dash/graphics/tablet/videos.png Greeter/Greeter.qml+2 Greeter/GreeterContent.qml+4−3 Launcher/Launcher.qml+4−4 Launcher/LauncherPanel.qml+3−3 MouseTouchAdaptor.cpp+29−12 MouseTouchAdaptor.h+2−5 Notifications/NotificationMenuItemFactory.qml+11−21 Panel/Indicators/DefaultIndicatorWidget.qml+2−6 Panel/Indicators/MessagingIndicatorWidget.qml+1−1 Panel/Indicators/NetworkIndicatorWidget.qml+6−6 Panel/Indicators/SoundIndicatorWidget.qml+1−1 Shell.qml+50−36 SideStage/SideStage.qml+1−1 debian/changelog+146 debian/control+9−7 debian/unity8-private.install+1 main.cpp+73−7 plugins/CMakeLists.txt+1 plugins/SessionBroadcast/CMakeLists.txt+13 plugins/SessionBroadcast/SessionBroadcast.cpp+41 plugins/SessionBroadcast/SessionBroadcast.h+41 plugins/SessionBroadcast/plugin.cpp+35 plugins/SessionBroadcast/plugin.h+33 plugins/SessionBroadcast/qmldir+3 plugins/Unity/Indicators/rootactionstate.cpp+8−8 plugins/Unity/IndicatorsLegacy/Messaging/qml/GroupedMessage.qml+1−1 plugins/Unity/IndicatorsLegacy/Messaging/qml/HeroMessage.qml+2−2 plugins/Unity/IndicatorsLegacy/Network/qml/AccessPoint.qml+2−2 plugins/Unity/Launcher/CMakeLists.txt+2−1 plugins/Unity/Launcher/backend/launcherbackend.cpp+11−7 plugins/Unity/Launcher/launcheritem.cpp+1−7 plugins/Unity/Launcher/launcheritem.h+1−3 plugins/Unity/Launcher/launchermodel.cpp+106−49 plugins/Unity/Launcher/launchermodel.h+10−1 plugins/Utils/qsortfilterproxymodelqml.cpp+13−1 plugins/Utils/qsortfilterproxymodelqml.h+1 po/ca.po+32−32 po/is.po+256 po/sl.po+29−24 run_on_device+2−1 tests/autopilot/unity8/application_lifecycle/__init__.py+20 tests/autopilot/unity8/application_lifecycle/tests/__init__.py tests/autopilot/unity8/application_lifecycle/tests/test_application_lifecycle.py+136 tests/autopilot/unity8/shell/__init__.py+10 tests/autopilot/unity8/shell/tests/__init__.py+4−1 tests/mocks/AccountsService/AccountsService.cpp+9−2 tests/mocks/AccountsService/AccountsService.h+5 tests/mocks/Ubuntu/Application/CMakeLists.txt−29 tests/mocks/Ubuntu/Application/qmldir−3 tests/mocks/Ubuntu/CMakeLists.txt−1 tests/mocks/Ubuntu/Application/ApplicationImage.cpp → tests/mocks/Unity/Application/ApplicationImage.cpp tests/mocks/Ubuntu/Application/ApplicationImage.h → tests/mocks/Unity/Application/ApplicationImage.h tests/mocks/Ubuntu/Application/ApplicationInfo.cpp → tests/mocks/Unity/Application/ApplicationInfo.cpp+15−2 tests/mocks/Ubuntu/Application/ApplicationInfo.h → tests/mocks/Unity/Application/ApplicationInfo.h+12−18 tests/mocks/Ubuntu/Application/ApplicationListModel.cpp → tests/mocks/Unity/Application/ApplicationListModel.cpp tests/mocks/Ubuntu/Application/ApplicationListModel.h → tests/mocks/Unity/Application/ApplicationListModel.h tests/mocks/Ubuntu/Application/ApplicationManager.cpp → tests/mocks/Unity/Application/ApplicationManager.cpp+185−153 tests/mocks/Ubuntu/Application/ApplicationManager.h → tests/mocks/Unity/Application/ApplicationManager.h+26−26 tests/mocks/Unity/Application/CMakeLists.txt+37 tests/mocks/Ubuntu/Application/InputFilterArea.qml → tests/mocks/Unity/Application/InputFilterArea.qml tests/mocks/Unity/Application/OSKController.qml+20 tests/mocks/Ubuntu/Application/plugin.cpp → tests/mocks/Unity/Application/plugin.cpp+6−5 tests/mocks/Ubuntu/Application/plugin.h → tests/mocks/Unity/Application/plugin.h+1−1 tests/mocks/Unity/Application/qmldir+4 tests/mocks/Unity/CMakeLists.txt+1 tests/mocks/Unity/Launcher/CMakeLists.txt+1−1 tests/mocks/Unity/Launcher/MockLauncherModel.cpp+7−4 tests/mocks/Unity/Launcher/MockLauncherModel.h+3−1 tests/plugins/Unity/Launcher/CMakeLists.txt+13−1 tests/plugins/Unity/Launcher/click-icon.desktop+4 tests/plugins/Unity/Launcher/click-icon.svg tests/plugins/Unity/Launcher/launcherbackendtest.cpp+33 tests/plugins/Unity/Launcher/launchermodeltest.cpp+148−19 tests/plugins/Unity/Launcher/rel-icon.desktop+1−1 tests/plugins/Unity/Launcher/rel-icon.svg tests/qmltests/Components/tst_Stage.qml+1−1 tests/qmltests/Dash/Apps/tst_RunningApplicationsGrid.qml+55−37 tests/qmltests/Dash/tst_DashContent.qml+1−1 tests/qmltests/Dash/tst_GenericScopeView.qml+3 tests/qmltests/Greeter/tst_Phone.qml+19−1 tests/qmltests/Launcher/tst_Launcher.qml+2−2 tests/qmltests/tst_Shell.qml+33−9 tests/uqmlscene/main.cpp−2
Applications/Application.qml+1−1
@@ -16,7 +16,7 @@
1616
1717import QtQuick 2.0
1818import "applications.js" as ApplicationsModel
19−import Ubuntu.Application 0.1
19+import Unity.Application 0.1
2020
2121/* This class is temporary. It is meant to be API compatible with qthybris' Application
2222 class.
Bottombar/Bottombar.qml+2−2
@@ -18,7 +18,7 @@ import QtQuick 2.0
1818import "../Components"
1919import "../Components/Math.js" as MathLocal
2020import Unity 0.1
21−import Ubuntu.Application 0.1
21+import Unity.Application 0.1
2222import Ubuntu.Gestures 0.1
2323
2424Item {
@@ -144,7 +144,7 @@ Item {
144144
145145 InputFilterArea {
146146 anchors.fill: parent
147− blockInput: hudButton.visible
147+ blockInput: (hudButton.opacity == 1)
148148 }
149149
150150 states: [
CMakeLists.txt+4
@@ -62,10 +62,13 @@ set(SHELL_PRIVATE_LIBDIR ${CMAKE_INSTALL_LIBDIR}/unity8)
6262
6363configure_file(paths.h.in ${CMAKE_CURRENT_BINARY_DIR}/paths.h @ONLY)
6464
65+pkg_check_modules(UNITY-MIR REQUIRED unity-mir)
66+
6567include_directories(
6668 ${CMAKE_CURRENT_BINARY_DIR}
6769 ${CMAKE_CURRENT_SOURCE_DIR}
6870 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
71+ ${UNITY-MIR_INCLUDE_DIRS}
6972 )
7073
7174set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
@@ -118,6 +121,7 @@ target_link_libraries(${SHELL_APP}
118121 ${Qt5Qml_LIBRARIES}
119122 ${Qt5Quick_LIBRARIES}
120123 ${XCB_LDFLAGS}
124+ ${CMAKE_DL_LIBS}
121125 )
122126
123127# install binaries
Components/ApplicationManagerWrapper.qml+89−42
@@ -15,15 +15,15 @@
1515 */
1616
1717import QtQuick 2.0
18−import Ubuntu.Application 0.1
18+import Unity.Application 0.1
1919
2020Item {
2121 id: applicationManager
2222
23− property var mainStageApplications: ApplicationManager.mainStageApplications
24− property var sideStageApplications: ApplicationManager.sideStageApplications
25− property var mainStageFocusedApplication: ApplicationManager.mainStageFocusedApplication
26− property var sideStageFocusedApplication: ApplicationManager.sideStageFocusedApplication
23+ property alias mainStageApplications: mainStageModel
24+ property alias sideStageApplications: sideStageModel
25+ property variant mainStageFocusedApplication: null
26+ property variant sideStageFocusedApplication: null
2727 property bool sideStageEnabled: true
2828 signal focusRequested(string desktopFile)
2929 property bool keyboardVisible: ApplicationManager.keyboardVisible
@@ -31,32 +31,76 @@ Item {
3131
3232 property bool fake: ApplicationManager.fake ? ApplicationManager.fake : false
3333
34− Component.onCompleted: {
35− // Start the watcher so that the ApplicationManager applications model can be populated.
36− ApplicationManager.startWatcher();
34+ ApplicationsModelStageFiltered {
35+ id: mainStageModel
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+ }
3765 }
3866
3967 function activateApplication(desktopFile, argument) {
40− var application;
41− application = getApplicationFromDesktopFile(desktopFile, ApplicationInfo.MainStage);
42− if (application == null) {
43− application = getApplicationFromDesktopFile(desktopFile, ApplicationInfo.SideStage);
68+ var appId;
69+
70+ // HACK: Applications identified sometimes with with appId, but mostly with desktopFile.
71+ // TODO: convert entire shell to use appId only.
72+ if (desktopFile.indexOf(".desktop") >= 0) {
73+ appId = desktopFileToAppId(desktopFile);
74+ } else {
75+ appId = desktopFile;
4476 }
45− if (application != null) {
77+
78+ var application = ApplicationManager.findApplication(appId);
79+ if (application !== null) {
4680 return application;
4781 }
4882
4983 var execFlags = sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage;
5084
5185 if (argument) {
52− return ApplicationManager.startProcess(desktopFile, execFlags, [argument]);
86+ return ApplicationManager.startApplication(appId, execFlags, [argument]);
5387 } else {
54− return ApplicationManager.startProcess(desktopFile, execFlags);
88+ return ApplicationManager.startApplication(appId, execFlags);
5589 }
5690 }
5791
58− function stopProcess(application) {
59− ApplicationManager.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+
103+ ApplicationManager.stopApplication(appId);
60104 }
61105
62106 function focusApplication(application) {
@@ -64,51 +108,54 @@ Item {
64108 return;
65109 }
66110
67− ApplicationManager.focusApplication(application.handle);
111+ ApplicationManager.focusApplication(application.appId);
68112 }
69113
70114 function unfocusCurrentApplication() {
71− ApplicationManager.unfocusCurrentApplication(ApplicationInfo.MainStage);
115+ ApplicationManager.unfocusCurrentApplication();
72116 }
73117
74118 function moveRunningApplicationStackPosition(from, to, stage) {
75− var applications;
119+ if (from == to || from < 0 || to < 0) return;
120+
76121 if (stage == ApplicationInfo.SideStage) {
77− applications = ApplicationManager.sideStageApplications;
122+ sideStageModel.move(from, to);
78123 } else {
79− applications = ApplicationManager.mainStageApplications;
124+ mainStageModel.move(from, to);
80125 }
81− // FIXME: applications.move(0, 0) crashes
82− if (from !== to && from >= 0 && to >= 0) applications.move(from, to);
83126 }
84127
85128 function getApplicationFromDesktopFile(desktopFile, stage) {
86− var foundSideStageApp, foundMainStageApp;
129+ var appId;
87130
88− foundMainStageApp = __find(desktopFile, ApplicationManager.mainStageApplications)
89− if (stage == ApplicationInfo.MainStage) {
90− return foundMainStageApp;
91− }
92− foundSideStageApp = __find(desktopFile, ApplicationManager.sideStageApplications)
93− if (stage == ApplicationInfo.SideStage) {
94− return foundSideStageApp;
131+ // HACK: Applications identified sometimes with with appId, but mostly with desktopFile.
132+ // TODO: convert entire shell to use appId only.
133+ if (desktopFile.indexOf(".desktop") >= 0) {
134+ appId = desktopFileToAppId(desktopFile);
135+ } else {
136+ appId = desktopFile;
95137 }
96138
97− // if stage not specified, return whichever app running on either stage
98− return (foundMainStageApp) ? foundMainStageApp : foundSideStageApp;
99−
139+ for (var i = 0, len = ApplicationManager.count; i < len; i++ ) {
140+ var app = ApplicationManager.get(i);
100141
101− function __find(desktopFile, applications) {
102− for (var i = 0; i < applications.count; i++ ) {
103− var application = applications.get(i);
104− if (application.desktopFile == desktopFile) {
105− return application;
106− }
142+ // if stage not specified, return whichever app running on either stage
143+ if (app.appId == appId && (stage == undefined || app.stage == stage)) {
144+ return app;
107145 }
108− return null;
109146 }
110147 }
111148
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+
112159 Connections {
113160 target: ApplicationManager
114161 onFocusRequested: {
Components/ApplicationScreenshot.qml+2−2
@@ -16,7 +16,7 @@
1616
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
19−import Ubuntu.Application 0.1
19+import Unity.Application 0.1
2020
2121Item {
2222 id: applicationScreenshot
@@ -56,6 +56,6 @@ Item {
5656 width: applicationScreenshot.application ? parent.width : 0
5757 height: applicationScreenshot.application ? parent.height : 0
5858 visible: applicationScreenshot.application != null && ready
59− source: applicationScreenshot.application
59+ source: ApplicationManager.findApplication((application) ? application.appId : "")
6060 }
6161}
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/EdgeDemoOverlay.qml+1−1
@@ -17,7 +17,7 @@
1717import Powerd 0.1
1818import QtQuick 2.0
1919import QtGraphicalEffects 1.0
20−import Ubuntu.Application 0.1
20+import Unity.Application 0.1
2121import Ubuntu.Components 0.1
2222
2323Showable {
Components/Stage.qml+1−1
@@ -15,7 +15,7 @@
1515 */
1616
1717import QtQuick 2.0
18−import Ubuntu.Application 0.1
18+import Unity.Application 0.1
1919import Ubuntu.Components 0.1
2020import Ubuntu.Gestures 0.1
2121
Components/VolumeControl.qml+5−20
@@ -21,37 +21,22 @@ Item {
2121 id: root
2222 objectName: "volumeControl"
2323 visible: false
24− property int volume
2524
2625 QDBusActionGroup {
2726 id: actionGroup
2827 busType: 1
29− busName: "com.canonical.settings.sound"
30− objectPath: "/com/canonical/settings/sound"
28+ busName: "com.canonical.indicator.sound"
29+ objectPath: "/com/canonical/indicator/sound"
3130
32− property variant actionObject: action("volume")
33− property variant serverVolume: actionObject.valid ? actionObject.state: 0
34− }
35−
36− Binding {
37− target: root
38− property: "volume"
39− value: actionGroup.serverVolume * 100
40− }
41−
42− onVolumeChanged: {
43− if (actionGroup.serverVolume != volume) {
44− var targetVolume = Math.min(1, Math.max(0, volume / 100));
45− actionGroup.actionObject.updateState(targetVolume);
46− }
31+ property variant actionObject: action("scroll")
4732 }
4833
4934 function volumeUp() {
50− actionGroup.actionObject.updateState(Math.min(1, volume/100 + 0.10));
35+ actionGroup.actionObject.activate(1);
5136 }
5237
5338 function volumeDown() {
54− actionGroup.actionObject.updateState(Math.max(0, volume/100 - 0.10));
39+ actionGroup.actionObject.activate(-1);
5540 }
5641
5742 Component.onCompleted: actionGroup.start()
Dash/Apps/RunningApplicationTile.qml+2−3
@@ -16,7 +16,7 @@
1616
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
19−import Ubuntu.Application 0.1
19+import Unity.Application 0.1
2020import "../../Components/"
2121import "../../Components/ListItems"
2222
@@ -76,10 +76,9 @@ AbstractButton {
7676
7777 ApplicationImage {
7878 id: applicationImage
79− source: application
79+ source: ApplicationManager.findApplication((application) ? application.appId : "")
8080 width: shapedApplicationImage.width
8181 height: shapedApplicationImage.height
82− fillMode: ApplicationImage.PreserveAspectCrop
8382 }
8483
8584 UbuntuShape {
Dash/Apps/RunningApplicationsGrid.qml+4−4
@@ -52,22 +52,22 @@ ResponsiveFlowView {
5252
5353 RunningApplicationTile {
5454 id: runningAppTile
55− objectName: "runningAppTile " + model.application.name
55+ objectName: "runningAppTile " + model.name
5656 anchors {
5757 top: parent.top
5858 horizontalCenter: parent.horizontalCenter
5959 }
60− application: model.application
60+ application: model
6161 onRequestedActivationMode: { root.terminationModeEnabled = false }
6262 onRequestedTerminationMode: {
6363 if (canEnableTerminationMode)
6464 root.terminationModeEnabled = true
6565 }
6666 onRequestedApplicationTermination: {
67− shell.applicationManager.stopProcess(application)
67+ shell.applicationManager.stopApplication(model.appId)
6868 }
6969 onRequestedApplicationActivation: {
70− shell.activateApplication(application.desktopFile)
70+ shell.activateApplication(model.appId)
7171 }
7272
7373 terminationModeEnabled: root.terminationModeEnabled
Dash/GenericScopeView.qml+4−1
@@ -21,10 +21,11 @@ import "../Components/ListItems" as ListItems
2121
2222ScopeView {
2323 id: scopeView
24− property alias previewShown: previewLoader.onScreen
24+ readonly property alias previewShown: previewLoader.onScreen
2525
2626 onIsCurrentChanged: {
2727 pageHeader.resetSearch();
28+ previewLoader.open = false;
2829 }
2930
3031 onMovementStarted: categoryView.showHeader()
@@ -179,6 +180,7 @@ ScopeView {
179180 case "grid": {
180181 switch (contentType) {
181182 case "video": return "Generic/GenericFilterGridPotrait.qml";
183+ case "music": return "Music/MusicFilterGrid.qml";
182184 default: return "Generic/GenericFilterGrid.qml";
183185 }
184186 }
@@ -246,6 +248,7 @@ ScopeView {
246248 }
247249
248250 Loader {
251+ objectName: "previewLoader"
249252 id: previewLoader
250253 property var previewData
251254 height: effect.bottomGapPx - effect.topGapPx
Dash/graphics/phone/home.pngdeleted

Binary file not shown.

Dash/graphics/phone/music.pngdeleted

Binary file not shown.

Dash/graphics/phone/videos.pngdeleted

Binary file not shown.

Dash/graphics/tablet/apps.pngdeleted

Binary file not shown.

Dash/graphics/tablet/home.pngdeleted

Binary file not shown.

Dash/graphics/tablet/music.pngdeleted

Binary file not shown.

Dash/graphics/tablet/people.pngdeleted

Binary file not shown.

Dash/graphics/tablet/videos.pngdeleted

Binary file not shown.

Greeter/Greeter.qml+2
@@ -26,6 +26,8 @@ Showable {
2626 enabled: shown
2727 created: greeterContentLoader.status == Loader.Ready && greeterContentLoader.item.ready
2828
29+ property url defaultBackground
30+
2931 // 1 when fully shown and 0 when fully hidden
3032 property real showProgress: MathLocal.clamp((width + x) / width, 0, 1)
3133
Greeter/GreeterContent.qml+4−3
@@ -40,11 +40,12 @@ MouseArea {
4040 color: "black"
4141 }
4242
43− property url backgroundValue: AccountsService.backgroundFile != undefined && AccountsService.backgroundFile.length > 0 ? AccountsService.backgroundFile : shell.defaultBackground
43+ property url backgroundValue: AccountsService.backgroundFile != undefined && AccountsService.backgroundFile.length > 0 ? AccountsService.backgroundFile : greeter.defaultBackground
4444 onBackgroundValueChanged: wallpaper.source = backgroundValue
4545
4646 CrossFadeImage {
4747 id: wallpaper
48+ objectName: "wallpaper"
4849 anchors.fill: parent
4950 fadeInFirst: false
5051 }
@@ -58,8 +59,8 @@ MouseArea {
5859 sourceSize.height: 0
5960 sourceSize.width: 0
6061 onStatusChanged: {
61− if (status == Image.Error && source != shell.defaultBackground) {
62− wallpaper.source = shell.defaultBackground
62+ if (status == Image.Error && source != greeter.defaultBackground) {
63+ wallpaper.source = greeter.defaultBackground
6364 }
6465 }
6566 }
Launcher/Launcher.qml+4−4
@@ -35,7 +35,7 @@ Item {
3535 readonly property bool shown: panel.x > -panel.width
3636
3737 // emitted when an application is selected
38− signal launcherApplicationSelected(string desktopFile)
38+ signal launcherApplicationSelected(string appId)
3939
4040 // emitted when the apps dash should be shown because of a swipe gesture
4141 signal dash()
@@ -159,7 +159,7 @@ Item {
159159
160160 onApplicationSelected: {
161161 root.state = ""
162− launcherApplicationSelected(desktopFile)
162+ launcherApplicationSelected(appId)
163163 }
164164 onDashItemSelected: {
165165 root.state = ""
@@ -192,12 +192,12 @@ Item {
192192
193193 direction: Direction.Rightwards
194194
195− enabled: root.available && root.state !== "visible"
195+ enabled: root.available
196196 width: root.dragAreaWidth
197197 height: root.height
198198
199199 onTouchXChanged: {
200− if (status !== DirectionalDragArea.Recognized)
200+ if (status !== DirectionalDragArea.Recognized || launcher.state == "visible")
201201 return;
202202
203203 // When the gesture finally gets recognized, the finger will likely be
Launcher/LauncherPanel.qml+3−3
@@ -34,7 +34,7 @@ Item {
3434 property bool preventHiding: moving || dndArea.draggedIndex >= 0 || dndArea.quickListPopover !== null || dndArea.pressed
3535 property int highlightIndex: -1
3636
37− signal applicationSelected(string desktopFile)
37+ signal applicationSelected(string appId)
3838 signal dashItemSelected(int index)
3939
4040 BorderImage {
@@ -300,7 +300,7 @@ Item {
300300 } else if (clickedItem.angle < -12) {
301301 launcherListView.flick(0, launcherListView.clickFlickSpeed);
302302 } else {
303− root.applicationSelected(LauncherModel.get(index).desktopFile);
303+ root.applicationSelected(LauncherModel.get(index).appId);
304304 }
305305 return;
306306 }
@@ -311,7 +311,7 @@ Item {
311311 } else if (clickedItem.angle < -30) {
312312 launcherListView.flick(0, launcherListView.clickFlickSpeed);
313313 } else {
314− root.applicationSelected(LauncherModel.get(index).desktopFile);
314+ root.applicationSelected(LauncherModel.get(index).appId);
315315 }
316316 }
317317
MouseTouchAdaptor.cpp+29−12
@@ -39,24 +39,16 @@ Qt::MouseButton translateMouseButton(xcb_button_t detail)
3939} // end of anonymous namespace
4040
4141MouseTouchAdaptor::MouseTouchAdaptor()
42− : m_targetWindow(0)
43− , m_leftButtonIsPressed(false)
42+ : m_leftButtonIsPressed(false)
4443{
4544 m_touchDevice = new QTouchDevice;
4645 m_touchDevice->setType(QTouchDevice::TouchScreen);
4746 QWindowSystemInterface::registerTouchDevice(m_touchDevice);
4847}
4948
50−void MouseTouchAdaptor::setTargetWindow(QWindow *window)
51−{
52− m_targetWindow = window;
53−}
54−
5549bool MouseTouchAdaptor::nativeEventFilter(const QByteArray & eventType,
5650 void * message, long * /*result*/)
5751{
58− Q_ASSERT(m_targetWindow);
59−
6052 if (eventType != "xcb_generic_event_t") {
6153 // wrong backend.
6254 qWarning("MouseTouchAdaptor: XCB backend not in use. Adaptor inoperative!");
@@ -91,7 +83,9 @@ bool MouseTouchAdaptor::handleButtonPress(xcb_button_press_event_t *pressEvent)
9183
9284 QPoint windowPos(pressEvent->event_x, pressEvent->event_y);
9385
94− QTouchEventSequence touchEvent = QTest::touchEvent(m_targetWindow, m_touchDevice,
86+ QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(pressEvent->event));
87+
88+ QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
9589 false /* autoCommit */);
9690 touchEvent.press(0 /* touchId */, windowPos);
9791 touchEvent.commit(false /* processEvents */);
@@ -110,7 +104,9 @@ bool MouseTouchAdaptor::handleButtonRelease(xcb_button_release_event_t *releaseE
110104
111105 QPoint windowPos(releaseEvent->event_x, releaseEvent->event_y);
112106
113− QTouchEventSequence touchEvent = QTest::touchEvent(m_targetWindow, m_touchDevice,
107+ QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(releaseEvent->event));
108+
109+ QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
114110 false /* autoCommit */);
115111 touchEvent.release(0 /* touchId */, windowPos);
116112 touchEvent.commit(false /* processEvents */);
@@ -127,10 +123,31 @@ bool MouseTouchAdaptor::handleMotionNotify(xcb_motion_notify_event_t *event)
127123
128124 QPoint windowPos(event->event_x, event->event_y);
129125
130− QTouchEventSequence touchEvent = QTest::touchEvent(m_targetWindow, m_touchDevice,
126+ QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(event->event));
127+
128+ QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
131129 false /* autoCommit */);
132130 touchEvent.move(0 /* touchId */, windowPos);
133131 touchEvent.commit(false /* processEvents */);
134132
135133 return true;
136134}
135+
136+QWindow *MouseTouchAdaptor::findQWindowWithXWindowID(WId windowId)
137+{
138+ QWindowList windowList = QGuiApplication::topLevelWindows();
139+ QWindow *foundWindow = nullptr;
140+
141+ int i = 0;
142+ while (!foundWindow && i < windowList.count()) {
143+ QWindow *window = windowList[i];
144+ if (window->winId() == windowId) {
145+ foundWindow = window;
146+ } else {
147+ ++i;
148+ }
149+ }
150+
151+ Q_ASSERT(foundWindow);
152+ return foundWindow;
153+}
MouseTouchAdaptor.h+2−5
@@ -20,11 +20,11 @@
2020#define MOUSE_TOUCH_ADAPTOR_H
2121
2222#include <QtCore/QAbstractNativeEventFilter>
23+#include <QWindow>
2324#include <xcb/xcb.h>
2425
2526class QMouseEvent;
2627class QTouchDevice;
27−class QWindow;
2828
2929// Transforms QMouseEvents into single-finger QTouchEvents.
3030class MouseTouchAdaptor : public QAbstractNativeEventFilter {
@@ -32,9 +32,6 @@ class MouseTouchAdaptor : public QAbstractNativeEventFilter {
3232public:
3333 MouseTouchAdaptor();
3434
35− // The window that will receive the generated QTouchEvents
36− void setTargetWindow(QWindow *window);
37−
3835 // Filters mouse events and posts the equivalent QTouchEvents.
3936 virtual bool nativeEventFilter(const QByteArray & eventType, void *message, long *result);
4037
@@ -43,8 +40,8 @@ private:
4340 bool handleButtonPress(xcb_button_press_event_t *pressEvent);
4441 bool handleButtonRelease(xcb_button_release_event_t *releaseEvent);
4542 bool handleMotionNotify(xcb_motion_notify_event_t *event);
43+ QWindow *findQWindowWithXWindowID(WId windowId);
4644
47− QWindow *m_targetWindow;
4845 QTouchDevice *m_touchDevice;
4946 bool m_leftButtonIsPressed;
5047};
Notifications/NotificationMenuItemFactory.qml+11−21
@@ -31,7 +31,6 @@ Loader {
3131
3232 property var _map: {
3333 "com.canonical.snapdecision.textfield": textfield,
34− "com.canonical.snapdecision.selectionlist": selectionlist,
3534 "com.canonical.snapdecision.pinlock" : pinLock,
3635 }
3736
@@ -55,13 +54,17 @@ Loader {
5554 Column {
5655 spacing: units.gu(.5)
5756
57+ anchors {
58+ left: parent.left
59+ right: parent.right
60+ }
61+
5862 Component.onCompleted: {
5963 menuModel.loadExtendedAttributes(menuIndex, {"x-echo-mode-password": "bool"});
6064 textfield.echoMode = menuData.ext.xEchoModePassword ? TextInput.Password : TextInput.Normal
6165 }
6266
6367 Label {
64− anchors.left: parent.left
6568 fontSize: "medium"
6669 color: "white"
6770 text: menuData.label
@@ -69,6 +72,12 @@ Loader {
6972
7073 TextField {
7174 id: textfield
75+
76+ anchors {
77+ left: parent.left
78+ right: parent.right
79+ }
80+
7281 onTextChanged: {
7382 menuModel.changeState(menuIndex, text);
7483 }
@@ -76,25 +85,6 @@ Loader {
7685 }
7786 }
7887
79− Component {
80− id: selectionlist
81−
82− Column {
83− spacing: units.gu(.5)
84− anchors {
85− left: parent.left
86− right: parent.right
87− }
88−
89− Label {
90− anchors.horizontalCenter: parent.horizontalCenter
91− fontSize: "large"
92− color: "white"
93− text: "Selection List"
94− }
95− }
96− }
97−
9888 Component {
9989 id: pinLock
10090 PinLockscreen {
Panel/Indicators/DefaultIndicatorWidget.qml+2−6
@@ -24,6 +24,7 @@ import Unity.IndicatorsLegacy 0.1 as Indicators
2424Indicators.IndicatorWidget {
2525 id: indicatorWidget
2626
27+ enabled:true
2728 width: itemRow.width + units.gu(0.5)
2829
2930 property alias label: itemLabel.text
@@ -63,19 +64,14 @@ Indicators.IndicatorWidget {
6364
6465 onActionStateChanged: {
6566 if (action == undefined || !action.valid) {
66− enabled = false;
6767 return;
6868 }
6969
7070 if (action.state == undefined) {
71− label = "";
72− iconSource = "";
73− enabled = false;
7471 return;
7572 }
7673
7774 label = action.state[Indicators.ActionState.Label];
78− iconSource = "image://gicon/" + action.state[Indicators.ActionState.IconSource];
79− enabled = action.state[Indicators.ActionState.Visible];
75+ iconSource = "image://theme/" + action.state[Indicators.ActionState.IconSource];
8076 }
8177}
Panel/Indicators/MessagingIndicatorWidget.qml+1−1
@@ -21,5 +21,5 @@ import QtQuick 2.0
2121
2222DefaultIndicatorWidget {
2323 // 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"
2525}
Panel/Indicators/NetworkIndicatorWidget.qml+6−6
@@ -97,16 +97,16 @@ Indicators.IndicatorWidget {
9797 function get_icon_for_signal(con_state, value) {
9898 if (con_state >= Indicators.NetworkConnection.Activating && con_state <= Indicators.NetworkConnection.Deactivating) {
9999 if (value == 0) {
100− return "image://gicon/nm-signal-00";
100+ return "image://theme/nm-signal-00";
101101 } else if (value <= 25) {
102− return "image://gicon/nm-signal-25";
102+ return "image://theme/nm-signal-25";
103103 } else if (value <= 50) {
104− return "image://gicon/nm-signal-50";
104+ return "image://theme/nm-signal-50";
105105 } else if (value <= 75) {
106− return "image://gicon/nm-signal-75";
106+ return "image://theme/nm-signal-75";
107107 }
108− return "image://gicon/nm-signal-100";
108+ return "image://theme/nm-signal-100";
109109 }
110− return "image://gicon/wifi-none";
110+ return "image://theme/wifi-none";
111111 }
112112}
Panel/Indicators/SoundIndicatorWidget.qml+1−1
@@ -21,6 +21,6 @@ import QtQuick 2.0
2121
2222DefaultIndicatorWidget {
2323 // 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"
2525 enabled: true
2626}
Shell.qml+50−36
@@ -17,12 +17,13 @@
1717import QtQuick 2.0
1818import AccountsService 0.1
1919import GSettings 1.0
20−import Ubuntu.Application 0.1
20+import Unity.Application 0.1
2121import Ubuntu.Components 0.1
2222import Ubuntu.Gestures 0.1
2323import Unity.Launcher 0.1
2424import LightDM 0.1 as LightDM
2525import Powerd 0.1
26+import SessionBroadcast 0.1
2627import "Dash"
2728import "Greeter"
2829import "Launcher"
@@ -65,6 +66,12 @@ FocusScope {
6566
6667 property var applicationManager: ApplicationManagerWrapper {}
6768
69+ Binding {
70+ target: LauncherModel
71+ property: "applicationManager"
72+ value: ApplicationManager
73+ }
74+
6875 Component.onCompleted: {
6976 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
7077
@@ -75,6 +82,11 @@ FocusScope {
7582 applicationManager.unfocusCurrentApplication();
7683 }
7784
85+ readonly property bool applicationFocused: !!applicationManager.mainStageFocusedApplication
86+ || !!applicationManager.sideStageFocusedApplication
87+ // Used for autopilot testing.
88+ readonly property string currentFocusedAppId: ApplicationManager.focusedApplicationId
89+
7890 readonly property bool fullscreenMode: {
7991 if (greeter.shown || lockscreen.shown) {
8092 return false;
@@ -96,15 +108,6 @@ FocusScope {
96108 greeter.hide();
97109 shell.activateApplication(desktopFile);
98110 }
99−
100− onMainStageFocusedApplicationChanged: {
101− var app = applicationManager.mainStageFocusedApplication
102− if (app != null) {
103− LauncherModel.applicationFocused(app.desktopFile);
104− } else {
105− LauncherModel.applicationFocused("");
106− }
107− }
108111 }
109112
110113 function activateApplication(desktopFile, argument) {
@@ -157,6 +160,10 @@ FocusScope {
157160 }
158161 }
159162
163+ OSKController {
164+ anchors.fill: parent // as needs to know the geometry of the shell
165+ }
166+
160167 VolumeControl {
161168 id: volumeControl
162169 }
@@ -255,7 +262,7 @@ FocusScope {
255262 property bool fullyShown: shown && x == 0 && parent.x == 0
256263 property bool fullyHidden: !shown && x == width
257264 available: !greeter.shown
258− hides: [launcher, panel.indicators]
265+ hides: [panel.indicators]
259266 shown: false
260267 opacity: 1.0
261268 showAnimation: StandardAnimation { property: "x"; duration: 350; to: 0; easing.type: Easing.OutCubic }
@@ -456,6 +463,8 @@ FocusScope {
456463 hides: [launcher, panel.indicators, hud]
457464 shown: true
458465
466+ defaultBackground: shell.background
467+
459468 y: panel.panelHeight
460469 width: parent.width
461470 height: parent.height - panel.panelHeight
@@ -492,7 +501,8 @@ FocusScope {
492501
493502 InputFilterArea {
494503 anchors.fill: parent
495− blockInput: greeter.shown || lockscreen.shown
504+ blockInput: !applicationFocused || greeter.shown || lockscreen.shown || launcher.shown
505+ || panel.indicators.shown || hud.shown
496506 }
497507
498508 Connections {
@@ -504,10 +514,8 @@ FocusScope {
504514
505515 function setFocused(focused) {
506516 if (!focused) {
507− // FIXME: *FocusedApplication are not updated when unfocused, hence the need to check whether
508− // the stage was actually shown
509− if (mainStage.fullyShown) powerConnection.previousMainApp = applicationManager.mainStageFocusedApplication;
510− if (sideStage.fullyShown) powerConnection.previousSideApp = applicationManager.sideStageFocusedApplication;
517+ powerConnection.previousMainApp = applicationManager.mainStageFocusedApplication;
518+ powerConnection.previousSideApp = applicationManager.sideStageFocusedApplication;
511519 applicationManager.unfocusCurrentApplication();
512520 } else {
513521 if (powerConnection.previousMainApp) {
@@ -540,6 +548,17 @@ FocusScope {
540548 }
541549 }
542550
551+ function showHome() {
552+ greeter.hide()
553+ // Animate if moving between application and dash
554+ if (!stages.shown) {
555+ dash.setCurrentScope("home.scope", true, false)
556+ } else {
557+ dash.setCurrentScope("home.scope", false, false)
558+ }
559+ stages.hide()
560+ }
561+
543562 Item {
544563 id: overlay
545564
@@ -558,8 +577,13 @@ FocusScope {
558577 searchVisible: !greeter.shown && !lockscreen.shown
559578
560579 InputFilterArea {
561− anchors.fill: parent
562− blockInput: panel.indicators.shown
580+ anchors {
581+ top: parent.top
582+ left: parent.left
583+ right: parent.right
584+ }
585+ height: (panel.fullscreenMode) ? shell.edgeSize : panel.panelHeight
586+ blockInput: true
563587 }
564588 }
565589
@@ -579,11 +603,6 @@ FocusScope {
579603 onMainStageFocusedApplicationChanged: hud.hide()
580604 onSideStageFocusedApplicationChanged: hud.hide()
581605 }
582−
583− InputFilterArea {
584− anchors.fill: parent
585− blockInput: hud.shown
586− }
587606 }
588607
589608 Revealer {
@@ -606,8 +625,7 @@ FocusScope {
606625 theHud: hud
607626 anchors.fill: parent
608627 enabled: !panel.indicators.shown
609− applicationIsOnForeground: applicationManager.mainStageFocusedApplication
610− || applicationManager.sideStageFocusedApplication
628+ applicationIsOnForeground: applicationFocused
611629 }
612630
613631 InputFilterArea {
@@ -628,16 +646,7 @@ FocusScope {
628646 width: parent.width
629647 dragAreaWidth: shell.edgeSize
630648 available: (!greeter.shown || greeter.narrowMode) && edgeDemo.launcherEnabled
631− onDashItemSelected: {
632− greeter.hide()
633− // Animate if moving between application and dash
634− if (!stages.shown) {
635− dash.setCurrentScope("home.scope", true, false)
636− } else {
637− dash.setCurrentScope("home.scope", false, false)
638− }
639− stages.hide();
640− }
649+ onDashItemSelected: showHome()
641650 onDash: {
642651 if (stages.shown) {
643652 dash.setCurrentScope("applications.scope", true, false)
@@ -647,7 +656,7 @@ FocusScope {
647656 }
648657 onLauncherApplicationSelected:{
649658 greeter.hide()
650− shell.activateApplication(desktopFile)
659+ shell.activateApplication(appId)
651660 }
652661 onShownChanged: {
653662 if (shown) {
@@ -745,4 +754,9 @@ FocusScope {
745754 indicators: panel.indicators
746755 underlay: underlay
747756 }
757+
758+ Connections {
759+ target: SessionBroadcast
760+ onShowHome: showHome()
761+ }
748762}
SideStage/SideStage.qml+1−1
@@ -15,7 +15,7 @@
1515 */
1616
1717import QtQuick 2.0
18−import Ubuntu.Application 0.1
18+import Unity.Application 0.1
1919import Ubuntu.Components 0.1
2020import "../Components"
2121
debian/changelog+146
@@ -1,3 +1,149 @@
1+unity8 (7.81.3+13.10.20130919.3-0ubuntu1) saucy; urgency=low
2+
3+ [ Michal Hruby ]
4+ * Add support for music grid renderer to GenericScopeView.
5+
6+ [ Nick Dedekind ]
7+ * Fixed the removal of messaging widget due to incompatible action
8+ state. (LP: #1225017)
9+
10+ [ Christopher Lee ]
11+ * Addition of initial autopilot tests for the application lifecycle.
12+
13+ [ Lars Uebernickel ]
14+ * VolumeControl: use action of the new indicator indicator-sound
15+ recently gained an action to increase and decrease the volume. This
16+ patch makes use of that to get rid of a bus round trip (to get the
17+ current volume) and a race (when the volume gets set between
18+ fetching the current volume and setting the new volume). (LP:
19+ #1219057)
20+
21+ [ Michael Terry ]
22+ * When AccountsService.backgroundFile is unset/invalid, have the
23+ greeter fall back to whatever the shell background is.
24+ * Add a tiny SessionBroadcast plugin that listens to unity-greeter-
25+ session-broadcast for the ShowHome signal.
26+
27+ [ Daniel d'Andrada ]
28+ * Remove obsolete, unused graphics.
29+ * Make MouseTouchAdaptor work with multiple QWindows.
30+
31+ [ Michael Zanetti ]
32+ * change how icons are searched a) try to find it the Icon as is b)
33+ prepend with Path if a Path variable is given c) fall back to the
34+ image://theme/ with just the icon name . (LP: #1225186)
35+ * fix an issue with removing a running app from the launcher and
36+ always store pinning to the config.
37+ * collapse any open preview when programmatically switching current
38+ dash index. (LP: #1221137)
39+
40+ [ Ubuntu daily release ]
41+ * Automatic snapshot from revision 333
42+
43+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 19 Sep 2013 15:15:07 +0000
44+
45+unity8 (7.81.3+13.10.20130916-0ubuntu1) saucy; urgency=low
46+
47+ [ Michael Zanetti ]
48+ * allow left edge gesture to minimize apps even when launcher is
49+ already visible.
50+ * Don't hide the launcher on changes in the stages.
51+ * ssh is now installed per default, but it's set to manual in the
52+ ssh.override.
53+
54+ [ Ubuntu daily release ]
55+ * Automatic snapshot from revision 320
56+
57+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 16 Sep 2013 11:49:28 +0000
58+
59+unity8 (7.81.3+13.10.20130912-0ubuntu1) saucy; urgency=low
60+
61+ [ Michael Zanetti ]
62+ * add support for finding icons from click package apps in the
63+ launcher.
64+ * update to latest launcher API for better integration with the
65+ AppManager.
66+
67+ [ Ricardo Mendoza ]
68+ * Fixes problems related to image 20130912.0, amongst: * Fix autopilot
69+ tests by preventing blocking of input during HUD button animations,
70+ only when fully visible * Fix loading of unity-mir library, major
71+ version wasn't specified so unless the dev package was there it
72+ would fail.
73+
74+ [ Ubuntu daily release ]
75+ * Automatic snapshot from revision 316
76+
77+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 12 Sep 2013 13:47:59 +0000
78+
79+unity8 (7.81.3+13.10.20130911.1-0ubuntu1) saucy; urgency=low
80+
81+ [ Michael Terry ]
82+ * Switch from deprecated image://gicon/ to new image://theme/.
83+
84+ [ Gerry Boland ]
85+ * Add OSKController so shell can control OSK correctly on Mir.
86+ * Remove InputFilterArea for bottom edge swipes, as applications also
87+ listen for such swipes for Toolbar reveal.
88+
89+ [ Ricardo Mendoza ]
90+ * Select the backend to use dynamically on runtime according to the
91+ QPA selected by the system.
92+
93+ [ Ubuntu daily release ]
94+ * Automatic snapshot from revision 311
95+
96+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 11 Sep 2013 16:22:55 +0000
97+
98+unity8 (7.81.3+13.10.20130911-0ubuntu1) saucy; urgency=low
99+
100+ [ Michal Hruby ]
101+ * Hide all gicon strings from the shell and use the image://theme icon
102+ provider that was recently added to the SDK.
103+
104+ [ Gerry Boland ]
105+ * Convert to new ApplicationManager API.
106+
107+ [ Nick Dedekind ]
108+ * Updated access point design as per spec.
109+ * Indicator visibility based on connection with backend service.
110+
111+ [ Albert Astals ]
112+ * Dash: Make assignments bindings This way if the model changes the
113+ item value also changes.
114+
115+ [ Michael Zanetti ]
116+ * adds support for highlighting the currently focused application in
117+ the launcher, adds tests.
118+ * include ~/.local/share/applications in launcher's .desktop file
119+ search path.
120+ * shrink size of area for revealing the HUD button and make it
121+ disappear on release again. fixes 1219035. (LP: #1219035)
122+ * revert revision 304 as it makes the Shell crash.
123+
124+ [ Michael Terry ]
125+ * Allow testers to set custom password or pin in demo mode, rather
126+ than hardcoding them.
127+ * Have the greeter use AccountsService to determine its background.
128+ (LP: #1218402)
129+ * Listen to changes in the "show edge demo" AccountsService setting.
130+
131+ [ Daniel d'Andrada ]
132+ * Update fake/mock plugins so that "./run --fake" works well again -
133+ You can now see the thumbnails of the fake running applications once
134+ again. - You no longer get hundreds of warnings due to icons not
135+ found.
136+ * Reset apps scope when returning from app to dash (LP #1193419) If an
137+ app is on foreground and you perform a long left-edge swipe to
138+ minimize it, and therefore return to the dash, the dash should be in
139+ the Applications scope and showing the running/recents applications.
140+ (LP: #1193419)
141+
142+ [ Ubuntu daily release ]
143+ * Automatic snapshot from revision 306
144+
145+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 11 Sep 2013 00:54:31 +0000
146+
1147unity8 (7.81.3+13.10.20130905.2-0ubuntu1) saucy; urgency=low
2148
3149 [ Michael Zanetti ]
debian/control+9−7
@@ -23,6 +23,7 @@ Build-Depends: cmake,
2323 libunity-api-dev (>= 7.80.3),
2424 libunity-core-6.0-dev (<< 7.80),
2525 libunity-dev (>= 7.0.12),
26+ libunity-mir-dev,
2627 libunity-scopes-json-def-phone,
2728 libupstart-dev,
2829 libusermetricsoutput1-dev,
@@ -54,7 +55,7 @@ Vcs-Browser: https://bazaar.launchpad.net/~unity-team/unity8/trunk
5455Package: indicators-client
5556Architecture: amd64 armhf i386
5657Depends: qmenumodel-qml (>= 0.2.7),
57− qtdeclarative5-ubuntu-ui-toolkit-plugin | qt-components-ubuntu,
58+ qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 0.1.46+13.10.20130829.1-0ubuntu1),
5859 unity8 (= ${binary:Version}),
5960 ${misc:Depends},
6061 ${shlibs:Depends},
@@ -65,13 +66,14 @@ Package: unity8
6566Architecture: any
6667Provides: indicator-renderer,
6768Depends: gsettings-desktop-schemas,
69+ libunity-mir1,
6870 qmenumodel-qml (>= 0.2.7),
6971 qtdeclarative5-dee-plugin,
7072 qtdeclarative5-gsettings1.0,
71− qtdeclarative5-ubuntu-ui-toolkit-plugin,
73+ qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 0.1.46+13.10.20130829.1-0ubuntu1),
7274 qtdeclarative5-unity-notifications-plugin | unity-notifications-impl,
7375 qtdeclarative5-xmllistmodel-plugin,
74− unity-launcher-impl-2,
76+ unity-launcher-impl-3,
7577 unity-notifications-impl-1,
7678 unity8-fake-env | qtubuntu-shell,
7779 unity8-private (= ${binary:Version}),
@@ -87,18 +89,18 @@ Description: Unity 8 shell
8789
8890Package: unity8-autopilot
8991Architecture: all
90−Depends: indicators-client (>= ${source:Version}),
92+Depends: gir1.2-glib-2.0,
93+ indicators-client (>= ${source:Version}),
9194 libautopilot-qt,
9295 libqt5test5,
9396 libqt5widgets5,
9497 python-evdev,
98+ python-gi,
9599 unity8 (>= ${source:Version}),
96100 unity8-fake-env (>= ${source:Version}),
97101 ${misc:Depends},
98102 ${python:Depends},
99103 ${shlibs:Depends},
100−Recommends: gir1.2-glib-2.0,
101− python-gi,
102104Description: Test package for Unity 8 shell
103105 Autopilot tests for the unity8 package
104106
@@ -120,7 +122,7 @@ Pre-Depends: ${misc:Pre-Depends},
120122Depends: ${misc:Depends},
121123 ${shlibs:Depends},
122124Provides: unity-launcher-impl,
123− unity-launcher-impl-2,
125+ unity-launcher-impl-3,
124126Description: Unity 8 private libs
125127 The Unity 8 shell is the primary user interface for Ubuntu devices.
126128 .
debian/unity8-private.install+1
@@ -3,6 +3,7 @@ usr/lib/*/unity8/qml/HudClient
33usr/lib/*/unity8/qml/LightDM
44usr/lib/*/unity8/qml/ListViewWithPageHeader
55usr/lib/*/unity8/qml/Powerd
6+usr/lib/*/unity8/qml/SessionBroadcast
67usr/lib/*/unity8/qml/Ubuntu
78usr/lib/*/unity8/qml/Unity
89usr/lib/*/unity8/qml/Utils
main.cpp+73−7
@@ -25,13 +25,17 @@
2525#include <QtQml/QQmlContext>
2626#include <qpa/qplatformnativeinterface.h>
2727#include <QLibrary>
28+#include <QDebug>
2829#include <libintl.h>
30+#include <dlfcn.h>
2931
3032// local
3133#include "paths.h"
3234#include "MouseTouchAdaptor.h"
3335#include "ApplicationArguments.h"
3436
37+#include <unity-mir/qmirserver.h>
38+
3539namespace {
3640
3741void prependImportPaths(QQmlEngine *engine, const QStringList &paths)
@@ -72,7 +76,7 @@ void resolveIconTheme() {
7276}
7377} // namespace {
7478
75−int main(int argc, char** argv)
79+int startShell(int argc, const char** argv, void* server)
7680{
7781 /* Workaround Qt platform integration plugin not advertising itself
7882 as having the following capabilities:
@@ -82,12 +86,29 @@ int main(int argc, char** argv)
8286 setenv("QML_FORCE_THREADED_RENDERER", "1", 1);
8387 setenv("QML_FIXED_ANIMATION_STEP", "1", 1);
8488
89+ const bool isUbuntuMirServer = qgetenv("QT_QPA_PLATFORM") == "ubuntumirserver";
90+
8591 QGuiApplication::setApplicationName("Unity 8");
86− QGuiApplication application(argc, argv);
92+ QGuiApplication *application;
93+ if (isUbuntuMirServer) {
94+ QLibrary unityMir("unity-mir", 1);
95+ unityMir.load();
96+
97+ typedef QGuiApplication* (*createServerApplication_t)(int&, const char **, void*);
98+ createServerApplication_t createQMirServerApplication = (createServerApplication_t) unityMir.resolve("createQMirServerApplication");
99+ if (!createQMirServerApplication) {
100+ qDebug() << "unable to resolve symbol: createQMirServerApplication";
101+ return 4;
102+ }
103+
104+ application = createQMirServerApplication(argc, argv, server);
105+ } else {
106+ application = new QGuiApplication(argc, (char**)argv);
107+ }
87108
88109 resolveIconTheme();
89110
90− QStringList args = application.arguments();
111+ QStringList args = application->arguments();
91112 ApplicationArguments qmlArgs(args);
92113
93114 // The testability driver is only loaded by QApplication but not by QGuiApplication.
@@ -123,8 +144,7 @@ int main(int argc, char** argv)
123144 MouseTouchAdaptor *mouseTouchAdaptor = 0;
124145 if (args.contains(QLatin1String("-mousetouch"))) {
125146 mouseTouchAdaptor = new MouseTouchAdaptor;
126− mouseTouchAdaptor->setTargetWindow(view);
127− application.installNativeEventFilter(mouseTouchAdaptor);
147+ application->installNativeEventFilter(mouseTouchAdaptor);
128148 }
129149
130150 QPlatformNativeInterface* nativeInterface = QGuiApplication::platformNativeInterface();
@@ -139,18 +159,64 @@ int main(int argc, char** argv)
139159 QUrl source("Shell.qml");
140160 prependImportPaths(view->engine(), ::overrideImportPaths());
141161 appendImportPaths(view->engine(), ::fallbackImportPaths());
162+
163+ QStringList importPath = view->engine()->importPathList().filter("qt5/imports");
164+ if (isUbuntuMirServer) {
165+ importPath.first().append("/Unity-Mir");
166+ view->engine()->addImportPath(importPath.first());
167+ }
168+
142169 view->setSource(source);
143170 view->setColor("transparent");
144171
145− if (qgetenv("QT_QPA_PLATFORM") == "ubuntu" || args.contains(QLatin1String("-fullscreen"))) {
172+ if (qgetenv("QT_QPA_PLATFORM") == "ubuntu" || isUbuntuMirServer || args.contains(QLatin1String("-fullscreen"))) {
146173 view->showFullScreen();
147174 } else {
148175 view->show();
149176 }
150177
151− int result = application.exec();
178+ int result = application->exec();
152179
153180 delete mouseTouchAdaptor;
181+ delete application;
154182
155183 return result;
156184}
185+
186+int main(int argc, const char *argv[])
187+{
188+ // For ubuntumirserver/ubuntumirclient
189+ if (qgetenv("QT_QPA_PLATFORM").startsWith("ubuntumir")) {
190+ setenv("QT_QPA_PLATFORM", "ubuntumirserver", 1);
191+
192+ // If we use unity-mir directly, we automatically link to the Mir-server
193+ // platform-api bindings, which result in unexpected behaviour when
194+ // running the non-Mir scenario.
195+ QLibrary unityMir("unity-mir", 1);
196+ unityMir.load();
197+ if (!unityMir.isLoaded()) {
198+ qDebug() << "Library unity-mir not found/loaded";
199+ return 1;
200+ }
201+
202+ typedef QMirServer* (*createServer_t)(int, const char **);
203+ createServer_t createQMirServer = (createServer_t) unityMir.resolve("createQMirServer");
204+ if (!createQMirServer) {
205+ qDebug() << "unable to resolve symbol: createQMirServer";
206+ return 2;
207+ }
208+
209+ QMirServer* mirServer = createQMirServer(argc, argv);
210+
211+ typedef int (*runWithClient_t)(QMirServer*, std::function<int(int, const char**, void*)>);
212+ runWithClient_t runWithClient = (runWithClient_t) unityMir.resolve("runQMirServerWithClient");
213+ if (!runWithClient) {
214+ qDebug() << "unable to resolve symbol: runWithClient";
215+ return 3;
216+ }
217+
218+ return runWithClient(mirServer, startShell);
219+ } else {
220+ return startShell(argc, argv, nullptr);
221+ }
222+}
plugins/CMakeLists.txt+1
@@ -3,6 +3,7 @@ add_subdirectory(HudClient)
33add_subdirectory(LightDM)
44add_subdirectory(ListViewWithPageHeader)
55add_subdirectory(Powerd)
6+add_subdirectory(SessionBroadcast)
67add_subdirectory(Ubuntu)
78add_subdirectory(Unity)
89add_subdirectory(Utils)
plugins/SessionBroadcast/CMakeLists.txtnew file+13
@@ -0,0 +1,13 @@
1+include(Plugins)
2+
3+add_definitions(-DSM_BUSNAME=systemBus)
4+
5+add_library(SessionBroadcast-qml MODULE
6+ SessionBroadcast.cpp
7+ plugin.cpp
8+ )
9+
10+qt5_use_modules(SessionBroadcast-qml DBus Qml)
11+
12+export_qmlfiles(SessionBroadcast SessionBroadcast)
13+export_qmlplugin(SessionBroadcast 0.1 SessionBroadcast TARGETS SessionBroadcast-qml)
plugins/SessionBroadcast/SessionBroadcast.cppnew file+41
@@ -0,0 +1,41 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Author: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#include "SessionBroadcast.h"
20+#include <QDBusConnection>
21+
22+SessionBroadcast::SessionBroadcast(QObject* parent)
23+ : QObject(parent)
24+{
25+ auto connection = QDBusConnection::SM_BUSNAME();
26+
27+ connection.connect("com.canonical.Unity.Greeter.Broadcast",
28+ "/com/canonical/Unity/Greeter/Broadcast",
29+ "com.canonical.Unity.Greeter.Broadcast",
30+ "ShowHome",
31+ this,
32+ SLOT(onShowHome(const QString &)));
33+}
34+
35+void SessionBroadcast::onShowHome(const QString &username)
36+{
37+ // Only listen to requests meant for us
38+ if (username == qgetenv("USER")) {
39+ Q_EMIT showHome();
40+ }
41+}
plugins/SessionBroadcast/SessionBroadcast.hnew file+41
@@ -0,0 +1,41 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#ifndef UNITY_SESSIONBROADCAST_H
20+#define UNITY_SESSIONBROADCAST_H
21+
22+#include <QObject>
23+#include <QString>
24+
25+class QDBusInterface;
26+
27+class SessionBroadcast: public QObject
28+{
29+ Q_OBJECT
30+
31+public:
32+ explicit SessionBroadcast(QObject *parent = 0);
33+
34+Q_SIGNALS:
35+ void showHome();
36+
37+private Q_SLOTS:
38+ void onShowHome(const QString &username);
39+};
40+
41+#endif
plugins/SessionBroadcast/plugin.cppnew file+35
@@ -0,0 +1,35 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#include "plugin.h"
20+#include "SessionBroadcast.h"
21+
22+#include <QtQml>
23+
24+static QObject *broadcast_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
25+{
26+ Q_UNUSED(engine)
27+ Q_UNUSED(scriptEngine)
28+ return new SessionBroadcast();
29+}
30+
31+void SessionBroadcastPlugin::registerTypes(const char *uri)
32+{
33+ Q_ASSERT(uri == QLatin1String("SessionBroadcast"));
34+ qmlRegisterSingletonType<SessionBroadcast>(uri, 0, 1, "SessionBroadcast", broadcast_provider);
35+}
plugins/SessionBroadcast/plugin.hnew file+33
@@ -0,0 +1,33 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#ifndef UNITY_SESSIONBROADCAST_PLUGIN_H
20+#define UNITY_SESSIONBROADCAST_PLUGIN_H
21+
22+#include <QQmlExtensionPlugin>
23+
24+class SessionBroadcastPlugin : public QQmlExtensionPlugin
25+{
26+ Q_OBJECT
27+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28+
29+public:
30+ void registerTypes(const char *uri);
31+};
32+
33+#endif
plugins/SessionBroadcast/qmldirnew file+3
@@ -0,0 +1,3 @@
1+module SessionBroadcast
2+plugin SessionBroadcast-qml
3+typeinfo plugin.qmltypes
plugins/Unity/Indicators/rootactionstate.cpp+8−8
@@ -148,15 +148,15 @@ static QString iconUri(GIcon *icon)
148148 QString uri;
149149
150150 if (G_IS_THEMED_ICON (icon)) {
151−
152151 const gchar* const* iconNames = g_themed_icon_get_names (G_THEMED_ICON (icon));
153− guint index = 0;
154− while(iconNames[index] != NULL) {
155− if (QIcon::hasThemeIcon(iconNames[index])) {
156− uri = QString("image://theme/%1").arg(iconNames[index]);
157− break;
158− }
159− index++;
152+
153+ QStringList iconNameList;
154+ for (uint index = 0; iconNames[index] != NULL; index++) {
155+ iconNameList << iconNames[index];
156+ }
157+
158+ if (!iconNameList.empty()) {
159+ uri = QString("image://theme/%1").arg(iconNameList.join(","));
160160 }
161161 }
162162 else if (G_IS_FILE_ICON (icon)) {
plugins/Unity/IndicatorsLegacy/Messaging/qml/GroupedMessage.qml+1−1
@@ -44,7 +44,7 @@ Indicators.BasicMenuItem {
4444 height: units.gu(6)
4545 width: units.gu(6)
4646 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"
4848 fillMode: Image.PreserveAspectFit
4949 }
5050 }
plugins/Unity/IndicatorsLegacy/Messaging/qml/HeroMessage.qml+2−2
@@ -48,8 +48,8 @@ Indicators.BasicMenuItem {
4848 anchors.left: parent.left
4949 anchors.right: parent.right
5050
51− avatar: menu && (menu.extra.canonical_icon.length > 0) ? "image://gicon/" + 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) : ""
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://theme/" + encodeURI(menu.extra.canonical_app_icon) : ""
5353 appIcon: icon
5454
5555 state: heroMessage.state
plugins/Unity/IndicatorsLegacy/Network/qml/AccessPoint.qml+2−2
@@ -47,10 +47,10 @@ Indicators.MenuItem {
4747 imageName += "-secure";
4848 }
4949
50− return "image://gicon/" + imageName;
50+ return "image://theme/" + imageName;
5151 }
5252
53− icon: menu && wifiApStrength ? getNetworkIcon(menu) : "image://gicon/wifi-none"
53+ icon: menu && wifiApStrength ? getNetworkIcon(menu) : "image://theme/wifi-none"
5454 iconFrame: false
5555 control: CheckBox {
5656 id: checkBoxActive
plugins/Unity/Launcher/CMakeLists.txt+2−1
@@ -1,5 +1,6 @@
11include(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)
34pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
45
56add_definitions(-DSM_BUSNAME=systemBus)
plugins/Unity/Launcher/backend/launcherbackend.cpp+11−7
@@ -132,11 +132,7 @@ QString LauncherBackend::icon(const QString &appId) const
132132 }
133133 }
134134
135− QFileInfo info(iconName);
136− if (info.exists()) {
137− return info.absoluteFilePath();
138− }
139− return "image://theme/" + iconName;
135+ return iconName;
140136}
141137
142138bool LauncherBackend::isPinned(const QString &appId) const
@@ -296,11 +292,19 @@ LauncherBackendItem* LauncherBackend::parseDesktopFile(const QString &desktopFil
296292{
297293 QSettings settings(desktopFile, QSettings::IniFormat);
298294
299−
300295 LauncherBackendItem* item = new LauncherBackendItem();
301296 item->desktopFile = desktopFile;
302297 item->displayName = settings.value("Desktop Entry/Name").toString();
303− item->icon = settings.value("Desktop Entry/Icon").toString();
298+
299+ QString iconString = settings.value("Desktop Entry/Icon").toString();
300+ QString pathString = settings.value("Desktop Entry/Path").toString();
301+ if (QFileInfo(iconString).exists()) {
302+ item->icon = QFileInfo(iconString).absoluteFilePath();
303+ } else if (QFileInfo(pathString + '/' + iconString).exists()) {
304+ item->icon = pathString + '/' + iconString;
305+ } else {
306+ item->icon = "image://theme/" + iconString;
307+ }
304308 item->pinned = false;
305309 return item;
306310}
plugins/Unity/Launcher/launcheritem.cpp+1−7
@@ -20,10 +20,9 @@
2020#include "launcheritem.h"
2121#include "quicklistmodel.h"
2222
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) :
2424 LauncherItemInterface(parent),
2525 m_appId(appId),
26− m_desktopFile(desktopFile),
2726 m_name(name),
2827 m_icon(icon),
2928 m_pinned(false),
@@ -48,11 +47,6 @@ QString LauncherItem::appId() const
4847 return m_appId;
4948}
5049
51−QString LauncherItem::desktopFile() const
52−{
53− return m_desktopFile;
54−}
55−
5650QString LauncherItem::name() const
5751{
5852 return m_name;
plugins/Unity/Launcher/launcheritem.h+1−3
@@ -32,10 +32,9 @@ class LauncherItem: public LauncherItemInterface
3232{
3333 Q_OBJECT
3434public:
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);
3636
3737 QString appId() const;
38− QString desktopFile() const;
3938 QString name() const;
4039 QString icon() const;
4140
@@ -65,7 +64,6 @@ Q_SIGNALS:
6564
6665private:
6766 QString m_appId;
68− QString m_desktopFile;
6967 QString m_name;
7068 QString m_icon;
7169 bool m_pinned;
plugins/Unity/Launcher/launchermodel.cpp+106−49
@@ -21,16 +21,20 @@
2121#include "launcheritem.h"
2222#include "backend/launcherbackend.h"
2323
24+#include <unity/shell/application/ApplicationInfoInterface.h>
25+
26+using namespace unity::shell::application;
27+
2428LauncherModel::LauncherModel(QObject *parent):
2529 LauncherModelInterface(parent),
26− m_backend(new LauncherBackend(true, this))
30+ m_backend(new LauncherBackend(true, this)),
31+ m_appManager(0)
2732{
2833 connect(m_backend, SIGNAL(countChanged(QString,int)), SLOT(countChanged(QString,int)));
2934 connect(m_backend, SIGNAL(progressChanged(QString,int)), SLOT(progressChanged(QString,int)));
3035
3136 Q_FOREACH (const QString &entry, m_backend->storedApplications()) {
3237 LauncherItem *item = new LauncherItem(entry,
33− m_backend->desktopFile(entry),
3438 m_backend->displayName(entry),
3539 m_backend->icon(entry),
3640 this);
@@ -61,9 +65,7 @@ QVariant LauncherModel::data(const QModelIndex &index, int role) const
6165 LauncherItem *item = m_list.at(index.row());
6266 switch(role) {
6367 case RoleAppId:
64− return item->desktopFile();
65− case RoleDesktopFile:
66− return item->desktopFile();
68+ return item->appId();
6769 case RoleName:
6870 return item->name();
6971 case RoleIcon:
@@ -113,9 +115,11 @@ void LauncherModel::move(int oldIndex, int newIndex)
113115 m_list.move(oldIndex, newIndex);
114116 endMoveRows();
115117
116− storeAppList();
117−
118− pin(m_list.at(newIndex)->appId());
118+ if (!m_list.at(newIndex)->pinned()) {
119+ pin(m_list.at(newIndex)->appId());
120+ } else {
121+ storeAppList();
122+ }
119123}
120124
121125void LauncherModel::pin(const QString &appId, int index)
@@ -137,7 +141,6 @@ void LauncherModel::pin(const QString &appId, int index)
137141 }
138142 beginInsertRows(QModelIndex(), index, index);
139143 LauncherItem *item = new LauncherItem(appId,
140− m_backend->desktopFile(appId),
141144 m_backend->displayName(appId),
142145 m_backend->icon(appId));
143146 item->setPinned(true);
@@ -145,6 +148,8 @@ void LauncherModel::pin(const QString &appId, int index)
145148 m_list.insert(index, item);
146149 endInsertRows();
147150 }
151+
152+ storeAppList();
148153}
149154
150155void LauncherModel::requestRemove(const QString &appId)
@@ -154,6 +159,11 @@ void LauncherModel::requestRemove(const QString &appId)
154159 return;
155160 }
156161
162+ if (m_appManager->findApplication(appId)) {
163+ m_list.at(index)->setPinned(false);
164+ return;
165+ }
166+
157167 beginRemoveRows(QModelIndex(), index, index);
158168 m_list.takeAt(index)->deleteLater();
159169 endRemoveRows();
@@ -193,45 +203,21 @@ void LauncherModel::setUser(const QString &username)
193203 m_backend->setUser(username);
194204}
195205
196−void LauncherModel::applicationFocused(const QString &appId)
206+ApplicationManagerInterface *LauncherModel::applicationManager() const
197207{
198− // Unfocus all apps
199− for(int i = 0; i < m_list.count(); ++i) {
200− LauncherItem *item = m_list.at(i);
201− if (item->focused()) {
202− item->setFocused(false);
203− Q_EMIT dataChanged(this->index(i), this->index(i), QVector<int>() << RoleFocused);
204− }
205− }
206−
207− if (appId.isEmpty()) {
208− return;
209− }
210−
211− // FIXME: drop this once we get real appIds from the AppManager
212− QString helper = appId.split('/').last();
213− if (helper.endsWith(".desktop")) {
214− helper.chop(8);
215− }
216−
217− int index = findApplication(helper);
218− if (index >= 0) {
219− m_list.at(index)->setFocused(true);
220− Q_EMIT dataChanged(this->index(index), this->index(index), QVector<int>() << RoleFocused);
221− } else {
222− // Add app to recent apps
223− QString desktopFile = m_backend->desktopFile(helper);
224− QString appName = m_backend->displayName(helper);
225− QString icon = m_backend->icon(helper);
226−
227− LauncherItem *item = new LauncherItem(helper, desktopFile, appName, icon);
228− item->setRecent(true);
229− item->setFocused(true);
230− beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
231− m_list.append(item);
232− endInsertRows();
208+ return m_appManager;
209+}
233210
234− // Clean up old recent apps
211+void LauncherModel::setApplicationManager(unity::shell::application::ApplicationManagerInterface *appManager)
212+{
213+ // Is there already another appmanager set?
214+ if (m_appManager) {
215+ // Disconnect any signals
216+ disconnect(this, SLOT(applicationAdded(QModelIndex,int)));
217+ disconnect(this, SLOT(applicationRemoved(QModelIndex,int)));
218+ disconnect(this, SLOT(focusedAppIdChanged()));
219+
220+ // remove any recent/running apps from the launcher
235221 QList<int> recentAppIndices;
236222 for (int i = 0; i < m_list.count(); ++i) {
237223 if (m_list.at(i)->recent()) {
@@ -239,22 +225,33 @@ void LauncherModel::applicationFocused(const QString &appId)
239225 }
240226 }
241227 int run = 0;
242− while (recentAppIndices.count() > 5) {
228+ while (recentAppIndices.count() > 0) {
243229 beginRemoveRows(QModelIndex(), recentAppIndices.first() - run, recentAppIndices.first() - run);
244230 m_list.takeAt(recentAppIndices.first() - run)->deleteLater();
245231 endRemoveRows();
246232 recentAppIndices.takeFirst();
247233 ++run;
248234 }
249− storeAppList();
235+ }
236+
237+ m_appManager = appManager;
238+ connect(m_appManager, SIGNAL(rowsInserted(QModelIndex, int, int)), SLOT(applicationAdded(QModelIndex,int)));
239+ connect(m_appManager, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), SLOT(applicationRemoved(QModelIndex,int)));
240+ connect(m_appManager, SIGNAL(focusedApplicationIdChanged()), SLOT(focusedAppIdChanged()));
241+
242+ Q_EMIT applicationManagerChanged();
243+
244+ for (int i = 0; i < appManager->count(); ++i) {
245+ applicationAdded(QModelIndex(), i);
250246 }
251247}
252248
249+
253250void LauncherModel::storeAppList()
254251{
255252 QStringList appIds;
256253 Q_FOREACH(LauncherItem *item, m_list) {
257− if (item->pinned() || item->recent()) {
254+ if (item->pinned()) {
258255 appIds << item->appId();
259256 }
260257 }
@@ -292,3 +289,63 @@ void LauncherModel::countChanged(const QString &appId, int count)
292289 Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleCount);
293290 }
294291}
292+
293+void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
294+{
295+ Q_UNUSED(parent);
296+
297+ ApplicationInfoInterface *app = m_appManager->get(row);
298+
299+ bool found = false;
300+ Q_FOREACH(LauncherItem *item, m_list) {
301+ if (app->appId() == item->appId()) {
302+ found = true;
303+ break;
304+ }
305+ }
306+ if (found) {
307+ // Shall we paint some running/recent app highlight? If yes, do it here.
308+ } else {
309+ LauncherItem *item = new LauncherItem(app->appId(), app->name(), app->icon().toString());
310+ item->setRecent(true);
311+ item->setFocused(app->focused());
312+
313+ beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
314+ m_list.append(item);
315+ endInsertRows();
316+ }
317+}
318+
319+void LauncherModel::applicationRemoved(const QModelIndex &parent, int row)
320+{
321+ Q_UNUSED(parent)
322+
323+ int appIndex = -1;
324+ for (int i = 0; i < m_list.count(); ++i) {
325+ if (m_list.at(i)->appId() == m_appManager->get(row)->appId()) {
326+ appIndex = i;
327+ break;
328+ }
329+ }
330+
331+ if (appIndex > -1 && !m_list.at(appIndex)->pinned()) {
332+ beginRemoveRows(QModelIndex(), appIndex, appIndex);
333+ m_list.takeAt(appIndex)->deleteLater();
334+ endRemoveRows();
335+ }
336+}
337+
338+void LauncherModel::focusedAppIdChanged()
339+{
340+ QString appId = m_appManager->focusedApplicationId();
341+ for (int i = 0; i < m_list.count(); ++i) {
342+ LauncherItem *item = m_list.at(i);
343+ if (!item->focused() && item->appId() == appId) {
344+ item->setFocused(true);
345+ Q_EMIT dataChanged(index(i), index(i), QVector<int>() << RoleFocused);
346+ } else if (item->focused() && item->appId() != appId) {
347+ item->setFocused(false);
348+ Q_EMIT dataChanged(index(i), index(i), QVector<int>() << RoleFocused);
349+ }
350+ }
351+}
plugins/Unity/Launcher/launchermodel.h+10−1
@@ -22,6 +22,7 @@
2222
2323// unity-api
2424#include <unity/shell/launcher/LauncherModelInterface.h>
25+#include <unity/shell/application/ApplicationManagerInterface.h>
2526
2627// Qt
2728#include <QAbstractListModel>
@@ -30,6 +31,7 @@ class LauncherItem;
3031class LauncherBackend;
3132
3233using namespace unity::shell::launcher;
34+using namespace unity::shell::application;
3335
3436class LauncherModel: public LauncherModelInterface
3537{
@@ -49,7 +51,9 @@ public:
4951 Q_INVOKABLE void requestRemove(const QString &appId);
5052 Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex);
5153 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);
5357
5458private:
5559 void storeAppList();
@@ -59,9 +63,14 @@ private Q_SLOTS:
5963 void progressChanged(const QString &appId, int progress);
6064 void countChanged(const QString &appId, int count);
6165
66+ void applicationAdded(const QModelIndex &parent, int row);
67+ void applicationRemoved(const QModelIndex &parent, int row);
68+ void focusedAppIdChanged();
69+
6270private:
6371 QList<LauncherItem*> m_list;
6472 LauncherBackend *m_backend;
73+ ApplicationManagerInterface *m_appManager;
6574};
6675
6776#endif // LAUNCHERMODEL_H
plugins/Utils/qsortfilterproxymodelqml.cpp+13−1
@@ -29,6 +29,17 @@ QSortFilterProxyModelQML::QSortFilterProxyModelQML(QObject *parent)
2929 connect(this, SIGNAL(rowsRemoved(QModelIndex,int,int)), SIGNAL(countChanged()));
3030}
3131
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+
3243QHash<int, QByteArray> QSortFilterProxyModelQML::roleNames() const
3344{
3445 return sourceModel() ? sourceModel()->roleNames() : QHash<int, QByteArray>();
@@ -51,6 +62,7 @@ QSortFilterProxyModelQML::setModel(QAbstractItemModel *itemModel)
5162 connect(itemModel, SIGNAL(modelReset()), SIGNAL(totalCountChanged()));
5263 connect(itemModel, SIGNAL(rowsInserted(QModelIndex,int,int)), SIGNAL(totalCountChanged()));
5364 connect(itemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), SIGNAL(totalCountChanged()));
65+
5466 Q_EMIT totalCountChanged();
5567 Q_EMIT modelChanged();
5668 }
@@ -140,4 +152,4 @@ QSortFilterProxyModelQML::mapToSource(int row)
140152 } else {
141153 return -1;
142154 }
143−}
155+}
plugins/Utils/qsortfilterproxymodelqml.h+1
@@ -34,6 +34,7 @@ public:
3434 Q_INVOKABLE QVariant data(int row, int role);
3535 Q_INVOKABLE int count();
3636 Q_INVOKABLE int findFirst(int role, const QVariant& value) const;
37+ Q_INVOKABLE int mapRowToSource(int row);
3738 virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
3839
3940 /* getters */
po/ca.po+32−32
@@ -8,83 +8,83 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-06-27 00:24+0000\n"
12−"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
11+"PO-Revision-Date: 2013-09-11 10:30+0000\n"
12+"Last-Translator: David Planella <david.planella@ubuntu.com>\n"
1313"Language-Team: Catalan <ca@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19−"X-Generator: Launchpad (build 16750)\n"
18+"X-Launchpad-Export-Date: 2013-09-12 08:06+0000\n"
19+"X-Generator: Launchpad (build 16761)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
23−msgstr ""
23+msgstr "Telèfon"
2424
2525#: Applications/applications.js:29
2626msgid "Camera"
27−msgstr ""
27+msgstr "Càmera"
2828
2929#: Applications/applications.js:35
3030msgid "Gallery"
31−msgstr ""
31+msgstr "Galeria"
3232
3333#: Applications/applications.js:40
3434msgid "Facebook"
35−msgstr ""
35+msgstr "Facebook"
3636
3737#: Applications/applications.js:46
3838msgid "Browser"
39−msgstr ""
39+msgstr "Navegador"
4040
4141#: Applications/applications.js:51
4242msgid "Twitter"
43−msgstr ""
43+msgstr "Twitter"
4444
4545#: Applications/applications.js:57
4646msgid "GMail"
47−msgstr ""
47+msgstr "GMail"
4848
4949#: Applications/applications.js:62
5050msgid "Weather"
51−msgstr ""
51+msgstr "El temps"
5252
5353#: Applications/applications.js:68
5454msgid "Notepad"
55−msgstr ""
55+msgstr "Bloc de notes"
5656
5757#: Applications/applications.js:74
5858msgid "Calendar"
59−msgstr ""
59+msgstr "Calendari"
6060
6161#: Applications/applications.js:80
6262msgid "Media Player"
63−msgstr ""
63+msgstr "Reproductor multimèdia"
6464
6565#: Applications/applications.js:86
6666msgid "Evernote"
67−msgstr ""
67+msgstr "Evernote"
6868
6969#: Applications/applications.js:91
7070msgid "Map"
71−msgstr ""
71+msgstr "Mapa"
7272
7373#: Applications/applications.js:96
7474msgid "Pinterest"
75−msgstr ""
75+msgstr "Pinterest"
7676
7777#: Applications/applications.js:101
7878msgid "SoundCloud"
79−msgstr ""
79+msgstr "SoundCloud"
8080
8181#: Applications/applications.js:106
8282msgid "Wikipedia"
83−msgstr ""
83+msgstr "Viquipèdia"
8484
8585#: Applications/applications.js:111
8686msgid "YouTube"
87−msgstr ""
87+msgstr "YouTube"
8888
8989#: Components/EdgeDemoOverlay.qml:145
9090msgid "Skip intro"
@@ -92,7 +92,7 @@ msgstr ""
9292
9393#: Components/EdgeDemo.qml:98
9494msgid "Right edge"
95−msgstr ""
95+msgstr "Vora dreta"
9696
9797#: Components/EdgeDemo.qml:99
9898msgid "Try swiping from the right edge to unlock the phone"
@@ -100,7 +100,7 @@ msgstr ""
100100
101101#: Components/EdgeDemo.qml:135
102102msgid "Top edge"
103−msgstr ""
103+msgstr "Vora superior"
104104
105105#: Components/EdgeDemo.qml:136
106106msgid "Try swiping from the top edge to access the indicators"
@@ -116,7 +116,7 @@ msgstr ""
116116
117117#: Components/EdgeDemo.qml:189
118118msgid "Left edge"
119−msgstr ""
119+msgstr "Vora esquerra"
120120
121121#: Components/EdgeDemo.qml:190
122122msgid "Swipe from the left to reveal the launcher for quick access to apps"
@@ -124,7 +124,7 @@ msgstr ""
124124
125125#: Components/EdgeDemo.qml:217
126126msgid "Well done"
127−msgstr ""
127+msgstr "Enhorabona!"
128128
129129#: Components/EdgeDemo.qml:218
130130msgid "You have now mastered the edge gestures and can start using the phone"
@@ -138,7 +138,7 @@ msgstr "Cerques recents"
138138#: Dash/Apps/AppInfo.qml:73
139139#, qt-format
140140msgid "(%1)"
141−msgstr ""
141+msgstr "(%1)"
142142
143143#. TRANSLATORS: Number of persons who wrote reviews for this app
144144#: Dash/Apps/AppInfo.qml:85
@@ -158,7 +158,7 @@ msgstr ""
158158
159159#: Dash/Apps/AppReviews.qml:84
160160msgid "Review"
161−msgstr ""
161+msgstr "Ressenya"
162162
163163#: Dash/Apps/AppReviews.qml:118
164164msgid "Send"
@@ -166,15 +166,15 @@ msgstr ""
166166
167167#: Dash/Apps/AppReviews.qml:136
168168msgid "Comments:"
169−msgstr ""
169+msgstr "Comentaris:"
170170
171171#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
172172msgid "Featured"
173−msgstr ""
173+msgstr "Destacats"
174174
175175#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
176176msgid "Recent"
177−msgstr ""
177+msgstr "Recents"
178178
179179#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
180180msgid "New Releases"
@@ -206,7 +206,7 @@ msgstr ""
206206
207207#: Dash/Video/VideoPreview.qml:176
208208msgid "Author:"
209−msgstr ""
209+msgstr "Autor:"
210210
211211#: Greeter/Lockscreen.qml:134
212212msgid "Emergency Call"
@@ -219,7 +219,7 @@ msgstr ""
219219
220220#: Greeter/PassphraseLockscreen.qml:59
221221msgid "Hello"
222−msgstr ""
222+msgstr "Hola"
223223
224224#: Hud/HudParametrizedActionsPage.qml:132
225225msgid "Confirm"
po/is.ponew file+256
@@ -0,0 +1,256 @@
1+# Icelandic translation for unity8
2+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
3+# This file is distributed under the same license as the unity8 package.
4+# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
5+#
6+msgid ""
7+msgstr ""
8+"Project-Id-Version: unity8\n"
9+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10+"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11+"PO-Revision-Date: 2013-09-18 16:22+0000\n"
12+"Last-Translator: Andri Thorlacius <Unknown>\n"
13+"Language-Team: Icelandic <is@li.org>\n"
14+"MIME-Version: 1.0\n"
15+"Content-Type: text/plain; charset=UTF-8\n"
16+"Content-Transfer-Encoding: 8bit\n"
17+"Plural-Forms: nplurals=2; plural=n != 1;\n"
18+"X-Launchpad-Export-Date: 2013-09-19 05:14+0000\n"
19+"X-Generator: Launchpad (build 16765)\n"
20+
21+#: Applications/applications.js:23
22+msgid "Phone"
23+msgstr "Sími"
24+
25+#: Applications/applications.js:29
26+msgid "Camera"
27+msgstr "Myndavél"
28+
29+#: Applications/applications.js:35
30+msgid "Gallery"
31+msgstr "Myndasafn"
32+
33+#: Applications/applications.js:40
34+msgid "Facebook"
35+msgstr "Facebook"
36+
37+#: Applications/applications.js:46
38+msgid "Browser"
39+msgstr "Vafri"
40+
41+#: Applications/applications.js:51
42+msgid "Twitter"
43+msgstr "Twitter"
44+
45+#: Applications/applications.js:57
46+msgid "GMail"
47+msgstr "GMail"
48+
49+#: Applications/applications.js:62
50+msgid "Weather"
51+msgstr "Veður"
52+
53+#: Applications/applications.js:68
54+msgid "Notepad"
55+msgstr "Skrifblokk"
56+
57+#: Applications/applications.js:74
58+msgid "Calendar"
59+msgstr "Dagatal"
60+
61+#: Applications/applications.js:80
62+msgid "Media Player"
63+msgstr "Margmiðlunarspilari"
64+
65+#: Applications/applications.js:86
66+msgid "Evernote"
67+msgstr "Evernote"
68+
69+#: Applications/applications.js:91
70+msgid "Map"
71+msgstr "Kort"
72+
73+#: Applications/applications.js:96
74+msgid "Pinterest"
75+msgstr "Pinterest"
76+
77+#: Applications/applications.js:101
78+msgid "SoundCloud"
79+msgstr "SoundCloud"
80+
81+#: Applications/applications.js:106
82+msgid "Wikipedia"
83+msgstr "Wikipedia"
84+
85+#: Applications/applications.js:111
86+msgid "YouTube"
87+msgstr "YouTube"
88+
89+#: Components/EdgeDemoOverlay.qml:145
90+msgid "Skip intro"
91+msgstr "Hoppa yfir kynningu"
92+
93+#: Components/EdgeDemo.qml:98
94+msgid "Right edge"
95+msgstr "Hægri brún"
96+
97+#: Components/EdgeDemo.qml:99
98+msgid "Try swiping from the right edge to unlock the phone"
99+msgstr ""
100+"Prufaðu að renna puttanum frá hægri brúninni til að aflæsa símanum þínum."
101+
102+#: Components/EdgeDemo.qml:135
103+msgid "Top edge"
104+msgstr "Efri brún"
105+
106+#: Components/EdgeDemo.qml:136
107+msgid "Try swiping from the top edge to access the indicators"
108+msgstr ""
109+
110+#: Components/EdgeDemo.qml:161
111+msgid "Close"
112+msgstr "Loka"
113+
114+#: Components/EdgeDemo.qml:162
115+msgid "Swipe up again to close the settings screen"
116+msgstr ""
117+
118+#: Components/EdgeDemo.qml:189
119+msgid "Left edge"
120+msgstr "Vinstri brún"
121+
122+#: Components/EdgeDemo.qml:190
123+msgid "Swipe from the left to reveal the launcher for quick access to apps"
124+msgstr ""
125+
126+#: Components/EdgeDemo.qml:217
127+msgid "Well done"
128+msgstr "Vel gert"
129+
130+#: Components/EdgeDemo.qml:218
131+msgid "You have now mastered the edge gestures and can start using the phone"
132+msgstr ""
133+
134+#: Components/PageHeader.qml:298
135+msgid "Recent searches"
136+msgstr "Nýlegar leitir"
137+
138+#. TRANSLATORS: Number of persons who rated this app
139+#: Dash/Apps/AppInfo.qml:73
140+#, qt-format
141+msgid "(%1)"
142+msgstr "(%1)"
143+
144+#. TRANSLATORS: Number of persons who wrote reviews for this app
145+#: Dash/Apps/AppInfo.qml:85
146+#, qt-format
147+msgid "%1 review"
148+msgid_plural "%1 reviews"
149+msgstr[0] "%1 ummæli"
150+msgstr[1] "%1 ummæli"
151+
152+#: Dash/Apps/AppPreview.qml:175
153+msgid "Rate this"
154+msgstr "Gefa þessu einkunn"
155+
156+#: Dash/Apps/AppReviews.qml:72
157+msgid "Add a review"
158+msgstr "Gefa umsögn"
159+
160+#: Dash/Apps/AppReviews.qml:84
161+msgid "Review"
162+msgstr "Umsögn"
163+
164+#: Dash/Apps/AppReviews.qml:118
165+msgid "Send"
166+msgstr "Senda"
167+
168+#: Dash/Apps/AppReviews.qml:136
169+msgid "Comments:"
170+msgstr "Athugasemdir:"
171+
172+#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
173+msgid "Featured"
174+msgstr "Efst á baugi"
175+
176+#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
177+msgid "Recent"
178+msgstr "Nýlegt"
179+
180+#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
181+msgid "New Releases"
182+msgstr "Nýjar Útgáfur"
183+
184+#: Dash/DashMusic.qml:30
185+msgid "Top Charting"
186+msgstr "Topp Listi"
187+
188+#: Dash/DashMusic.qml:91
189+msgid "Music"
190+msgstr "Tónlist"
191+
192+#: Dash/DashVideos.qml:31
193+msgid "Popular Online"
194+msgstr "Vinsælt á Netinu"
195+
196+#: Dash/DashVideos.qml:146
197+msgid "Videos"
198+msgstr "Myndbönd"
199+
200+#: Dash/Video/VideoPreview.qml:130
201+msgid "Directed by:"
202+msgstr "Leikstýrt af:"
203+
204+#: Dash/Video/VideoPreview.qml:153
205+msgid "Starring:"
206+msgstr "Meðal leikara eru:"
207+
208+#: Dash/Video/VideoPreview.qml:176
209+msgid "Author:"
210+msgstr "Höfundur:"
211+
212+#: Greeter/Lockscreen.qml:134
213+msgid "Emergency Call"
214+msgstr "Neyðarsímtal"
215+
216+#: Greeter/PassphraseLockscreen.qml:59
217+#, qt-format
218+msgid "Hello %1"
219+msgstr "Hæ %1"
220+
221+#: Greeter/PassphraseLockscreen.qml:59
222+msgid "Hello"
223+msgstr "Hæ"
224+
225+#: Hud/HudParametrizedActionsPage.qml:132
226+msgid "Confirm"
227+msgstr "Staðfesta"
228+
229+#: Hud/Hud.qml:61 Hud/Hud.qml:99 Hud/Hud.qml:372
230+msgid "Type or say a command"
231+msgstr "Skrifaðu eða segðu eitthvað"
232+
233+#: Hud/Hud.qml:84
234+msgid "Loading. Please Wait..."
235+msgstr "Hleð. Vinsamlegast Bíðið..."
236+
237+#: Hud/Hud.qml:89
238+msgid "Speak Now..."
239+msgstr "Talaðu Núna..."
240+
241+#: Hud/Hud.qml:94
242+msgid "Speaking..."
243+msgstr "Tala..."
244+
245+#: Panel/SearchIndicator.qml:27
246+msgid "Search"
247+msgstr "Leita"
248+
249+#: plugins/Unity/scope.cpp:317
250+msgid "Sorry, there is nothing that matches your search."
251+msgstr "Því miður, það var ekkert sem passaði við leitarorðið þitt."
252+
253+#: Shell.qml:429
254+#, qt-format
255+msgid "Please enter %1"
256+msgstr ""
po/sl.po+29−24
@@ -8,7 +8,7 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-07-02 12:59+0000\n"
11+"PO-Revision-Date: 2013-09-19 19:48+0000\n"
1212"Last-Translator: Damir Jerovšek <Unknown>\n"
1313"Language-Team: Slovenian <sl@li.org>\n"
1414"MIME-Version: 1.0\n"
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || "
1818"n%100==4 ? 3 : 0);\n"
19−"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
20−"X-Generator: Launchpad (build 16750)\n"
19+"X-Launchpad-Export-Date: 2013-09-20 06:21+0000\n"
20+"X-Generator: Launchpad (build 16765)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
@@ -25,7 +25,7 @@ msgstr "Telefon"
2525
2626#: Applications/applications.js:29
2727msgid "Camera"
28−msgstr ""
28+msgstr "Fotoaparat"
2929
3030#: Applications/applications.js:35
3131msgid "Gallery"
@@ -89,47 +89,50 @@ msgstr "YouTube"
8989
9090#: Components/EdgeDemoOverlay.qml:145
9191msgid "Skip intro"
92−msgstr ""
92+msgstr "Preskoči uvod"
9393
9494#: Components/EdgeDemo.qml:98
9595msgid "Right edge"
96−msgstr ""
96+msgstr "Desni rob"
9797
9898#: Components/EdgeDemo.qml:99
9999msgid "Try swiping from the right edge to unlock the phone"
100−msgstr ""
100+msgstr "Poskusite povleči od desnega roba za odklep telefona"
101101
102102#: Components/EdgeDemo.qml:135
103103msgid "Top edge"
104−msgstr ""
104+msgstr "Zgornji rob"
105105
106106#: Components/EdgeDemo.qml:136
107107msgid "Try swiping from the top edge to access the indicators"
108−msgstr ""
108+msgstr "Poskusite povleči od zgornjega roba za dostop do kazalnikov"
109109
110110#: Components/EdgeDemo.qml:161
111111msgid "Close"
112−msgstr ""
112+msgstr "Zapri"
113113
114114#: Components/EdgeDemo.qml:162
115115msgid "Swipe up again to close the settings screen"
116−msgstr ""
116+msgstr "Povlecite ponovno navzgor za zaprtje zaslona z nastavitvami"
117117
118118#: Components/EdgeDemo.qml:189
119119msgid "Left edge"
120−msgstr ""
120+msgstr "Levi rob"
121121
122122#: Components/EdgeDemo.qml:190
123123msgid "Swipe from the left to reveal the launcher for quick access to apps"
124124msgstr ""
125+"Poskusite povleči od leve za razkritje zaganjalnika za hiter dostop do "
126+"programov"
125127
126128#: Components/EdgeDemo.qml:217
127129msgid "Well done"
128−msgstr ""
130+msgstr "Odlično"
129131
130132#: Components/EdgeDemo.qml:218
131133msgid "You have now mastered the edge gestures and can start using the phone"
132134msgstr ""
135+"Zdaj, ko ste osvojili kretnje z robovi, lahko začnete uporabljati telefon"
133136
134137#: Components/PageHeader.qml:298
135138msgid "Recent searches"
@@ -139,35 +142,37 @@ msgstr "Nedavna iskanja"
139142#: Dash/Apps/AppInfo.qml:73
140143#, qt-format
141144msgid "(%1)"
142−msgstr ""
145+msgstr "(%1)"
143146
144147#. TRANSLATORS: Number of persons who wrote reviews for this app
145148#: Dash/Apps/AppInfo.qml:85
146149#, qt-format
147150msgid "%1 review"
148151msgid_plural "%1 reviews"
149−msgstr[0] ""
150−msgstr[1] ""
152+msgstr[0] "%1 ocen"
153+msgstr[1] "%1 ocena"
154+msgstr[2] "%1 oceni"
155+msgstr[3] "%1 ocene"
151156
152157#: Dash/Apps/AppPreview.qml:175
153158msgid "Rate this"
154−msgstr ""
159+msgstr "Ocenite"
155160
156161#: Dash/Apps/AppReviews.qml:72
157162msgid "Add a review"
158−msgstr ""
163+msgstr "Dodaj oceno"
159164
160165#: Dash/Apps/AppReviews.qml:84
161166msgid "Review"
162−msgstr ""
167+msgstr "Ocena"
163168
164169#: Dash/Apps/AppReviews.qml:118
165170msgid "Send"
166−msgstr ""
171+msgstr "Pošlji"
167172
168173#: Dash/Apps/AppReviews.qml:136
169174msgid "Comments:"
170−msgstr ""
175+msgstr "Opombe:"
171176
172177#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
173178msgid "Featured"
@@ -211,7 +216,7 @@ msgstr ""
211216
212217#: Greeter/Lockscreen.qml:134
213218msgid "Emergency Call"
214−msgstr ""
219+msgstr "Klic v sili"
215220
216221#: Greeter/PassphraseLockscreen.qml:59
217222#, qt-format
@@ -220,7 +225,7 @@ msgstr "Pozdravljeni, %1"
220225
221226#: Greeter/PassphraseLockscreen.qml:59
222227msgid "Hello"
223−msgstr ""
228+msgstr "Pozdravljeni"
224229
225230#: Hud/HudParametrizedActionsPage.qml:132
226231msgid "Confirm"
@@ -253,4 +258,4 @@ msgstr "Nič se ne ujema z vašim iskalnim nizom."
253258#: Shell.qml:429
254259#, qt-format
255260msgid "Please enter %1"
256−msgstr ""
261+msgstr "Vnesite %1"
run_on_device+2−1
@@ -65,8 +65,9 @@ setup_adb_forwarding() {
6565}
6666
6767install_dependencies() {
68+ exec_with_adb rm /etc/init/ssh.override
69+ exec_with_adb service ssh start
6870 exec_with_adb apt-get update
69− exec_with_adb apt-get -y install openssh-server
7071 exec_with_ssh $SUDO apt-get -y install build-essential rsync bzr ccache gdb ninja-build devscripts equivs
7172}
7273
tests/autopilot/unity8/application_lifecycle/__init__.pynew file+20
@@ -0,0 +1,20 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2013 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+"""Tests for the application lifecycle base package."""
tests/autopilot/unity8/application_lifecycle/tests/__init__.pynew file

No changes to the content.

tests/autopilot/unity8/application_lifecycle/tests/test_application_lifecycle.pynew file+136
@@ -0,0 +1,136 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2013 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+"""Tests for the application lifecycle."""
21+
22+from __future__ import absolute_import
23+
24+from unity8.shell import disable_qml_mocking
25+from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
26+
27+from autopilot.matchers import Eventually
28+from autopilot.platform import model
29+from testtools.matchers import Equals, NotEquals
30+
31+import logging
32+
33+logger = logging.getLogger(__name__)
34+
35+
36+class ApplicationLifecycleTests(UnityTestCase):
37+
38+ scenarios = _get_device_emulation_scenarios()
39+
40+ def setUp(self):
41+ super(ApplicationLifecycleTests, self).setUp()
42+ if model() == "Desktop":
43+ self.skipTest("Test cannot be run on the desktop.")
44+
45+ def swipe_screen_from_right(self):
46+ qml_view = self.main_window.get_qml_view()
47+ width = qml_view.width
48+ height = qml_view.height
49+ start_x = width
50+ start_y = int(height/2)
51+ end_x = int(width/2)
52+ end_y = start_y
53+
54+ logger.info("Swiping screen from the right edge")
55+ self.touch.drag(start_x, start_y, end_x, end_y)
56+
57+ def _get_current_focused_app_id(self):
58+ return self._proxy.select_single("Shell").currentFocusedAppId
59+
60+ def _launch_app(self, app_name):
61+ """Launches the application *app_name*
62+
63+ Assumes that the desktop file resides at:
64+ /usr/share/applications/{app_name}.desktop
65+
66+ """
67+ desktop_file = "--desktop_file_hint="\
68+ "/usr/share/applications/{app_name}.desktop".format(
69+ app_name=app_name
70+ )
71+ return self.launch_test_application(
72+ app_name,
73+ desktop_file,
74+ "--stage_hint=main_stage",
75+ app_type='qt'
76+ )
77+
78+ @disable_qml_mocking
79+ def test_can_launch_application(self):
80+ """Must be able to launch an application."""
81+ self.launch_unity()
82+ self.main_window.get_greeter().swipe()
83+
84+ app = self._launch_app("messaging-app")
85+
86+ self.assertThat(app, NotEquals(None))
87+ self.assertThat(
88+ self._get_current_focused_app_id(),
89+ Eventually(Equals("messaging-app"))
90+ )
91+
92+ @disable_qml_mocking
93+ def test_can_launch_multiple_applications(self):
94+ """A second application launched must be focused."""
95+ self.launch_unity()
96+ self.main_window.get_greeter().swipe()
97+
98+ self._launch_app("messaging-app")
99+ self.assertThat(
100+ self._get_current_focused_app_id(),
101+ Eventually(Equals("messaging-app"))
102+ )
103+
104+ self._launch_app("address-book-app")
105+ self.assertThat(
106+ self._get_current_focused_app_id(),
107+ Eventually(Equals("address-book-app"))
108+ )
109+
110+ @disable_qml_mocking
111+ def test_app_moves_from_unfocused_to_focused(self):
112+ """An application that is in the unfocused state must be able to be
113+ brought back to the focused state.
114+
115+ """
116+ self.launch_unity()
117+ self.main_window.get_greeter().swipe()
118+
119+ self._launch_app("messaging-app")
120+ self.assertThat(
121+ self._get_current_focused_app_id(),
122+ Eventually(Equals("messaging-app"))
123+ )
124+
125+ self._launch_app("address-book-app")
126+ self.assertThat(
127+ self._get_current_focused_app_id(),
128+ Eventually(Equals("address-book-app"))
129+ )
130+
131+ self.swipe_screen_from_right()
132+
133+ self.assertThat(
134+ self._get_current_focused_app_id(),
135+ Eventually(Equals("messaging-app"))
136+ )
tests/autopilot/unity8/shell/__init__.py+10
@@ -36,3 +36,13 @@ def with_lightdm_mock(mock_type):
3636 return fn(*args, **kwargs)
3737 return wrapper
3838 return with_lightdm_mock_internal
39+
40+
41+def disable_qml_mocking(fn):
42+ """Simple decorator that disables the QML mocks from being loaded."""
43+ @wraps(fn)
44+ def wrapper(*args, **kwargs):
45+ tests_self = args[0]
46+ tests_self._qml_mock_enabled = False
47+ return fn(*args, **kwargs)
48+ return wrapper
tests/autopilot/unity8/shell/tests/__init__.py+4−1
@@ -86,6 +86,7 @@ class UnityTestCase(AutopilotTestCase):
8686
8787 self._proxy = None
8888 self._lightdm_mock_type = None
89+ self._qml_mock_enabled = True
8990 self.touch = Touch.create()
9091 self._setup_display_details()
9192
@@ -160,7 +161,9 @@ class UnityTestCase(AutopilotTestCase):
160161
161162 if self._lightdm_mock_type is None:
162163 self.patch_lightdm_mock()
163− self._setup_extra_mock_environment_patch()
164+
165+ if self._qml_mock_enabled:
166+ self._setup_extra_mock_environment_patch()
164167
165168 app_proxy = self.launch_test_application(
166169 binary_path,
tests/mocks/AccountsService/AccountsService.cpp+9−2
@@ -19,7 +19,8 @@
1919#include "AccountsService.h"
2020
2121AccountsService::AccountsService(QObject* parent)
22− : QObject(parent)
22+ : QObject(parent),
23+ m_backgroundFile(TOP_SRCDIR "/graphics/phone_background.jpg")
2324{
2425}
2526
@@ -45,5 +46,11 @@ void AccountsService::setDemoEdges(bool demoEdges)
4546
4647QString AccountsService::getBackgroundFile()
4748{
48− return TOP_SRCDIR "/graphics/phone_background.jpg";
49+ return m_backgroundFile;
50+}
51+
52+void AccountsService::setBackgroundFile(const QString &backgroundFile)
53+{
54+ m_backgroundFile = backgroundFile;
55+ backgroundFileChanged();
4956}
tests/mocks/AccountsService/AccountsService.h+5
@@ -37,6 +37,7 @@ class AccountsService: public QObject
3737 NOTIFY demoEdgesChanged)
3838 Q_PROPERTY (QString backgroundFile
3939 READ getBackgroundFile
40+ WRITE setBackgroundFile // only available in mock
4041 NOTIFY backgroundFileChanged)
4142
4243public:
@@ -47,11 +48,15 @@ public:
4748 bool getDemoEdges();
4849 void setDemoEdges(bool demoEdges);
4950 QString getBackgroundFile();
51+ void setBackgroundFile(const QString &backgroundFile);
5052
5153Q_SIGNALS:
5254 void userChanged();
5355 void demoEdgesChanged();
5456 void backgroundFileChanged();
57+
58+private:
59+ QString m_backgroundFile;
5560};
5661
5762#endif
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)
21add_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 @@
2121#include <QQuickView>
2222#include <QQmlComponent>
2323
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+
2437ApplicationInfo::ApplicationInfo(QObject *parent)
25− : QObject(parent)
26− ,m_handle(0)
38+ : ApplicationInfoInterface(QString(), parent)
2739 ,m_stage(MainStage)
2840 ,m_state(Starting)
41+ ,m_focused(false)
2942 ,m_fullscreen(false)
3043 ,m_windowItem(0)
3144 ,m_windowComponent(0)
tests/mocks/Ubuntu/Application/ApplicationInfo.h → tests/mocks/Unity/Application/ApplicationInfo.hrenamed+12−18
@@ -22,21 +22,18 @@
2222
2323class QQuickItem;
2424
25+// unity-api
26+#include <unity/shell/application/ApplicationInfoInterface.h>
27+
2528// A pretty dumb file. Just a container for properties.
2629// Implemented in C++ instead of QML just because of the enumerations
2730// See QTBUG-14861
28−class ApplicationInfo : public QObject {
31+
32+using namespace unity::shell::application;
33+
34+class ApplicationInfo : public ApplicationInfoInterface {
2935 Q_OBJECT
30− Q_ENUMS(Stage)
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)
36+
4037 Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged)
4138
4239 // Only exists in this fake implementation
@@ -48,10 +45,8 @@ class ApplicationInfo : public QObject {
4845 Q_PROPERTY(QString windowQml READ windowQml WRITE setWindowQml NOTIFY windowQmlChanged)
4946
5047 public:
51− enum Stage { MainStage, SideStage };
52− enum State { Starting, Running };
53−
5448 ApplicationInfo(QObject *parent = NULL);
49+ ApplicationInfo(const QString &appId, QObject *parent = NULL);
5550
5651 #define IMPLEMENT_PROPERTY(name, Name, type) \
5752 public: \
@@ -68,14 +63,13 @@ class ApplicationInfo : public QObject {
6863 private: \
6964 type m_##name;
7065
71− IMPLEMENT_PROPERTY(desktopFile, DesktopFile, QString)
66+ IMPLEMENT_PROPERTY(appId, AppId, QString)
7267 IMPLEMENT_PROPERTY(name, Name, QString)
7368 IMPLEMENT_PROPERTY(comment, Comment, QString)
74− IMPLEMENT_PROPERTY(icon, Icon, QString)
75− IMPLEMENT_PROPERTY(exec, Exec, QString)
76− IMPLEMENT_PROPERTY(handle, Handle, qint64)
69+ IMPLEMENT_PROPERTY(icon, Icon, QUrl)
7770 IMPLEMENT_PROPERTY(stage, Stage, Stage)
7871 IMPLEMENT_PROPERTY(state, State, State)
72+ IMPLEMENT_PROPERTY(focused, Focused, bool)
7973 IMPLEMENT_PROPERTY(fullscreen, Fullscreen, bool)
8074 IMPLEMENT_PROPERTY(imageQml, ImageQml, QString)
8175 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 @@
1616
1717#include "ApplicationManager.h"
1818#include "ApplicationInfo.h"
19−#include "ApplicationListModel.h"
2019#include "paths.h"
2120
2221#include <QDir>
@@ -26,11 +25,7 @@
2625#include <QQmlComponent>
2726
2827ApplicationManager::ApplicationManager(QObject *parent)
29− : QObject(parent)
30− , m_mainStageApplications(new ApplicationListModel())
31− , m_sideStageApplications(new ApplicationListModel())
32− , m_mainStageFocusedApplication(0)
33− , m_sideStageFocusedApplication(0)
28+ : ApplicationManagerInterface(parent)
3429 , m_mainStageComponent(0)
3530 , m_mainStage(0)
3631 , m_sideStageComponent(0)
@@ -41,8 +36,84 @@ ApplicationManager::ApplicationManager(QObject *parent)
4136
4237ApplicationManager::~ApplicationManager()
4338{
44− delete m_mainStageApplications;
45− delete m_sideStageApplications;
39+}
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+ }
46117}
47118
48119int ApplicationManager::keyboardHeight() const
@@ -70,36 +141,21 @@ ApplicationManager::FormFactorHint ApplicationManager::formFactorHint() const
70141 return PhoneFormFactor;
71142}
72143
73−ApplicationListModel* ApplicationManager::mainStageApplications() const
74−{
75− return m_mainStageApplications;
76−}
77−
78−ApplicationListModel* ApplicationManager::sideStageApplications() const
144+ApplicationInfo* ApplicationManager::startApplication(const QString &appId,
145+ const QStringList &arguments)
79146{
80− return m_sideStageApplications;
147+ return startApplication(appId, NoFlag, arguments);
81148}
82149
83−ApplicationInfo* ApplicationManager::mainStageFocusedApplication() const
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,
150+ApplicationInfo* ApplicationManager::startApplication(const QString &appId,
94151 ExecFlags flags,
95− QStringList arguments)
152+ const QStringList &arguments)
96153{
97154 Q_UNUSED(arguments)
98155 ApplicationInfo *application = 0;
99156
100− for (int i = 0; i < m_availableApplications.count(); ++i) {
101− ApplicationInfo *availableApp = m_availableApplications[i];
102− if (availableApp->desktopFile() == desktopFile) {
157+ for (ApplicationInfo *availableApp : m_availableApplications) {
158+ if (availableApp->appId() == appId) {
103159 application = availableApp;
104160 break;
105161 }
@@ -109,86 +165,91 @@ ApplicationInfo* ApplicationManager::startProcess(QString desktopFile,
109165 return 0;
110166
111167 if (flags.testFlag(ApplicationManager::ForceMainStage)
112− || application->stage() == ApplicationInfo::MainStage) {
113− m_mainStageApplications->add(application);
114− } else {
115− m_sideStageApplications->add(application);
168+ && application->stage() == ApplicationInfo::SideStage) {
169+ application->setStage(ApplicationInfo::MainStage);
116170 }
171+ add(application);
117172
118173 return application;
119174}
120175
121−void ApplicationManager::stopProcess(ApplicationInfo* application)
176+bool ApplicationManager::stopApplication(const QString &appId)
122177{
123− if (m_mainStageApplications->contains(application)) {
124− m_mainStageApplications->remove(application);
178+ ApplicationInfo *application = findApplication(appId);
179+ if (application == nullptr)
180+ return false;
125181
126− if (m_mainStageFocusedApplication == application) {
127− m_mainStageFocusedApplication = 0;
128− Q_EMIT mainStageFocusedApplicationChanged();
129− }
130− } else if (m_sideStageApplications->contains(application)){
131− m_sideStageApplications->remove(application);
182+ remove(application);
183+ Q_EMIT focusedApplicationIdChanged();
184+ return true;
185+}
132186
133− if (m_sideStageFocusedApplication == application) {
134− m_sideStageFocusedApplication = 0;
135− Q_EMIT sideStageFocusedApplicationChanged();
187+QString ApplicationManager::focusedApplicationId() const {
188+ for (ApplicationInfo *app : m_runningApplications) {
189+ if (app->focused()) {
190+ return app->appId();
136191 }
137192 }
193+ return QString();
138194}
139195
140−void ApplicationManager::focusApplication(int handle)
196+bool ApplicationManager::focusApplication(const QString &appId)
141197{
142− for (int i = 0; i < m_mainStageApplications->m_applications.count(); ++i) {
143− ApplicationInfo *application = m_mainStageApplications->m_applications[i];
144− if (application->handle() == handle) {
145− if (m_mainStageFocusedApplication)
146− m_mainStageFocusedApplication->hideWindow();
147− m_mainStageFocusedApplication = application;
148− if (!m_mainStage)
149− createMainStage();
150− application->showWindow(m_mainStage);
151− m_mainStage->setZ(-1000);
152− if (m_sideStage)
153− m_sideStage->setZ(-2000);
154− Q_EMIT mainStageFocusedApplicationChanged();
155− return;
198+ ApplicationInfo *application = findApplication(appId);
199+ if (application == nullptr)
200+ return false;
201+
202+ if (application->stage() == ApplicationInfo::MainStage) {
203+ // unfocus currently focused mainstage app
204+ for (ApplicationInfo *app : m_runningApplications) {
205+ if (app->focused() && app->stage() == ApplicationInfo::MainStage) {
206+ app->setFocused(false);
207+ app->hideWindow();
208+ }
156209 }
157− }
158210
159− for (int i = 0; i < m_sideStageApplications->m_applications.count(); ++i) {
160− ApplicationInfo *application = m_sideStageApplications->m_applications[i];
161− if (application->handle() == handle) {
162− if (m_sideStageFocusedApplication)
163− m_sideStageFocusedApplication->hideWindow();
164− m_sideStageFocusedApplication = application;
165− if (!m_sideStage)
166− createSideStage();
167− application->showWindow(m_sideStage);
168− m_sideStage->setZ(-1000);
169− if (m_mainStage)
170− m_mainStage->setZ(-2000);
171− Q_EMIT sideStageFocusedApplicationChanged();
172− return;
211+ // focus this app
212+ application->setFocused(true);
213+ if (!m_mainStage)
214+ createMainStage();
215+ application->showWindow(m_mainStage);
216+ m_mainStage->setZ(-1000);
217+ if (m_sideStage)
218+ m_sideStage->setZ(-2000);
219+ } else if (application->stage() == ApplicationInfo::SideStage) {
220+ // unfocus currently focused sidestage app
221+ for (ApplicationInfo *app : m_runningApplications) {
222+ if (app->focused() && app->stage() == ApplicationInfo::SideStage) {
223+ app->setFocused(false);
224+ app->hideWindow();
225+ }
173226 }
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);
174236 }
237+
238+ // move app to top of stack
239+ move(m_runningApplications.indexOf(application), 0);
240+ Q_EMIT focusedApplicationIdChanged();
241+ return true;
175242}
176243
177−void ApplicationManager::unfocusCurrentApplication(StageHint stageHint)
244+void ApplicationManager::unfocusCurrentApplication()
178245{
179− if (stageHint == SideStage) {
180− if (m_sideStageFocusedApplication) {
181− m_sideStageFocusedApplication->hideWindow();
182− m_sideStageFocusedApplication = 0;
183− Q_EMIT sideStageFocusedApplicationChanged();
184− }
185− } else {
186− if (m_mainStageFocusedApplication) {
187− m_mainStageFocusedApplication->hideWindow();
188− m_mainStageFocusedApplication = 0;
189− Q_EMIT mainStageFocusedApplicationChanged();
246+ for (ApplicationInfo *app : m_runningApplications) {
247+ if (app->focused()) {
248+ app->hideWindow();
249+ app->setFocused(false);
190250 }
191251 }
252+ Q_EMIT focusedApplicationIdChanged();
192253}
193254
194255void ApplicationManager::generateQmlStrings(ApplicationInfo *application)
@@ -213,7 +274,7 @@ void ApplicationManager::generateQmlStrings(ApplicationInfo *application)
213274 " fillMode: Image.PreserveAspectCrop\n"
214275 "}").arg(topMargin)
215276 .arg(shellAppDirectory())
216− .arg(application->icon());
277+ .arg(application->icon().toString());
217278 application->setWindowQml(windowQml);
218279
219280 QString imageQml = QString(
@@ -224,159 +285,130 @@ void ApplicationManager::generateQmlStrings(ApplicationInfo *application)
224285 " smooth: true\n"
225286 " fillMode: Image.PreserveAspectCrop\n"
226287 "}").arg(shellAppDirectory())
227− .arg(application->icon());
288+ .arg(application->icon().toString());
228289 application->setImageQml(imageQml);
229290}
230291
231292void ApplicationManager::buildListOfAvailableApplications()
232293{
233294 ApplicationInfo *application;
234− qint64 nextHandle = 1;
235295
236296 application = new ApplicationInfo(this);
237− application->setDesktopFile("/usr/share/applications/phone-app.desktop");
297+ application->setAppId("phone-app");
238298 application->setName("Phone");
239− application->setIcon("phone");
240− application->setExec("/usr/bin/phone-app");
299+ application->setIcon(QUrl("phone"));
241300 application->setStage(ApplicationInfo::SideStage);
242− application->setHandle(nextHandle++);
243301 generateQmlStrings(application);
244302 m_availableApplications.append(application);
245303
246304 application = new ApplicationInfo(this);
247− application->setDesktopFile("/usr/share/applications/camera-app.desktop");
305+ application->setAppId("camera-app");
248306 application->setName("Camera");
249− application->setIcon("camera");
307+ application->setIcon(QUrl("camera"));
250308 application->setFullscreen(true);
251− application->setExec("/usr/bin/camera-app --fullscreen");
252− application->setHandle(nextHandle++);
253309 generateQmlStrings(application);
254310 m_availableApplications.append(application);
255311
256312 application = new ApplicationInfo(this);
257− application->setDesktopFile("/usr/share/applications/gallery-app.desktop");
313+ application->setAppId("gallery-app");
258314 application->setName("Gallery");
259− application->setIcon("gallery");
260− application->setExec("/usr/bin/gallery-app");
261− application->setHandle(nextHandle++);
315+ application->setIcon(QUrl("gallery"));
262316 generateQmlStrings(application);
263317 m_availableApplications.append(application);
264318
265319 application = new ApplicationInfo(this);
266− application->setDesktopFile("/usr/share/applications/facebook-webapp.desktop");
320+ application->setAppId("facebook-webapp");
267321 application->setName("Facebook");
268− application->setIcon("facebook");
269− application->setExec("/usr/bin/webbrowser-app --chromeless http://m.facebook.com");
322+ application->setIcon(QUrl("facebook"));
270323 application->setStage(ApplicationInfo::SideStage);
271− application->setHandle(nextHandle++);
272324 generateQmlStrings(application);
273325 m_availableApplications.append(application);
274326
275327 application = new ApplicationInfo(this);
276− application->setDesktopFile("/usr/share/applications/webbrowser-app.desktop");
328+ application->setAppId("webbrowser-app");
277329 application->setName("Browser");
278− application->setIcon("browser");
279− application->setExec("/usr/bin/webbrowser-app");
280− application->setHandle(nextHandle++);
330+ application->setIcon(QUrl("browser"));
281331 generateQmlStrings(application);
282332 m_availableApplications.append(application);
283333
284334 application = new ApplicationInfo(this);
285− application->setDesktopFile("/usr/share/applications/twitter-webapp.desktop");
335+ application->setAppId("twitter-webapp");
286336 application->setName("Twitter");
287− application->setIcon("twitter");
288− application->setExec("/usr/bin/webbrowser-app --chromeless http://www.twitter.com");
337+ application->setIcon(QUrl("twitter"));
289338 application->setStage(ApplicationInfo::SideStage);
290− application->setHandle(nextHandle++);
291339 generateQmlStrings(application);
292340 m_availableApplications.append(application);
293341
294342 application = new ApplicationInfo(this);
295− application->setDesktopFile("/usr/share/applications/gmail-webapp.desktop");
343+ application->setAppId("gmail-webapp");
296344 application->setName("GMail");
297− application->setIcon("gmail");
298− application->setExec("/usr/bin/webbrowser-app --chromeless http://m.gmail.com");
299− application->setHandle(nextHandle++);
345+ application->setIcon(QUrl("gmail"));
300346 m_availableApplications.append(application);
301347
302348 application = new ApplicationInfo(this);
303− application->setDesktopFile("/usr/share/applications/ubuntu-weather-app.desktop");
349+ application->setAppId("ubuntu-weather-app");
304350 application->setName("Weather");
305− application->setIcon("weather");
306− application->setExec("/usr/bin/qmlscene /usr/share/ubuntu-weather-app/ubuntu-weather-app.qml");
351+ application->setIcon(QUrl("weather"));
307352 application->setStage(ApplicationInfo::SideStage);
308− application->setHandle(nextHandle++);
309353 generateQmlStrings(application);
310354 m_availableApplications.append(application);
311355
312356 application = new ApplicationInfo(this);
313− application->setDesktopFile("/usr/share/applications/notes-app.desktop");
357+ application->setAppId("notes-app");
314358 application->setName("Notepad");
315− application->setIcon("notepad");
316− application->setExec("/usr/bin/qmlscene /usr/share/notes-app/NotesApp.qml");
359+ application->setIcon(QUrl("notepad"));
317360 application->setStage(ApplicationInfo::SideStage);
318− application->setHandle(nextHandle++);
319361 m_availableApplications.append(application);
320362
321363 application = new ApplicationInfo(this);
322− application->setDesktopFile("/usr/share/applications/calendar-app.desktop");
364+ application->setAppId("calendar-app");
323365 application->setName("Calendar");
324− application->setIcon("calendar");
325− application->setExec("/usr/bin/qmlscene /usr/share/calendar-app/calendar.qml");
366+ application->setIcon(QUrl("calendar"));
326367 application->setStage(ApplicationInfo::SideStage);
327− application->setHandle(nextHandle++);
328368 m_availableApplications.append(application);
329369
330370 application = new ApplicationInfo(this);
331− application->setDesktopFile("/usr/share/applications/mediaplayer-app.desktop");
371+ application->setAppId("mediaplayer-app");
332372 application->setName("Media Player");
333− application->setIcon("mediaplayer-app");
373+ application->setIcon(QUrl("mediaplayer-app"));
334374 application->setFullscreen(true);
335− application->setExec("/usr/bin/mediaplayer-app");
336− application->setHandle(nextHandle++);
337375 m_availableApplications.append(application);
338376
339377 application = new ApplicationInfo(this);
340− application->setDesktopFile("/usr/share/applications/evernote.desktop");
378+ application->setAppId("evernote");
341379 application->setName("Evernote");
342− application->setIcon("evernote");
343− application->setHandle(nextHandle++);
380+ application->setIcon(QUrl("evernote"));
344381 m_availableApplications.append(application);
345382
346383 application = new ApplicationInfo(this);
347− application->setDesktopFile("/usr/share/applications/map.desktop");
384+ application->setAppId("map");
348385 application->setName("Map");
349− application->setIcon("map");
350− application->setHandle(nextHandle++);
386+ application->setIcon(QUrl("map"));
351387 generateQmlStrings(application);
352388 m_availableApplications.append(application);
353389
354390 application = new ApplicationInfo(this);
355− application->setDesktopFile("/usr/share/applications/pinterest.desktop");
391+ application->setAppId("pinterest");
356392 application->setName("Pinterest");
357− application->setIcon("pinterest");
358− application->setHandle(nextHandle++);
393+ application->setIcon(QUrl("pinterest"));
359394 m_availableApplications.append(application);
360395
361396 application = new ApplicationInfo(this);
362− application->setDesktopFile("/usr/share/applications/soundcloud.desktop");
397+ application->setAppId("soundcloud");
363398 application->setName("SoundCloud");
364− application->setIcon("soundcloud");
365− application->setHandle(nextHandle++);
399+ application->setIcon(QUrl("soundcloud"));
366400 m_availableApplications.append(application);
367401
368402 application = new ApplicationInfo(this);
369− application->setDesktopFile("/usr/share/applications/wikipedia.desktop");
403+ application->setAppId("wikipedia");
370404 application->setName("Wikipedia");
371− application->setIcon("wikipedia");
372− application->setHandle(nextHandle++);
405+ application->setIcon(QUrl("wikipedia"));
373406 m_availableApplications.append(application);
374407
375408 application = new ApplicationInfo(this);
376− application->setDesktopFile("/usr/share/applications/youtube.desktop");
409+ application->setAppId("youtube");
377410 application->setName("YouTube");
378− application->setIcon("youtube");
379− application->setHandle(nextHandle++);
411+ application->setIcon(QUrl("youtube"));
380412 m_availableApplications.append(application);
381413}
382414
tests/mocks/Ubuntu/Application/ApplicationManager.h → tests/mocks/Unity/Application/ApplicationManager.hrenamed+26−26
@@ -20,12 +20,15 @@
2020#include <QObject>
2121#include <QList>
2222#include <QStringList>
23−#include "ApplicationListModel.h"
2423#include "ApplicationInfo.h"
2524
25+// unity-api
26+#include <unity/shell/application/ApplicationManagerInterface.h>
27+
2628class QQuickItem;
29+using namespace unity::shell::application;
2730
28−class ApplicationManager : public QObject {
31+class ApplicationManager : public ApplicationManagerInterface {
2932 Q_OBJECT
3033 Q_ENUMS(Role)
3134 Q_ENUMS(StageHint)
@@ -39,12 +42,6 @@ class ApplicationManager : public QObject {
3942 Q_PROPERTY(int sideStageWidth READ sideStageWidth)
4043 Q_PROPERTY(StageHint stageHint READ stageHint)
4144 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)
4845
4946 Q_PROPERTY(bool fake READ fake CONSTANT)
5047
@@ -64,7 +61,8 @@ class ApplicationManager : public QObject {
6461 DesktopFormFactor, PhoneFormFactor, TabletFormFactor
6562 };
6663 enum FavoriteApplication {
67− CameraApplication, GalleryApplication, BrowserApplication, ShareApplication
64+ CameraApplication, GalleryApplication, BrowserApplication, ShareApplication,
65+ PhoneApplication, DialerApplication, MessagingApplication, AddressbookApplication
6866 };
6967 enum Flag {
7068 NoFlag = 0x0,
@@ -77,29 +75,34 @@ class ApplicationManager : public QObject {
7775 int sideStageWidth() const;
7876 StageHint stageHint() const;
7977 FormFactorHint formFactorHint() const;
80− ApplicationListModel* mainStageApplications() const;
81− ApplicationListModel* sideStageApplications() const;
82− ApplicationInfo* mainStageFocusedApplication() const;
83− ApplicationInfo* sideStageFocusedApplication() const;
8478
8579 bool fake() { return true; }
8680
87− Q_INVOKABLE void focusApplication(int handle);
88− Q_INVOKABLE void unfocusCurrentApplication(StageHint stageHint);
89− Q_INVOKABLE ApplicationInfo* startProcess(QString desktopFile,
90− ExecFlags flags,
91− QStringList arguments = QStringList());
92− Q_INVOKABLE void stopProcess(ApplicationInfo* application);
93− Q_INVOKABLE void startWatcher() {}
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;
91+ Q_INVOKABLE void unfocusCurrentApplication() override;
92+ Q_INVOKABLE ApplicationInfo *startApplication(const QString &appId, const QStringList &arguments = QStringList()) override;
93+ Q_INVOKABLE ApplicationInfo *startApplication(const QString &appId, ExecFlags flags, const QStringList &arguments = QStringList());
94+ Q_INVOKABLE bool stopApplication(const QString &appId) override;
95+
96+ QString focusedApplicationId() const override;
9497
9598 Q_SIGNALS:
9699 void keyboardHeightChanged();
97100 void keyboardVisibleChanged();
98− void mainStageFocusedApplicationChanged();
99− void sideStageFocusedApplicationChanged();
100101 void focusRequested(FavoriteApplication favoriteApplication);
101102
102103 private:
104+ void add(ApplicationInfo *application);
105+ void remove(ApplicationInfo* application);
103106 void showApplicationWindow(ApplicationInfo *application);
104107 void buildListOfAvailableApplications();
105108 void generateQmlStrings(ApplicationInfo *application);
@@ -109,10 +112,7 @@ class ApplicationManager : public QObject {
109112 void createSideStage();
110113 int m_keyboardHeight;
111114 bool m_keyboardVisible;
112− ApplicationListModel* m_mainStageApplications;
113− ApplicationListModel* m_sideStageApplications;
114− ApplicationInfo* m_mainStageFocusedApplication;
115− ApplicationInfo* m_sideStageFocusedApplication;
115+ QList<ApplicationInfo*> m_runningApplications;
116116 QList<ApplicationInfo*> m_availableApplications;
117117 QQmlComponent *m_mainStageComponent;
118118 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 @@
1717#include "plugin.h"
1818#include "ApplicationInfo.h"
1919#include "ApplicationImage.h"
20−#include "ApplicationListModel.h"
2120#include "ApplicationManager.h"
2221
2322#include <qqml.h>
@@ -28,11 +27,13 @@ static QObject* applicationManagerSingleton(QQmlEngine* engine, QJSEngine* scrip
2827 return new ApplicationManager();
2928}
3029
31−void FakeUbuntuApplicationQmlPlugin::registerTypes(const char *uri)
30+void FakeUnityApplicationQmlPlugin::registerTypes(const char *uri)
3231{
33− qmlRegisterSingletonType<ApplicationManager>(
34− uri, 0, 1, "ApplicationManager", applicationManagerSingleton);
32+ qmlRegisterUncreatableType<unity::shell::application::ApplicationManagerInterface>(uri, 0, 1, "ApplicationManagerInterface", "Abstract interface. Cannot be created in QML");
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");
3536 qmlRegisterType<ApplicationInfo>(uri, 0, 1, "ApplicationInfo");
37+
3638 qmlRegisterType<ApplicationImage>(uri, 0, 1, "ApplicationImage");
37− qmlRegisterType<ApplicationListModel>(uri, 0, 1, "ApplicationListModel");
3839}
tests/mocks/Ubuntu/Application/plugin.h → tests/mocks/Unity/Application/plugin.hrenamed+1−1
@@ -19,7 +19,7 @@
1919
2020#include <QQmlExtensionPlugin>
2121
22−class FakeUbuntuApplicationQmlPlugin : public QQmlExtensionPlugin
22+class FakeUnityApplicationQmlPlugin : public QQmlExtensionPlugin
2323{
2424 Q_OBJECT
2525 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+1
@@ -1,3 +1,4 @@
1+add_subdirectory(Application)
12add_subdirectory(Indicators)
23
34pkg_search_module(DEE dee-1.0 REQUIRED)
tests/mocks/Unity/Launcher/CMakeLists.txt+1−1
@@ -1,5 +1,5 @@
11include(FindPkgConfig)
2−pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=2)
2+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=3)
33
44add_definitions(-DTOP_SRCDIR="${CMAKE_SOURCE_DIR}")
55
tests/mocks/Unity/Launcher/MockLauncherModel.cpp+7−4
@@ -71,8 +71,6 @@ QVariant MockLauncherModel::data(const QModelIndex& index, int role) const
7171 LauncherItemInterface *item = m_list.at(index.row());
7272 switch(role)
7373 {
74− case RoleDesktopFile:
75− return item->desktopFile();
7674 case RoleName:
7775 return item->name();
7876 case RoleIcon:
@@ -185,7 +183,12 @@ void MockLauncherModel::setUser(const QString &username)
185183 // TODO: implement this...
186184}
187185
188−void MockLauncherModel::applicationFocused(const QString &appId)
186+void MockLauncherModel::setApplicationManager(unity::shell::application::ApplicationManagerInterface *applicationManager)
189187{
190− Q_UNUSED(appId)
188+ Q_UNUSED(applicationManager)
189+}
190+
191+unity::shell::application::ApplicationManagerInterface *MockLauncherModel::applicationManager() const
192+{
193+ return nullptr;
191194}
tests/mocks/Unity/Launcher/MockLauncherModel.h+3−1
@@ -44,7 +44,9 @@ public:
4444 Q_INVOKABLE void requestRemove(const QString &appId);
4545 Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex);
4646 Q_INVOKABLE void setUser(const QString &username);
47− Q_INVOKABLE void applicationFocused(const QString &appId);
47+
48+ unity::shell::application::ApplicationManagerInterface *applicationManager() const;
49+ void setApplicationManager(unity::shell::application::ApplicationManagerInterface *applicationManager);
4850
4951Q_SIGNALS:
5052 void quickListTriggered(const QString &appId, int index);
tests/plugins/Unity/Launcher/CMakeLists.txt+13−1
@@ -1,5 +1,6 @@
11pkg_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)
34
45include_directories(
56 ${CMAKE_CURRENT_BINARY_DIR}
@@ -45,6 +46,8 @@ add_executable(launchermodeltestExec
4546 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
4647 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
4748 ${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
4851 )
4952target_link_libraries(launchermodeltestExec ${GSETTINGS_QT_LDFLAGS} )
5053qt5_use_modules(launchermodeltestExec Test Core DBus)
@@ -57,3 +60,12 @@ foreach(DESKTOP_FILE ${DESKTOP_FILES})
5760 DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
5861 )
5962endforeach()
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/click-icon.svgnew file

No changes to the content.

tests/plugins/Unity/Launcher/launcherbackendtest.cpp+33
@@ -26,6 +26,15 @@ class LauncherBackendTest : public QObject
2626 Q_OBJECT
2727
2828private Q_SLOTS:
29+
30+ void initTestCase()
31+ {
32+ // As we want to test absolute file paths in the .desktop file, we need to modify the
33+ // sample file and replace the path in there with the current build dir.
34+ QSettings settings(QDir::currentPath() + "/click-icon.desktop", QSettings::IniFormat);
35+ settings.setValue("Desktop Entry/Path", QDir::currentPath());
36+ }
37+
2938 void testFileNames()
3039 {
3140 LauncherBackend backend(false);
@@ -54,6 +63,30 @@ private Q_SLOTS:
5463 QCOMPARE(backend.isPinned("rel-icon"), true);
5564 QCOMPARE(backend.isPinned("no-name"), false); // doesn't exist anymore!
5665 }
66+
67+ void testIcon_data() {
68+ QTest::addColumn<QString>("appId");
69+ QTest::addColumn<QString>("expectedIcon");
70+
71+ // Needs to expand a relative icon to the absolute path
72+ QTest::newRow("relative icon path") << "rel-icon" << QDir::currentPath() + "/rel-icon.svg";
73+
74+ // In case an icon is not found on disk, it needs to fallback on image://theme/ for it
75+ QTest::newRow("fallback on theme") << "abs-icon" << "image://theme//path/to/icon.png";
76+
77+ // Click packages have a relative icon path but an absolute path as a separate entry
78+ QTest::newRow("click package icon") << "click-icon" << QDir::currentPath() + "/click-icon.svg";
79+ }
80+
81+ void testIcon() {
82+ QFETCH(QString, appId);
83+ QFETCH(QString, expectedIcon);
84+
85+ LauncherBackend backend(false);
86+ backend.setStoredApplications(QStringList() << appId);
87+
88+ QCOMPARE(backend.icon(appId), expectedIcon);
89+ }
5790};
5891
5992QTEST_GUILESS_MAIN(LauncherBackendTest)
tests/plugins/Unity/Launcher/launchermodeltest.cpp+148−19
@@ -19,38 +19,116 @@
1919
2020// unity-api
2121#include <unity/shell/launcher/LauncherModelInterface.h>
22+#include <unity/shell/application/ApplicationInfoInterface.h>
2223
2324#include "launcheritem.h"
2425#include "launchermodel.h"
2526
2627#include <QtTest>
2728
29+// This is a mock, specifically to test the LauncherModel
30+class MockApp: public unity::shell::application::ApplicationInfoInterface
31+{
32+ Q_OBJECT
33+public:
34+ MockApp(const QString &appId, QObject *parent = 0): ApplicationInfoInterface(appId, parent), m_appId(appId), m_focused(false) { }
35+ QString appId() const { return m_appId; }
36+ QString name() const { return "mock"; }
37+ QString comment() const { return "this is a mock"; }
38+ QUrl icon() const { return QUrl(); }
39+ ApplicationInfoInterface::Stage stage() const { return ApplicationInfoInterface::MainStage; }
40+ ApplicationInfoInterface::State state() const { return ApplicationInfoInterface::Running; }
41+ bool focused() const { return m_focused; }
42+
43+ // Methods used for mocking (not in the interface)
44+ void setFocused(bool focused) { m_focused = focused; Q_EMIT focusedChanged(focused); }
45+private:
46+ QString m_appId;
47+ bool m_focused;
48+};
49+
50+// This is a mock, specifically to test the LauncherModel
51+class MockAppManager: public unity::shell::application::ApplicationManagerInterface
52+{
53+ Q_OBJECT
54+public:
55+ MockAppManager(QObject *parent = 0): ApplicationManagerInterface(parent) {}
56+ int rowCount(const QModelIndex &) const { return m_list.count(); }
57+ QVariant data(const QModelIndex &, int ) const { return QVariant(); }
58+ QString focusedApplicationId() const {
59+ Q_FOREACH(MockApp *app, m_list) {
60+ if (app->focused()) return app->appId();
61+ }
62+ return QString();
63+ }
64+ unity::shell::application::ApplicationInfoInterface *get(int index) const { return m_list.at(index); }
65+ unity::shell::application::ApplicationInfoInterface *findApplication(const QString &appId) const {
66+ Q_FOREACH(MockApp* app, m_list) {
67+ if (app->appId() == appId) {
68+ return app;
69+ }
70+ }
71+ return nullptr;
72+ }
73+ unity::shell::application::ApplicationInfoInterface *startApplication(const QString &, const QStringList &) { return nullptr; }
74+ bool stopApplication(const QString &) { return false; }
75+ bool focusApplication(const QString &appId) {
76+ Q_FOREACH(MockApp* app, m_list) {
77+ app->setFocused(app->appId() == appId);
78+ }
79+ Q_EMIT focusedApplicationIdChanged();
80+ return true;
81+ }
82+
83+ void unfocusCurrentApplication() { }
84+
85+ void addApplication(MockApp *app) {
86+ beginInsertRows(QModelIndex(), count(), count());
87+ m_list.append(app);
88+ endInsertRows();
89+ }
90+ void removeApplication(int index) {
91+ beginRemoveRows(QModelIndex(), index, index);
92+ m_list.takeAt(index)->deleteLater();
93+ endRemoveRows();
94+ }
95+
96+private:
97+ QList<MockApp*> m_list;
98+};
99+
28100class LauncherModelTest : public QObject
29101{
30102 Q_OBJECT
31103
32104private:
33105 LauncherModel *launcherModel;
106+ MockAppManager *appManager;
34107
35108private Q_SLOTS:
36109
37110 void initTestCase() {
38111 launcherModel = new LauncherModel(this);
39112 QCOMPARE(launcherModel->rowCount(QModelIndex()), 0);
113+
114+ appManager = new MockAppManager(this);
115+ launcherModel->setApplicationManager(appManager);
40116 }
41117
118+ // Adding 2 apps to the mock appmanager. Both should appear in the launcher.
42119 void init() {
43− qDebug() << "init";
44− launcherModel->applicationFocused("abs-icon");
120+ appManager->addApplication(new MockApp("abs-icon"));
45121 QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
46122
47− launcherModel->applicationFocused("no-icon.desktop");
123+ appManager->addApplication(new MockApp("no-icon"));
48124 QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
49−
50− launcherModel->applicationFocused(QString());
51125 }
52126
127+ // Removing apps from appmanager and launcher as pinned ones would stick
53128 void cleanup() {
129+ while (appManager->count() > 0) {
130+ appManager->removeApplication(0);
131+ }
54132 while (launcherModel->rowCount(QModelIndex()) > 0) {
55133 launcherModel->requestRemove(launcherModel->get(0)->appId());
56134 }
@@ -80,9 +158,54 @@ private Q_SLOTS:
80158 QCOMPARE(launcherModel->get(1)->pinned(), false);
81159 }
82160
161+ void testRemove_data() {
162+
163+ QTest::addColumn<bool>("pinned");
164+ QTest::addColumn<bool>("running");
165+
166+ QTest::newRow("non-pinned, running") << false << true;
167+ QTest::newRow("pinned, running") << true << false;
168+ QTest::newRow("pinned, non-running") << true << false;
169+ }
170+
83171 void testRemove() {
172+ QFETCH(bool, pinned);
173+ QFETCH(bool, running);
174+
175+ // In the beginning we always have two items
84176 QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
85− launcherModel->requestRemove(launcherModel->get(0)->appId());
177+
178+ // pin one if required
179+ if (pinned) {
180+ launcherModel->pin(launcherModel->get(1)->appId());
181+ }
182+
183+ // stop it if required
184+ if (!running) {
185+ appManager->removeApplication(1);
186+ }
187+
188+ // Now remove it
189+ launcherModel->requestRemove(launcherModel->get(1)->appId());
190+
191+ if (running) {
192+ // both apps are running, both apps must still be here
193+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
194+
195+ // Item must be unpinned now
196+ QCOMPARE(launcherModel->get(1)->pinned(), false);
197+
198+ } else if (pinned) {
199+ // Item 1 must go away, item 0 is here to stay
200+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
201+ }
202+
203+ // done our checks. now stop the app if was still running
204+ if (running) {
205+ appManager->removeApplication(1);
206+ }
207+
208+ // It needs to go away in any case now
86209 QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
87210 }
88211
@@ -110,6 +233,13 @@ private Q_SLOTS:
110233
111234 // quicklist needs to transform to remove item. trigger it and check it item goes away
112235 launcherModel->quickListActionInvoked(launcherModel->get(0)->appId(), pinActionIndex);
236+ QCOMPARE(launcherModel->get(0)->pinned(), false);
237+
238+ // still needs to be here as the app is still here
239+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
240+ // close the app
241+ appManager->removeApplication(0);
242+ // Now it needs to go away
113243 QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
114244 }
115245
@@ -118,27 +248,26 @@ private Q_SLOTS:
118248 QCOMPARE(launcherModel->get(0)->focused(), false);
119249 QCOMPARE(launcherModel->get(1)->focused(), false);
120250
121− launcherModel->applicationFocused("abs-icon");
251+ appManager->focusApplication("abs-icon");
122252 QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
123253 QCOMPARE(launcherModel->get(0)->focused(), true);
124254 QCOMPARE(launcherModel->get(1)->focused(), false);
125255
126− launcherModel->applicationFocused("no-icon");
256+ appManager->focusApplication("no-icon");
127257 QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
128258 QCOMPARE(launcherModel->get(0)->focused(), false);
129259 QCOMPARE(launcherModel->get(1)->focused(), true);
260+ }
130261
131− launcherModel->applicationFocused("rel-icon");
132− QCOMPARE(launcherModel->rowCount(QModelIndex()), 3);
133− QCOMPARE(launcherModel->get(0)->focused(), false);
134− QCOMPARE(launcherModel->get(1)->focused(), false);
135− QCOMPARE(launcherModel->get(2)->focused(), true);
136−
137− launcherModel->applicationFocused(QString());
138− QCOMPARE(launcherModel->rowCount(QModelIndex()), 3);
139− QCOMPARE(launcherModel->get(0)->focused(), false);
140− QCOMPARE(launcherModel->get(1)->focused(), false);
141− QCOMPARE(launcherModel->get(2)->focused(), false);
262+ void testClosingApps() {
263+ // At the start there are 2 items. Let's pin one.
264+ launcherModel->pin("abs-icon");
265+ while (appManager->count() > 0) {
266+ appManager->removeApplication(0);
267+ }
268+ // The pinned one needs to stay, the other needs to disappear
269+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
270+ QCOMPARE(launcherModel->get(0)->appId(), QLatin1String("abs-icon"));
142271 }
143272};
144273
tests/plugins/Unity/Launcher/rel-icon.desktop+1−1
@@ -1,3 +1,3 @@
11[Desktop Entry]
22Name=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/qmltests/Components/tst_Stage.qml+1−1
@@ -18,7 +18,7 @@ import QtQuick 2.0
1818import QtTest 1.0
1919import ".."
2020import "../../../Components"
21−import Ubuntu.Application 0.1
21+import Unity.Application 0.1
2222import Ubuntu.Components 0.1
2323import Unity.Test 0.1 as UT
2424import "tst_Stage"
tests/qmltests/Dash/Apps/tst_RunningApplicationsGrid.qml+55−37
@@ -16,7 +16,6 @@
1616
1717import QtQuick 2.0
1818import QtTest 1.0
19−import Ubuntu.Application 0.1
2019import "../../../../Dash/Apps"
2120import Unity.Test 0.1 as UT
2221
@@ -29,8 +28,12 @@ Item {
2928
3029 property bool sideStageEnabled: false
3130
32− function stopProcess(application) {
33− fakeRunningAppsModel.remove(application)
31+ function stopApplication(appId) {
32+ for (var i=0, len=fakeRunningAppsModel.count; i<len; i++) {
33+ if (appId == fakeRunningAppsModel.get(i).appId) {
34+ fakeRunningAppsModel.remove(i)
35+ }
36+ }
3437 }
3538 }
3639
@@ -40,47 +43,62 @@ Item {
4043 property bool stageScreenshotsReady: false
4144 property var applicationManager: fakeApplicationManager
4245
43− function activateApplication(desktopFile) {
46+ function activateApplication(appId) {
4447 }
4548 }
4649
47− ApplicationListModel { id: fakeRunningAppsModel }
48−
49− ApplicationInfo {
50− id: phoneApp
51− name: "Phone"
52− icon: "phone-app"
53− exec: "/usr/bin/phone-app"
54− stage: ApplicationInfo.MainStage
55− desktopFile: "phone.desktop"
56− imageQml: "import QtQuick 2.0\n" +
57− "Rectangle { \n" +
58− " anchors.fill:parent \n" +
59− " color:'darkgreen' \n" +
60− " Text { anchors.centerIn: parent; text: 'PHONE' } \n" +
61− "}"
50+ ListModel {
51+ id: fakeRunningAppsModel
52+
53+ function contains(appId) {
54+ for (var i=0, len=fakeRunningAppsModel.count; i<len; i++) {
55+ if (appId == fakeRunningAppsModel.get(i).appId) {
56+ return true;
57+ }
58+ }
59+ return false;
60+ }
61+
62+ function rePopulate() {
63+ for (var i=0, len=availableAppsModel.count; i<len; i++) {
64+ fakeRunningAppsModel.append(availableAppsModel.get(i));
65+ }
66+ }
6267 }
6368
64− ApplicationInfo {
65− id: calendarApp
66− name: "Calendar"
67− icon: "calendar-app"
68− exec: "/usr/bin/calendar-app"
69− stage: ApplicationInfo.MainStage
70− desktopFile: "calendar.desktop"
71− imageQml: "import QtQuick 2.0\n" +
72− "Rectangle { \n" +
73− " anchors.fill:parent \n" +
74− " color:'darkblue' \n" +
75− " Text { anchors.centerIn: parent; text: 'CALENDAR'\n" +
76− " color:'white'} \n" +
77− "}"
69+ ListModel {
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 {
85+ name: "Calendar"
86+ icon: "calendar-app"
87+ exec: "/usr/bin/calendar-app"
88+ appId: "calendar"
89+ imageQml: "import QtQuick 2.0\n \
90+ Rectangle { \n \
91+ anchors.fill:parent \n \
92+ color:'darkblue' \n \
93+ Text { anchors.centerIn: parent; text: 'CALENDAR'\n \
94+ color:'white'} \n \
95+ }"
96+ }
7897 }
7998
8099 function resetRunningApplications() {
81100 fakeRunningAppsModel.clear()
82− fakeRunningAppsModel.add(phoneApp)
83− fakeRunningAppsModel.add(calendarApp)
101+ fakeRunningAppsModel.rePopulate()
84102 }
85103
86104 Component.onCompleted: {
@@ -185,11 +203,11 @@ Item {
185203 var calendarTile = findChild(runningApplicationsGrid, "runningAppTile Calendar")
186204 verify(calendarTile != undefined)
187205
188− verify(fakeRunningAppsModel.contains(calendarApp))
206+ verify(fakeRunningAppsModel.contains("calendar"))
189207
190208 mouseClick(calendarTile, calendarTile.width/2, calendarTile.height/2)
191209
192− verify(!fakeRunningAppsModel.contains(calendarApp))
210+ verify(!fakeRunningAppsModel.contains("calendar"))
193211
194212 // The tile for the Calendar app should eventually vanish since the
195213 // application has been terminated
tests/qmltests/Dash/tst_DashContent.qml+1−1
@@ -106,7 +106,7 @@ Item {
106106 contentEndReachedSpy.clear()
107107 clear_scope_status();
108108
109− // clear, wait for dahs to empty and load scopes.
109+ // clear, wait for dash to empty and load scopes.
110110 var dashContentList = findChild(dashContent, "dashContentList");
111111 verify(dashContentList != undefined)
112112 scopesModel.clear();
tests/qmltests/Dash/tst_GenericScopeView.qml+3
@@ -44,10 +44,13 @@ Item {
4444
4545 function test_isCurrent() {
4646 var pageHeader = findChild(genericScopeView, "pageHeader");
47+ var previewLoader = findChild(genericScopeView, "previewLoader");
4748 genericScopeView.isCurrent = true
4849 pageHeader.searchQuery = "test"
50+ previewLoader.open = true
4951 genericScopeView.isCurrent = false
5052 tryCompare(pageHeader, "searchQuery", "")
53+ tryCompare(genericScopeView, "previewShown", false);
5154 }
5255 }
5356 }
tests/qmltests/Greeter/tst_Phone.qml+19−1
@@ -18,8 +18,8 @@ import QtQuick 2.0
1818import QtTest 1.0
1919import ".."
2020import "../../../Greeter"
21+import AccountsService 0.1
2122import Ubuntu.Components 0.1
22−import LightDM 0.1 as LightDM
2323import Unity.Test 0.1 as UT
2424
2525Item {
@@ -32,6 +32,8 @@ Item {
3232 height: parent.height
3333 x: 0; y: 0
3434
35+ defaultBackground: "../../../graphics/phone_background.jpg"
36+
3537 property int minX: 0
3638
3739 onXChanged: {
@@ -102,5 +104,21 @@ Item {
102104 // Wait until we're back to 0
103105 tryCompareFunction(function() { return greeter.x;}, 0);
104106 }
107+
108+ function test_wallpaper_data() {
109+ return [
110+ {tag: "set", accounts: "../tests/data/unity/backgrounds/blue.png", expected: "blue.png"},
111+ {tag: "unset", accounts: "", expected: "background.jpg"},
112+ {tag: "invalid", accounts: "invalid", expected: "background.jpg"},
113+ ]
114+ }
115+
116+ function test_wallpaper(data) {
117+ var loader = findChild(greeter, "greeterContentLoader")
118+ var wallpaper = findChild(loader.item, "wallpaper")
119+ AccountsService.backgroundFile = data.accounts
120+ tryCompareFunction(function() { return wallpaper.source.toString().indexOf(data.expected) !== -1; }, true)
121+ tryCompare(wallpaper, "status", Image.Ready)
122+ }
105123 }
106124}
tests/qmltests/Launcher/tst_Launcher.qml+2−2
@@ -38,7 +38,7 @@ Item {
3838 property string lastSelectedApplication
3939
4040 onLauncherApplicationSelected: {
41− lastSelectedApplication = desktopFile
41+ lastSelectedApplication = appId
4242 }
4343
4444 property int dashItemSelected_count: 0
@@ -131,7 +131,7 @@ Item {
131131 mouseClick(appIcon, appIcon.width/2, appIcon.height/2)
132132
133133 tryCompare(launcher, "lastSelectedApplication",
134− "/usr/share/applications/phone-app.desktop")
134+ "phone-app")
135135
136136 // Tapping on an application icon also dismisses the launcher
137137 revealer.waitUntilLauncherDisappears()
tests/qmltests/tst_Shell.qml+33−9
@@ -20,7 +20,7 @@
2020import QtQuick 2.0
2121import QtTest 1.0
2222import GSettings 1.0
23−import Ubuntu.Application 0.1
23+import Unity.Application 0.1
2424import Unity.Test 0.1 as UT
2525import Powerd 0.1
2626
@@ -66,16 +66,16 @@ Item {
6666 }
6767
6868 // kill all (fake) running apps
69− killApps(ApplicationManager.mainStageApplications);
70− killApps(ApplicationManager.sideStageApplications);
69+ killApps(ApplicationManager);
7170
7271 var dashHome = findChild(shell, "DashHome");
7372 swipeUntilScopeViewIsReached(dashHome);
7473 }
7574
7675 function killApps(apps) {
76+ if (!apps) return;
7777 while (apps.count > 0) {
78− ApplicationManager.stopProcess(apps.get(0));
78+ ApplicationManager.stopApplication(apps.get(0).appId);
7979 }
8080 }
8181
@@ -114,6 +114,26 @@ Item {
114114 checkRightEdgeDragWithNoRunningApps();
115115 }
116116
117+ function test_leftEdgeDrag_data() {
118+ return [
119+ {tag: "without launcher", revealLauncher: false},
120+ {tag: "with launcher", revealLauncher: true},
121+ ];
122+ }
123+
124+ function test_leftEdgeDrag(data) {
125+ dragLauncherIntoView();
126+ tapOnAppIconInLauncher();
127+ waitUntilApplicationWindowIsFullyVisible();
128+
129+ if (data.revealLauncher) {
130+ dragLauncherIntoView();
131+ }
132+
133+ swipeFromLeftEdge();
134+ waitUntilApplicationWindowIsFullyHidden();
135+ }
136+
117137 function test_suspend() {
118138 var greeter = findChild(shell, "greeter");
119139
@@ -122,8 +142,8 @@ Item {
122142 tapOnAppIconInLauncher();
123143 waitUntilApplicationWindowIsFullyVisible();
124144
125− var mainApp = ApplicationManager.mainStageFocusedApplication;
126− tryCompareFunction(function() { return mainApp != null; }, true);
145+ var mainApp = ApplicationManager.focusedApplicationId;
146+ tryCompareFunction(function() { return mainApp != ""; }, true);
127147
128148 // Try to suspend while proximity is engaged...
129149 Powerd.displayPowerStateChange(Powerd.Off, Powerd.UseProximity);
@@ -132,11 +152,11 @@ Item {
132152 // Now really suspend
133153 Powerd.displayPowerStateChange(Powerd.Off, 0);
134154 tryCompare(greeter, "showProgress", 1);
135− tryCompare(ApplicationManager, "mainStageFocusedApplication", null);
155+ tryCompare(ApplicationManager, "focusedApplicationId", "");
136156
137157 // And wake up
138158 Powerd.displayPowerStateChange(Powerd.On, 0);
139− tryCompare(ApplicationManager, "mainStageFocusedApplication", mainApp);
159+ tryCompare(ApplicationManager, "focusedApplicationId", mainApp);
140160 tryCompare(greeter, "showProgress", 1);
141161 }
142162
@@ -223,7 +243,11 @@ Item {
223243 function dragLauncherIntoView() {
224244 var launcherPanel = findChild(shell, "launcherPanel");
225245 verify(launcherPanel.x = - launcherPanel.width);
226− swipeFromLeftEdge();
246+
247+ var touchStartX = 2;
248+ var touchStartY = shell.height / 2;
249+ touchFlick(shell, touchStartX, touchStartY, launcherPanel.width + units.gu(1), touchStartY);
250+
227251 tryCompare(launcherPanel, "x", 0);
228252 }
229253
tests/uqmlscene/main.cpp−2
@@ -497,8 +497,6 @@ int main(int argc, char ** argv)
497497 }
498498
499499 if (window) {
500− mouseTouchAdaptor.setTargetWindow(window);
501−
502500 QSurfaceFormat surfaceFormat = window->requestedFormat();
503501 if (options.multisample)
504502 surfaceFormat.setSamples(16);