on xenial help sign in
Refactor Dialogs.qml to use proper in-scene dialogs
a4ee85bDaniel d'Andrada
qml/Components/Dialogs.qml+61−67
@@ -19,11 +19,22 @@ import QtQuick 2.0
19import Unity.Application 0.1
19import Unity.Application 0.1
20import Unity.Session 0.1
20import Unity.Session 0.1
21import Ubuntu.Components 1.1
21import Ubuntu.Components 1.1
22−import Ubuntu.Components.Popups 0.1
23
22
24Item {
23Item {
25 id: root
24 id: root
26
25
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+
27 function onPowerKeyPressed() {
38 function onPowerKeyPressed() {
28 // FIXME: event.isAutoRepeat is always false on Nexus 4.
39 // FIXME: event.isAutoRepeat is always false on Nexus 4.
29 // So we use powerKeyTimer.running to avoid the PowerOff key repeat
40 // So we use powerKeyTimer.running to avoid the PowerOff key repeat
@@ -41,16 +52,21 @@ Item {
41
52
42 QtObject {
53 QtObject {
43 id: d // private stuff
54 id: d // private stuff
55+ objectName: "dialogsPrivate"
44
56
45− property bool dialogShown: false
46
57
47 function showPowerDialog() {
58 function showPowerDialog() {
48− if (!d.dialogShown) {
59+ if (!dialogLoader.active) {
49− d.dialogShown = true;
60+ dialogLoader.sourceComponent = powerDialogComponent;
50− PopupUtils.open(powerDialog, root, {"z": root.z});
61+ dialogLoader.active = true;
51 }
62 }
52 }
63 }
53 }
64 }
65+ Loader {
66+ id: dialogLoader
67+ anchors.fill: parent
68+ active: false
69+ }
54
70
55 Timer {
71 Timer {
56 id: powerKeyTimer
72 id: powerKeyTimer
@@ -64,91 +80,84 @@ Item {
64 }
80 }
65
81
66 Component {
82 Component {
67− id: logoutDialog
83+ id: logoutDialogComponent
68− Dialog {
84+ ShellDialog {
69− id: dialogueLogout
85+ id: logoutDialog
70 title: i18n.tr("Log out")
86 title: i18n.tr("Log out")
71 text: i18n.tr("Are you sure you want to log out?")
87 text: i18n.tr("Are you sure you want to log out?")
72 Button {
88 Button {
73 text: i18n.tr("No")
89 text: i18n.tr("No")
74 onClicked: {
90 onClicked: {
75− PopupUtils.close(dialogueLogout);
91+ logoutDialog.hide();
76− d.dialogShown = false;
77 }
92 }
78 }
93 }
79 Button {
94 Button {
80 text: i18n.tr("Yes")
95 text: i18n.tr("Yes")
81 onClicked: {
96 onClicked: {
82− DBusUnitySessionService.Logout();
97+ unitySessionService.logout();
83− PopupUtils.close(dialogueLogout);
98+ logoutDialog.hide();
84− d.dialogShown = false;
85 }
99 }
86 }
100 }
87 }
101 }
88 }
102 }
89
103
90 Component {
104 Component {
91− id: shutdownDialog
105+ id: shutdownDialogComponent
92− Dialog {
106+ ShellDialog {
93− id: dialogueShutdown
107+ id: shutdownDialog
94 title: i18n.tr("Shut down")
108 title: i18n.tr("Shut down")
95 text: i18n.tr("Are you sure you want to shut down?")
109 text: i18n.tr("Are you sure you want to shut down?")
96 Button {
110 Button {
97 text: i18n.tr("No")
111 text: i18n.tr("No")
98 onClicked: {
112 onClicked: {
99− PopupUtils.close(dialogueShutdown);
113+ shutdownDialog.hide();
100− d.dialogShown = false;
101 }
114 }
102 }
115 }
103 Button {
116 Button {
104 text: i18n.tr("Yes")
117 text: i18n.tr("Yes")
105 onClicked: {
118 onClicked: {
106− dBusUnitySessionServiceConnection.closeAllApps();
119+ root.closeAllApps();
107− DBusUnitySessionService.Shutdown();
120+ unitySessionService.shutdown();
108− PopupUtils.close(dialogueShutdown);
121+ shutdownDialog.hide();
109− d.dialogShown = false;
110 }
122 }
111 }
123 }
112 }
124 }
113 }
125 }
114
126
115 Component {
127 Component {
116− id: rebootDialog
128+ id: rebootDialogComponent
117− Dialog {
129+ ShellDialog {
118− id: dialogueReboot
130+ id: rebootDialog
119 title: i18n.tr("Reboot")
131 title: i18n.tr("Reboot")
120 text: i18n.tr("Are you sure you want to reboot?")
132 text: i18n.tr("Are you sure you want to reboot?")
121 Button {
133 Button {
122 text: i18n.tr("No")
134 text: i18n.tr("No")
123 onClicked: {
135 onClicked: {
124− PopupUtils.close(dialogueReboot)
136+ rebootDialog.hide();
125− d.dialogShown = false;
126 }
137 }
127 }
138 }
128 Button {
139 Button {
129 text: i18n.tr("Yes")
140 text: i18n.tr("Yes")
130 onClicked: {
141 onClicked: {
131− dBusUnitySessionServiceConnection.closeAllApps();
142+ root.closeAllApps();
132− DBusUnitySessionService.Reboot();
143+ unitySessionService.reboot();
133− PopupUtils.close(dialogueReboot);
144+ rebootDialog.hide();
134− d.dialogShown = false;
135 }
145 }
136 }
146 }
137 }
147 }
138 }
148 }
139
149
140 Component {
150 Component {
141− id: powerDialog
151+ id: powerDialogComponent
142− Dialog {
152+ ShellDialog {
143− id: dialoguePower
153+ id: powerDialog
144 title: i18n.tr("Power")
154 title: i18n.tr("Power")
145 text: i18n.tr("Are you sure you would like\nto power off?")
155 text: i18n.tr("Are you sure you would like\nto power off?")
146 Button {
156 Button {
147 text: i18n.tr("Power off")
157 text: i18n.tr("Power off")
148 onClicked: {
158 onClicked: {
149− dBusUnitySessionServiceConnection.closeAllApps();
159+ root.closeAllApps();
150− PopupUtils.close(dialoguePower);
160+ powerDialog.hide();
151− d.dialogShown = false;
152 root.powerOffClicked();
161 root.powerOffClicked();
153 }
162 }
154 color: UbuntuColors.red
163 color: UbuntuColors.red
@@ -156,66 +165,51 @@ Item {
156 Button {
165 Button {
157 text: i18n.tr("Restart")
166 text: i18n.tr("Restart")
158 onClicked: {
167 onClicked: {
159− dBusUnitySessionServiceConnection.closeAllApps();
168+ root.closeAllApps();
160− DBusUnitySessionService.Reboot();
169+ unitySessionService.reboot();
161− PopupUtils.close(dialoguePower);
170+ powerDialog.hide();
162− d.dialogShown = false;
163 }
171 }
164 color: UbuntuColors.green
172 color: UbuntuColors.green
165 }
173 }
166 Button {
174 Button {
167 text: i18n.tr("Cancel")
175 text: i18n.tr("Cancel")
168 onClicked: {
176 onClicked: {
169− PopupUtils.close(dialoguePower);
177+ powerDialog.hide();
170− d.dialogShown = false;
171 }
178 }
172 color: UbuntuColors.coolGrey
179 color: UbuntuColors.coolGrey
173 }
180 }
174 }
181 }
175 }
182 }
176
183
177−
178 Connections {
184 Connections {
179− id: dBusUnitySessionServiceConnection
185+ target: root.unitySessionService
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− }
192
186
193 onLogoutRequested: {
187 onLogoutRequested: {
194 // Display a dialog to ask the user to confirm.
188 // Display a dialog to ask the user to confirm.
195− if (!d.dialogShown) {
189+ if (!dialogLoader.active) {
196− d.dialogShown = true;
190+ dialogLoader.sourceComponent = logoutDialogComponent;
197− PopupUtils.open(logoutDialog, root, {"z": root.z});
191+ dialogLoader.active = true;
198 }
192 }
199 }
193 }
200
194
201 onShutdownRequested: {
195 onShutdownRequested: {
202 // Display a dialog to ask the user to confirm.
196 // Display a dialog to ask the user to confirm.
203− if (!d.dialogShown) {
197+ if (!dialogLoader.active) {
204− d.dialogShown = true;
198+ dialogLoader.sourceComponent = shutdownDialogComponent;
205− PopupUtils.open(shutdownDialog, root, {"z": root.z});
199+ dialogLoader.active = true;
206 }
200 }
207 }
201 }
208
202
209 onRebootRequested: {
203 onRebootRequested: {
210 // Display a dialog to ask the user to confirm.
204 // Display a dialog to ask the user to confirm.
211− if (!d.dialogShown) {
205+ if (!dialogLoader.active) {
212− d.dialogShown = true;
206+ dialogLoader.sourceComponent = rebootDialogComponent;
213− PopupUtils.open(rebootDialog, root, {"z": root.z});
207+ dialogLoader.active = true;
214 }
208 }
215 }
209 }
216
210
217 onLogoutReady: {
211 onLogoutReady: {
218− closeAllApps();
212+ root.closeAllApps();
219 Qt.quit();
213 Qt.quit();
220 }
214 }
221 }
215 }
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
23add_qml_test(. TabletShell ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full:${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
23add_qml_test(. TabletShell ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full:${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
24add_qml_test(Components Background)
24add_qml_test(Components Background)
25add_qml_test(Components Carousel)
25add_qml_test(Components Carousel)
26+add_qml_test(Components Dialogs)
26add_qml_test(Components DraggingArea)
27add_qml_test(Components DraggingArea)
27add_qml_test(Components EdgeDemoOverlay)
28add_qml_test(Components EdgeDemoOverlay)
28add_qml_test(Components LazyImage)
29add_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+}