on xenial help sign in
Refactor Dialogs.qml to use proper in-scene dialogs

Proper in-scene dialogs keep its Loader as parent and therefore carry on all its transformations, following its rotation, etc. It needs Dialog from ubuntu-ui-toolkit to comply with the reparentToRootItem property.

commita4ee85b0b0763067ee34873d49ced8a15554a05c authorDaniel d'Andrada <daniel.dandrada@canonical.com> dateMon 8 Dec 2014, 11:39 (12 years ago) parent07607c6
4 files changed+203−67
qml/Components/Dialogs.qml+61−67 qml/Components/ShellDialog.qml+37 tests/qmltests/CMakeLists.txt+1 tests/qmltests/Components/tst_Dialogs.qml+104
qml/Components/Dialogs.qml+61−67
@@ -19,11 +19,22 @@ import QtQuick 2.0
1919import Unity.Application 0.1
2020import Unity.Session 0.1
2121import Ubuntu.Components 1.1
22−import Ubuntu.Components.Popups 0.1
2322
2423Item {
2524 id: root
2625
26+ // to be set from outside, useful mostly for testing purposes
27+ property var unitySessionService: DBusUnitySessionService
28+ property var closeAllApps: function() {
29+ while (true) {
30+ var app = ApplicationManager.get(0);
31+ if (app === null) {
32+ break;
33+ }
34+ ApplicationManager.stopApplication(app.appId);
35+ }
36+ }
37+
2738 function onPowerKeyPressed() {
2839 // FIXME: event.isAutoRepeat is always false on Nexus 4.
2940 // So we use powerKeyTimer.running to avoid the PowerOff key repeat
@@ -41,16 +52,21 @@ Item {
4152
4253 QtObject {
4354 id: d // private stuff
55+ objectName: "dialogsPrivate"
4456
45− property bool dialogShown: false
4657
4758 function showPowerDialog() {
48− if (!d.dialogShown) {
49− d.dialogShown = true;
50− PopupUtils.open(powerDialog, root, {"z": root.z});
59+ if (!dialogLoader.active) {
60+ dialogLoader.sourceComponent = powerDialogComponent;
61+ dialogLoader.active = true;
5162 }
5263 }
5364 }
65+ Loader {
66+ id: dialogLoader
67+ anchors.fill: parent
68+ active: false
69+ }
5470
5571 Timer {
5672 id: powerKeyTimer
@@ -64,91 +80,84 @@ Item {
6480 }
6581
6682 Component {
67− id: logoutDialog
68− Dialog {
69− id: dialogueLogout
83+ id: logoutDialogComponent
84+ ShellDialog {
85+ id: logoutDialog
7086 title: i18n.tr("Log out")
7187 text: i18n.tr("Are you sure you want to log out?")
7288 Button {
7389 text: i18n.tr("No")
7490 onClicked: {
75− PopupUtils.close(dialogueLogout);
76− d.dialogShown = false;
91+ logoutDialog.hide();
7792 }
7893 }
7994 Button {
8095 text: i18n.tr("Yes")
8196 onClicked: {
82− DBusUnitySessionService.Logout();
83− PopupUtils.close(dialogueLogout);
84− d.dialogShown = false;
97+ unitySessionService.logout();
98+ logoutDialog.hide();
8599 }
86100 }
87101 }
88102 }
89103
90104 Component {
91− id: shutdownDialog
92− Dialog {
93− id: dialogueShutdown
105+ id: shutdownDialogComponent
106+ ShellDialog {
107+ id: shutdownDialog
94108 title: i18n.tr("Shut down")
95109 text: i18n.tr("Are you sure you want to shut down?")
96110 Button {
97111 text: i18n.tr("No")
98112 onClicked: {
99− PopupUtils.close(dialogueShutdown);
100− d.dialogShown = false;
113+ shutdownDialog.hide();
101114 }
102115 }
103116 Button {
104117 text: i18n.tr("Yes")
105118 onClicked: {
106− dBusUnitySessionServiceConnection.closeAllApps();
107− DBusUnitySessionService.Shutdown();
108− PopupUtils.close(dialogueShutdown);
109− d.dialogShown = false;
119+ root.closeAllApps();
120+ unitySessionService.shutdown();
121+ shutdownDialog.hide();
110122 }
111123 }
112124 }
113125 }
114126
115127 Component {
116− id: rebootDialog
117− Dialog {
118− id: dialogueReboot
128+ id: rebootDialogComponent
129+ ShellDialog {
130+ id: rebootDialog
119131 title: i18n.tr("Reboot")
120132 text: i18n.tr("Are you sure you want to reboot?")
121133 Button {
122134 text: i18n.tr("No")
123135 onClicked: {
124− PopupUtils.close(dialogueReboot)
125− d.dialogShown = false;
136+ rebootDialog.hide();
126137 }
127138 }
128139 Button {
129140 text: i18n.tr("Yes")
130141 onClicked: {
131− dBusUnitySessionServiceConnection.closeAllApps();
132− DBusUnitySessionService.Reboot();
133− PopupUtils.close(dialogueReboot);
134− d.dialogShown = false;
142+ root.closeAllApps();
143+ unitySessionService.reboot();
144+ rebootDialog.hide();
135145 }
136146 }
137147 }
138148 }
139149
140150 Component {
141− id: powerDialog
142− Dialog {
143− id: dialoguePower
151+ id: powerDialogComponent
152+ ShellDialog {
153+ id: powerDialog
144154 title: i18n.tr("Power")
145155 text: i18n.tr("Are you sure you would like\nto power off?")
146156 Button {
147157 text: i18n.tr("Power off")
148158 onClicked: {
149− dBusUnitySessionServiceConnection.closeAllApps();
150− PopupUtils.close(dialoguePower);
151− d.dialogShown = false;
159+ root.closeAllApps();
160+ powerDialog.hide();
152161 root.powerOffClicked();
153162 }
154163 color: UbuntuColors.red
@@ -156,66 +165,51 @@ Item {
156165 Button {
157166 text: i18n.tr("Restart")
158167 onClicked: {
159− dBusUnitySessionServiceConnection.closeAllApps();
160− DBusUnitySessionService.Reboot();
161− PopupUtils.close(dialoguePower);
162− d.dialogShown = false;
168+ root.closeAllApps();
169+ unitySessionService.reboot();
170+ powerDialog.hide();
163171 }
164172 color: UbuntuColors.green
165173 }
166174 Button {
167175 text: i18n.tr("Cancel")
168176 onClicked: {
169− PopupUtils.close(dialoguePower);
170− d.dialogShown = false;
177+ powerDialog.hide();
171178 }
172179 color: UbuntuColors.coolGrey
173180 }
174181 }
175182 }
176183
177−
178184 Connections {
179− id: dBusUnitySessionServiceConnection
180− objectName: "dBusUnitySessionServiceConnection"
181− target: DBusUnitySessionService
182−
183− function closeAllApps() {
184− while (true) {
185− var app = ApplicationManager.get(0);
186− if (app === null) {
187− break;
188− }
189− ApplicationManager.stopApplication(app.appId);
190− }
191− }
185+ target: root.unitySessionService
192186
193187 onLogoutRequested: {
194188 // Display a dialog to ask the user to confirm.
195− if (!d.dialogShown) {
196− d.dialogShown = true;
197− PopupUtils.open(logoutDialog, root, {"z": root.z});
189+ if (!dialogLoader.active) {
190+ dialogLoader.sourceComponent = logoutDialogComponent;
191+ dialogLoader.active = true;
198192 }
199193 }
200194
201195 onShutdownRequested: {
202196 // Display a dialog to ask the user to confirm.
203− if (!d.dialogShown) {
204− d.dialogShown = true;
205− PopupUtils.open(shutdownDialog, root, {"z": root.z});
197+ if (!dialogLoader.active) {
198+ dialogLoader.sourceComponent = shutdownDialogComponent;
199+ dialogLoader.active = true;
206200 }
207201 }
208202
209203 onRebootRequested: {
210204 // Display a dialog to ask the user to confirm.
211− if (!d.dialogShown) {
212− d.dialogShown = true;
213− PopupUtils.open(rebootDialog, root, {"z": root.z});
205+ if (!dialogLoader.active) {
206+ dialogLoader.sourceComponent = rebootDialogComponent;
207+ dialogLoader.active = true;
214208 }
215209 }
216210
217211 onLogoutReady: {
218− closeAllApps();
212+ root.closeAllApps();
219213 Qt.quit();
220214 }
221215 }
qml/Components/ShellDialog.qmlnew file+37
@@ -0,0 +1,37 @@
1+/*
2+ * Copyright (C) 2014 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+import Ubuntu.Components 1.1
20+import Ubuntu.Components.Popups 0.1
21+
22+/*
23+ A Dialog configured for use as a proper in-scene Dialog
24+
25+ This is a helper component for Dialogs.qml, thus some assumptions
26+ on context are (or will be) made here.
27+ */
28+Dialog {
29+ automaticOrientation: false
30+
31+ // NB: PopupBase, Dialog's superclass, will check for the existence of this property
32+ property bool reparentToRootItem: false
33+
34+ onVisibleChanged: { if (!visible) { dialogLoader.active = false; } }
35+
36+ Component.onCompleted: show()
37+}
tests/qmltests/CMakeLists.txt+1
@@ -23,6 +23,7 @@ add_qml_test(. ShellWithPin ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tes
2323add_qml_test(. TabletShell ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full:${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
2424add_qml_test(Components Background)
2525add_qml_test(Components Carousel)
26+add_qml_test(Components Dialogs)
2627add_qml_test(Components DraggingArea)
2728add_qml_test(Components EdgeDemoOverlay)
2829add_qml_test(Components LazyImage)
tests/qmltests/Components/tst_Dialogs.qmlnew file+104
@@ -0,0 +1,104 @@
1+/*
2+ * Copyright (C) 2014 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.2
18+import QtTest 1.0
19+import Ubuntu.Components 1.1
20+import Unity.Test 0.1
21+
22+import "../../../qml/Components"
23+
24+Rectangle {
25+ id: root
26+ color: "black"
27+ width: units.gu(70)
28+ height: fakeShell.longestDimension
29+
30+ QtObject {
31+ id: fakeUnitySession
32+ signal logoutRequested
33+ signal shutdownRequested
34+ signal rebootRequested
35+ function logout() {}
36+ function shutdown() {}
37+ function reboot() {}
38+ }
39+
40+ Rectangle {
41+ id: fakeShell
42+ color: "green"
43+ readonly property real longestDimension: units.gu(71)
44+ readonly property real shortestDimension: units.gu(40)
45+ readonly property bool landscape: rotation === 90 || rotation === 270
46+ x: (shortestDimension - width) / 2
47+ y: (longestDimension - height) / 2
48+ width: landscape ? longestDimension : shortestDimension
49+ height: landscape ? shortestDimension : longestDimension
50+
51+ Text {
52+ text: "Shell"
53+ color: "black"
54+ anchors.fill: parent
55+ fontSizeMode: Text.Fit
56+ minimumPixelSize: 10
57+ font.pixelSize: 200
58+ verticalAlignment: Text.AlignVCenter
59+ horizontalAlignment: Text.AlignHCenter
60+ }
61+
62+ Dialogs {
63+ id: dialogs
64+ anchors.fill: parent
65+ unitySessionService: fakeUnitySession
66+ closeAllApps: function() {}
67+ }
68+ }
69+
70+ Rectangle {
71+ color: "white"
72+ x: fakeShell.shortestDimension
73+ width: root.width - x
74+ anchors {
75+ top: parent.top
76+ bottom: parent.bottom
77+ }
78+
79+ Column {
80+ anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
81+ spacing: units.gu(1)
82+ Button { text: "Power dialog"; onClicked: { testCase.showPowerDialog(); } }
83+ Button { text: "Logout Requested"; onClicked: { fakeUnitySession.logoutRequested(); } }
84+ Button { text: "Shutdown Requested"; onClicked: { fakeUnitySession.shutdownRequested(); } }
85+ Button { text: "Reboot Requested"; onClicked: { fakeUnitySession.rebootRequested(); } }
86+ Label { text: "Rotation:" }
87+ Button { text: "0"; onClicked: {fakeShell.rotation = 0;} }
88+ Button { text: "90"; onClicked: {fakeShell.rotation = 90;} }
89+ Button { text: "180"; onClicked: {fakeShell.rotation = 180;} }
90+ Button { text: "270"; onClicked: {fakeShell.rotation = 270;} }
91+ }
92+ }
93+
94+ UnityTestCase {
95+ id: testCase
96+ name: "Dialogs"
97+ when: windowShown
98+
99+ function showPowerDialog() {
100+ var dialogsPrivate = findInvisibleChild(dialogs, "dialogsPrivate");
101+ dialogsPrivate.showPowerDialog();
102+ }
103+ }
104+}