Merge lp:~unity-team/unity/infographics-with-lightdm into lp:unity/phablet
- infographics-with-lightdm
- Merge into phablet
Proposed by
Nicolas d'Offay
Status: | Superseded |
---|---|
Proposed branch: | lp:~unity-team/unity/infographics-with-lightdm |
Merge into: | lp:unity/phablet |
Diff against target: |
2968 lines (+2427/-107) 36 files modified
Greeter/Circle.qml (+61/-0) Greeter/CirclePositioner.qml (+36/-0) Greeter/Dot.qml (+36/-0) Greeter/Greeter.qml (+6/-42) Greeter/GreeterContent.qml (+17/-11) Greeter/Infographics.desktop (+9/-0) Greeter/Infographics.qml (+300/-0) Greeter/Infographics.qmlproject (+20/-0) Greeter/LoginList.qml (+45/-16) Shell.qml (+7/-3) debian/control (+0/-1) debian/qml-phone-shell.install (+1/-0) plugins/CMakeLists.txt (+1/-0) plugins/LightDM/CMakeLists.txt (+49/-0) plugins/LightDM/greeter.cpp (+133/-0) plugins/LightDM/greeter.h (+70/-0) plugins/LightDM/infographicmodel.cpp (+21/-0) plugins/LightDM/infographicmodel.h (+26/-0) plugins/LightDM/lightdm-greeter.cpp (+195/-0) plugins/LightDM/lightdm-greeter.h (+105/-0) plugins/LightDM/lightdm-infographicmodel.cpp (+370/-0) plugins/LightDM/lightdm-infographicmodel.h (+95/-0) plugins/LightDM/lightdm-usersmodel.cpp (+166/-0) plugins/LightDM/lightdm-usersmodel.h (+66/-0) plugins/LightDM/plugin.cpp (+57/-0) plugins/LightDM/plugin.h (+35/-0) plugins/LightDM/qmldir (+2/-0) plugins/LightDM/qvariantlistmodel.cpp (+243/-0) plugins/LightDM/qvariantlistmodel.h (+57/-0) plugins/LightDM/usersmodel.cpp (+68/-0) plugins/LightDM/usersmodel.h (+37/-0) plugins/Utils/qsortfilterproxymodelqml.cpp (+10/-0) plugins/Utils/qsortfilterproxymodelqml.h (+1/-0) tests/autopilot/qml_phone_shell/tests/helpers.py (+36/-13) tests/qmltests/CMakeLists.txt (+2/-2) tests/qmltests/Greeter/tst_Greeter.qml (+44/-19) |
To merge this branch: | bzr merge lp:~unity-team/unity/infographics-with-lightdm |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michael Zanetti | Pending | ||
MichaĆ Sawicz | progress | Pending | |
Review via email: mp+163302@code.launchpad.net |
This proposal has been superseded by a proposal from 2013-05-10.
Commit message
Commit of infographics with initial animation.
Description of the change
This is an initial MP of the infographics with one animation. Currently everything is done via QML for the visuals however in future the circles will have to be rendered together via C++/GL. Any suggestions on what could be improved with the Infographics.qml would be much appreciated.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added file 'Greeter/Circle.qml' |
2 | --- Greeter/Circle.qml 1970-01-01 00:00:00 +0000 |
3 | +++ Greeter/Circle.qml 2013-05-10 12:09:35 +0000 |
4 | @@ -0,0 +1,61 @@ |
5 | +/* |
6 | + * Copyright (C) 2013 Canonical, Ltd. |
7 | + * |
8 | + * This program is free software; you can redistribute it and/or modify |
9 | + * it under the terms of the GNU General Public License as published by |
10 | + * the Free Software Foundation; version 3. |
11 | + * |
12 | + * This program is distributed in the hope that it will be useful, |
13 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | + * GNU General Public License for more details. |
16 | + * |
17 | + * You should have received a copy of the GNU General Public License |
18 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | + */ |
20 | + |
21 | +import QtQuick 2.0 |
22 | + |
23 | +Item { |
24 | + property color color |
25 | + |
26 | + scale: 0.0 |
27 | + |
28 | + ShaderEffect { |
29 | + id: shader |
30 | + |
31 | + property real size: Math.min(width, height) * 0.5 |
32 | + property variant scale: Qt.size(width >= height ? width / height : 1.0, |
33 | + width >= height ? 1.0 : height / width) |
34 | + property color color: Qt.rgba(parent.color.r * parent.color.a, |
35 | + parent.color.g * parent.color.a, |
36 | + parent.color.b * parent.color.a, |
37 | + parent.color.a) |
38 | + |
39 | + visible: size > 0.0 |
40 | + anchors.fill: parent |
41 | + vertexShader: " |
42 | + uniform mediump mat4 qt_Matrix; |
43 | + uniform mediump vec2 scale; |
44 | + attribute mediump vec4 qt_Vertex; |
45 | + attribute mediump vec2 qt_MultiTexCoord0; |
46 | + varying highp vec2 coord; |
47 | + void main() { |
48 | + // Put coord in the range [-1, 1]. |
49 | + coord = ((qt_MultiTexCoord0 * 2.0) - 1.0) * scale; |
50 | + gl_Position = qt_Matrix * qt_Vertex; |
51 | + } |
52 | + " |
53 | + fragmentShader: " |
54 | + varying highp vec2 coord; |
55 | + uniform mediump float qt_Opacity; |
56 | + uniform mediump vec4 color; |
57 | + uniform mediump float size; |
58 | + void main() { |
59 | + // Distance function for antialiased circle. |
60 | + mediump float value = clamp(size + 0.5 - size * length(coord), 0.0, 1.0); |
61 | + gl_FragColor = color.rgba * vec4(qt_Opacity * value); |
62 | + } |
63 | + " |
64 | + } |
65 | +} |
66 | |
67 | === added file 'Greeter/CirclePositioner.qml' |
68 | --- Greeter/CirclePositioner.qml 1970-01-01 00:00:00 +0000 |
69 | +++ Greeter/CirclePositioner.qml 2013-05-10 12:09:35 +0000 |
70 | @@ -0,0 +1,36 @@ |
71 | +/* |
72 | + * Copyright (C) 2013 Canonical, Ltd. |
73 | + * |
74 | + * This program is free software; you can redistribute it and/or modify |
75 | + * it under the terms of the GNU General Public License as published by |
76 | + * the Free Software Foundation; version 3. |
77 | + * |
78 | + * This program is distributed in the hope that it will be useful, |
79 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
80 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
81 | + * GNU General Public License for more details. |
82 | + * |
83 | + * You should have received a copy of the GNU General Public License |
84 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
85 | + */ |
86 | + |
87 | +import QtQuick 2.0 |
88 | +import Ubuntu.Components 0.1 |
89 | + |
90 | +Item { |
91 | + property int count |
92 | + property int index |
93 | + property real radius |
94 | + property real halfSize |
95 | + property real posOffset |
96 | + |
97 | + property real slice: (2 * Math.PI / count) * index; |
98 | + |
99 | + implicitWidth: childrenRect.width |
100 | + implicitHeight: childrenRect.height |
101 | + |
102 | + x: (radius - halfSize * posOffset) * Math.sin(slice) + radius - halfSize |
103 | + y: (radius - halfSize * posOffset) * -Math.cos(slice) + radius - halfSize |
104 | + |
105 | + rotation: Math.atan2(radius-(y+halfSize), radius-(x+halfSize)) * 180 / Math.PI - 90 |
106 | +} |
107 | |
108 | === added file 'Greeter/Dot.qml' |
109 | --- Greeter/Dot.qml 1970-01-01 00:00:00 +0000 |
110 | +++ Greeter/Dot.qml 2013-05-10 12:09:35 +0000 |
111 | @@ -0,0 +1,36 @@ |
112 | +/* |
113 | + * Copyright (C) 2013 Canonical, Ltd. |
114 | + * |
115 | + * This program is free software; you can redistribute it and/or modify |
116 | + * it under the terms of the GNU General Public License as published by |
117 | + * the Free Software Foundation; version 3. |
118 | + * |
119 | + * This program is distributed in the hope that it will be useful, |
120 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
121 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
122 | + * GNU General Public License for more details. |
123 | + * |
124 | + * You should have received a copy of the GNU General Public License |
125 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
126 | + */ |
127 | + |
128 | +import QtQuick 2.0 |
129 | + |
130 | +Image { |
131 | +states: [ |
132 | + State { |
133 | + name: "unfilled" |
134 | + PropertyChanges { target: dot; source: "graphics/dot_empty@30.png" } |
135 | + }, |
136 | + |
137 | + State { |
138 | + name: "filled" |
139 | + PropertyChanges { target: dot; source: "graphics/dot_filled@30.png" } |
140 | + }, |
141 | + |
142 | + State { |
143 | + name: "pointer" |
144 | + PropertyChanges { target: dot; source: "graphics/dot_pointer@30.png" } |
145 | + } |
146 | +] |
147 | +} |
148 | |
149 | === modified file 'Greeter/Greeter.qml' |
150 | --- Greeter/Greeter.qml 2013-04-09 00:39:33 +0000 |
151 | +++ Greeter/Greeter.qml 2013-05-10 12:09:35 +0000 |
152 | @@ -16,7 +16,7 @@ |
153 | |
154 | import QtQuick 2.0 |
155 | import Ubuntu.Components 0.1 |
156 | -import QtQuick.XmlListModel 2.0 |
157 | +import LightDM 0.1 as LightDM |
158 | import "../Components" |
159 | |
160 | Showable { |
161 | @@ -24,8 +24,8 @@ |
162 | enabled: shown |
163 | created: greeterContentLoader.status == Loader.Ready && greeterContentLoader.item.ready |
164 | |
165 | - property alias model: userList |
166 | - property bool locked: shown && multiUser && !greeterContentLoader.guestAccount |
167 | + property alias model: greeterContentLoader.model |
168 | + property bool locked: shown && multiUser && !greeterContentLoader.promptless |
169 | |
170 | readonly property bool narrowMode: width <= units.gu(60) |
171 | readonly property bool multiUser: !narrowMode // TODO: populate with real value |
172 | @@ -33,50 +33,14 @@ |
173 | signal selected(int uid) |
174 | signal unlocked(int uid) |
175 | |
176 | - ListModel { |
177 | - id: userList |
178 | - objectName: "userList" |
179 | - ListElement { name: "Guest"; background: "graphics/tablet_background.jpg" } |
180 | - } |
181 | - |
182 | - // TODO: Replace with a ModelAggregator once we have one. |
183 | - // Check Unity2D for a possibly usable one. |
184 | - XmlListModel { |
185 | - id: xmlReader |
186 | - source: "/usr/share/demo-assets/shell/users.xml" |
187 | - query: "/users/user" |
188 | - |
189 | - XmlRole { name: "name"; query: "username/string()" } |
190 | - XmlRole { name: "password"; query: "password/string()" } |
191 | - XmlRole { name: "background"; query: "background/string()" } |
192 | - XmlRole { name: "infographic"; query: "infographic/string()" } |
193 | - |
194 | - onStatusChanged: { |
195 | - if (status == XmlListModel.Ready) { |
196 | - // Need to reset the model to make sure everything updates correctly. |
197 | - // Otherwise currentIndex, count etc could stay the same and bindings are not updated. |
198 | - greeterContentLoader.currentIndex = -1; |
199 | - greeterContentLoader.model = undefined; |
200 | - |
201 | - userList.clear(); |
202 | - for (var i = 0; i < xmlReader.count; i++) { |
203 | - userList.append(xmlReader.get(i)); |
204 | - } |
205 | - userList.append({ "name": "Guest", background: "graphics/tablet_background.jpg" }); |
206 | - |
207 | - greeterContentLoader.model = userList; |
208 | - greeterContentLoader.currentIndex = 0; |
209 | - } |
210 | - } |
211 | - } |
212 | - |
213 | Loader { |
214 | id: greeterContentLoader |
215 | objectName: "greeterContentLoader" |
216 | anchors.fill: parent |
217 | - property variant model: userList |
218 | + property variant model: LightDM.Users |
219 | property int currentIndex: 0 |
220 | - property bool guestAccount: item ? item.guestAccount : false |
221 | + property bool promptless: item ? item.promptless : false |
222 | + property variant infographicModel: LightDM.Infographic |
223 | |
224 | source: required ? "GreeterContent.qml" : "" |
225 | |
226 | |
227 | === modified file 'Greeter/GreeterContent.qml' |
228 | --- Greeter/GreeterContent.qml 2013-04-05 11:03:11 +0000 |
229 | +++ Greeter/GreeterContent.qml 2013-05-10 12:09:35 +0000 |
230 | @@ -16,13 +16,14 @@ |
231 | |
232 | import QtQuick 2.0 |
233 | import Ubuntu.Components 0.1 |
234 | +import LightDM 0.1 as LightDM |
235 | import "../Components" |
236 | |
237 | MouseArea { |
238 | id: root |
239 | anchors.fill: parent |
240 | |
241 | - property bool guestAccount: loginLoader.status == Loader.Ready && loginLoader.item.guestAccount |
242 | + property bool promptless: loginLoader.status == Loader.Ready && LightDM.Greeter.promptless |
243 | property bool ready: wallpaper.status == Image.Ready |
244 | |
245 | signal selected(int uid) |
246 | @@ -69,6 +70,8 @@ |
247 | |
248 | onLoaded: { |
249 | item.currentIndex = greeterContentLoader.currentIndex |
250 | + greeterContentLoader.infographicModel.username = greeterContentLoader.model.data( |
251 | + greeterContentLoader.currentIndex, LightDM.UserRoles.NameRole) |
252 | } |
253 | |
254 | Binding { |
255 | @@ -90,25 +93,28 @@ |
256 | |
257 | onCurrentIndexChanged: { |
258 | greeterContentLoader.currentIndex = loginLoader.item.currentIndex; |
259 | + greeterContentLoader.infographicModel.username = greeterContentLoader.model.data( |
260 | + greeterContentLoader.currentIndex, LightDM.UserRoles.NameRole) |
261 | } |
262 | } |
263 | } |
264 | |
265 | - // FIXME: The images are way bigger than their content because the infographic |
266 | - // bubbles can grow a lot. Because of that the infographic image reaches under the |
267 | - // login list. This code makes sure that it never really overlaps until unusable |
268 | - // with the current artwork. Will be replaced by real infographic. |
269 | - CrossFadeImage { |
270 | + Infographics { |
271 | id: infographics |
272 | - width: narrowMode ? sourceSize.width : Math.min(parent.width - loginLoader.x - loginLoader.width/2, units.gu(90)) |
273 | - height: narrowMode ? sourceSize.height : width * 8/9 |
274 | + width: narrowMode ? parent.width : parent.width / 1.7 |
275 | + height: narrowMode ? parent.height : width / 1.7 |
276 | + |
277 | + Component.onCompleted: { |
278 | + greeterContentLoader.infographicModel.username = "phablet" |
279 | + } |
280 | + |
281 | + model: greeterContentLoader.infographicModel |
282 | |
283 | anchors { |
284 | verticalCenter: parent.verticalCenter |
285 | horizontalCenter: narrowMode ? parent.horizontalCenter : undefined |
286 | - right: narrowMode ? undefined : parent.right |
287 | - rightMargin: narrowMode ? 0 : units.gu(-6) |
288 | + left: narrowMode ? undefined : loginLoader.right |
289 | + leftMargin: narrowMode ? 0 : width / 6 |
290 | } |
291 | - source: narrowMode ? "graphics/infographic_tweeter_cut.png" : userList.get(greeterContentLoader.currentIndex).infographic ? userList.get(greeterContentLoader.currentIndex).infographic : "" |
292 | } |
293 | } |
294 | |
295 | === added file 'Greeter/Infographics.desktop' |
296 | --- Greeter/Infographics.desktop 1970-01-01 00:00:00 +0000 |
297 | +++ Greeter/Infographics.desktop 2013-05-10 12:09:35 +0000 |
298 | @@ -0,0 +1,9 @@ |
299 | +[Desktop Entry] |
300 | +Name=Infographics |
301 | +Comment=My project description |
302 | +Exec=/usr/bin/qmlscene $@ /usr/share/Infographics/Infographics.qml |
303 | +Icon=qmlscene |
304 | +Terminal=false |
305 | +Type=Application |
306 | +X-Ubuntu-Touch=true |
307 | +Name[en_GB]=Infographics.desktop |
308 | |
309 | === added file 'Greeter/Infographics.qml' |
310 | --- Greeter/Infographics.qml 1970-01-01 00:00:00 +0000 |
311 | +++ Greeter/Infographics.qml 2013-05-10 12:09:35 +0000 |
312 | @@ -0,0 +1,300 @@ |
313 | +/* |
314 | + * Copyright (C) 2013 Canonical, Ltd. |
315 | + * |
316 | + * This program is free software; you can redistribute it and/or modify |
317 | + * it under the terms of the GNU General Public License as published by |
318 | + * the Free Software Foundation; version 3. |
319 | + * |
320 | + * This program is distributed in the hope that it will be useful, |
321 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
322 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
323 | + * GNU General Public License for more details. |
324 | + * |
325 | + * You should have received a copy of the GNU General Public License |
326 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
327 | + */ |
328 | + |
329 | +import QtQuick 2.0 |
330 | +import Ubuntu.Components 0.1 |
331 | + |
332 | +Rectangle { |
333 | + id: infographic |
334 | + |
335 | + property int animDuration: 20 |
336 | + |
337 | + Component.onCompleted: { |
338 | + dotAnimTimer.start(); |
339 | + notification.showAnim.start(); |
340 | + } |
341 | + |
342 | + color: "transparent" |
343 | + |
344 | + property variant model |
345 | + |
346 | + Connections { |
347 | + target: model |
348 | + |
349 | + onLabelChanged: { |
350 | + dotAnimTimer.dotCounter = 0; |
351 | + circleAnimTimer.pastCircleCounter = 0; |
352 | + circleAnimTimer.presentCircleCounter = 0; |
353 | + dotAnimTimer.start(); |
354 | + notification.showAnim.start(); |
355 | + } |
356 | + } |
357 | + |
358 | + visible: model.label !== "" |
359 | + |
360 | + Item { |
361 | + id: dataCircle |
362 | + |
363 | + width: Math.min(parent.height, parent.width) / 1.5 |
364 | + height: width |
365 | + |
366 | + anchors.centerIn: parent |
367 | + |
368 | + Timer { |
369 | + id: circleAnimTimer |
370 | + |
371 | + property int pastCircleCounter: 0 |
372 | + property int presentCircleCounter: 0 |
373 | + |
374 | + interval: infographic.animDuration; running: false; repeat: true |
375 | + onTriggered: { |
376 | + if(presentCircles.count === 0 || pastCircles.count === 0) { |
377 | + stop() |
378 | + pastCircleCounter = presentCircleCounter = 0 |
379 | + } |
380 | + |
381 | + if (pastCircleCounter < pastCircles.count) { |
382 | + var nextCircle = pastCircles.itemAt(pastCircleCounter++) |
383 | + nextCircle.pastUnlockAnim.start() |
384 | + } |
385 | + if (pastCircleCounter >= pastCircles.count / 2) { |
386 | + var nextCircle = presentCircles.itemAt(presentCircleCounter++) |
387 | + nextCircle.presentUnlockAnim.start() |
388 | + } |
389 | + if (presentCircleCounter >= presentCircles.count) { |
390 | + stop() |
391 | + pastCircleCounter = presentCircleCounter = 0 |
392 | + } |
393 | + } |
394 | + } |
395 | + |
396 | + Repeater { |
397 | + id: pastCircles |
398 | + |
399 | + model: infographic.model.secondMonth |
400 | + |
401 | + delegate: CirclePositioner { |
402 | + index: model.index |
403 | + count: pastCircles.count |
404 | + radius: parent.width / 2 |
405 | + halfSize: pastCircle.width / 2 |
406 | + posOffset: 0.0 |
407 | + visible: modelData !== null |
408 | + |
409 | + property var pastUnlockAnim: pastCircleUnlockAnim |
410 | + |
411 | + Circle { |
412 | + id: pastCircle |
413 | + |
414 | + width: dataCircle.width / 2 |
415 | + height: dataCircle.height / 2 |
416 | + |
417 | + Component.onCompleted: { |
418 | + color = infographic.model.secondColor |
419 | + } |
420 | + |
421 | + SequentialAnimation { |
422 | + id: pastCircleUnlockAnim |
423 | + |
424 | + loops: 1 |
425 | + ParallelAnimation { |
426 | + PropertyAnimation { |
427 | + target: pastCircle |
428 | + property: "opacity" |
429 | + from: 0.0 |
430 | + to: 0.1 |
431 | + easing.type: Easing.OutCurve |
432 | + duration: circleAnimTimer.interval * 4 |
433 | + } |
434 | + PropertyAnimation { |
435 | + target: pastCircle |
436 | + property: "scale" |
437 | + to: 0.6 + modelData |
438 | + easing.type: Easing.OutCurve |
439 | + duration: circleAnimTimer.interval * 4 |
440 | + } |
441 | + } |
442 | + } |
443 | + } |
444 | + } |
445 | + } |
446 | + |
447 | + Repeater { |
448 | + id: presentCircles |
449 | + |
450 | + model: infographic.model.firstMonth |
451 | + |
452 | + delegate: CirclePositioner { |
453 | + index: model.index |
454 | + count: presentCircles.count |
455 | + radius: parent.width / 2 |
456 | + halfSize: presentCircle.width / 2 |
457 | + posOffset: 0.0 |
458 | + visible: modelData !== null |
459 | + |
460 | + property var presentUnlockAnim: presentCircleUnlockAnim |
461 | + |
462 | + Circle { |
463 | + id: presentCircle |
464 | + |
465 | + width: dataCircle.width / 2 |
466 | + height: dataCircle.height / 2 |
467 | + |
468 | + Component.onCompleted: { |
469 | + color = infographic.model.firstColor |
470 | + } |
471 | + |
472 | + SequentialAnimation { |
473 | + id: presentCircleUnlockAnim |
474 | + |
475 | + loops: 1 |
476 | + |
477 | + ParallelAnimation { |
478 | + PropertyAnimation { |
479 | + target: presentCircle |
480 | + property: "opacity" |
481 | + from: 0.0 |
482 | + to: 0.3 |
483 | + easing.type: Easing.OutCurve |
484 | + duration: circleAnimTimer.interval * 4 |
485 | + } |
486 | + PropertyAnimation { |
487 | + target: presentCircle |
488 | + property: "scale" |
489 | + from: 0.0 |
490 | + to: modelData |
491 | + easing.type: Easing.OutCurve |
492 | + duration: circleAnimTimer.interval * 4 |
493 | + } |
494 | + } |
495 | + } |
496 | + } |
497 | + } |
498 | + } |
499 | + |
500 | + Image { |
501 | + id: backgroundCircle |
502 | + |
503 | + anchors.fill: parent |
504 | + opacity: 0.9 |
505 | + |
506 | + source: "graphics/infographic_circle.png" |
507 | + } |
508 | + |
509 | + Timer { |
510 | + id: dotAnimTimer |
511 | + |
512 | + property int dotCounter: 0 |
513 | + |
514 | + interval: animDuration * 0.5; running: false; repeat: true |
515 | + onTriggered: { |
516 | + if (dotCounter < dots.count) { |
517 | + var nextDot = dots.itemAt(dotCounter++); |
518 | + nextDot.unlockAnimation.start() |
519 | + } |
520 | + else { |
521 | + stop() |
522 | + } |
523 | + if (dotCounter >= dots.count / 2) { |
524 | + circleAnimTimer.start() |
525 | + } |
526 | + } |
527 | + } |
528 | + |
529 | + Repeater { |
530 | + id: dots |
531 | + |
532 | + model: infographic.model.firstMonth |
533 | + |
534 | + delegate: CirclePositioner { |
535 | + index: model.index |
536 | + count: dots.count |
537 | + radius: backgroundCircle.width / 2 |
538 | + halfSize: dot.width / 2 |
539 | + posOffset: radius / 180 |
540 | + state: dot.state |
541 | + |
542 | + property var unlockAnimation: dotUnlockAnim |
543 | + |
544 | + property int currentDay: infographic.model.currentDay |
545 | + |
546 | + Dot { |
547 | + id: dot |
548 | + |
549 | + visible: false |
550 | + smooth: true |
551 | + scale: radius / 1000 |
552 | + state: { |
553 | + if (index < currentDay) |
554 | + "filled" |
555 | + else if (index == currentDay) |
556 | + "pointer" |
557 | + else |
558 | + "unfilled" |
559 | + } |
560 | + |
561 | + SequentialAnimation { |
562 | + id: dotUnlockAnim |
563 | + |
564 | + PropertyAnimation { |
565 | + target: dot |
566 | + property: "visible" |
567 | + to: "true" |
568 | + duration: dotAnimTimer.interval / 2 |
569 | + } |
570 | + } |
571 | + } |
572 | + } |
573 | + } |
574 | + |
575 | + Text { |
576 | + id: notification |
577 | + |
578 | + height: 0.7 * backgroundCircle.width |
579 | + width: notification.height |
580 | + anchors.centerIn: parent |
581 | + |
582 | + text: infographic.model.label |
583 | + font.pixelSize: notification.height / 10 |
584 | + |
585 | + wrapMode: Text.WordWrap |
586 | + horizontalAlignment: Text.AlignHCenter |
587 | + verticalAlignment: Text.AlignVCenter |
588 | + color: "white" |
589 | + |
590 | + opacity: 0.0 |
591 | + |
592 | + property variant showAnim: increaseOpacity |
593 | + |
594 | + PropertyAnimation { |
595 | + id: increaseOpacity |
596 | + |
597 | + target: notification |
598 | + property: "opacity" |
599 | + to: 1.0 |
600 | + duration: dotAnimTimer.interval * dots.count * 2 |
601 | + } |
602 | + } |
603 | + } |
604 | + |
605 | + MouseArea { |
606 | + anchors.fill: dataCircle |
607 | + |
608 | + onClicked: { |
609 | + infographic.model.nextDataSource(); |
610 | + } |
611 | + } |
612 | +} |
613 | |
614 | === added file 'Greeter/Infographics.qmlproject' |
615 | --- Greeter/Infographics.qmlproject 1970-01-01 00:00:00 +0000 |
616 | +++ Greeter/Infographics.qmlproject 2013-05-10 12:09:35 +0000 |
617 | @@ -0,0 +1,20 @@ |
618 | +/* File generated by Qt Creator, version 2.7.0 */ |
619 | + |
620 | +import QmlProject 1.1 |
621 | + |
622 | +Project { |
623 | + mainFile: "Infographics.qml" |
624 | + |
625 | + /* Include .qml, .js, and image files from current directory and subdirectories */ |
626 | + QmlFiles { |
627 | + directory: "." |
628 | + } |
629 | + JavaScriptFiles { |
630 | + directory: "." |
631 | + } |
632 | + ImageFiles { |
633 | + directory: "." |
634 | + } |
635 | + /* List of plugin directories passed to QML runtime */ |
636 | + // importPaths: [ "../exampleplugin" ] |
637 | +} |
638 | |
639 | === modified file 'Greeter/LoginList.qml' |
640 | --- Greeter/LoginList.qml 2013-04-12 05:54:57 +0000 |
641 | +++ Greeter/LoginList.qml 2013-05-10 12:09:35 +0000 |
642 | @@ -16,17 +16,18 @@ |
643 | |
644 | import QtQuick 2.0 |
645 | import Ubuntu.Components 0.1 |
646 | +import LightDM 0.1 as LightDM |
647 | |
648 | Item { |
649 | id: root |
650 | |
651 | + property alias userList: userList |
652 | property alias model: userList.model |
653 | property alias currentIndex: userList.currentIndex |
654 | |
655 | readonly property int cellHeight: units.gu(6) |
656 | readonly property int highlightedHeight: units.gu(10) |
657 | readonly property int moveDuration: 200 |
658 | - readonly property bool guestAccount: userList.model.get(userList.currentIndex).password === undefined |
659 | |
660 | signal selected(int uid) |
661 | signal unlocked(int uid) |
662 | @@ -66,9 +67,18 @@ |
663 | readonly property int offsetStartDistance: units.gu(7) |
664 | readonly property int fadeOutDistance: pathStartMargin - units.gu(1) |
665 | |
666 | + onCountChanged: { |
667 | + // Start authentication when we start up |
668 | + if (!LightDM.Greeter.authenticationUser && userList.currentItem) { |
669 | + root.selected(userList.currentIndex); |
670 | + root.resetAuthentication(); |
671 | + } |
672 | + } |
673 | + |
674 | onCurrentIndexChanged: { |
675 | - passwordInput.text = ""; |
676 | - passwordInput.focus = false |
677 | + if (LightDM.Greeter.authenticationUser != userList.model.data(currentIndex, LightDM.UserRoles.NameRole)) { |
678 | + root.resetAuthentication(); |
679 | + } |
680 | } |
681 | |
682 | onMovingInternallyChanged: { |
683 | @@ -157,7 +167,7 @@ |
684 | right: parent.right |
685 | rightMargin: units.gu(2) |
686 | } |
687 | - text: name |
688 | + text: realName |
689 | color: "white" |
690 | elide: Text.ElideRight |
691 | } |
692 | @@ -201,7 +211,7 @@ |
693 | } |
694 | height: units.gu(4.5) |
695 | width: parent.width - anchors.margins * 2 |
696 | - placeholderText: root.guestAccount ? "Tap to unlock" : "Password" |
697 | + placeholderText: LightDM.Greeter.promptless ? "Tap to unlock" : "Password" |
698 | echoMode: TextInput.Password |
699 | opacity: userList.movingInternally ? 0 : 1 |
700 | |
701 | @@ -209,15 +219,7 @@ |
702 | NumberAnimation { duration: 100 } |
703 | } |
704 | |
705 | - onAccepted: { |
706 | - if (text === userList.model.get(userList.currentIndex).password) { |
707 | - root.unlocked(userList.currentIndex); |
708 | - passwordInput.focus = false; |
709 | - } else { |
710 | - wrongPasswordAnimation.start(); |
711 | - } |
712 | - text = ""; |
713 | - } |
714 | + onAccepted: LightDM.Greeter.respond(text) |
715 | |
716 | Image { |
717 | anchors { |
718 | @@ -225,7 +227,7 @@ |
719 | rightMargin: units.gu(2) |
720 | verticalCenter: parent.verticalCenter |
721 | } |
722 | - visible: root.guestAccount |
723 | + visible: LightDM.Greeter.promptless |
724 | source: "graphics/icon_arrow.png" |
725 | } |
726 | |
727 | @@ -265,11 +267,38 @@ |
728 | } |
729 | |
730 | } |
731 | + |
732 | MouseArea { |
733 | anchors.fill: passwordInput |
734 | - enabled: root.guestAccount |
735 | + enabled: LightDM.Greeter.promptless |
736 | onClicked: { |
737 | root.unlocked(userList.currentIndex); |
738 | } |
739 | } |
740 | + |
741 | + function resetAuthentication() { |
742 | + if (!userList.currentItem) { |
743 | + return; |
744 | + } |
745 | + passwordInput.text = ""; |
746 | + passwordInput.focus = false; |
747 | + LightDM.Greeter.authenticate(userList.model.data(currentIndex, LightDM.UserRoles.NameRole)); |
748 | + } |
749 | + |
750 | + Connections { |
751 | + target: LightDM.Greeter |
752 | + |
753 | + onAuthenticationComplete: { |
754 | + if (LightDM.Greeter.promptless) { |
755 | + return; |
756 | + } |
757 | + if (LightDM.Greeter.authenticated) { |
758 | + root.unlocked(userList.currentIndex); |
759 | + passwordInput.focus = false; |
760 | + } else { |
761 | + wrongPasswordAnimation.start(); |
762 | + } |
763 | + passwordInput.text = ""; |
764 | + } |
765 | + } |
766 | } |
767 | |
768 | === added file 'Greeter/graphics/dot_empty@30.png' |
769 | Binary files Greeter/graphics/dot_empty@30.png 1970-01-01 00:00:00 +0000 and Greeter/graphics/dot_empty@30.png 2013-05-10 12:09:35 +0000 differ |
770 | === added file 'Greeter/graphics/dot_filled@30.png' |
771 | Binary files Greeter/graphics/dot_filled@30.png 1970-01-01 00:00:00 +0000 and Greeter/graphics/dot_filled@30.png 2013-05-10 12:09:35 +0000 differ |
772 | === added file 'Greeter/graphics/dot_pointer@30.png' |
773 | Binary files Greeter/graphics/dot_pointer@30.png 1970-01-01 00:00:00 +0000 and Greeter/graphics/dot_pointer@30.png 2013-05-10 12:09:35 +0000 differ |
774 | === added file 'Greeter/graphics/infographic_circle.png' |
775 | Binary files Greeter/graphics/infographic_circle.png 1970-01-01 00:00:00 +0000 and Greeter/graphics/infographic_circle.png 2013-05-10 12:09:35 +0000 differ |
776 | === removed file 'Greeter/graphics/infographic_default@20.png' |
777 | Binary files Greeter/graphics/infographic_default@20.png 2013-02-12 17:43:28 +0000 and Greeter/graphics/infographic_default@20.png 1970-01-01 00:00:00 +0000 differ |
778 | === removed file 'Greeter/graphics/infographic_tweeter_cut@18.png' |
779 | Binary files Greeter/graphics/infographic_tweeter_cut@18.png 2012-11-23 17:15:36 +0000 and Greeter/graphics/infographic_tweeter_cut@18.png 1970-01-01 00:00:00 +0000 differ |
780 | === modified file 'Shell.qml' |
781 | --- Shell.qml 2013-05-02 22:07:11 +0000 |
782 | +++ Shell.qml 2013-05-10 12:09:35 +0000 |
783 | @@ -17,6 +17,7 @@ |
784 | import QtQuick 2.0 |
785 | import Ubuntu.Application 0.1 |
786 | import Ubuntu.Components 0.1 |
787 | +import LightDM 0.1 as LightDM |
788 | import "Dash" |
789 | import "Greeter" |
790 | import "Launcher" |
791 | @@ -36,7 +37,8 @@ |
792 | height: tablet ? units.gu(100) : units.gu(71) |
793 | |
794 | property real edgeSize: units.gu(2) |
795 | - property url background: shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg" |
796 | + property url default_background: shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg" |
797 | + property url background: default_background |
798 | readonly property real panelHeight: panel.panelHeight |
799 | |
800 | property bool dashShown: dash.shown |
801 | @@ -351,8 +353,10 @@ |
802 | onShownChanged: if (shown) greeter.forceActiveFocus() |
803 | |
804 | onUnlocked: greeter.hide() |
805 | - onSelected: shell.background = greeter.model.get(uid).background; |
806 | - |
807 | + onSelected: { |
808 | + var bgPath = greeter.model.data(uid, LightDM.UserRoles.BackgroundPathRole) |
809 | + shell.background = bgPath ? bgPath : default_background |
810 | + } |
811 | } |
812 | |
813 | Revealer { |
814 | |
815 | === modified file 'debian/control' |
816 | --- debian/control 2013-05-09 08:55:23 +0000 |
817 | +++ debian/control 2013-05-10 12:09:35 +0000 |
818 | @@ -4,7 +4,6 @@ |
819 | Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com> |
820 | Build-Depends: cmake, |
821 | debhelper (>= 9), |
822 | - demo-assets, |
823 | doxygen, |
824 | graphviz, |
825 | libboost-regex1.49-dev (>= 1.49), |
826 | |
827 | === modified file 'debian/qml-phone-shell.install' |
828 | --- debian/qml-phone-shell.install 2013-04-18 18:53:42 +0000 |
829 | +++ debian/qml-phone-shell.install 2013-05-10 12:09:35 +0000 |
830 | @@ -12,5 +12,6 @@ |
831 | /usr/share/qml-phone-shell/SideStage/* |
832 | /usr/share/qml-phone-shell/graphics/* |
833 | /usr/share/qml-phone-shell/plugins/HudClient/* |
834 | +/usr/share/qml-phone-shell/plugins/LightDM/* |
835 | /usr/share/qml-phone-shell/plugins/Unity/* |
836 | /usr/share/qml-phone-shell/plugins/Utils/* |
837 | |
838 | === modified file 'plugins/CMakeLists.txt' |
839 | --- plugins/CMakeLists.txt 2013-04-18 17:20:37 +0000 |
840 | +++ plugins/CMakeLists.txt 2013-05-10 12:09:35 +0000 |
841 | @@ -1,3 +1,4 @@ |
842 | add_subdirectory(Utils) |
843 | add_subdirectory(Unity) |
844 | add_subdirectory(HudClient) |
845 | +add_subdirectory(LightDM) |
846 | |
847 | === added directory 'plugins/LightDM' |
848 | === added file 'plugins/LightDM/CMakeLists.txt' |
849 | --- plugins/LightDM/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
850 | +++ plugins/LightDM/CMakeLists.txt 2013-05-10 12:09:35 +0000 |
851 | @@ -0,0 +1,49 @@ |
852 | +# Dependencies |
853 | +# TODO: Once we split out a separate greeter process, uncomment these lines |
854 | +#include(FindPkgConfig) |
855 | +#pkg_check_modules(LIBLIGHTDM REQUIRED liblightdm-qt5-2) |
856 | + |
857 | +include_directories( |
858 | + ${CMAKE_CURRENT_SOURCE_DIR} |
859 | + ${CMAKE_CURRENT_BINARY_DIR} |
860 | + ${LIBLIGHTDM_INCLUDE_DIRS} |
861 | +) |
862 | + |
863 | +set(QMLPLUGIN_SRC |
864 | + ../Utils/qsortfilterproxymodelqml.cpp # FIXME evaluate a more generic approach for using other plugins |
865 | + greeter.cpp |
866 | + infographicmodel.cpp |
867 | + plugin.cpp |
868 | + usersmodel.cpp |
869 | + # TODO: Once we split out a separate greeter process, we should move these |
870 | + # files to a mock plugin and link this plugin to the real liblightdm |
871 | + lightdm-greeter.cpp |
872 | + lightdm-usersmodel.cpp |
873 | + lightdm-infographicmodel.cpp |
874 | + qvariantlistmodel.cpp |
875 | + ) |
876 | + |
877 | +add_library(LightDM-qml MODULE |
878 | + ${QMLPLUGIN_SRC} |
879 | + ) |
880 | + |
881 | +# TODO: Once we split out a separate greeter process, uncomment these lines |
882 | +#target_link_libraries(LightDM-qml |
883 | +# ${LIBLIGHTDM_LDFLAGS} |
884 | +# ) |
885 | + |
886 | +qt5_use_modules(LightDM-qml Gui Qml) |
887 | + |
888 | +# copy qmldir file into build directory for shadow builds |
889 | +file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/qmldir" |
890 | + DESTINATION ${CMAKE_CURRENT_BINARY_DIR} |
891 | + ) |
892 | + |
893 | +install(TARGETS LightDM-qml |
894 | + DESTINATION ${SHELL_APP_DIR}/plugins/LightDM |
895 | + ) |
896 | + |
897 | +install(FILES qmldir |
898 | + DESTINATION ${SHELL_APP_DIR}/plugins/LightDM |
899 | + ) |
900 | + |
901 | |
902 | === added file 'plugins/LightDM/greeter.cpp' |
903 | --- plugins/LightDM/greeter.cpp 1970-01-01 00:00:00 +0000 |
904 | +++ plugins/LightDM/greeter.cpp 2013-05-10 12:09:35 +0000 |
905 | @@ -0,0 +1,133 @@ |
906 | +/* |
907 | + * Copyright (C) 2013 Canonical, Ltd. |
908 | + * |
909 | + * This program is free software; you can redistribute it and/or modify |
910 | + * it under the terms of the GNU General Public License as published by |
911 | + * the Free Software Foundation; version 3. |
912 | + * |
913 | + * This program is distributed in the hope that it will be useful, |
914 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
915 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
916 | + * GNU General Public License for more details. |
917 | + * |
918 | + * You should have received a copy of the GNU General Public License |
919 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
920 | + * |
921 | + * Author: Michael Terry <michael.terry@canonical.com> |
922 | + */ |
923 | + |
924 | +#include "greeter.h" |
925 | +#include "lightdm-greeter.h" |
926 | + |
927 | +class GreeterPrivate |
928 | +{ |
929 | +public: |
930 | + explicit GreeterPrivate(Greeter *parent); |
931 | + |
932 | + QLightDM::Greeter *m_greeter; |
933 | + bool wasPrompted; |
934 | + bool promptless; |
935 | + |
936 | +protected: |
937 | + Greeter * const q_ptr; |
938 | + |
939 | +private: |
940 | + Q_DECLARE_PUBLIC(Greeter) |
941 | +}; |
942 | + |
943 | + |
944 | +GreeterPrivate::GreeterPrivate(Greeter* parent) |
945 | + : m_greeter(new QLightDM::Greeter(parent)), |
946 | + wasPrompted(false), |
947 | + promptless(false), |
948 | + q_ptr(parent) |
949 | +{ |
950 | +} |
951 | + |
952 | +Greeter::Greeter(QObject* parent) |
953 | + : QObject(parent), |
954 | + d_ptr(new GreeterPrivate(this)) |
955 | +{ |
956 | + Q_D(Greeter); |
957 | + |
958 | + connect(d->m_greeter, SIGNAL(showMessage(QString, QLightDM::Greeter::MessageType)), |
959 | + this, SLOT(showMessageFilter(QString, QLightDM::Greeter::MessageType))); |
960 | + connect(d->m_greeter, SIGNAL(showPrompt(QString, QLightDM::Greeter::PromptType)), |
961 | + this, SLOT(showPromptFilter(QString, QLightDM::Greeter::PromptType))); |
962 | + connect(d->m_greeter, SIGNAL(authenticationComplete()), |
963 | + this, SLOT(authenticationCompleteFilter())); |
964 | + |
965 | + d->m_greeter->connectSync(); |
966 | +} |
967 | + |
968 | +bool Greeter::isAuthenticated() const |
969 | +{ |
970 | + Q_D(const Greeter); |
971 | + return d->m_greeter->isAuthenticated(); |
972 | +} |
973 | + |
974 | +QString Greeter::authenticationUser() const |
975 | +{ |
976 | + Q_D(const Greeter); |
977 | + return d->m_greeter->authenticationUser(); |
978 | +} |
979 | + |
980 | +bool Greeter::promptless() const |
981 | +{ |
982 | + Q_D(const Greeter); |
983 | + return d->promptless; |
984 | +} |
985 | + |
986 | +void Greeter::authenticate(const QString &username) |
987 | +{ |
988 | + Q_D(Greeter); |
989 | + d->wasPrompted = false; |
990 | + if (d->promptless) { |
991 | + d->promptless = false; |
992 | + Q_EMIT promptlessChanged(); |
993 | + } |
994 | + |
995 | + d->m_greeter->authenticate(username); |
996 | +} |
997 | + |
998 | +void Greeter::respond(const QString &response) |
999 | +{ |
1000 | + Q_D(Greeter); |
1001 | + d->m_greeter->respond(response); |
1002 | +} |
1003 | + |
1004 | +bool Greeter::startSessionSync(const QString &session) |
1005 | +{ |
1006 | + Q_D(Greeter); |
1007 | + return d->m_greeter->startSessionSync(session); |
1008 | +} |
1009 | + |
1010 | +void Greeter::showPromptFilter(QString text, QLightDM::Greeter::PromptType type) |
1011 | +{ |
1012 | + Q_D(Greeter); |
1013 | + d->wasPrompted = true; |
1014 | + |
1015 | + // Strip prompt of any colons at the end |
1016 | + text = text.trimmed(); |
1017 | + if (text.endsWith(":") || text.endsWith("ïŒ")) { |
1018 | + text.chop(1); |
1019 | + } |
1020 | + |
1021 | + Q_EMIT showPrompt(text, type == QLightDM::Greeter::PromptTypeSecret); |
1022 | +} |
1023 | + |
1024 | +void Greeter::showMessageFilter(QString text, QLightDM::Greeter::MessageType type) |
1025 | +{ |
1026 | + Q_EMIT showMessage(text, type == QLightDM::Greeter::MessageTypeError); |
1027 | +} |
1028 | + |
1029 | +void Greeter::authenticationCompleteFilter() |
1030 | +{ |
1031 | + Q_D(Greeter); |
1032 | + if (!d->wasPrompted) { |
1033 | + d->promptless = true; |
1034 | + Q_EMIT promptlessChanged(); |
1035 | + } |
1036 | + |
1037 | + Q_EMIT authenticationComplete(); |
1038 | +} |
1039 | |
1040 | === added file 'plugins/LightDM/greeter.h' |
1041 | --- plugins/LightDM/greeter.h 1970-01-01 00:00:00 +0000 |
1042 | +++ plugins/LightDM/greeter.h 2013-05-10 12:09:35 +0000 |
1043 | @@ -0,0 +1,70 @@ |
1044 | +/* |
1045 | + * Copyright (C) 2012,2013 Canonical, Ltd. |
1046 | + * |
1047 | + * This program is free software; you can redistribute it and/or modify |
1048 | + * it under the terms of the GNU General Public License as published by |
1049 | + * the Free Software Foundation; version 3. |
1050 | + * |
1051 | + * This program is distributed in the hope that it will be useful, |
1052 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1053 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1054 | + * GNU General Public License for more details. |
1055 | + * |
1056 | + * You should have received a copy of the GNU General Public License |
1057 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1058 | + * |
1059 | + * Authors: Michael Terry <michael.terry@canonical.com> |
1060 | + */ |
1061 | + |
1062 | +/* This class is a really tiny filter around QLightDM::Greeter. There are some |
1063 | + operations that we want to edit a bit for the benefit of Qml. Specifically, |
1064 | + we want to chop colons off of any password prompts. But there may be more |
1065 | + such edits in the future, and by inserting ourselves here, we have more |
1066 | + control. */ |
1067 | + |
1068 | +#ifndef GREETER_H |
1069 | +#define GREETER_H |
1070 | + |
1071 | +#include "lightdm-greeter.h" |
1072 | +#include <QtCore/QObject> |
1073 | + |
1074 | +class GreeterPrivate; |
1075 | + |
1076 | +class Greeter : public QObject |
1077 | +{ |
1078 | + Q_OBJECT |
1079 | + |
1080 | + Q_PROPERTY(bool authenticated READ isAuthenticated) |
1081 | + Q_PROPERTY(QString authenticationUser READ authenticationUser) |
1082 | + Q_PROPERTY(bool promptless READ promptless NOTIFY promptlessChanged) |
1083 | + |
1084 | +public: |
1085 | + explicit Greeter(QObject* parent=0); |
1086 | + |
1087 | + bool isAuthenticated() const; |
1088 | + QString authenticationUser() const; |
1089 | + bool promptless() const; |
1090 | + |
1091 | +public Q_SLOTS: |
1092 | + void authenticate(const QString &username=QString()); |
1093 | + void respond(const QString &response); |
1094 | + bool startSessionSync(const QString &session=QString()); |
1095 | + |
1096 | +Q_SIGNALS: |
1097 | + void showMessage(QString text, bool isError); |
1098 | + void showPrompt(QString text, bool isSecret); |
1099 | + void authenticationComplete(); |
1100 | + void promptlessChanged(); |
1101 | + |
1102 | +private: |
1103 | + GreeterPrivate * const d_ptr; |
1104 | + |
1105 | + Q_DECLARE_PRIVATE(Greeter) |
1106 | + |
1107 | +private Q_SLOTS: |
1108 | + void showMessageFilter(QString text, QLightDM::Greeter::MessageType type); |
1109 | + void showPromptFilter(QString text, QLightDM::Greeter::PromptType type); |
1110 | + void authenticationCompleteFilter(); |
1111 | +}; |
1112 | + |
1113 | +#endif |
1114 | |
1115 | === added file 'plugins/LightDM/infographicmodel.cpp' |
1116 | --- plugins/LightDM/infographicmodel.cpp 1970-01-01 00:00:00 +0000 |
1117 | +++ plugins/LightDM/infographicmodel.cpp 2013-05-10 12:09:35 +0000 |
1118 | @@ -0,0 +1,21 @@ |
1119 | +/* |
1120 | + * Copyright (C) 2012,2013 Canonical, Ltd. |
1121 | + * |
1122 | + * This program is free software; you can redistribute it and/or modify |
1123 | + * it under the terms of the GNU General Public License as published by |
1124 | + * the Free Software Foundation; version 3. |
1125 | + * |
1126 | + * This program is distributed in the hope that it will be useful, |
1127 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1128 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1129 | + * GNU General Public License for more details. |
1130 | + * |
1131 | + * You should have received a copy of the GNU General Public License |
1132 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1133 | + * |
1134 | + * Authors: Pete Woods <pete.woods@canonical.com> |
1135 | + */ |
1136 | + |
1137 | +#include "infographicmodel.h" |
1138 | + |
1139 | +#include "infographicmodel.moc" |
1140 | |
1141 | === added file 'plugins/LightDM/infographicmodel.h' |
1142 | --- plugins/LightDM/infographicmodel.h 1970-01-01 00:00:00 +0000 |
1143 | +++ plugins/LightDM/infographicmodel.h 2013-05-10 12:09:35 +0000 |
1144 | @@ -0,0 +1,26 @@ |
1145 | +/* |
1146 | + * Copyright (C) 2012,2013 Canonical, Ltd. |
1147 | + * |
1148 | + * This program is free software; you can redistribute it and/or modify |
1149 | + * it under the terms of the GNU General Public License as published by |
1150 | + * the Free Software Foundation; version 3. |
1151 | + * |
1152 | + * This program is distributed in the hope that it will be useful, |
1153 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1154 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1155 | + * GNU General Public License for more details. |
1156 | + * |
1157 | + * You should have received a copy of the GNU General Public License |
1158 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1159 | + * |
1160 | + * Authors: Pete Woods <pete.woods@canonical.com> |
1161 | + */ |
1162 | + |
1163 | +#ifndef INFOGRAPHICMODEL_H |
1164 | +#define INFOGRAPHICMODEL_H |
1165 | + |
1166 | +#include "lightdm-infographicmodel.h" |
1167 | + |
1168 | +typedef QLightDM::InfographicModel InfographicModel; |
1169 | + |
1170 | +#endif |
1171 | |
1172 | === added file 'plugins/LightDM/lightdm-greeter.cpp' |
1173 | --- plugins/LightDM/lightdm-greeter.cpp 1970-01-01 00:00:00 +0000 |
1174 | +++ plugins/LightDM/lightdm-greeter.cpp 2013-05-10 12:09:35 +0000 |
1175 | @@ -0,0 +1,195 @@ |
1176 | +/* |
1177 | + * Copyright (C) 2013 Canonical, Ltd. |
1178 | + * |
1179 | + * This program is free software; you can redistribute it and/or modify |
1180 | + * it under the terms of the GNU General Public License as published by |
1181 | + * the Free Software Foundation; version 3. |
1182 | + * |
1183 | + * This program is distributed in the hope that it will be useful, |
1184 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1185 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1186 | + * GNU General Public License for more details. |
1187 | + * |
1188 | + * You should have received a copy of the GNU General Public License |
1189 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1190 | + * |
1191 | + * Author: Michael Terry <michael.terry@canonical.com> |
1192 | + */ |
1193 | + |
1194 | +#include "lightdm-greeter.h" |
1195 | +#include <QtCore/QCoreApplication> |
1196 | + |
1197 | +namespace QLightDM |
1198 | +{ |
1199 | + |
1200 | +class GreeterPrivate |
1201 | +{ |
1202 | +public: |
1203 | + explicit GreeterPrivate(Greeter *parent); |
1204 | + |
1205 | + bool authenticated; |
1206 | + QString authenticationUser; |
1207 | + |
1208 | +protected: |
1209 | + Greeter * const q_ptr; |
1210 | + |
1211 | +private: |
1212 | + Q_DECLARE_PUBLIC(Greeter) |
1213 | +}; |
1214 | + |
1215 | +GreeterPrivate::GreeterPrivate(Greeter* parent) |
1216 | + : authenticated(false), |
1217 | + authenticationUser(), |
1218 | + q_ptr(parent) |
1219 | +{ |
1220 | +} |
1221 | + |
1222 | +Greeter::Greeter(QObject *parent) |
1223 | + : QObject(parent), |
1224 | + d_ptr(new GreeterPrivate(this)) |
1225 | +{ |
1226 | +} |
1227 | + |
1228 | +Greeter::~Greeter() |
1229 | +{ |
1230 | +} |
1231 | + |
1232 | +QString Greeter::authenticationUser() const |
1233 | +{ |
1234 | + Q_D(const Greeter); |
1235 | + return d->authenticationUser; |
1236 | +} |
1237 | + |
1238 | +bool Greeter::hasGuestAccountHint() const |
1239 | +{ |
1240 | + return true; |
1241 | +} |
1242 | + |
1243 | +QString Greeter::getHint(const QString &name) const |
1244 | +{ |
1245 | + Q_UNUSED(name) |
1246 | + return ""; |
1247 | +} |
1248 | + |
1249 | +QString Greeter::defaultSessionHint() const |
1250 | +{ |
1251 | + return "ubuntu"; |
1252 | +} |
1253 | + |
1254 | +bool Greeter::hideUsersHint() const |
1255 | +{ |
1256 | + return false; |
1257 | +} |
1258 | + |
1259 | +bool Greeter::showManualLoginHint() const |
1260 | +{ |
1261 | + return true; |
1262 | +} |
1263 | + |
1264 | +bool Greeter::showRemoteLoginHint() const |
1265 | +{ |
1266 | + return true; |
1267 | +} |
1268 | + |
1269 | +bool Greeter::lockHint () const |
1270 | +{ |
1271 | + return false; |
1272 | +} |
1273 | + |
1274 | +QString Greeter::selectUserHint() const |
1275 | +{ |
1276 | + return ""; |
1277 | +} |
1278 | + |
1279 | +bool Greeter::selectGuestHint() const |
1280 | +{ |
1281 | + return false; |
1282 | +} |
1283 | + |
1284 | +QString Greeter::autologinUserHint() const |
1285 | +{ |
1286 | + return ""; |
1287 | +} |
1288 | + |
1289 | +bool Greeter::autologinGuestHint() const |
1290 | +{ |
1291 | + return false; |
1292 | +} |
1293 | + |
1294 | +int Greeter::autologinTimeoutHint() const |
1295 | +{ |
1296 | + return 0; |
1297 | +} |
1298 | + |
1299 | +bool Greeter::inAuthentication() const |
1300 | +{ |
1301 | + return false; |
1302 | +} |
1303 | + |
1304 | +QString Greeter::hostname() const |
1305 | +{ |
1306 | + return "hostname1"; |
1307 | +} |
1308 | + |
1309 | +bool Greeter::isAuthenticated() const |
1310 | +{ |
1311 | + Q_D(const Greeter); |
1312 | + return d->authenticated; |
1313 | +} |
1314 | + |
1315 | +bool Greeter::connectSync() |
1316 | +{ |
1317 | + return true; |
1318 | +} |
1319 | + |
1320 | +void Greeter::authenticate(const QString &username) |
1321 | +{ |
1322 | + Q_D(Greeter); |
1323 | + |
1324 | + d->authenticated = false; |
1325 | + d->authenticationUser = username; |
1326 | + |
1327 | + if (d->authenticationUser == "no-password") { |
1328 | + d->authenticated = true; |
1329 | + Q_EMIT authenticationComplete(); |
1330 | + } else { |
1331 | + Q_EMIT showPrompt("Password: ", PromptTypeSecret); |
1332 | + } |
1333 | +} |
1334 | + |
1335 | +void Greeter::authenticateAsGuest() |
1336 | +{} |
1337 | + |
1338 | +void Greeter::authenticateAutologin() |
1339 | +{} |
1340 | + |
1341 | +void Greeter::authenticateRemote(const QString &session, const QString &username) |
1342 | +{ |
1343 | + Q_UNUSED(session) |
1344 | + Q_UNUSED(username) |
1345 | +} |
1346 | + |
1347 | +void Greeter::cancelAuthentication() |
1348 | +{} |
1349 | + |
1350 | +void Greeter::setLanguage (const QString &language) |
1351 | +{ |
1352 | + Q_UNUSED(language) |
1353 | +} |
1354 | + |
1355 | +bool Greeter::startSessionSync(const QString &session) |
1356 | +{ |
1357 | + Q_UNUSED(session) |
1358 | + QCoreApplication::quit(); |
1359 | + return true; |
1360 | +} |
1361 | + |
1362 | +void Greeter::respond(const QString &response) |
1363 | +{ |
1364 | + Q_D(Greeter); |
1365 | + |
1366 | + d->authenticated = (response == "password"); |
1367 | + Q_EMIT authenticationComplete(); |
1368 | +} |
1369 | + |
1370 | +} |
1371 | |
1372 | === added file 'plugins/LightDM/lightdm-greeter.h' |
1373 | --- plugins/LightDM/lightdm-greeter.h 1970-01-01 00:00:00 +0000 |
1374 | +++ plugins/LightDM/lightdm-greeter.h 2013-05-10 12:09:35 +0000 |
1375 | @@ -0,0 +1,105 @@ |
1376 | +/* |
1377 | + * Copyright (C) 2013 Canonical, Ltd. |
1378 | + * Copyright (C) 2010-2011 David Edmundson. |
1379 | + * Copyright (C) 2010-2011 Robert Ancell |
1380 | + * |
1381 | + * This program is free software; you can redistribute it and/or modify |
1382 | + * it under the terms of the GNU General Public License as published by |
1383 | + * the Free Software Foundation; version 3. |
1384 | + * |
1385 | + * This program is distributed in the hope that it will be useful, |
1386 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1387 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1388 | + * GNU General Public License for more details. |
1389 | + * |
1390 | + * You should have received a copy of the GNU General Public License |
1391 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1392 | + * |
1393 | + * Author: David Edmundson <kde@davidedmundson.co.uk> |
1394 | + */ |
1395 | + |
1396 | +#ifndef LIGHTDM_GREETER_H |
1397 | +#define LIGHTDM_GREETER_H |
1398 | + |
1399 | +#include <QtCore/QObject> |
1400 | +#include <QtCore/QVariant> |
1401 | + |
1402 | + |
1403 | +namespace QLightDM |
1404 | +{ |
1405 | + class GreeterPrivate; |
1406 | + |
1407 | +class Q_DECL_EXPORT Greeter : public QObject |
1408 | +{ |
1409 | + Q_OBJECT |
1410 | + |
1411 | + Q_PROPERTY(bool authenticated READ isAuthenticated ) //NOTFIY authenticationComplete |
1412 | + Q_PROPERTY(QString authenticationUser READ authenticationUser ) |
1413 | + Q_PROPERTY(QString defaultSession READ defaultSessionHint CONSTANT) |
1414 | + Q_PROPERTY(QString selectUser READ selectUserHint CONSTANT) |
1415 | + Q_PROPERTY(bool selectGuest READ selectGuestHint CONSTANT) |
1416 | + |
1417 | + Q_PROPERTY(QString hostname READ hostname CONSTANT) |
1418 | + Q_PROPERTY(bool hasGuestAccount READ hasGuestAccountHint CONSTANT) |
1419 | + Q_PROPERTY(bool locked READ lockHint CONSTANT) |
1420 | + |
1421 | + Q_PROPERTY(QString hostname READ hostname CONSTANT) |
1422 | + |
1423 | + Q_ENUMS(PromptType MessageType) |
1424 | + |
1425 | +public: |
1426 | + enum PromptType { |
1427 | + PromptTypeQuestion, |
1428 | + PromptTypeSecret |
1429 | + }; |
1430 | + |
1431 | + enum MessageType { |
1432 | + MessageTypeInfo, |
1433 | + MessageTypeError |
1434 | + }; |
1435 | + |
1436 | + explicit Greeter(QObject* parent=0); |
1437 | + virtual ~Greeter(); |
1438 | + |
1439 | + QString getHint(const QString &name) const; |
1440 | + QString defaultSessionHint() const; |
1441 | + bool hideUsersHint() const; |
1442 | + bool showManualLoginHint() const; |
1443 | + bool showRemoteLoginHint() const; |
1444 | + bool lockHint () const; |
1445 | + bool hasGuestAccountHint() const; |
1446 | + QString selectUserHint() const; |
1447 | + bool selectGuestHint() const; |
1448 | + QString autologinUserHint() const; |
1449 | + bool autologinGuestHint() const; |
1450 | + int autologinTimeoutHint() const; |
1451 | + |
1452 | + bool inAuthentication() const; |
1453 | + bool isAuthenticated() const; |
1454 | + QString authenticationUser() const; |
1455 | + QString hostname() const; |
1456 | + |
1457 | +public Q_SLOTS: |
1458 | + bool connectSync(); |
1459 | + void authenticate(const QString &username=QString()); |
1460 | + void authenticateAsGuest(); |
1461 | + void authenticateAutologin(); |
1462 | + void authenticateRemote(const QString &session=QString(), const QString &username=QString()); |
1463 | + void respond(const QString &response); |
1464 | + void cancelAuthentication(); |
1465 | + void setLanguage (const QString &language); |
1466 | + bool startSessionSync(const QString &session=QString()); |
1467 | + |
1468 | +Q_SIGNALS: |
1469 | + void showMessage(QString text, QLightDM::Greeter::MessageType type); |
1470 | + void showPrompt(QString text, QLightDM::Greeter::PromptType type); |
1471 | + void authenticationComplete(); |
1472 | + void autologinTimerExpired(); |
1473 | + |
1474 | +private: |
1475 | + GreeterPrivate *d_ptr; |
1476 | + Q_DECLARE_PRIVATE(Greeter) |
1477 | +}; |
1478 | +} |
1479 | + |
1480 | +#endif // LIGHTDM_GREETER_H |
1481 | |
1482 | === added file 'plugins/LightDM/lightdm-infographicmodel.cpp' |
1483 | --- plugins/LightDM/lightdm-infographicmodel.cpp 1970-01-01 00:00:00 +0000 |
1484 | +++ plugins/LightDM/lightdm-infographicmodel.cpp 2013-05-10 12:09:35 +0000 |
1485 | @@ -0,0 +1,370 @@ |
1486 | +/* |
1487 | + * Copyright (C) 2013 Canonical, Ltd. |
1488 | + * |
1489 | + * This program is free software; you can redistribute it and/or modify |
1490 | + * it under the terms of the GNU General Public License as published by |
1491 | + * the Free Software Foundation; version 3. |
1492 | + * |
1493 | + * This program is distributed in the hope that it will be useful, |
1494 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1495 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1496 | + * GNU General Public License for more details. |
1497 | + * |
1498 | + * You should have received a copy of the GNU General Public License |
1499 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1500 | + * |
1501 | + * Author: Pete Woods <pete.woods@canonical.com> |
1502 | + */ |
1503 | + |
1504 | +// LightDM currently is Qt4 compatible, and so doesn't define setRoleNames. |
1505 | +// To use the same method of setting role name that it does, we |
1506 | +// set our compatibility to Qt4 here too. |
1507 | +#define QT_DISABLE_DEPRECATED_BEFORE QT_VERSION_CHECK(4, 0, 0) |
1508 | + |
1509 | +#include "lightdm-infographicmodel.h" |
1510 | +#include <QtCore/QDebug> |
1511 | +#include <QtCore/QDir> |
1512 | +#include <QtCore/QString> |
1513 | +#include <QtGui/QIcon> |
1514 | + |
1515 | +#include <QMultiMap> |
1516 | + |
1517 | +#include <random> |
1518 | +#include <iostream> |
1519 | + |
1520 | +using namespace QLightDM; |
1521 | + |
1522 | +namespace QLightDM |
1523 | +{ |
1524 | + |
1525 | +class InfographicData |
1526 | +{ |
1527 | +public: |
1528 | + explicit InfographicData(QObject *parent); |
1529 | + |
1530 | + explicit InfographicData(QString label, QColor first_color, |
1531 | + QVariantList &first_month, QColor second_color, |
1532 | + QVariantList &second_month, QObject *parent); |
1533 | + |
1534 | +public: |
1535 | + QObject * const q_ptr; |
1536 | + QString label; |
1537 | + QColor first_color; |
1538 | + QVariantListModel first_month; |
1539 | + QColor second_color; |
1540 | + QVariantListModel second_month; |
1541 | + |
1542 | +private: |
1543 | + Q_DECLARE_PUBLIC(QObject) |
1544 | +}; |
1545 | + |
1546 | +class InfographicModelPrivate: QObject |
1547 | +{ |
1548 | +Q_OBJECT |
1549 | + |
1550 | +public: |
1551 | + explicit InfographicModelPrivate(InfographicModel *parent); |
1552 | + |
1553 | + void generateFakeData(); |
1554 | + |
1555 | + void nextFakeData(); |
1556 | + |
1557 | +protected: |
1558 | + InfographicModel * const q_ptr; |
1559 | + InfographicData data; |
1560 | + int current_day; |
1561 | + QString username; |
1562 | + int data_index; |
1563 | + QMultiMap<QString, QSharedPointer<InfographicData>> fake_data; |
1564 | + QSharedPointer<InfographicData> empty_data; |
1565 | + |
1566 | +protected: |
1567 | + void setFakeData(int data_index); |
1568 | + |
1569 | +private: |
1570 | + Q_DECLARE_PUBLIC(InfographicModel) |
1571 | +}; |
1572 | +} |
1573 | + |
1574 | +InfographicData::InfographicData(QObject *parent) : |
1575 | + q_ptr(parent) |
1576 | +{ |
1577 | +} |
1578 | + |
1579 | +InfographicData::InfographicData(QString label, QColor first_color, |
1580 | + QVariantList &first_month, QColor second_color, |
1581 | + QVariantList &second_month, QObject* parent) : |
1582 | + q_ptr(parent), label(label), first_color(first_color), first_month( |
1583 | + first_month, parent), second_color(second_color), second_month( |
1584 | + second_month, parent) |
1585 | +{ |
1586 | +} |
1587 | + |
1588 | +InfographicModelPrivate::InfographicModelPrivate(InfographicModel *parent) : |
1589 | + q_ptr(parent), data(this), current_day(0) |
1590 | +{ |
1591 | + generateFakeData(); |
1592 | + setFakeData(0); |
1593 | +} |
1594 | + |
1595 | +void InfographicModelPrivate::generateFakeData() |
1596 | +{ |
1597 | + std::default_random_engine generator; |
1598 | + std::normal_distribution<qreal> distribution(0.5, 0.2); |
1599 | + auto rand = std::bind(distribution, generator); |
1600 | + |
1601 | + QColor orange = QColor::fromRgbF(0.9, 0.3, 0.1, 1.0); |
1602 | + QColor yellow = QColor::fromRgbF(1.0, 0.6, 0.0, 1.0); |
1603 | + QColor red = QColor::fromRgbF(0.8, 0.0, 0.0, 1.0); |
1604 | + QColor dark_purple = QColor::fromRgbF(0.5, 0.2, 0.3, 1.0); |
1605 | + QColor light_purple = QColor::fromRgbF(0.8, 0.1, 0.8, 1.0); |
1606 | + |
1607 | + { |
1608 | + QVariantList month; |
1609 | + QColor black; |
1610 | + empty_data.reset( |
1611 | + new InfographicData("", black, month, black, month, this)); |
1612 | + } |
1613 | + |
1614 | + { |
1615 | + QVariantList first_month( { 0.1, 0.2, 0.4, 0.6, 0.1, 0.2 }); |
1616 | + while (first_month.size() < 31) |
1617 | + first_month.push_back(QVariant()); |
1618 | + QVariantList second_month; |
1619 | + while (second_month.size() < 31) |
1620 | + second_month.push_back(QVariant(rand())); |
1621 | + QSharedPointer<InfographicData> data( |
1622 | + new InfographicData("Wow, you've walked <b>5</b>kms today", |
1623 | + yellow, first_month, orange, second_month, this)); |
1624 | + fake_data.insert("phablet", data); |
1625 | + } |
1626 | + |
1627 | + { |
1628 | + QVariantList first_month( |
1629 | + { 0.1, 0.2, 1.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.7, 0.8, 0.2, 0.3, |
1630 | + 0.4, 0.2, 0.3, 0.4, 0.5, 0.7, 0.8, 0.5, 0.7, 0.8 }); |
1631 | + while (first_month.size() < 31) |
1632 | + first_month.push_back(QVariant()); |
1633 | + QVariantList second_month; |
1634 | + while (second_month.size() < 31) |
1635 | + second_month.push_back(QVariant(rand())); |
1636 | + QSharedPointer<InfographicData> data( |
1637 | + new InfographicData("You've received <b>15</b> messages today", |
1638 | + orange, first_month, red, second_month, this)); |
1639 | + fake_data.insert("phablet", data); |
1640 | + } |
1641 | + |
1642 | + { |
1643 | + QVariantList first_month( { 0.1, 0.2, 1.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.7, |
1644 | + 0.8, 0.9, 1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1 }); |
1645 | + while (first_month.size() < 31) |
1646 | + first_month.push_back(QVariant()); |
1647 | + QVariantList second_month; |
1648 | + while (second_month.size() < 31) |
1649 | + second_month.push_back(QVariant(rand())); |
1650 | + QSharedPointer<InfographicData> data( |
1651 | + new InfographicData("Klout score of <b>50.20</b>", light_purple, |
1652 | + first_month, dark_purple, second_month, this)); |
1653 | + fake_data.insert("phablet", data); |
1654 | + } |
1655 | + |
1656 | + { |
1657 | + QVariantList first_month( { 0.1, 0.2, 1.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.7, |
1658 | + 0.8, 1.0, 0.2, 0.6, 0.1, 0.8 }); |
1659 | + while (first_month.size() < 31) |
1660 | + first_month.push_back(QVariant(rand())); |
1661 | + QVariantList second_month; |
1662 | + while (second_month.size() < 31) |
1663 | + second_month.push_back(QVariant(rand())); |
1664 | + QSharedPointer<InfographicData> data( |
1665 | + new InfographicData("<b>1</b>hr watching videos today", red, |
1666 | + first_month, dark_purple, second_month, this)); |
1667 | + fake_data.insert("phablet", data); |
1668 | + } |
1669 | + |
1670 | + { |
1671 | + QVariantList first_month; |
1672 | + while (first_month.size() < 5) |
1673 | + first_month.push_back(QVariant(rand())); |
1674 | + while (first_month.size() < 31) |
1675 | + first_month.push_back(QVariant()); |
1676 | + QVariantList second_month; |
1677 | + while (second_month.size() < 31) |
1678 | + second_month.push_back(QVariant(rand())); |
1679 | + QSharedPointer<InfographicData> data( |
1680 | + new InfographicData("<b>4</b>hrs watching videos today", red, |
1681 | + first_month, dark_purple, second_month, this)); |
1682 | + fake_data.insert("anna", data); |
1683 | + } |
1684 | + |
1685 | + { |
1686 | + QVariantList first_month; |
1687 | + while (first_month.size() < 20) |
1688 | + first_month.push_back(QVariant(rand())); |
1689 | + while (first_month.size() < 31) |
1690 | + first_month.push_back(QVariant()); |
1691 | + QVariantList second_month; |
1692 | + while (second_month.size() < 31) |
1693 | + second_month.push_back(QVariant(rand())); |
1694 | + QSharedPointer<InfographicData> data( |
1695 | + new InfographicData("You've received <b>23</b> messages today", |
1696 | + orange, first_month, red, second_month, this)); |
1697 | + fake_data.insert("anna", data); |
1698 | + } |
1699 | + |
1700 | + { |
1701 | + QVariantList first_month; |
1702 | + while (first_month.size() < 2) |
1703 | + first_month.push_back(QVariant(rand())); |
1704 | + while (first_month.size() < 31) |
1705 | + first_month.push_back(QVariant()); |
1706 | + QVariantList second_month; |
1707 | + while (second_month.size() < 31) |
1708 | + second_month.push_back(QVariant(rand())); |
1709 | + QSharedPointer<InfographicData> data( |
1710 | + new InfographicData("<b>8</b>hrs watching videos today", red, |
1711 | + first_month, dark_purple, second_month, this)); |
1712 | + fake_data.insert("lois", data); |
1713 | + } |
1714 | + |
1715 | + { |
1716 | + QVariantList first_month; |
1717 | + while (first_month.size() < 29) |
1718 | + first_month.push_back(QVariant(rand())); |
1719 | + while (first_month.size() < 31) |
1720 | + first_month.push_back(QVariant()); |
1721 | + QVariantList second_month; |
1722 | + while (second_month.size() < 31) |
1723 | + second_month.push_back(QVariant(rand())); |
1724 | + QSharedPointer<InfographicData> data( |
1725 | + new InfographicData("<b>2</b>hrs watching videos today", red, |
1726 | + first_month, dark_purple, second_month, this)); |
1727 | + fake_data.insert("toomas", data); |
1728 | + } |
1729 | + |
1730 | + { |
1731 | + QVariantList first_month; |
1732 | + while (first_month.size() < 15) |
1733 | + first_month.push_back(QVariant(rand())); |
1734 | + while (first_month.size() < 31) |
1735 | + first_month.push_back(QVariant()); |
1736 | + QVariantList second_month; |
1737 | + while (second_month.size() < 31) |
1738 | + second_month.push_back(QVariant(rand())); |
1739 | + QSharedPointer<InfographicData> data( |
1740 | + new InfographicData("<b>6</b>hrs watching videos today", red, |
1741 | + first_month, dark_purple, second_month, this)); |
1742 | + fake_data.insert("empty-name", data); |
1743 | + } |
1744 | +} |
1745 | + |
1746 | +void InfographicModelPrivate::setFakeData(int new_index) |
1747 | +{ |
1748 | + std::cout << "Data sets for user " << username.toStdString() << " = " |
1749 | + << fake_data.values(username).size() << ", index = " << new_index |
1750 | + << std::endl; |
1751 | + |
1752 | + QSharedPointer<InfographicData> new_data; |
1753 | + |
1754 | + if (!fake_data.contains(username)) |
1755 | + { |
1756 | + data_index = 0; |
1757 | + new_data = empty_data; |
1758 | + } else |
1759 | + { |
1760 | + data_index = new_index; |
1761 | + new_data = fake_data.values(username).at(data_index); |
1762 | + } |
1763 | + |
1764 | + data.label = new_data->label; |
1765 | + data.first_color = new_data->first_color; |
1766 | + data.first_month.setVariantList(new_data->first_month.variantList()); |
1767 | + data.second_color = new_data->second_color; |
1768 | + data.second_month.setVariantList(new_data->second_month.variantList()); |
1769 | + |
1770 | + QVariantListModel &first_month(data.first_month); |
1771 | + |
1772 | + for (int i(first_month.rowCount()); i != 0; --i) |
1773 | + { |
1774 | + if (!first_month.data(first_month.index(i), Qt::DisplayRole).isNull()) |
1775 | + { |
1776 | + current_day = i; |
1777 | + break; |
1778 | + } |
1779 | + |
1780 | + } |
1781 | + |
1782 | + q_ptr->labelChanged(data.label); |
1783 | + q_ptr->firstColorChanged(data.first_color); |
1784 | + q_ptr->secondColorChanged(data.second_color); |
1785 | + q_ptr->currentDayChanged(current_day); |
1786 | +} |
1787 | + |
1788 | +void InfographicModelPrivate::nextFakeData() |
1789 | +{ |
1790 | + if (!fake_data.contains(username)) |
1791 | + { |
1792 | + return; |
1793 | + } |
1794 | + |
1795 | + setFakeData((data_index + 1) % fake_data.values(username).size()); |
1796 | +} |
1797 | + |
1798 | +InfographicModel::InfographicModel(QObject *parent) : |
1799 | + QObject(parent), d_ptr(new InfographicModelPrivate(this)) |
1800 | +{ |
1801 | +} |
1802 | + |
1803 | +InfographicModel::~InfographicModel() |
1804 | +{ |
1805 | + delete d_ptr; |
1806 | +} |
1807 | + |
1808 | +QString InfographicModel::label() const |
1809 | +{ |
1810 | + return d_ptr->data.label; |
1811 | +} |
1812 | + |
1813 | +QString InfographicModel::username() const |
1814 | +{ |
1815 | + return d_ptr->username; |
1816 | +} |
1817 | + |
1818 | +void InfographicModel::setUsername(const QString &username) |
1819 | +{ |
1820 | + d_ptr->username = username; |
1821 | + d_ptr->setFakeData(0); |
1822 | + usernameChanged(d_ptr->username); |
1823 | +} |
1824 | + |
1825 | +QColor InfographicModel::firstColor() const |
1826 | +{ |
1827 | + return d_ptr->data.first_color; |
1828 | +} |
1829 | + |
1830 | +QColor InfographicModel::secondColor() const |
1831 | +{ |
1832 | + return d_ptr->data.second_color; |
1833 | +} |
1834 | + |
1835 | +QAbstractItemModel * InfographicModel::firstMonth() const |
1836 | +{ |
1837 | + return &d_ptr->data.first_month; |
1838 | +} |
1839 | + |
1840 | +QAbstractItemModel * InfographicModel::secondMonth() const |
1841 | +{ |
1842 | + return &d_ptr->data.second_month; |
1843 | +} |
1844 | + |
1845 | +int InfographicModel::currentDay() const |
1846 | +{ |
1847 | + return d_ptr->current_day; |
1848 | +} |
1849 | + |
1850 | +void InfographicModel::nextDataSource() |
1851 | +{ |
1852 | + d_ptr->nextFakeData(); |
1853 | +} |
1854 | +#include "lightdm-infographicmodel.moc" |
1855 | + |
1856 | |
1857 | === added file 'plugins/LightDM/lightdm-infographicmodel.h' |
1858 | --- plugins/LightDM/lightdm-infographicmodel.h 1970-01-01 00:00:00 +0000 |
1859 | +++ plugins/LightDM/lightdm-infographicmodel.h 2013-05-10 12:09:35 +0000 |
1860 | @@ -0,0 +1,95 @@ |
1861 | +/* |
1862 | + * Copyright (C) 2013 Canonical, Ltd. |
1863 | + * Copyright (C) 2010-2011 David Edmundson. |
1864 | + * |
1865 | + * This program is free software; you can redistribute it and/or modify |
1866 | + * it under the terms of the GNU General Public License as published by |
1867 | + * the Free Software Foundation; version 3. |
1868 | + * |
1869 | + * This program is distributed in the hope that it will be useful, |
1870 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1871 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1872 | + * GNU General Public License for more details. |
1873 | + * |
1874 | + * You should have received a copy of the GNU General Public License |
1875 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1876 | + * |
1877 | + * Author: Pete Woods <pete.woods@canonical.com> |
1878 | + */ |
1879 | + |
1880 | +#ifndef LIGHTDM_INFOGRAPHICMODEL_H |
1881 | +#define LIGHTDM_INFOGRAPHICMODEL_H |
1882 | + |
1883 | +#include <QtCore/QString> |
1884 | +#include <QtGui/qcolor.h> |
1885 | +#include <QtCore/QSharedDataPointer> |
1886 | +#include <QAbstractListModel> |
1887 | + |
1888 | +#include "qvariantlistmodel.h" |
1889 | + |
1890 | +namespace QLightDM |
1891 | +{ |
1892 | +class InfographicModelPrivate; |
1893 | + |
1894 | +class Q_DECL_EXPORT InfographicModel : public QObject |
1895 | +{ |
1896 | + Q_OBJECT |
1897 | + |
1898 | + Q_PROPERTY(QString label READ label NOTIFY labelChanged FINAL) |
1899 | + Q_PROPERTY(QString username READ username WRITE setUsername NOTIFY usernameChanged FINAL) |
1900 | + Q_PROPERTY(QColor firstColor READ firstColor NOTIFY firstColorChanged FINAL) |
1901 | + Q_PROPERTY(QColor secondColor READ secondColor NOTIFY secondColorChanged FINAL) |
1902 | + Q_PROPERTY(QAbstractItemModel *firstMonth READ firstMonth NOTIFY firstMonthChanged FINAL) |
1903 | + Q_PROPERTY(QAbstractItemModel *secondMonth READ secondMonth NOTIFY secondMonthChanged FINAL) |
1904 | + Q_PROPERTY(int currentDay READ currentDay NOTIFY currentDayChanged FINAL) |
1905 | + |
1906 | +public: |
1907 | + explicit InfographicModel(QObject *parent = 0); |
1908 | + ~InfographicModel(); |
1909 | + |
1910 | + QString label() const; |
1911 | + |
1912 | + QString username() const; |
1913 | + |
1914 | + void setUsername(const QString &username); |
1915 | + |
1916 | + QColor firstColor() const; |
1917 | + |
1918 | + QAbstractItemModel *firstMonth() const; |
1919 | + |
1920 | + int currentDay() const; |
1921 | + |
1922 | + QColor secondColor() const; |
1923 | + |
1924 | + QAbstractItemModel *secondMonth() const; |
1925 | + |
1926 | +Q_SIGNALS: |
1927 | + void labelChanged(const QString &label); |
1928 | + |
1929 | + void usernameChanged(const QString &username); |
1930 | + |
1931 | + void firstColorChanged(const QColor &color); |
1932 | + |
1933 | + void firstMonthChanged(QAbstractItemModel *first_month); |
1934 | + |
1935 | + void currentDayChanged(int length); |
1936 | + |
1937 | + void secondColorChanged(const QColor &color); |
1938 | + |
1939 | + void secondMonthChanged(QAbstractItemModel *second_month); |
1940 | + |
1941 | +public Q_SLOTS: |
1942 | + void nextDataSource(); |
1943 | + |
1944 | +protected: |
1945 | + |
1946 | +private: |
1947 | + InfographicModelPrivate * const d_ptr; |
1948 | + |
1949 | + Q_DECLARE_PRIVATE(InfographicModel) |
1950 | + |
1951 | +}; |
1952 | + |
1953 | +} |
1954 | + |
1955 | +#endif // LIGHTDM_INFOGRAPHICMODEL_H |
1956 | |
1957 | === added file 'plugins/LightDM/lightdm-usersmodel.cpp' |
1958 | --- plugins/LightDM/lightdm-usersmodel.cpp 1970-01-01 00:00:00 +0000 |
1959 | +++ plugins/LightDM/lightdm-usersmodel.cpp 2013-05-10 12:09:35 +0000 |
1960 | @@ -0,0 +1,166 @@ |
1961 | +/* |
1962 | + * Copyright (C) 2013 Canonical, Ltd. |
1963 | + * |
1964 | + * This program is free software; you can redistribute it and/or modify |
1965 | + * it under the terms of the GNU General Public License as published by |
1966 | + * the Free Software Foundation; version 3. |
1967 | + * |
1968 | + * This program is distributed in the hope that it will be useful, |
1969 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1970 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1971 | + * GNU General Public License for more details. |
1972 | + * |
1973 | + * You should have received a copy of the GNU General Public License |
1974 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1975 | + * |
1976 | + * Author: Michael Terry <michael.terry@canonical.com> |
1977 | + */ |
1978 | + |
1979 | +// LightDM currently is Qt4 compatible, and so doesn't define setRoleNames. |
1980 | +// To use the same method of setting role name that it does, we |
1981 | +// set our compatibility to Qt4 here too. |
1982 | +#define QT_DISABLE_DEPRECATED_BEFORE QT_VERSION_CHECK(4, 0, 0) |
1983 | + |
1984 | +#include "lightdm-usersmodel.h" |
1985 | +#include <QtCore/QDebug> |
1986 | +#include <QtCore/QDir> |
1987 | +#include <QtCore/QString> |
1988 | +#include <QtGui/QIcon> |
1989 | + |
1990 | +using namespace QLightDM; |
1991 | + |
1992 | +class Entry |
1993 | +{ |
1994 | +public: |
1995 | + QString username; |
1996 | + QString real_name; |
1997 | + QString background; |
1998 | + QString layouts; |
1999 | + bool is_active; |
2000 | + bool has_messages; |
2001 | + QString session; |
2002 | +}; |
2003 | + |
2004 | +const Entry fake_entries[] = |
2005 | +{ |
2006 | + { "anna", "Anna Olson", "*", 0, false, false, 0 }, |
2007 | + { "lois", "Lois Mcqueen", "*", 0, false, false, 0 }, |
2008 | + { "lola", "Lola Chang", "*", 0, false, false, 0 }, |
2009 | + { "toomas", "Toomas Vilms", "*", 0, false, false, 0 }, |
2010 | + { "empty-name", "", "*", 0, false, false, 0 }, |
2011 | + { "no-password", "Guest", "*", 0, false, false, 0 }, |
2012 | + { "", "", 0, 0, false, false, 0 } |
2013 | +}; |
2014 | + |
2015 | +namespace QLightDM |
2016 | +{ |
2017 | +class UsersModelPrivate |
2018 | +{ |
2019 | +public: |
2020 | + explicit UsersModelPrivate(UsersModel *parent); |
2021 | + QList<Entry> entries; |
2022 | + |
2023 | +protected: |
2024 | + UsersModel * const q_ptr; |
2025 | + void fillEntries(); |
2026 | + |
2027 | +private: |
2028 | + Q_DECLARE_PUBLIC(UsersModel) |
2029 | +}; |
2030 | +} |
2031 | + |
2032 | +UsersModelPrivate::UsersModelPrivate(UsersModel* parent) |
2033 | + : q_ptr(parent) |
2034 | +{ |
2035 | +} |
2036 | + |
2037 | +void UsersModelPrivate::fillEntries() |
2038 | +{ |
2039 | + QDir bgdir = QDir("/usr/share/demo-assets/shell/backgrounds/"); |
2040 | + QStringList backgrounds = bgdir.entryList(QDir::Files | QDir::NoDotAndDotDot); |
2041 | + |
2042 | + for (int i = 0, j = 0; fake_entries[i].username != ""; i++) { |
2043 | + Entry entry = fake_entries[i]; |
2044 | + if (entry.background == "*") { |
2045 | + if (backgrounds.isEmpty()) { |
2046 | + entry.background = ""; // to avoid warnings about a 404 on "*" |
2047 | + } else { |
2048 | + entry.background = bgdir.filePath(backgrounds[j++]); |
2049 | + if (j >= backgrounds.length()) { |
2050 | + j = 0; |
2051 | + } |
2052 | + } |
2053 | + } |
2054 | + entries.append(entry); |
2055 | + } |
2056 | +} |
2057 | + |
2058 | +UsersModel::UsersModel(QObject *parent) : |
2059 | + QAbstractListModel(parent), |
2060 | + d_ptr(new UsersModelPrivate(this)) |
2061 | +{ |
2062 | + Q_D(UsersModel); |
2063 | + // Extend roleNames (we want to keep the "display" role) |
2064 | + QHash<int, QByteArray> roles = roleNames(); |
2065 | + roles[NameRole] = "name"; |
2066 | + roles[RealNameRole] = "realName"; |
2067 | + roles[LoggedInRole] = "loggedIn"; |
2068 | + roles[BackgroundRole] = "background"; |
2069 | + roles[BackgroundPathRole] = "backgroundPath"; |
2070 | + roles[SessionRole] = "session"; |
2071 | + roles[HasMessagesRole] = "hasMessages"; |
2072 | + roles[ImagePathRole] = "imagePath"; |
2073 | + setRoleNames(roles); |
2074 | + d->fillEntries(); |
2075 | +} |
2076 | + |
2077 | +UsersModel::~UsersModel() |
2078 | +{ |
2079 | + delete d_ptr; |
2080 | +} |
2081 | + |
2082 | +int UsersModel::rowCount(const QModelIndex &parent) const |
2083 | +{ |
2084 | + Q_D(const UsersModel); |
2085 | + |
2086 | + if (parent.isValid()) { |
2087 | + return 0; |
2088 | + } else { // parent is root |
2089 | + return d->entries.size(); |
2090 | + } |
2091 | +} |
2092 | + |
2093 | +QVariant UsersModel::data(const QModelIndex &index, int role) const |
2094 | +{ |
2095 | + Q_D(const UsersModel); |
2096 | + |
2097 | + if (!index.isValid()) { |
2098 | + return QVariant(); |
2099 | + } |
2100 | + |
2101 | + int row = index.row(); |
2102 | + switch (role) { |
2103 | + case Qt::DisplayRole: |
2104 | + return d->entries[row].real_name; |
2105 | + case Qt::DecorationRole: |
2106 | + return QIcon(); |
2107 | + case UsersModel::NameRole: |
2108 | + return d->entries[row].username; |
2109 | + case UsersModel::RealNameRole: |
2110 | + return d->entries[row].real_name; |
2111 | + case UsersModel::SessionRole: |
2112 | + return d->entries[row].session; |
2113 | + case UsersModel::LoggedInRole: |
2114 | + return d->entries[row].is_active; |
2115 | + case UsersModel::BackgroundRole: |
2116 | + return QPixmap(d->entries[row].background); |
2117 | + case UsersModel::BackgroundPathRole: |
2118 | + return d->entries[row].background; |
2119 | + case UsersModel::HasMessagesRole: |
2120 | + return d->entries[row].has_messages; |
2121 | + case UsersModel::ImagePathRole: |
2122 | + return ""; |
2123 | + default: |
2124 | + return QVariant(); |
2125 | + } |
2126 | +} |
2127 | |
2128 | === added file 'plugins/LightDM/lightdm-usersmodel.h' |
2129 | --- plugins/LightDM/lightdm-usersmodel.h 1970-01-01 00:00:00 +0000 |
2130 | +++ plugins/LightDM/lightdm-usersmodel.h 2013-05-10 12:09:35 +0000 |
2131 | @@ -0,0 +1,66 @@ |
2132 | +/* |
2133 | + * Copyright (C) 2013 Canonical, Ltd. |
2134 | + * Copyright (C) 2010-2011 David Edmundson. |
2135 | + * |
2136 | + * This program is free software; you can redistribute it and/or modify |
2137 | + * it under the terms of the GNU General Public License as published by |
2138 | + * the Free Software Foundation; version 3. |
2139 | + * |
2140 | + * This program is distributed in the hope that it will be useful, |
2141 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2142 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2143 | + * GNU General Public License for more details. |
2144 | + * |
2145 | + * You should have received a copy of the GNU General Public License |
2146 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2147 | + * |
2148 | + * Author: David Edmundson <kde@davidedmundson.co.uk> |
2149 | + */ |
2150 | + |
2151 | +#ifndef LIGHTDM_USERSMODEL_H |
2152 | +#define LIGHTDM_USERSMODEL_H |
2153 | + |
2154 | +#include <QtCore/QString> |
2155 | +#include <QtCore/QSharedDataPointer> |
2156 | +#include <QAbstractListModel> |
2157 | + |
2158 | + |
2159 | +namespace QLightDM |
2160 | +{ |
2161 | +class UsersModelPrivate; |
2162 | + |
2163 | +class Q_DECL_EXPORT UsersModel : public QAbstractListModel |
2164 | +{ |
2165 | + Q_OBJECT |
2166 | + |
2167 | + Q_ENUMS(UserModelRoles) |
2168 | + |
2169 | +public: |
2170 | + explicit UsersModel(QObject *parent = 0); |
2171 | + ~UsersModel(); |
2172 | + |
2173 | + enum UserModelRoles {NameRole = Qt::UserRole, |
2174 | + RealNameRole, |
2175 | + LoggedInRole, |
2176 | + BackgroundRole, |
2177 | + SessionRole, |
2178 | + HasMessagesRole, |
2179 | + ImagePathRole, |
2180 | + BackgroundPathRole |
2181 | + }; |
2182 | + |
2183 | + int rowCount(const QModelIndex &parent) const; |
2184 | + QVariant data(const QModelIndex &index, int role) const; |
2185 | + |
2186 | +protected: |
2187 | + |
2188 | +private: |
2189 | + UsersModelPrivate * const d_ptr; |
2190 | + |
2191 | + Q_DECLARE_PRIVATE(UsersModel) |
2192 | + |
2193 | +}; |
2194 | + |
2195 | +} |
2196 | + |
2197 | +#endif // LIGHTDM_USERSMODEL_H |
2198 | |
2199 | === added file 'plugins/LightDM/plugin.cpp' |
2200 | --- plugins/LightDM/plugin.cpp 1970-01-01 00:00:00 +0000 |
2201 | +++ plugins/LightDM/plugin.cpp 2013-05-10 12:09:35 +0000 |
2202 | @@ -0,0 +1,57 @@ |
2203 | +/* |
2204 | + * Copyright (C) 2012,2013 Canonical, Ltd. |
2205 | + * |
2206 | + * This program is free software; you can redistribute it and/or modify |
2207 | + * it under the terms of the GNU General Public License as published by |
2208 | + * the Free Software Foundation; version 3. |
2209 | + * |
2210 | + * This program is distributed in the hope that it will be useful, |
2211 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2212 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2213 | + * GNU General Public License for more details. |
2214 | + * |
2215 | + * You should have received a copy of the GNU General Public License |
2216 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2217 | + * |
2218 | + * Authors: Gerry Boland <gerry.boland@canonical.com> |
2219 | + * Michael Terry <michael.terry@canonical.com> |
2220 | + */ |
2221 | + |
2222 | +#include "plugin.h" |
2223 | +#include "greeter.h" |
2224 | +#include "lightdm-usersmodel.h" |
2225 | +#include "usersmodel.h" |
2226 | +#include "infographicmodel.h" |
2227 | +#include <QtCore/QAbstractItemModel> |
2228 | +#include <QtQml> |
2229 | + |
2230 | +static QObject *greeter_provider(QQmlEngine *engine, QJSEngine *scriptEngine) |
2231 | +{ |
2232 | + Q_UNUSED(engine) |
2233 | + Q_UNUSED(scriptEngine) |
2234 | + return new Greeter(); |
2235 | +} |
2236 | + |
2237 | +static QObject *users_provider(QQmlEngine *engine, QJSEngine *scriptEngine) |
2238 | +{ |
2239 | + Q_UNUSED(engine) |
2240 | + Q_UNUSED(scriptEngine) |
2241 | + return new UsersModel(); |
2242 | +} |
2243 | + |
2244 | +static QObject *infographic_provider(QQmlEngine *engine, QJSEngine *scriptEngine) |
2245 | +{ |
2246 | + Q_UNUSED(engine) |
2247 | + Q_UNUSED(scriptEngine) |
2248 | + return new InfographicModel(); |
2249 | +} |
2250 | + |
2251 | +void LightDMPlugin::registerTypes(const char *uri) |
2252 | +{ |
2253 | + Q_ASSERT(uri == QLatin1String("LightDM")); |
2254 | + qmlRegisterSingletonType<Greeter>(uri, 0, 1, "Greeter", greeter_provider); |
2255 | + qmlRegisterSingletonType<UsersModel>(uri, 0, 1, "Users", users_provider); |
2256 | + qmlRegisterUncreatableType<QLightDM::UsersModel>(uri, 0, 1, "UserRoles", "Type is not instantiable"); |
2257 | + qmlRegisterSingletonType<InfographicModel>(uri, 0, 1, "Infographic", infographic_provider); |
2258 | +} |
2259 | + |
2260 | |
2261 | === added file 'plugins/LightDM/plugin.h' |
2262 | --- plugins/LightDM/plugin.h 1970-01-01 00:00:00 +0000 |
2263 | +++ plugins/LightDM/plugin.h 2013-05-10 12:09:35 +0000 |
2264 | @@ -0,0 +1,35 @@ |
2265 | +/* |
2266 | + * Copyright (C) 2012,2013 Canonical, Ltd. |
2267 | + * |
2268 | + * This program is free software; you can redistribute it and/or modify |
2269 | + * it under the terms of the GNU General Public License as published by |
2270 | + * the Free Software Foundation; version 3. |
2271 | + * |
2272 | + * This program is distributed in the hope that it will be useful, |
2273 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2274 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2275 | + * GNU General Public License for more details. |
2276 | + * |
2277 | + * You should have received a copy of the GNU General Public License |
2278 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2279 | + * |
2280 | + * Authors: Gerry Boland <gerry.boland@canonical.com> |
2281 | + * Michael Terry <michael.terry@canonical.com> |
2282 | + */ |
2283 | + |
2284 | +#ifndef LIGHTDM_PLUGIN_H |
2285 | +#define LIGHTDM_PLUGIN_H |
2286 | + |
2287 | +#include <QtQml/QQmlEngine> |
2288 | +#include <QtQml/QQmlExtensionPlugin> |
2289 | + |
2290 | +class LightDMPlugin : public QQmlExtensionPlugin |
2291 | +{ |
2292 | + Q_OBJECT |
2293 | + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") |
2294 | + |
2295 | +public: |
2296 | + void registerTypes(const char *uri); |
2297 | +}; |
2298 | + |
2299 | +#endif |
2300 | |
2301 | === added file 'plugins/LightDM/qmldir' |
2302 | --- plugins/LightDM/qmldir 1970-01-01 00:00:00 +0000 |
2303 | +++ plugins/LightDM/qmldir 2013-05-10 12:09:35 +0000 |
2304 | @@ -0,0 +1,2 @@ |
2305 | +module LightDM |
2306 | +plugin LightDM-qml |
2307 | |
2308 | === added file 'plugins/LightDM/qvariantlistmodel.cpp' |
2309 | --- plugins/LightDM/qvariantlistmodel.cpp 1970-01-01 00:00:00 +0000 |
2310 | +++ plugins/LightDM/qvariantlistmodel.cpp 2013-05-10 12:09:35 +0000 |
2311 | @@ -0,0 +1,243 @@ |
2312 | +/* |
2313 | + A simple model that uses a QVariantList as its data source. |
2314 | +*/ |
2315 | + |
2316 | +// LightDM currently is Qt4 compatible, and so doesn't define setRoleNames. |
2317 | +// To use the same method of setting role name that it does, we |
2318 | +// set our compatibility to Qt4 here too. |
2319 | +#define QT_DISABLE_DEPRECATED_BEFORE QT_VERSION_CHECK(4, 0, 0) |
2320 | + |
2321 | +#include "qvariantlistmodel.h" |
2322 | + |
2323 | +#include <QtCore/qvector.h> |
2324 | + |
2325 | + |
2326 | +/*! |
2327 | + \class QVariantListModel |
2328 | + \inmodule QtCore |
2329 | + \brief The QVariantListModel class provides a model that supplies strings to views. |
2330 | + |
2331 | + \ingroup model-view |
2332 | + |
2333 | + QVariantListModel is an editable model that can be used for simple |
2334 | + cases where you need to display a number of strings in a view |
2335 | + widget, such as a QListView or a QComboBox. |
2336 | + |
2337 | + The model provides all the standard functions of an editable |
2338 | + model, representing the data in the string list as a model with |
2339 | + one column and a number of rows equal to the number of items in |
2340 | + the list. |
2341 | + |
2342 | + Model indexes corresponding to items are obtained with the |
2343 | + \l{QAbstractListModel::index()}{index()} function, and item flags |
2344 | + are obtained with flags(). Item data is read with the data() |
2345 | + function and written with setData(). The number of rows (and |
2346 | + number of items in the string list) can be found with the |
2347 | + rowCount() function. |
2348 | + |
2349 | + The model can be constructed with an existing string list, or |
2350 | + strings can be set later with the setStringList() convenience |
2351 | + function. Strings can also be inserted in the usual way with the |
2352 | + insertRows() function, and removed with removeRows(). The contents |
2353 | + of the string list can be retrieved with the stringList() |
2354 | + convenience function. |
2355 | + |
2356 | + An example usage of QVariantListModel: |
2357 | + |
2358 | + \snippet qvariantlistmodel/main.cpp 0 |
2359 | + |
2360 | + \sa QAbstractListModel, QAbstractItemModel, {Model Classes} |
2361 | +*/ |
2362 | + |
2363 | +/*! |
2364 | + Constructs a variant list model with the given \a parent. |
2365 | +*/ |
2366 | + |
2367 | +QVariantListModel::QVariantListModel(QObject *parent) |
2368 | + : QAbstractListModel(parent) |
2369 | +{ |
2370 | + QHash<int, QByteArray> roles(roleNames()); |
2371 | + roles[Qt::DisplayRole] = "modelData"; |
2372 | + setRoleNames(roles); |
2373 | +} |
2374 | + |
2375 | +/*! |
2376 | + Constructs a variant list model containing the specified \a list |
2377 | + with the given \a parent. |
2378 | +*/ |
2379 | + |
2380 | +QVariantListModel::QVariantListModel(const QVariantList &list, QObject *parent) |
2381 | + : QAbstractListModel(parent), lst(list) |
2382 | +{ |
2383 | + QHash<int, QByteArray> roles(roleNames()); |
2384 | + roles[Qt::DisplayRole] = "modelData"; |
2385 | + setRoleNames(roles); |
2386 | +} |
2387 | + |
2388 | +/*! |
2389 | + Returns the number of rows in the model. This value corresponds to the |
2390 | + number of items in the model's internal variant list. |
2391 | + |
2392 | + The optional \a parent argument is in most models used to specify |
2393 | + the parent of the rows to be counted. Because this is a list if a |
2394 | + valid parent is specified, the result will always be 0. |
2395 | + |
2396 | + \sa insertRows(), removeRows(), QAbstractItemModel::rowCount() |
2397 | +*/ |
2398 | + |
2399 | +int QVariantListModel::rowCount(const QModelIndex &parent) const |
2400 | +{ |
2401 | + if (parent.isValid()) |
2402 | + return 0; |
2403 | + |
2404 | + return lst.count(); |
2405 | +} |
2406 | + |
2407 | +/*! |
2408 | + \reimp |
2409 | +*/ |
2410 | +QModelIndex QVariantListModel::sibling(int row, int column, const QModelIndex &idx) const |
2411 | +{ |
2412 | + if (!idx.isValid() || column != 0 || row >= lst.count()) |
2413 | + return QModelIndex(); |
2414 | + |
2415 | + return createIndex(row, 0); |
2416 | +} |
2417 | + |
2418 | +/*! |
2419 | + Returns data for the specified \a role, from the item with the |
2420 | + given \a index. |
2421 | + |
2422 | + If the view requests an invalid index, an invalid variant is returned. |
2423 | + |
2424 | + \sa setData() |
2425 | +*/ |
2426 | + |
2427 | +QVariant QVariantListModel::data(const QModelIndex &index, int role) const |
2428 | +{ |
2429 | + if (index.row() < 0 || index.row() >= lst.size()) |
2430 | + return QVariant(); |
2431 | + |
2432 | + if (role == Qt::DisplayRole || role == Qt::EditRole) |
2433 | + return lst.at(index.row()); |
2434 | + |
2435 | + return QVariant(); |
2436 | +} |
2437 | + |
2438 | +/*! |
2439 | + Returns the flags for the item with the given \a index. |
2440 | + |
2441 | + Valid items are enabled, selectable, editable, drag enabled and drop enabled. |
2442 | + |
2443 | + \sa QAbstractItemModel::flags() |
2444 | +*/ |
2445 | + |
2446 | +Qt::ItemFlags QVariantListModel::flags(const QModelIndex &index) const |
2447 | +{ |
2448 | + if (!index.isValid()) |
2449 | + return QAbstractListModel::flags(index) | Qt::ItemIsDropEnabled; |
2450 | + |
2451 | + return QAbstractListModel::flags(index) | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; |
2452 | +} |
2453 | + |
2454 | +/*! |
2455 | + Sets the data for the specified \a role in the item with the given |
2456 | + \a index in the model, to the provided \a value. |
2457 | + |
2458 | + The dataChanged() signal is emitted if the item is changed. |
2459 | + |
2460 | + \sa Qt::ItemDataRole, data() |
2461 | +*/ |
2462 | + |
2463 | +bool QVariantListModel::setData(const QModelIndex &index, const QVariant &value, int role) |
2464 | +{ |
2465 | + if (index.row() >= 0 && index.row() < lst.size() |
2466 | + && (role == Qt::EditRole || role == Qt::DisplayRole)) { |
2467 | + lst.replace(index.row(), value); |
2468 | + dataChanged(index, index, QVector<int>() << role); |
2469 | + return true; |
2470 | + } |
2471 | + return false; |
2472 | +} |
2473 | + |
2474 | +/*! |
2475 | + Inserts \a count rows into the model, beginning at the given \a row. |
2476 | + |
2477 | + The \a parent index of the rows is optional and is only used for |
2478 | + consistency with QAbstractItemModel. By default, a null index is |
2479 | + specified, indicating that the rows are inserted in the top level of |
2480 | + the model. |
2481 | + |
2482 | + \sa QAbstractItemModel::insertRows() |
2483 | +*/ |
2484 | + |
2485 | +bool QVariantListModel::insertRows(int row, int count, const QModelIndex &parent) |
2486 | +{ |
2487 | + if (count < 1 || row < 0 || row > rowCount(parent)) |
2488 | + return false; |
2489 | + |
2490 | + beginInsertRows(QModelIndex(), row, row + count - 1); |
2491 | + |
2492 | + for (int r = 0; r < count; ++r) |
2493 | + lst.insert(row, QVariant()); |
2494 | + |
2495 | + endInsertRows(); |
2496 | + |
2497 | + return true; |
2498 | +} |
2499 | + |
2500 | +/*! |
2501 | + Removes \a count rows from the model, beginning at the given \a row. |
2502 | + |
2503 | + The \a parent index of the rows is optional and is only used for |
2504 | + consistency with QAbstractItemModel. By default, a null index is |
2505 | + specified, indicating that the rows are removed in the top level of |
2506 | + the model. |
2507 | + |
2508 | + \sa QAbstractItemModel::removeRows() |
2509 | +*/ |
2510 | + |
2511 | +bool QVariantListModel::removeRows(int row, int count, const QModelIndex &parent) |
2512 | +{ |
2513 | + if (count <= 0 || row < 0 || (row + count) > rowCount(parent)) |
2514 | + return false; |
2515 | + |
2516 | + beginRemoveRows(QModelIndex(), row, row + count - 1); |
2517 | + |
2518 | + for (int r = 0; r < count; ++r) |
2519 | + lst.removeAt(row); |
2520 | + |
2521 | + endRemoveRows(); |
2522 | + |
2523 | + return true; |
2524 | +} |
2525 | + |
2526 | +/*! |
2527 | + Returns the variant list used by the model to store data. |
2528 | +*/ |
2529 | +QVariantList QVariantListModel::variantList() const |
2530 | +{ |
2531 | + return lst; |
2532 | +} |
2533 | + |
2534 | +/*! |
2535 | + Sets the model's internal variant list to \a list. The model will |
2536 | + notify any attached views that its underlying data has changed. |
2537 | + |
2538 | + \sa dataChanged() |
2539 | +*/ |
2540 | +void QVariantListModel::setVariantList(const QVariantList &list) |
2541 | +{ |
2542 | + beginResetModel(); |
2543 | + lst = list; |
2544 | + endResetModel(); |
2545 | +} |
2546 | + |
2547 | +/*! |
2548 | + \reimp |
2549 | +*/ |
2550 | +Qt::DropActions QVariantListModel::supportedDropActions() const |
2551 | +{ |
2552 | + return QAbstractItemModel::supportedDropActions() | Qt::MoveAction; |
2553 | +} |
2554 | + |
2555 | |
2556 | === added file 'plugins/LightDM/qvariantlistmodel.h' |
2557 | --- plugins/LightDM/qvariantlistmodel.h 1970-01-01 00:00:00 +0000 |
2558 | +++ plugins/LightDM/qvariantlistmodel.h 2013-05-10 12:09:35 +0000 |
2559 | @@ -0,0 +1,57 @@ |
2560 | +/* |
2561 | + * Copyright (C) 2013 Canonical, Ltd. |
2562 | + * Copyright (C) 2010-2011 David Edmundson. |
2563 | + * |
2564 | + * This program is free software; you can redistribute it and/or modify |
2565 | + * it under the terms of the GNU General Public License as published by |
2566 | + * the Free Software Foundation; version 3. |
2567 | + * |
2568 | + * This program is distributed in the hope that it will be useful, |
2569 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2570 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2571 | + * GNU General Public License for more details. |
2572 | + * |
2573 | + * You should have received a copy of the GNU General Public License |
2574 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2575 | + * |
2576 | + * Author: Pete Woods <pete.woods@canonical.com> |
2577 | + */ |
2578 | + |
2579 | +#ifndef QVARIANTLISTMODEL_H |
2580 | +#define QVARIANTLISTMODEL_H |
2581 | + |
2582 | +#include <QAbstractListModel> |
2583 | +#include <QVariantList> |
2584 | + |
2585 | +class Q_CORE_EXPORT QVariantListModel : public QAbstractListModel |
2586 | +{ |
2587 | + Q_OBJECT |
2588 | +public: |
2589 | + explicit QVariantListModel(QObject *parent = 0); |
2590 | + explicit QVariantListModel(const QVariantList &list, QObject *parent = 0); |
2591 | + |
2592 | + int rowCount(const QModelIndex &parent = QModelIndex()) const; |
2593 | + QModelIndex sibling(int row, int column, const QModelIndex &idx) const; |
2594 | + |
2595 | + QVariant data(const QModelIndex &index, int role) const; |
2596 | + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); |
2597 | + |
2598 | + Qt::ItemFlags flags(const QModelIndex &index) const; |
2599 | + |
2600 | + bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()); |
2601 | + bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); |
2602 | + |
2603 | + //void sort(int column, Qt::SortOrder order = Qt::AscendingOrder); |
2604 | + |
2605 | + QVariantList variantList() const; |
2606 | + void setVariantList(const QVariantList &list); |
2607 | + |
2608 | + Qt::DropActions supportedDropActions() const; |
2609 | + |
2610 | +private: |
2611 | + Q_DISABLE_COPY(QVariantListModel) |
2612 | + QVariantList lst; |
2613 | +}; |
2614 | + |
2615 | + |
2616 | +#endif // QVARIANTLISTMODEL_H |
2617 | |
2618 | === added file 'plugins/LightDM/usersmodel.cpp' |
2619 | --- plugins/LightDM/usersmodel.cpp 1970-01-01 00:00:00 +0000 |
2620 | +++ plugins/LightDM/usersmodel.cpp 2013-05-10 12:09:35 +0000 |
2621 | @@ -0,0 +1,68 @@ |
2622 | +/* |
2623 | + * Copyright (C) 2013 Canonical, Ltd. |
2624 | + * |
2625 | + * This program is free software; you can redistribute it and/or modify |
2626 | + * it under the terms of the GNU General Public License as published by |
2627 | + * the Free Software Foundation; version 3. |
2628 | + * |
2629 | + * This program is distributed in the hope that it will be useful, |
2630 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2631 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2632 | + * GNU General Public License for more details. |
2633 | + * |
2634 | + * You should have received a copy of the GNU General Public License |
2635 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2636 | + * |
2637 | + * Author: Michael Terry <michael.terry@canonical.com> |
2638 | + */ |
2639 | + |
2640 | +#include "usersmodel.h" |
2641 | +#include "lightdm-usersmodel.h" |
2642 | +#include <QtCore/QSortFilterProxyModel> |
2643 | + |
2644 | +// First, we define an internal class that wraps LightDM's UsersModel. This |
2645 | +// class will modify some of the data coming from LightDM. For example, we |
2646 | +// modify any empty Real Names into just normal Names. |
2647 | +// (We can't modify the data directly in UsersModel below because it won't sort |
2648 | +// using the modified data.) |
2649 | +class MangleModel : public QSortFilterProxyModel |
2650 | +{ |
2651 | + Q_OBJECT |
2652 | + |
2653 | +public: |
2654 | + explicit MangleModel(QObject* parent=0); |
2655 | + |
2656 | + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; |
2657 | +}; |
2658 | + |
2659 | +MangleModel::MangleModel(QObject* parent) |
2660 | + : QSortFilterProxyModel(parent) |
2661 | +{ |
2662 | + setSourceModel(new QLightDM::UsersModel(this)); |
2663 | +} |
2664 | + |
2665 | +QVariant MangleModel::data(const QModelIndex &index, int role) const |
2666 | +{ |
2667 | + QVariant data = QSortFilterProxyModel::data(index, role); |
2668 | + |
2669 | + // If user's real name is empty, switch to unix name |
2670 | + if (role == QLightDM::UsersModel::RealNameRole && data.toString().isEmpty()) { |
2671 | + data = QSortFilterProxyModel::data(index, QLightDM::UsersModel::NameRole); |
2672 | + } |
2673 | + |
2674 | + return data; |
2675 | +} |
2676 | + |
2677 | +// **** Now we continue with actual UsersModel class **** |
2678 | + |
2679 | +UsersModel::UsersModel(QObject* parent) |
2680 | + : QSortFilterProxyModelQML(parent) |
2681 | +{ |
2682 | + setModel(new MangleModel(this)); |
2683 | + setSortCaseSensitivity(Qt::CaseInsensitive); |
2684 | + setSortLocaleAware(true); |
2685 | + setSortRole(QLightDM::UsersModel::RealNameRole); |
2686 | + sort(0); |
2687 | +} |
2688 | + |
2689 | +#include "usersmodel.moc" |
2690 | |
2691 | === added file 'plugins/LightDM/usersmodel.h' |
2692 | --- plugins/LightDM/usersmodel.h 1970-01-01 00:00:00 +0000 |
2693 | +++ plugins/LightDM/usersmodel.h 2013-05-10 12:09:35 +0000 |
2694 | @@ -0,0 +1,37 @@ |
2695 | +/* |
2696 | + * Copyright (C) 2012,2013 Canonical, Ltd. |
2697 | + * |
2698 | + * This program is free software; you can redistribute it and/or modify |
2699 | + * it under the terms of the GNU General Public License as published by |
2700 | + * the Free Software Foundation; version 3. |
2701 | + * |
2702 | + * This program is distributed in the hope that it will be useful, |
2703 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2704 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2705 | + * GNU General Public License for more details. |
2706 | + * |
2707 | + * You should have received a copy of the GNU General Public License |
2708 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2709 | + * |
2710 | + * Authors: Michael Terry <michael.terry@canonical.com> |
2711 | + */ |
2712 | + |
2713 | +/* This class is a really tiny filter around QLightDM::UsersModel. There are |
2714 | + some operations that we want to edit a bit for the benefit of Qml. |
2715 | + Specifically, we want to sort users according to realName. */ |
2716 | + |
2717 | +#ifndef USERSMODEL_H |
2718 | +#define USERSMODEL_H |
2719 | + |
2720 | +#include "plugins/Utils/qsortfilterproxymodelqml.h" |
2721 | +#include <QtCore/QObject> |
2722 | + |
2723 | +class UsersModel : public QSortFilterProxyModelQML |
2724 | +{ |
2725 | + Q_OBJECT |
2726 | + |
2727 | +public: |
2728 | + explicit UsersModel(QObject* parent=0); |
2729 | +}; |
2730 | + |
2731 | +#endif |
2732 | |
2733 | === modified file 'plugins/Utils/qsortfilterproxymodelqml.cpp' |
2734 | --- plugins/Utils/qsortfilterproxymodelqml.cpp 2013-05-09 14:23:10 +0000 |
2735 | +++ plugins/Utils/qsortfilterproxymodelqml.cpp 2013-05-10 12:09:35 +0000 |
2736 | @@ -57,6 +57,16 @@ |
2737 | } |
2738 | } |
2739 | |
2740 | +QVariant |
2741 | +QSortFilterProxyModelQML::data(int row, int role) |
2742 | +{ |
2743 | + if (sourceModel() == NULL) { |
2744 | + return QVariant(); |
2745 | + } |
2746 | + |
2747 | + return index(row, 0).data(role); |
2748 | +} |
2749 | + |
2750 | int |
2751 | QSortFilterProxyModelQML::totalCount() const |
2752 | { |
2753 | |
2754 | === modified file 'plugins/Utils/qsortfilterproxymodelqml.h' |
2755 | --- plugins/Utils/qsortfilterproxymodelqml.h 2013-05-08 11:22:15 +0000 |
2756 | +++ plugins/Utils/qsortfilterproxymodelqml.h 2013-05-10 12:09:35 +0000 |
2757 | @@ -31,6 +31,7 @@ |
2758 | public: |
2759 | explicit QSortFilterProxyModelQML(QObject *parent = 0); |
2760 | |
2761 | + Q_INVOKABLE QVariant data(int row, int role); |
2762 | Q_INVOKABLE int count(); |
2763 | Q_INVOKABLE int findFirst(int role, const QVariant& value) const; |
2764 | virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; |
2765 | |
2766 | === modified file 'tests/autopilot/qml_phone_shell/tests/helpers.py' |
2767 | --- tests/autopilot/qml_phone_shell/tests/helpers.py 2013-04-05 11:03:11 +0000 |
2768 | +++ tests/autopilot/qml_phone_shell/tests/helpers.py 2013-05-10 12:09:35 +0000 |
2769 | @@ -15,26 +15,49 @@ |
2770 | class TestShellHelpers(object): |
2771 | """Helpers for testing the Shell""" |
2772 | |
2773 | - def unlock_greeter(self, retries=2): |
2774 | + def select_greeter_user(self, username): |
2775 | greeter = self.main_window.get_greeter() |
2776 | self.assertThat(greeter.created, Eventually(Equals(True))) |
2777 | - |
2778 | - if greeter.multiUser: |
2779 | - login_loader = self.main_window.get_login_loader() |
2780 | - self.assertThat(login_loader.progress, Eventually(Equals(1))) |
2781 | - login_list = self.main_window.get_login_list() |
2782 | - path_view = login_list.get_children_by_type("QQuickPathView")[0] |
2783 | + self.assertThat(greeter.multiUser, Eventually(Equals(True))) |
2784 | + |
2785 | + login_loader = self.main_window.get_login_loader() |
2786 | + self.assertThat(login_loader.progress, Eventually(Equals(1))) |
2787 | + |
2788 | + login_list = self.main_window.get_login_list() |
2789 | + path_view = login_list.get_children_by_type("QQuickPathView")[0] |
2790 | + |
2791 | + try_count = 0 |
2792 | + max_tries = 50 # just in case we go off rails |
2793 | + while try_count < max_tries: |
2794 | users = path_view.get_children_by_type("QQuickItem") |
2795 | + target_user = None |
2796 | for user in users: |
2797 | try: |
2798 | user_label = user.get_children_by_type("Label")[0] |
2799 | - if user_label.text == "Guest": |
2800 | - self.pointing_device.move_to_object(user_label) |
2801 | - self.pointing_device.click() |
2802 | - except: |
2803 | + if user_label.text == username: |
2804 | + target_user = user |
2805 | + break |
2806 | + elif target_user is None or user.y > target_user.y: |
2807 | + target_user = user |
2808 | + except Exception: |
2809 | pass |
2810 | - |
2811 | - password_field = login_list.get_children_by_type("TextField")[0] |
2812 | + if target_user is None: |
2813 | + break |
2814 | + user_label = target_user.get_children_by_type("Label")[0] |
2815 | + self.pointing_device.move_to_object(user_label) |
2816 | + self.pointing_device.click() |
2817 | + self.assertThat(path_view.movingInternally, Eventually(Equals(False))) |
2818 | + if user_label.text == username: |
2819 | + return login_list.get_children_by_type("TextField")[0] |
2820 | + try_count = try_count + 1 |
2821 | + self.fail() # We didn't find it |
2822 | + |
2823 | + def unlock_greeter(self, retries=2): |
2824 | + greeter = self.main_window.get_greeter() |
2825 | + self.assertThat(greeter.created, Eventually(Equals(True))) |
2826 | + |
2827 | + if greeter.multiUser: |
2828 | + password_field = self.select_greeter_user("Guest") |
2829 | self.pointing_device.move_to_object(password_field) |
2830 | self.assertThat(password_field.opacity, Eventually(Equals(1))) |
2831 | self.pointing_device.click() |
2832 | |
2833 | === modified file 'tests/qmltests/CMakeLists.txt' |
2834 | --- tests/qmltests/CMakeLists.txt 2013-05-09 07:01:25 +0000 |
2835 | +++ tests/qmltests/CMakeLists.txt 2013-05-10 12:09:35 +0000 |
2836 | @@ -49,7 +49,7 @@ |
2837 | ${CMAKE_BINARY_DIR}/tests/mocks) |
2838 | add_qml_test(Dash/Apps RunningApplicationsGrid IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks) |
2839 | add_qml_test(Dash/People PeopleFilterGrid IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${CMAKE_CURRENT_SOURCE_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}) |
2840 | -add_qml_test(Greeter Greeter) |
2841 | +add_qml_test(Greeter Greeter IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins) |
2842 | add_qml_test(Hud Hud) |
2843 | add_qml_test(Hud Result) |
2844 | add_qml_test(Launcher Launcher) |
2845 | @@ -60,4 +60,4 @@ |
2846 | add_qml_test(Panel Panel) |
2847 | add_qml_test(Panel SearchIndicator) |
2848 | add_qml_test(Panel/Menus IndicatorMenuWindow IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS}) |
2849 | -add_qml_test(SideStage SideStage IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks) |
2850 | +add_qml_test(SideStage SideStage IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks) |
2851 | \ No newline at end of file |
2852 | |
2853 | === modified file 'tests/qmltests/Greeter/tst_Greeter.qml' |
2854 | --- tests/qmltests/Greeter/tst_Greeter.qml 2013-04-17 13:01:10 +0000 |
2855 | +++ tests/qmltests/Greeter/tst_Greeter.qml 2013-05-10 12:09:35 +0000 |
2856 | @@ -46,53 +46,69 @@ |
2857 | name: "Greeter" |
2858 | when: windowShown |
2859 | |
2860 | + function select_user(name) { |
2861 | + // We could be anywhere in list; find target index to know which direction |
2862 | + for (var i = 0; i < greeter.model.count; i++) { |
2863 | + if (greeter.model.get(i).name == name) { |
2864 | + break |
2865 | + } |
2866 | + } |
2867 | + if (i == greeter.model.count) { |
2868 | + return |
2869 | + } |
2870 | + var pathview = findChild(greeter, "userList") |
2871 | + while (pathview.currentIndex != i) { |
2872 | + var next = pathview.currentIndex + 1 |
2873 | + if (pathview.currentIndex > i) { |
2874 | + next = pathview.currentIndex - 1 |
2875 | + } |
2876 | + var account = findChild(greeter, "username"+next) |
2877 | + mouseClick(account, 1, 1) |
2878 | + tryCompare(pathview, "currentIndex", next) |
2879 | + } |
2880 | + } |
2881 | + |
2882 | function test_cycle_data() { |
2883 | - tryCompare(findChild(greeter, "userList"), "count", 5) |
2884 | + tryCompare(findChild(greeter, "userList"), "count", 6) |
2885 | var data = new Array() |
2886 | for (var i = 1; i < greeter.model.count; i++) { |
2887 | data[i] = {tag: greeter.model.get(i).name, username: "username"+i, uid: i } |
2888 | } |
2889 | + // We add first name last in data to guarantee a selected signal |
2890 | data[greeter.model.count] = {tag: greeter.model.get(0).name, username: "username0", uid: 0 } |
2891 | return data |
2892 | } |
2893 | |
2894 | function test_cycle(data) { |
2895 | - tryCompare(findChild(greeter, "userList"), "count", 5) |
2896 | + tryCompare(findChild(greeter, "userList"), "count", 6) |
2897 | selectionSpy.clear(); |
2898 | var user = findChild(greeter, data.username) |
2899 | mouseClick(user, user.width / 2, user.height / 2) |
2900 | var pathview = findChild(greeter, "userList") |
2901 | tryCompare(pathview, "currentIndex", data.uid) |
2902 | - tryCompare(greeter, "locked", greeter.model.get(data.uid).password !== undefined) |
2903 | + tryCompare(greeter, "locked", data.tag !== "no-password") |
2904 | tryCompare(selectionSpy, "count", 1) |
2905 | } |
2906 | |
2907 | function test_unlock_password() { |
2908 | + select_user("lois") // to guarantee a selected signal |
2909 | unlockSpy.clear() |
2910 | - // First one is Lolas account right now. Replace with password protected user from lightdm |
2911 | - var account = findChild(greeter, "username1") |
2912 | - mouseClick(account, 1, 1) |
2913 | - account = findChild(greeter, "username0") |
2914 | - mouseClick(account, 1, 1) |
2915 | + select_user("lola") |
2916 | var passwordInput = findChild(greeter, "passwordInput") |
2917 | - tryCompare(passwordInput, "opacity", 0) |
2918 | tryCompare(passwordInput, "opacity", 1) |
2919 | mouseClick(passwordInput, 1, 1) |
2920 | compare(unlockSpy.count, 0) |
2921 | - typeString(greeter.model.get(0).password) |
2922 | + typeString("password") |
2923 | keyClick(Qt.Key_Enter) |
2924 | unlockSpy.wait() |
2925 | } |
2926 | |
2927 | function test_unlock_wrong_password() { |
2928 | + select_user("lois") // to guarantee a selected signal |
2929 | unlockSpy.clear() |
2930 | - // First one is Lolas account right now. Replace with password protected user from lightdm |
2931 | - var account = findChild(greeter, "username1") |
2932 | - mouseClick(account, 1, 1) |
2933 | - account = findChild(greeter, "username0") |
2934 | - var passwordInput = findChild(greeter, "passwordInput") |
2935 | - mouseClick(account, 1, 1) |
2936 | + select_user("lola") |
2937 | wait(0) // spin event loop to start any pending animations |
2938 | + var passwordInput = findChild(greeter, "passwordInput") |
2939 | tryCompare(passwordInput, "opacity", 1) // wait for opacity animation to be finished |
2940 | mouseClick(passwordInput, 1, 1) |
2941 | compare(unlockSpy.count, 0) |
2942 | @@ -103,14 +119,23 @@ |
2943 | |
2944 | function test_unlock_no_password() { |
2945 | unlockSpy.clear() |
2946 | - // Last one is the guest account for now. Replace with passwordless user from lightdm |
2947 | - var guestAccount = findChild(greeter, "username" + (greeter.model.count - 1)) |
2948 | - mouseClick(guestAccount, guestAccount.width / 2, guestAccount.height / 2) |
2949 | + select_user("no-password") |
2950 | var passwordInput = findChild(greeter, "passwordInput") |
2951 | tryCompare(passwordInput, "opacity", 1) |
2952 | mouseClick(passwordInput, 1, 1) |
2953 | unlockSpy.wait() |
2954 | compare(unlockSpy.count, 1) |
2955 | } |
2956 | + |
2957 | + function test_empty_name() { |
2958 | + for (var i = 0; i < greeter.model.count; i++) { |
2959 | + if (greeter.model.get(i).name == "empty-name") { |
2960 | + compare(greeter.model.get(i).realName, greeter.model.get(i).name) |
2961 | + return |
2962 | + } |
2963 | + } |
2964 | + // Never found empty-name... |
2965 | + throw new Error("QtQuickTest::fail") |
2966 | + } |
2967 | } |
2968 | } |