on xenial help sign in
merge prereqs
commit7e4b5ed5e62241238de3209ecf7def734e491e7f authorMichael Zanetti <michael.zanetti@canonical.com> dateThu 7 May 2015, 13:27 (11 years ago) parentf2a23930dd13b0
9 files changed+228−120
qml/Stages/DesktopStage.qml+13−10 qml/Stages/PhoneStage.qml+4−4 qml/Stages/TabletStage.qml+10−11 tests/mocks/Utils/HomeKeyWatcher.qml+21 tests/mocks/Utils/plugin.cpp+15−2 tests/mocks/Utils/plugin.h+1−1 tests/mocks/Utils/qmldir+1 tests/qmltests/Stages/tst_DesktopStage.qml+29−8 tests/qmltests/tst_Shell.qml+134−84
qml/Stages/DesktopStage.qml+13−10
@@ -24,13 +24,12 @@ import "../Components/PanelState"
2424import Utils 0.1
2525import Ubuntu.Gestures 0.1
2626
27−FocusScope {
27+Rectangle {
2828 id: root
2929
3030 anchors.fill: parent
3131
3232 property alias background: wallpaper.source
33− property var windowStateStorage: WindowStateStorage
3433 property bool altTabPressed: false
3534
3635 onAltTabPressedChanged: {
@@ -96,7 +95,16 @@ FocusScope {
9695 id: priv
9796
9897 readonly property string focusedAppId: ApplicationManager.focusedApplicationId
99− readonly property var focusedAppDelegate: focusedAppId ? appRepeater.itemAt(indexOf(focusedAppId)) : null
98+ readonly property var focusedAppDelegate: {
99+ var index = indexOf(focusedAppId);
100+ return index >= 0 && index < appRepeater.count ? appRepeater.itemAt(index) : null
101+ }
102+
103+ onFocusedAppDelegateChanged: {
104+ if (focusedAppDelegate) {
105+ focusedAppDelegate.focus = true;
106+ }
107+ }
100108
101109 function indexOf(appId) {
102110 for (var i = 0; i < ApplicationManager.count; i++) {
@@ -221,7 +229,7 @@ FocusScope {
221229 resizeHandleWidth: units.gu(0.5)
222230 windowId: model.appId // FIXME: Change this to point to windowId once we have such a thing
223231
224− onPressed: decoratedWindow.focus = true;
232+ onPressed: appDelegate.focus = true;
225233 }
226234
227235 DecoratedWindow {
@@ -232,12 +240,7 @@ FocusScope {
232240 windowHeight: appDelegate.height
233241 application: ApplicationManager.get(index)
234242 active: ApplicationManager.focusedApplicationId === model.appId
235−
236− onFocusChanged: {
237− if (focus) {
238− ApplicationManager.focusApplication(model.appId);
239− }
240− }
243+ focus: false
241244
242245 onClose: ApplicationManager.stopApplication(model.appId)
243246 onMaximize: appDelegate.state = (appDelegate.state == "maximized" ? "normal" : "maximized")
qml/Stages/PhoneStage.qml+4−4
@@ -117,14 +117,14 @@ Rectangle {
117117
118118 readonly property int firstSpreadIndex: root.focusFirstApp ? 1 : 0
119119 property string focusedAppId: applicationManager.focusedApplicationId
120− property var focusedApplication: applicationManager.findApplication(focusedAppId)
121− property var focusedAppDelegate: null
120+ readonly property var focusedAppDelegate: {
121+ var index = indexOf(focusedAppId);
122+ return index >= 0 && index < spreadRepeater.count ? spreadRepeater.itemAt(index) : null
123+ }
122124
123125 property real oldInverseProgress: 0
124126 property bool animateX: false
125127
126− onFocusedAppIdChanged: focusedAppDelegate = spreadRepeater.itemAt(0);
127−
128128 onFocusedAppDelegateChanged: {
129129 if (focusedAppDelegate) {
130130 focusedAppDelegate.focus = true;
qml/Stages/TabletStage.qml+10−11
@@ -53,6 +53,11 @@ Rectangle {
5353 id: priv
5454
5555 property string focusedAppId: ApplicationManager.focusedApplicationId
56+ readonly property var focusedAppDelegate: {
57+ var index = indexOf(focusedAppId);
58+ return index >= 0 && index < spreadRepeater.count ? spreadRepeater.itemAt(index) : null
59+ }
60+
5661 property string oldFocusedAppId: ""
5762
5863 property string mainStageAppId
@@ -76,19 +81,11 @@ Rectangle {
7681
7782 appId0 = ApplicationManager.count >= 1 ? ApplicationManager.get(0).appId : "";
7883 appId1 = ApplicationManager.count > 1 ? ApplicationManager.get(1).appId : "";
79−
80− // Update the QML focus accordingly
81− updateSpreadDelegateFocus();
8284 }
8385
84− function updateSpreadDelegateFocus() {
85− if (priv.focusedAppId) {
86− var focusedAppIndex = priv.indexOf(priv.focusedAppId);
87− if (focusedAppIndex !== -1) {
88− spreadRepeater.itemAt(focusedAppIndex).focus = true;
89− } else {
90− console.warn("TabletStage: Failed to find the SpreadDelegate for appID=" + priv.focusedAppId);
91− }
86+ onFocusedAppDelegateChanged: {
87+ if (focusedAppDelegate) {
88+ focusedAppDelegate.focus = true;
9289 }
9390 }
9491
@@ -495,6 +492,8 @@ Rectangle {
495492
496493 delegate: TransformedTabletSpreadDelegate {
497494 id: spreadTile
495+ objectName: model.appId ? "tabletSpreadDelegate_" + model.appId
496+ : "tabletSpreadDelegate_null";
498497 height: spreadView.height
499498 width: model.stage == ApplicationInfoInterface.MainStage ? spreadView.width : spreadView.sideStageWidth
500499 active: model.appId == priv.mainStageAppId || model.appId == priv.sideStageAppId
tests/mocks/Utils/HomeKeyWatcher.qmlnew file+21
@@ -0,0 +1,21 @@
1+/*
2+ * Copyright (C) 2015 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+QtObject {
20+ signal activated()
21+}
tests/mocks/Utils/plugin.cpp+15−2
@@ -1,5 +1,9 @@
11/*
2+<<<<<<< TREE
23 * Copyright (C) 2012 Canonical, Ltd.
4+=======
5+ * Copyright (C) 2015 Canonical, Ltd.
6+>>>>>>> MERGE-SOURCE
37 *
48 * This program is free software; you can redistribute it and/or modify
59 * it under the terms of the GNU General Public License as published by
@@ -20,10 +24,9 @@
2024#include <QQmlContext>
2125#include <QtQuick/QQuickWindow>
2226#include <QDebug>
23−// self
24−#include "plugin.h"
2527
2628// local
29+#include "plugin.h"
2730#include "inputwatcher.h"
2831#include "qlimitproxymodelqml.h"
2932#include "unitysortfilterproxymodelqml.h"
@@ -36,6 +39,16 @@
3639#include "spreadflickable.h"
3740#include "constants.h"
3841
42+// plugin
43+#include <inputwatcher.h>
44+#include <qlimitproxymodelqml.h>
45+#include <unitysortfilterproxymodelqml.h>
46+#include <relativetimeformatter.h>
47+#include <timeformatter.h>
48+#include <unitymenumodelpaths.h>
49+#include <windowkeysfilter.h>
50+#include <easingcurve.h>
51+
3952static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
4053{
4154 Q_UNUSED(engine)
tests/mocks/Utils/plugin.h+1−1
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2012 Canonical, Ltd.
2+ * Copyright (C) 2015 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
tests/mocks/Utils/qmldir+1
@@ -2,3 +2,4 @@ module Utils
22plugin FakeUtils-qml
33typeinfo Utils.qmltypes
44Style 0.1 Style.js
5+HomeKeyWatcher 0.1 HomeKeyWatcher.qml
tests/qmltests/Stages/tst_DesktopStage.qml+29−8
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2013,2014 Canonical, Ltd.
2+ * Copyright (C) 2015 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -95,9 +95,6 @@ Rectangle {
9595
9696 property Item desktopStage: desktopStageLoader.status === Loader.Ready ? desktopStageLoader.item : null
9797
98− function init() {
99− }
100−
10198 function cleanup() {
10299 desktopStageLoader.itemDestroyed = false;
103100 desktopStageLoader.active = false;
@@ -163,14 +160,38 @@ Rectangle {
163160 tryCompare(ApplicationManager.findApplication(data.apps[data.focusTo]).session.surface, "activeFocus", true);
164161 }
165162
166− function test_decorationPressFocusesApplication_data() {
163+ function test_tappingOnWindowChangesFocusedApp_data() {
164+ return [
165+ {tag: "dash", apps: [ "unity8-dash", "dialer-app", "camera-app" ], focusfrom: 0, focusTo: 1 },
166+ {tag: "dash", apps: [ "unity8-dash", "dialer-app", "camera-app" ], focusfrom: 1, focusTo: 0 },
167+ ]
168+ }
169+
170+ function test_tappingOnWindowChangesFocusedApp(data) {
171+ var i;
172+ for (i = 0; i < data.apps.length; i++) {
173+ startApplication(data.apps[i]);
174+ }
175+
176+ var fromAppWindow = findChild(desktopStage, "appWindow_" + data.apps[data.focusfrom]);
177+ verify(fromAppWindow);
178+ tap(fromAppWindow);
179+ compare(fromAppWindow.application.session.surface.activeFocus, true);
180+
181+ var toAppWindow = findChild(desktopStage, "appWindow_" + data.apps[data.focusTo]);
182+ verify(toAppWindow);
183+ tap(toAppWindow);
184+ compare(toAppWindow.application.session.surface.activeFocus, true);
185+ }
186+
187+ function test_tappingOnDecorationFocusesApplication_data() {
167188 return [
168189 {tag: "dash", apps: [ "unity8-dash", "dialer-app", "camera-app" ], focusfrom: 0, focusTo: 1 },
169190 {tag: "dash", apps: [ "unity8-dash", "dialer-app", "camera-app" ], focusfrom: 1, focusTo: 0 },
170191 ]
171192 }
172193
173− function test_decorationPressFocusesApplication(data) {
194+ function test_tappingOnDecorationFocusesApplication(data) {
174195 var i;
175196 for (i = 0; i < data.apps.length; i++) {
176197 startApplication(data.apps[i]);
@@ -178,12 +199,12 @@ Rectangle {
178199
179200 var fromAppDecoration = findChild(desktopStage, "appWindowDecoration_" + data.apps[data.focusfrom]);
180201 verify(fromAppDecoration);
181− mouseClick(fromAppDecoration);
202+ tap(fromAppDecoration);
182203 tryCompare(ApplicationManager.findApplication(data.apps[data.focusfrom]).session.surface, "activeFocus", true);
183204
184205 var toAppDecoration = findChild(desktopStage, "appWindowDecoration_" + data.apps[data.focusTo]);
185206 verify(toAppDecoration);
186− mouseClick(toAppDecoration);
207+ tap(toAppDecoration);
187208 tryCompare(ApplicationManager.findApplication(data.apps[data.focusTo]).session.surface, "activeFocus", true);
188209 }
189210 }
tests/qmltests/tst_Shell.qml+134−84
@@ -138,92 +138,105 @@ Rectangle {
138138 }
139139 }
140140
141− Rectangle {
141+ Flickable {
142142 id: controls
143− color: "darkgrey"
144− width: units.gu(30)
143+ contentHeight: controlRect.height
144+
145145 anchors.top: root.top
146146 anchors.bottom: root.bottom
147147 anchors.right: root.right
148+ width: units.gu(30)
148149
149− Column {
150− anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
151− spacing: units.gu(1)
152− Row {
153− Button {
154− text: "Show Greeter"
155− activeFocusOnPress: false
156− onClicked: {
157− if (shellLoader.status !== Loader.Ready)
158− return;
150+ Rectangle {
151+ id: controlRect
152+ anchors { left: parent.left; right: parent.right }
153+ color: "darkgrey"
154+ height: childrenRect.height + units.gu(2)
159155
160− var greeter = testCase.findChild(shellLoader.item, "greeter");
161− if (!greeter.shown) {
162− LightDM.Greeter.showGreeter();
156+ Column {
157+ anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
158+ spacing: units.gu(1)
159+
160+ Row {
161+ spacing: units.gu(1)
162+ Button {
163+ text: "Show Greeter"
164+ activeFocusOnPress: false
165+ onClicked: {
166+ if (shellLoader.status !== Loader.Ready)
167+ return;
168+
169+ var greeter = testCase.findChild(shellLoader.item, "greeter");
170+ if (!greeter.shown) {
171+ LightDM.Greeter.showGreeter();
172+ }
173+ }
174+ }
175+ Button {
176+ text: "Hide Greeter"
177+ activeFocusOnPress: false
178+ onClicked: {
179+ if (shellLoader.status !== Loader.Ready)
180+ return;
181+
182+ var greeter = testCase.findChild(shellLoader.item, "greeter");
183+ if (greeter.shown) {
184+ greeter.hide()
185+ }
163186 }
164187 }
165188 }
166− Button {
167− text: "Hide Greeter"
189+ ListItem.ItemSelector {
190+ anchors { left: parent.left; right: parent.right }
168191 activeFocusOnPress: false
169− onClicked: {
170− if (shellLoader.status !== Loader.Ready)
171− return;
172−
173− var greeter = testCase.findChild(shellLoader.item, "greeter");
174− if (greeter.shown) {
175− greeter.hide()
176− }
192+ text: "LightDM mock mode"
193+ model: ["single", "single-passphrase", "single-pin", "full"]
194+ onSelectedIndexChanged: {
195+ shellLoader.active = false;
196+ LightDM.Greeter.mockMode = model[selectedIndex];
197+ LightDM.Users.mockMode = model[selectedIndex];
198+ shellLoader.active = true;
177199 }
178200 }
179− }
180− ListItem.ItemSelector {
181− anchors { left: parent.left; right: parent.right }
182− activeFocusOnPress: false
183− text: "LightDM mock mode"
184− model: ["single", "single-passphrase", "single-pin", "full"]
185− onSelectedIndexChanged: {
186− shellLoader.active = false;
187− LightDM.Greeter.mockMode = model[selectedIndex];
188− LightDM.Users.mockMode = model[selectedIndex];
189− shellLoader.active = true;
201+ ListItem.ItemSelector {
202+ anchors { left: parent.left; right: parent.right }
203+ activeFocusOnPress: false
204+ text: "Size"
205+ model: ["phone", "tablet", "desktop"]
206+ onSelectedIndexChanged: {
207+ shellLoader.active = false;
208+ shellLoader.state = model[selectedIndex];
209+ shellLoader.active = true;
210+ }
190211 }
191− }
192− ListItem.ItemSelector {
193− anchors { left: parent.left; right: parent.right }
194− activeFocusOnPress: false
195− text: "Size"
196− model: ["phone", "tablet", "desktop"]
197− onSelectedIndexChanged: {
198− shellLoader.active = false;
199− shellLoader.state = model[selectedIndex];
200− shellLoader.active = true;
212+ ListItem.ItemSelector {
213+ id: usageModeSelector
214+ anchors { left: parent.left; right: parent.right }
215+ activeFocusOnPress: false
216+ text: "Usage mode"
217+ model: ["Staged", "Windowed"]
218+ onSelectedIndexChanged: {
219+ GSettingsController.setUsageMode(model[selectedIndex]);
220+ }
201221 }
202− }
203− MouseTouchEmulationCheckbox {
204− id: mouseEmulation
205− checked: true
206− color: "white"
207− }
222+ MouseTouchEmulationCheckbox {
223+ id: mouseEmulation
224+ checked: true
225+ color: "white"
226+ }
227+
228+ Label { text: "Applications"; font.bold: true }
208229
209− Button {
210− anchors { left: parent.left; right: parent.right }
211− text: "Start all apps"
212− onClicked: {
213− for (var i = 0; i < appRepeater.count; i++) {
214− var appId = ApplicationManager.availableApplications[i]
215− if (!ApplicationManager.findApplication(appId)) {
230+ Button {
231+ text: "Start all apps"
232+ width: parent.width
233+ onClicked: {
234+ for (var i = 0; i < ApplicationManager.availableApplications.length; i++) {
235+ var appId = ApplicationManager.availableApplications[i];
216236 ApplicationManager.startApplication(appId)
217237 }
218238 }
219239 }
220− }
221−
222− Column {
223− anchors { left: parent.left; right: parent.right }
224− spacing: units.gu(1)
225−
226− Label { text: "Applications"; font.bold: true }
227240
228241 Repeater {
229242 id: appRepeater
@@ -313,6 +326,7 @@ Rectangle {
313326 mouseEmulation.checked = true;
314327 tryCompare(shell, "enabled", true); // make sure greeter didn't leave us in disabled state
315328 tearDown();
329+ GSettingsController.setUsageMode("Staged");
316330 }
317331
318332 function loadShell(formFactor) {
@@ -759,23 +773,57 @@ Rectangle {
759773
760774 function test_launchedAppHasActiveFocus_data() {
761775 return [
762− {tag: "phone", formFactor: "phone"},
763− {tag: "tablet", formFactor: "tablet"},
764− {tag: "desktop", formFactor: "desktop"}
765− ];
776+ {tag: "phone", formFactor: "phone", usageMode: "Staged"},
777+ {tag: "tablet", formFactor: "tablet", usageMode: "Staged"},
778+ {tag: "desktop", formFactor: "tablet", usageMode: "Windowed"}
779+ ]
766780 }
767781
768782 function test_launchedAppHasActiveFocus(data) {
783+ GSettingsController.setUsageMode(data.usageMode);
769784 loadShell(data.formFactor);
770785 swipeAwayGreeter();
771786
772− var dialerApp = ApplicationManager.startApplication("webbrowser-app");
773− verify(dialerApp);
787+ var webApp = ApplicationManager.startApplication("webbrowser-app");
788+ verify(webApp);
789+ waitUntilAppSurfaceShowsUp("webbrowser-app")
790+
791+ verify(webApp.session.surface);
792+
793+ tryCompare(webApp.session.surface, "activeFocus", true);
794+ }
795+
796+ function test_launchedAppKeepsActiveFocusOnUsageModeChange() {
797+ loadShell("tablet");
798+ swipeAwayGreeter();
799+
800+ var webApp = ApplicationManager.startApplication("webbrowser-app");
801+ verify(webApp);
774802 waitUntilAppSurfaceShowsUp("webbrowser-app")
775803
776− verify(dialerApp.session.surface);
804+ verify(webApp.session.surface);
805+
806+ tryCompare(webApp.session.surface, "activeFocus", true);
807+
808+ GSettingsController.setUsageMode("Windowed");
809+
810+ // check that the desktop stage and window have been loaded
811+ {
812+ var desktopWindow = findChild(shell, "decoratedWindow_webbrowser-app");
813+ verify(desktopWindow);
814+ }
815+
816+ tryCompare(webApp.session.surface, "activeFocus", true);
777817
778− tryCompare(dialerApp.session.surface, "activeFocus", true);
818+ GSettingsController.setUsageMode("Staged");
819+
820+ // check that the tablet stage and app surface delegate have been loaded
821+ {
822+ var desktopWindow = findChild(shell, "tabletSpreadDelegate_webbrowser-app");
823+ verify(desktopWindow);
824+ }
825+
826+ tryCompare(webApp.session.surface, "activeFocus", true);
779827 }
780828
781829 function waitUntilAppSurfaceShowsUp(appId) {
@@ -1261,31 +1309,33 @@ Rectangle {
12611309
12621310 function test_stageLoader_data() {
12631311 return [
1264− {tag: "phone", source: "Stages/PhoneStage.qml"},
1265− {tag: "tablet", source: "Stages/TabletStage.qml"},
1266− {tag: "desktop", source: "Stages/DesktopStage.qml"}
1312+ {tag: "phone", source: "Stages/PhoneStage.qml", formFactor: "phone", usageMode: "Staged"},
1313+ {tag: "tablet", source: "Stages/TabletStage.qml", formFactor: "tablet", usageMode: "Staged"},
1314+ {tag: "desktop", source: "Stages/DesktopStage.qml", formFactor: "tablet", usageMode: "Windowed"}
12671315 ]
12681316 }
12691317
12701318 function test_stageLoader(data) {
1271− loadShell(data.tag);
1319+ GSettingsController.setUsageMode(data.usageMode);
1320+ loadShell(data.formFactor);
12721321 var stageLoader = findChild(shell, "applicationsDisplayLoader");
12731322 verify(String(stageLoader.source).indexOf(data.source) >= 0);
12741323 }
12751324
12761325 function test_launcherInverted_data() {
12771326 return [
1278− {tag: "phone", formFactor: "phone"},
1279− {tag: "tablet", formFactor: "tablet"},
1280− {tag: "desktop", formFactor: "desktop"}
1281− ];
1327+ {tag: "phone", formFactor: "phone", usageMode: "Staged", launcherInverted: true},
1328+ {tag: "tablet", formFactor: "tablet", usageMode: "Staged", launcherInverted: true},
1329+ {tag: "desktop", formFactor: "tablet", usageMode: "Windowed", launcherInverted: false}
1330+ ]
12821331 }
12831332
12841333 function test_launcherInverted(data) {
1334+ GSettingsController.setUsageMode(data.usageMode);
12851335 loadShell(data.formFactor);
12861336
12871337 var launcher = findChild(shell, "launcher");
1288− compare(launcher.inverted, data.formFactor !== "desktop");
1338+ compare(launcher.inverted, data.launcherInverted);
12891339 }
12901340 }
12911341}