Merge lp:~mterry/unity8/greeter-focus into lp:unity8
- greeter-focus
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~mterry/unity8/greeter-focus |
Merge into: | lp:unity8 |
Prerequisite: | lp:~josharenson/unity8/slim_greeter_real_lightdm |
Diff against target: |
2260 lines (+1309/-134) 43 files modified
plugins/LightDM/CMakeLists.txt (+1/-2) plugins/LightDM/FullLightDM/CMakeLists.txt (+4/-1) plugins/LightDM/Greeter.cpp (+7/-2) plugins/LightDM/Greeter.h (+3/-2) plugins/LightDM/IntegratedLightDM/CMakeLists.txt (+2/-3) plugins/LightDM/IntegratedLightDM/QLightDM/Greeter (+17/-0) plugins/LightDM/IntegratedLightDM/QLightDM/SessionsModel (+17/-0) plugins/LightDM/IntegratedLightDM/QLightDM/UsersModel (+17/-0) plugins/LightDM/IntegratedLightDM/liblightdm/CMakeLists.txt (+2/-0) plugins/LightDM/IntegratedLightDM/liblightdm/SessionsModel.cpp (+88/-0) plugins/LightDM/IntegratedLightDM/liblightdm/SessionsModel.h (+72/-0) plugins/LightDM/IntegratedLightDM/liblightdm/SessionsModelPrivate.cpp (+36/-0) plugins/LightDM/IntegratedLightDM/liblightdm/SessionsModelPrivate.h (+54/-0) plugins/LightDM/SessionsModel.cpp (+122/-0) plugins/LightDM/SessionsModel.h (+68/-0) plugins/LightDM/plugin.cpp (+17/-7) qml/Greeter/Greeter.qml (+28/-24) qml/Greeter/GreeterPrompt.qml (+64/-12) qml/Greeter/LoginList.qml (+27/-16) qml/Greeter/NarrowView.qml (+2/-1) qml/Greeter/WideView.qml (+4/-3) qml/Shell.qml (+5/-3) tests/mocks/LightDM/IntegratedLightDM/CMakeLists.txt (+2/-0) tests/mocks/LightDM/IntegratedLightDM/MockSessionsModel.cpp (+37/-0) tests/mocks/LightDM/IntegratedLightDM/MockSessionsModel.h (+34/-0) tests/mocks/LightDM/IntegratedLightDM/QLightDM/SessionsModel (+17/-0) tests/mocks/LightDM/IntegratedLightDM/liblightdm/CMakeLists.txt (+2/-0) tests/mocks/LightDM/IntegratedLightDM/liblightdm/Greeter.cpp (+1/-1) tests/mocks/LightDM/IntegratedLightDM/liblightdm/SessionsModel.cpp (+99/-0) tests/mocks/LightDM/IntegratedLightDM/liblightdm/SessionsModel.h (+72/-0) tests/mocks/LightDM/IntegratedLightDM/liblightdm/SessionsModelPrivate.cpp (+73/-0) tests/mocks/LightDM/IntegratedLightDM/liblightdm/SessionsModelPrivate.h (+59/-0) tests/mocks/LightDM/IntegratedLightDM/liblightdm/UsersModelPrivate.cpp (+22/-22) tests/mocks/LightDM/IntegratedLightDM/plugin.cpp (+11/-0) tests/plugins/LightDM/IntegratedLightDM/CMakeLists.txt (+23/-0) tests/plugins/LightDM/IntegratedLightDM/sessionsmodel.cpp (+96/-0) tests/qmltests/Greeter/TestView.qml (+0/-1) tests/qmltests/Greeter/tst_Greeter.qml (+2/-12) tests/qmltests/Greeter/tst_WideView.qml (+90/-12) tests/qmltests/Tutorial/tst_Tutorial.qml (+1/-1) tests/qmltests/tst_OrientedShell.qml (+2/-2) tests/qmltests/tst_Shell.qml (+3/-3) tests/qmltests/tst_ShellWithPin.qml (+6/-4) |
To merge this branch: | bzr merge lp:~mterry/unity8/greeter-focus |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Unity8 CI Bot | continuous-integration | Needs Fixing | |
Unity Team | Pending | ||
Review via email: mp+298113@code.launchpad.net |
This proposal has been superseded by a proposal from 2016-06-30.
Commit message
Fix tablet greeter focus to be always-on, no longer hiding the OSK or forcing a mouse click to type a password.
I've also squeezed some other small fixes in:
- Support Up and Down keys in user list.
- Don't accept non-digit characters when prompting for passcode (we ask OSK to show only digits, but due to bug 1586435, it shows other characters too; plus if the user has an external keyboard, they can type anything anyway).
- When prompting for a passcode in wide-view (tablet/desktop), stop at 4 digits just like we do in narrow-view.
- Don't show "Retry" during brief period before a prompt comes in from PAM.
- Don't let user drag user list if there's only one entry.
Now as for the focus changes...
One of the big reasons we lost keyboard focus before was because we set the shell to disabled whenever the greeter was "between PAM events" -- mostly so that the user can't swipe away greeter before we get our first prompt or are otherwise unsure about exactly what authentication is needed.
But disabled qml items can't be focused. So I've rejiggered things a bit. Instead of disabling the whole shell, I just disable the launcher, the indicators, and make the greeter non-swipeable.
I also do some tricks with the prompt so that it looks disabled (while we check with PAM about the password) but isn't actually. I don't want to make it look to the user that pressing backspace while they wait for PAM does anything, so after the user presses Enter, I present a fake label on top of the prompt that looks like a disabled prompt, while simultaneously hiding the prompt contents.
Description of the change
You could mostly just test this on your desktop. Changes are all to the wide-view side of things.
* Are there any related MPs required for this MP to build/function as expected? Please list.
No
* Did you perform an exploratory manual test run of your code change and any related functionality?
Yes
* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
NA
* If you changed the UI, has there been a design review?
NA
Michael Terry (mterry) wrote : | # |
Michael Terry (mterry) wrote : | # |
OK, tests added.
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:2496
https:/
Executed test runs:
SUCCESS: https:/
UNSTABLE: https:/
UNSTABLE: https:/
UNSTABLE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:2497
https:/
Executed test runs:
SUCCESS: https:/
FAILURE: https:/
UNSTABLE: https:/
UNSTABLE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:2498
https:/
Executed test runs:
SUCCESS: https:/
UNSTABLE: https:/
UNSTABLE: https:/
UNSTABLE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
- 1994. By Michael Terry
-
Fix focus on greeter and various other bugs
- 1995. By Michael Terry
-
Merge from slim_greeter_
real_lightdm - 1996. By Michael Terry
-
Whoops, reset po files that got changed somehow
- 1997. By Michael Terry
-
Fix minor issue when auto-responding with a passcode
- 1998. By Michael Terry
-
Merge parent
- 1999. By Michael Terry
-
Merge sessions-model
- 2000. By Michael Terry
-
Be smoother about focus in GreeterPrompt
- 2001. By Michael Terry
-
remove unneeded check, fixes test
- 2002. By Michael Terry
-
Merge in greeter-
hide-indicators - 2003. By Michael Terry
-
Update copyrights
- 2004. By Michael Terry
-
Give wideview test focus to start
- 2005. By Michael Terry
-
Merge focus refactor from dandrader
- 2006. By Michael Terry
-
Merge tryWideView focus refactor from dandrader
- 2007. By Michael Terry
-
Make it clear in GreeterPrompt that fakeLabel is for OSK focus
- 2008. By Michael Terry
-
Fix a test
Unmerged revisions
Preview Diff
1 | === modified file 'plugins/LightDM/CMakeLists.txt' |
2 | --- plugins/LightDM/CMakeLists.txt 2016-06-30 19:05:01 +0000 |
3 | +++ plugins/LightDM/CMakeLists.txt 2016-06-30 19:05:07 +0000 |
4 | @@ -7,9 +7,7 @@ |
5 | ${CMAKE_CURRENT_SOURCE_DIR} |
6 | ${CMAKE_CURRENT_BINARY_DIR} |
7 | ${CMAKE_SOURCE_DIR}/plugins/Utils |
8 | - ${CMAKE_SOURCE_DIR}/tests/mocks/LightDM/IntegratedLightDM |
9 | ${CMAKE_BINARY_DIR}/tests/mocks/LightDM/IntegratedLightDM |
10 | - ${LIBLIGHTDM_INCLUDE_DIRS} |
11 | ${libunity8-private_SOURCE_DIR} |
12 | ${LIBUSERMETRICSOUTPUT_INCLUDE_DIRS} |
13 | ) |
14 | @@ -20,6 +18,7 @@ |
15 | DBusGreeterList.cpp |
16 | Greeter.cpp |
17 | plugin.cpp |
18 | + SessionsModel.cpp |
19 | UsersModel.cpp |
20 | ) |
21 | |
22 | |
23 | === modified file 'plugins/LightDM/FullLightDM/CMakeLists.txt' |
24 | --- plugins/LightDM/FullLightDM/CMakeLists.txt 2016-06-30 19:05:01 +0000 |
25 | +++ plugins/LightDM/FullLightDM/CMakeLists.txt 2016-06-30 19:05:07 +0000 |
26 | @@ -4,7 +4,10 @@ |
27 | |
28 | add_definitions(-DFULL_LIGHTDM) |
29 | |
30 | -include_directories(../) |
31 | +include_directories( |
32 | + ../ |
33 | + ${LIBLIGHTDM_INCLUDE_DIRS} |
34 | + ) |
35 | |
36 | foreach(source_file ${QMLPLUGIN_SRC}) |
37 | list(APPEND RELATIVE_QMLPLUGIN_SRC ../${source_file}) |
38 | |
39 | === modified file 'plugins/LightDM/Greeter.cpp' |
40 | --- plugins/LightDM/Greeter.cpp 2016-06-30 19:05:01 +0000 |
41 | +++ plugins/LightDM/Greeter.cpp 2016-06-30 19:05:07 +0000 |
42 | @@ -1,5 +1,5 @@ |
43 | /* |
44 | - * Copyright (C) 2013 Canonical, Ltd. |
45 | + * Copyright (C) 2013, 2015 Canonical, Ltd. |
46 | * |
47 | * This program is free software; you can redistribute it and/or modify |
48 | * it under the terms of the GNU General Public License as published by |
49 | @@ -13,7 +13,6 @@ |
50 | * You should have received a copy of the GNU General Public License |
51 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
52 | * |
53 | - * Author: Michael Terry <michael.terry@canonical.com> |
54 | */ |
55 | |
56 | #include "Greeter.h" |
57 | @@ -72,6 +71,12 @@ |
58 | return d->m_greeter->authenticationUser(); |
59 | } |
60 | |
61 | +QString Greeter::defaultSessionHint() const |
62 | +{ |
63 | + Q_D(const Greeter); |
64 | + return d->m_greeter->defaultSessionHint(); |
65 | +} |
66 | + |
67 | bool Greeter::promptless() const |
68 | { |
69 | Q_D(const Greeter); |
70 | |
71 | === modified file 'plugins/LightDM/Greeter.h' |
72 | --- plugins/LightDM/Greeter.h 2016-06-30 19:05:01 +0000 |
73 | +++ plugins/LightDM/Greeter.h 2016-06-30 19:05:07 +0000 |
74 | @@ -1,5 +1,5 @@ |
75 | /* |
76 | - * Copyright (C) 2012,2013 Canonical, Ltd. |
77 | + * Copyright (C) 2012,2013,2015 Canonical, Ltd. |
78 | * |
79 | * This program is free software; you can redistribute it and/or modify |
80 | * it under the terms of the GNU General Public License as published by |
81 | @@ -13,7 +13,6 @@ |
82 | * You should have received a copy of the GNU General Public License |
83 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
84 | * |
85 | - * Authors: Michael Terry <michael.terry@canonical.com> |
86 | */ |
87 | |
88 | /* This class is a really tiny filter around QLightDM::Greeter. There are some |
89 | @@ -37,6 +36,7 @@ |
90 | Q_PROPERTY(bool active READ isActive WRITE setIsActive NOTIFY isActiveChanged) |
91 | Q_PROPERTY(bool authenticated READ isAuthenticated NOTIFY isAuthenticatedChanged) |
92 | Q_PROPERTY(QString authenticationUser READ authenticationUser NOTIFY authenticationUserChanged) |
93 | + Q_PROPERTY(QString defaultSession READ defaultSessionHint CONSTANT) |
94 | Q_PROPERTY(bool promptless READ promptless NOTIFY promptlessChanged) |
95 | Q_PROPERTY(QString selectUser READ selectUser CONSTANT) |
96 | |
97 | @@ -46,6 +46,7 @@ |
98 | bool isActive() const; |
99 | bool isAuthenticated() const; |
100 | QString authenticationUser() const; |
101 | + QString defaultSessionHint() const; |
102 | bool promptless() const; |
103 | QString selectUser() const; |
104 | |
105 | |
106 | === modified file 'plugins/LightDM/IntegratedLightDM/CMakeLists.txt' |
107 | --- plugins/LightDM/IntegratedLightDM/CMakeLists.txt 2016-06-30 19:05:01 +0000 |
108 | +++ plugins/LightDM/IntegratedLightDM/CMakeLists.txt 2016-06-30 19:05:07 +0000 |
109 | @@ -7,9 +7,8 @@ |
110 | endforeach() |
111 | |
112 | include_directories( |
113 | - ${QMLPLUGIN_INCLUDES} |
114 | - ${libunity8-private_SOURCE_DIR} |
115 | -) |
116 | + . #QLightDM |
117 | + ) |
118 | |
119 | foreach(source_file ${QMLPLUGIN_SRC}) |
120 | list(APPEND RELATIVE_QMLPLUGIN_SRC ../${source_file}) |
121 | |
122 | === added directory 'plugins/LightDM/IntegratedLightDM/QLightDM' |
123 | === added file 'plugins/LightDM/IntegratedLightDM/QLightDM/Greeter' |
124 | --- plugins/LightDM/IntegratedLightDM/QLightDM/Greeter 1970-01-01 00:00:00 +0000 |
125 | +++ plugins/LightDM/IntegratedLightDM/QLightDM/Greeter 2016-06-30 19:05:07 +0000 |
126 | @@ -0,0 +1,17 @@ |
127 | +/* |
128 | + * Copyright (C) 2016 Canonical, Ltd. |
129 | + * |
130 | + * This program is free software; you can redistribute it and/or modify |
131 | + * it under the terms of the GNU General Public License as published by |
132 | + * the Free Software Foundation; version 3. |
133 | + * |
134 | + * This program is distributed in the hope that it will be useful, |
135 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
136 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
137 | + * GNU General Public License for more details. |
138 | + * |
139 | + * You should have received a copy of the GNU General Public License |
140 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
141 | + */ |
142 | + |
143 | +#include "../liblightdm/Greeter.h" |
144 | |
145 | === added file 'plugins/LightDM/IntegratedLightDM/QLightDM/SessionsModel' |
146 | --- plugins/LightDM/IntegratedLightDM/QLightDM/SessionsModel 1970-01-01 00:00:00 +0000 |
147 | +++ plugins/LightDM/IntegratedLightDM/QLightDM/SessionsModel 2016-06-30 19:05:07 +0000 |
148 | @@ -0,0 +1,17 @@ |
149 | +/* |
150 | + * Copyright (C) 2016 Canonical, Ltd. |
151 | + * |
152 | + * This program is free software; you can redistribute it and/or modify |
153 | + * it under the terms of the GNU General Public License as published by |
154 | + * the Free Software Foundation; version 3. |
155 | + * |
156 | + * This program is distributed in the hope that it will be useful, |
157 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
158 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
159 | + * GNU General Public License for more details. |
160 | + * |
161 | + * You should have received a copy of the GNU General Public License |
162 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
163 | + */ |
164 | + |
165 | +#include "../liblightdm/SessionsModel.h" |
166 | |
167 | === added file 'plugins/LightDM/IntegratedLightDM/QLightDM/UsersModel' |
168 | --- plugins/LightDM/IntegratedLightDM/QLightDM/UsersModel 1970-01-01 00:00:00 +0000 |
169 | +++ plugins/LightDM/IntegratedLightDM/QLightDM/UsersModel 2016-06-30 19:05:07 +0000 |
170 | @@ -0,0 +1,17 @@ |
171 | +/* |
172 | + * Copyright (C) 2016 Canonical, Ltd. |
173 | + * |
174 | + * This program is free software; you can redistribute it and/or modify |
175 | + * it under the terms of the GNU General Public License as published by |
176 | + * the Free Software Foundation; version 3. |
177 | + * |
178 | + * This program is distributed in the hope that it will be useful, |
179 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
180 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
181 | + * GNU General Public License for more details. |
182 | + * |
183 | + * You should have received a copy of the GNU General Public License |
184 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
185 | + */ |
186 | + |
187 | +#include "../liblightdm/UsersModel.h" |
188 | |
189 | === modified file 'plugins/LightDM/IntegratedLightDM/liblightdm/CMakeLists.txt' |
190 | --- plugins/LightDM/IntegratedLightDM/liblightdm/CMakeLists.txt 2016-06-30 19:05:01 +0000 |
191 | +++ plugins/LightDM/IntegratedLightDM/liblightdm/CMakeLists.txt 2016-06-30 19:05:07 +0000 |
192 | @@ -2,8 +2,10 @@ |
193 | |
194 | set(LibLightDM_SOURCES |
195 | Greeter.cpp |
196 | + SessionsModel.cpp |
197 | UsersModel.cpp |
198 | GreeterPrivate.cpp |
199 | + SessionsModelPrivate.cpp |
200 | UsersModelPrivate.cpp |
201 | ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp |
202 | ${CMAKE_SOURCE_DIR}/plugins/Utils/qvariantlistmodel.cpp |
203 | |
204 | === added file 'plugins/LightDM/IntegratedLightDM/liblightdm/SessionsModel.cpp' |
205 | --- plugins/LightDM/IntegratedLightDM/liblightdm/SessionsModel.cpp 1970-01-01 00:00:00 +0000 |
206 | +++ plugins/LightDM/IntegratedLightDM/liblightdm/SessionsModel.cpp 2016-06-30 19:05:07 +0000 |
207 | @@ -0,0 +1,88 @@ |
208 | +/* |
209 | + * Copyright (C) 2015 Canonical, Ltd. |
210 | + * |
211 | + * This program is free software; you can redistribute it and/or modify |
212 | + * it under the terms of the GNU General Public License as published by |
213 | + * the Free Software Foundation; version 3. |
214 | + * |
215 | + * This program is distributed in the hope that it will be useful, |
216 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
217 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
218 | + * GNU General Public License for more details. |
219 | + * |
220 | + * You should have received a copy of the GNU General Public License |
221 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
222 | + * |
223 | + */ |
224 | + |
225 | + |
226 | +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
227 | + * CHANGES MADE HERE MUST BE REFLECTED ON THE MOCK LIB |
228 | + * COUNTERPART IN tests/mocks/LightDM/IntegratedLightDM/liblightdm |
229 | + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ |
230 | + |
231 | +// LightDM currently is Qt4 compatible, and so doesn't define setRoleNames. |
232 | +// To use the same method of setting role name that it does, we |
233 | +// set our compatibility to Qt4 here too. |
234 | +#define QT_DISABLE_DEPRECATED_BEFORE QT_VERSION_CHECK(4, 0, 0) |
235 | + |
236 | +#include "SessionsModel.h" |
237 | +#include "SessionsModelPrivate.h" |
238 | +#include <QtCore/QDir> |
239 | +#include <QtCore/QString> |
240 | + |
241 | +namespace QLightDM |
242 | +{ |
243 | + |
244 | +SessionsModel::SessionsModel(QObject* parent) : |
245 | + QAbstractListModel(parent), |
246 | + d_ptr(new SessionsModelPrivate(this)) |
247 | +{ |
248 | + Q_D(SessionsModel); |
249 | + m_roleNames = QAbstractListModel::roleNames(); |
250 | + m_roleNames[KeyRole] = "key"; |
251 | + m_roleNames[TypeRole] = "type"; |
252 | +} |
253 | + |
254 | +SessionsModel::~SessionsModel() |
255 | +{ |
256 | + delete d_ptr; |
257 | +} |
258 | + |
259 | +QVariant SessionsModel::data(const QModelIndex& index, int role) const |
260 | +{ |
261 | + Q_D(const SessionsModel); |
262 | + |
263 | + if(!index.isValid()) { |
264 | + return QVariant(); |
265 | + } |
266 | + |
267 | + int row = index.row(); |
268 | + |
269 | + switch (role) { |
270 | + case QLightDM::SessionsModel::KeyRole: |
271 | + return d->sessionItems[row].key; |
272 | + case Qt::DisplayRole: |
273 | + return d->sessionItems[row].name; |
274 | + default: |
275 | + return QVariant(); |
276 | + } |
277 | +} |
278 | + |
279 | +QHash<int, QByteArray> SessionsModel::roleNames() const |
280 | +{ |
281 | + return m_roleNames; |
282 | +} |
283 | + |
284 | +int SessionsModel::rowCount(const QModelIndex& parent) const |
285 | +{ |
286 | + Q_D(const SessionsModel); |
287 | + |
288 | + if (parent.isValid()) { |
289 | + return 0; |
290 | + } else { // parent is root |
291 | + return d->sessionItems.size(); |
292 | + } |
293 | +} |
294 | + |
295 | +} // namespace QLightDM |
296 | |
297 | === added file 'plugins/LightDM/IntegratedLightDM/liblightdm/SessionsModel.h' |
298 | --- plugins/LightDM/IntegratedLightDM/liblightdm/SessionsModel.h 1970-01-01 00:00:00 +0000 |
299 | +++ plugins/LightDM/IntegratedLightDM/liblightdm/SessionsModel.h 2016-06-30 19:05:07 +0000 |
300 | @@ -0,0 +1,72 @@ |
301 | +/* |
302 | + * Copyright (C) 2015 Canonical, Ltd. |
303 | + * |
304 | + * This program is free software; you can redistribute it and/or modify |
305 | + * it under the terms of the GNU General Public License as published by |
306 | + * the Free Software Foundation; version 3. |
307 | + * |
308 | + * This program is distributed in the hope that it will be useful, |
309 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
310 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
311 | + * GNU General Public License for more details. |
312 | + * |
313 | + * You should have received a copy of the GNU General Public License |
314 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
315 | + * |
316 | + */ |
317 | + |
318 | +#ifndef UNITY_INTEGRATED_SESSIONSMODEL_H |
319 | +#define UNITY_INTEGRATED_SESSIONSMODEL_H |
320 | + |
321 | +#include <QtCore/QAbstractListModel> |
322 | +#include <QtCore/QString> |
323 | + |
324 | +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
325 | + * CHANGES MADE HERE MUST BE REFLECTED ON THE MOCK LIB |
326 | + * COUNTERPART IN tests/mocks/LightDM/IntegratedLightDM/liblightdm |
327 | + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ |
328 | + |
329 | +// This is taken from liblightdm and modified to confirm to our syle conventions |
330 | +namespace QLightDM |
331 | +{ |
332 | +class SessionsModelPrivate; |
333 | + |
334 | +class Q_DECL_EXPORT SessionsModel : public QAbstractListModel |
335 | + { |
336 | + Q_OBJECT |
337 | + |
338 | + Q_ENUMS(SessionModelRoles SessionType) |
339 | + |
340 | + public: |
341 | + |
342 | + enum SessionModelRoles { |
343 | + //name is exposed as Qt::DisplayRole |
344 | + //comment is exposed as Qt::TooltipRole |
345 | + KeyRole = Qt::UserRole, |
346 | + IdRole = KeyRole, /** Deprecated */ |
347 | + TypeRole |
348 | + }; |
349 | + |
350 | + enum SessionType { |
351 | + LocalSessions, |
352 | + RemoteSessions |
353 | + }; |
354 | + |
355 | + explicit SessionsModel(QObject* parent=0); /** Deprecated. Loads local sessions*/ |
356 | + explicit SessionsModel(SessionsModel::SessionType, QObject* parent=0); |
357 | + virtual ~SessionsModel(); |
358 | + |
359 | + QHash<int, QByteArray> roleNames() const override; |
360 | + int rowCount(const QModelIndex& parent) const override; |
361 | + QVariant data(const QModelIndex& index, int role) const override; |
362 | + |
363 | + protected: |
364 | + SessionsModelPrivate* const d_ptr; |
365 | + |
366 | + private: |
367 | + QHash<int, QByteArray> m_roleNames; |
368 | + Q_DECLARE_PRIVATE(SessionsModel) |
369 | + }; |
370 | +} |
371 | + |
372 | +#endif // UNITY_INTEGRATED_SESSIONSMODEL_H |
373 | |
374 | === added file 'plugins/LightDM/IntegratedLightDM/liblightdm/SessionsModelPrivate.cpp' |
375 | --- plugins/LightDM/IntegratedLightDM/liblightdm/SessionsModelPrivate.cpp 1970-01-01 00:00:00 +0000 |
376 | +++ plugins/LightDM/IntegratedLightDM/liblightdm/SessionsModelPrivate.cpp 2016-06-30 19:05:07 +0000 |
377 | @@ -0,0 +1,36 @@ |
378 | +/* |
379 | + * Copyright (C) 2015 Canonical, Ltd. |
380 | + * |
381 | + * This program is free software; you can redistribute it and/or modify |
382 | + * it under the terms of the GNU General Public License as published by |
383 | + * the Free Software Foundation; version 3. |
384 | + * |
385 | + * This program is distributed in the hope that it will be useful, |
386 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
387 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
388 | + * GNU General Public License for more details. |
389 | + * |
390 | + * You should have received a copy of the GNU General Public License |
391 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
392 | + * |
393 | + */ |
394 | + |
395 | +#include "SessionsModelPrivate.h" |
396 | + |
397 | +#include <QDir> |
398 | +#include <QSettings> |
399 | +#include <QStringList> |
400 | + |
401 | +namespace QLightDM |
402 | +{ |
403 | + |
404 | +SessionsModelPrivate::SessionsModelPrivate(SessionsModel* parent) |
405 | + : q_ptr(parent) |
406 | +{ |
407 | + // Since this model is never visible, as there is only 1 session, |
408 | + // just use the session name as the key |
409 | + QString sessionName = qgetenv("XDG_SESSION_DESKTOP"); |
410 | + sessionItems.append({sessionName, "", sessionName, ""}); |
411 | +} |
412 | + |
413 | +} // namespace QLightDM |
414 | |
415 | === added file 'plugins/LightDM/IntegratedLightDM/liblightdm/SessionsModelPrivate.h' |
416 | --- plugins/LightDM/IntegratedLightDM/liblightdm/SessionsModelPrivate.h 1970-01-01 00:00:00 +0000 |
417 | +++ plugins/LightDM/IntegratedLightDM/liblightdm/SessionsModelPrivate.h 2016-06-30 19:05:07 +0000 |
418 | @@ -0,0 +1,54 @@ |
419 | +/* |
420 | + * Copyright (C) 2015 Canonical, Ltd. |
421 | + * |
422 | + * This program is free software; you can redistribute it and/or modify |
423 | + * it under the terms of the GNU General Public License as published by |
424 | + * the Free Software Foundation; version 3. |
425 | + * |
426 | + * This program is distributed in the hope that it will be useful, |
427 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
428 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
429 | + * GNU General Public License for more details. |
430 | + * |
431 | + * You should have received a copy of the GNU General Public License |
432 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
433 | + * |
434 | + */ |
435 | + |
436 | +#ifndef UNITY_INTEGRATED_SESSIONSMODEL_PRIVATE_H |
437 | +#define UNITY_INTEGRATED_SESSIONSMODEL_PRIVATE_H |
438 | + |
439 | +#include <QtCore/QList> |
440 | +#include <QtCore/QString> |
441 | + |
442 | +namespace QLightDM |
443 | +{ |
444 | +class SessionsModel; |
445 | + |
446 | +class SessionItem |
447 | +{ |
448 | +public: |
449 | + QString key; |
450 | + QString type; // unused |
451 | + QString name; |
452 | + QString comment; // unused |
453 | +}; |
454 | + |
455 | +class SessionsModelPrivate |
456 | +{ |
457 | +public: |
458 | + explicit SessionsModelPrivate(SessionsModel* parent=0); |
459 | + virtual ~SessionsModelPrivate() = default; |
460 | + |
461 | + QList<SessionItem> sessionItems; |
462 | + |
463 | +protected: |
464 | + SessionsModel* const q_ptr; |
465 | + |
466 | +private: |
467 | + Q_DECLARE_PUBLIC(SessionsModel) |
468 | +}; |
469 | + |
470 | +} // namespace QLightDM |
471 | + |
472 | +#endif // UNITY_INTEGRATED_SESSIONSMODEL_PRIVATE_H |
473 | |
474 | === added file 'plugins/LightDM/SessionsModel.cpp' |
475 | --- plugins/LightDM/SessionsModel.cpp 1970-01-01 00:00:00 +0000 |
476 | +++ plugins/LightDM/SessionsModel.cpp 2016-06-30 19:05:07 +0000 |
477 | @@ -0,0 +1,122 @@ |
478 | +/* |
479 | + * Copyright (C) 2015 Canonical, Ltd. |
480 | + * |
481 | + * This program is free software; you can redistribute it and/or modify |
482 | + * it under the terms of the GNU General Public License as published by |
483 | + * the Free Software Foundation; version 3. |
484 | + * |
485 | + * This program is distributed in the hope that it will be useful, |
486 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
487 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
488 | + * GNU General Public License for more details. |
489 | + * |
490 | + * You should have received a copy of the GNU General Public License |
491 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
492 | + * |
493 | + */ |
494 | + |
495 | +#include "SessionsModel.h" |
496 | +#include <QtCore/QFile> |
497 | +#include <QtCore/QSortFilterProxyModel> |
498 | + |
499 | +QHash<int, QByteArray> SessionsModel::roleNames() const |
500 | +{ |
501 | + return m_roleNames; |
502 | +} |
503 | + |
504 | +int SessionsModel::rowCount(const QModelIndex& parent) const |
505 | +{ |
506 | + return m_model->rowCount(parent); |
507 | +} |
508 | + |
509 | +QList<QUrl> SessionsModel::iconSearchDirectories() const |
510 | +{ |
511 | + return m_iconSearchDirectories; |
512 | +} |
513 | + |
514 | +void SessionsModel::setIconSearchDirectories(const QList<QUrl> searchDirectories) |
515 | +{ |
516 | + // QML gives us a url with file:// prepended which breaks QFile::exists() |
517 | + // so convert the url to a local file |
518 | + QList<QUrl> localList = {}; |
519 | + Q_FOREACH(const QUrl& searchDirectory, searchDirectories) |
520 | + { |
521 | + localList.append(searchDirectory.toLocalFile()); |
522 | + } |
523 | + m_iconSearchDirectories = localList; |
524 | + Q_EMIT iconSearchDirectoriesChanged(); |
525 | +} |
526 | + |
527 | +QUrl SessionsModel::iconUrl(const QString sessionName) const |
528 | +{ |
529 | + Q_FOREACH(const QUrl& searchDirectory, m_iconSearchDirectories) |
530 | + { |
531 | + // This is an established icon naming convention |
532 | + QString customIconUrl = searchDirectory.toString(QUrl::StripTrailingSlash) + |
533 | + "/custom_" + sessionName + "_badge.png"; |
534 | + QString iconUrl = searchDirectory.toString(QUrl::StripTrailingSlash) + |
535 | + "/" + sessionName + "_badge.png"; |
536 | + |
537 | + QFile customIconFile(customIconUrl); |
538 | + QFile iconFile(iconUrl); |
539 | + if (customIconFile.exists()) { |
540 | + return QUrl(customIconUrl); |
541 | + } else if (iconFile.exists()) { |
542 | + return QUrl(iconUrl); |
543 | + } else{ |
544 | + // Search the legacy way |
545 | + QString path = searchDirectory.toString(QUrl::StripTrailingSlash) + "/"; |
546 | + if (sessionName == "ubuntu" || sessionName == "ubuntu-2d") { |
547 | + path += "ubuntu_badge.png"; |
548 | + } else if( |
549 | + sessionName == "gnome-classic" || |
550 | + sessionName == "gnome-flashback-compiz" || |
551 | + sessionName == "gnome-flashback-metacity" || |
552 | + sessionName == "gnome-shell" || |
553 | + sessionName == "gnome-wayland" || |
554 | + sessionName == "gnome" |
555 | + ){ |
556 | + path += "gnome_badge.png"; |
557 | + } else if (sessionName == "plasma") { |
558 | + path += "kde_badge.png"; |
559 | + } else if (sessionName == "xterm") { |
560 | + path += "recovery_console_badge.png"; |
561 | + } else if (sessionName == "remote-login") { |
562 | + path += "remote_login_help.png"; |
563 | + } |
564 | + |
565 | + if (QFile(path).exists()) { |
566 | + return path; |
567 | + } |
568 | + } |
569 | + } |
570 | + |
571 | + // FIXME make this smarter |
572 | + return QUrl("./graphics/session_icons/unknown_badge.png"); |
573 | +} |
574 | + |
575 | +QVariant SessionsModel::data(const QModelIndex& index, int role) const |
576 | +{ |
577 | + switch (role) { |
578 | + case SessionsModel::IconRole: |
579 | + return iconUrl(m_model->data(index, Qt::DisplayRole).toString()); |
580 | + default: |
581 | + return m_model->data(index, role); |
582 | + } |
583 | +} |
584 | + |
585 | +SessionsModel::SessionsModel(QObject* parent) |
586 | + : UnitySortFilterProxyModelQML(parent) |
587 | +{ |
588 | + // Add a custom IconRole that isn't in either of the lightdm implementations |
589 | + m_model = new QLightDM::SessionsModel(this); |
590 | + m_roleNames = m_model->roleNames(); |
591 | + m_roleNames[IconRole] = "icon_url"; |
592 | + |
593 | + setModel(m_model); |
594 | + setSourceModel(m_model); |
595 | + setSortCaseSensitivity(Qt::CaseInsensitive); |
596 | + setSortLocaleAware(true); |
597 | + setSortRole(Qt::DisplayRole); |
598 | + sort(0); |
599 | +} |
600 | |
601 | === added file 'plugins/LightDM/SessionsModel.h' |
602 | --- plugins/LightDM/SessionsModel.h 1970-01-01 00:00:00 +0000 |
603 | +++ plugins/LightDM/SessionsModel.h 2016-06-30 19:05:07 +0000 |
604 | @@ -0,0 +1,68 @@ |
605 | +/* |
606 | + * Copyright (C) 2015 Canonical, Ltd. |
607 | + * |
608 | + * This program is free software; you can redistribute it and/or modify |
609 | + * it under the terms of the GNU General Public License as published by |
610 | + * the Free Software Foundation; version 3. |
611 | + * |
612 | + * This program is distributed in the hope that it will be useful, |
613 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
614 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
615 | + * GNU General Public License for more details. |
616 | + * |
617 | + * You should have received a copy of the GNU General Public License |
618 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
619 | + * |
620 | + */ |
621 | + |
622 | +#ifndef UNITY_SESSIONSMODEL_H |
623 | +#define UNITY_SESSIONSMODEL_H |
624 | + |
625 | +#include <unitysortfilterproxymodelqml.h> |
626 | +#include <QLightDM/SessionsModel> |
627 | +#include <QtCore/QHash> |
628 | +#include <QtCore/QObject> |
629 | +#include <QtCore/QUrl> |
630 | + |
631 | +class SessionsModel : public UnitySortFilterProxyModelQML |
632 | +{ |
633 | + Q_OBJECT |
634 | + |
635 | + Q_ENUMS(SessionModelRoles) |
636 | + |
637 | + Q_PROPERTY(QList<QUrl> iconSearchDirectories READ iconSearchDirectories |
638 | + WRITE setIconSearchDirectories NOTIFY iconSearchDirectoriesChanged) |
639 | +Q_SIGNALS: |
640 | + void iconSearchDirectoriesChanged(); |
641 | + |
642 | +public: |
643 | + enum SessionModelRoles { |
644 | + /* This is tricky / ugly. Since we are ultimately chaining 3 enums together, |
645 | + * the _first_ value of this enum MUST be the _last_ value of |
646 | + * QLightDM::SessionsModel::SessionModelRoles and consquently, this must |
647 | + * also match the last value in the corresponding enum of the integrated lib |
648 | + */ |
649 | + TypeRole = QLightDM::SessionsModel::SessionModelRoles::TypeRole, |
650 | + IconRole |
651 | + }; |
652 | + |
653 | + explicit SessionsModel(QObject* parent=nullptr); |
654 | + |
655 | + QHash<int, QByteArray> roleNames() const override; |
656 | + int rowCount(const QModelIndex& parent) const override; |
657 | + QVariant data(const QModelIndex& index, int role) const override; |
658 | + QList<QUrl> iconSearchDirectories() const; |
659 | + Q_INVOKABLE QUrl iconUrl(const QString sessionName) const; |
660 | + |
661 | + void setIconSearchDirectories(const QList<QUrl> searchDirectories); |
662 | +private: |
663 | + QLightDM::SessionsModel* m_model; |
664 | + QHash<int, QByteArray> m_roleNames; |
665 | + QList<QUrl> m_iconSearchDirectories{ |
666 | + QUrl("/usr/share/unity8/Greeter/graphics/session_icons"), |
667 | + QUrl("/usr/local/share/unity-greeter"), |
668 | + QUrl("/usr/share/unity-greeter/")}; |
669 | + |
670 | +}; |
671 | + |
672 | +#endif // UNITY_SESSIONSMODEL_H |
673 | |
674 | === modified file 'plugins/LightDM/plugin.cpp' |
675 | --- plugins/LightDM/plugin.cpp 2016-06-30 19:05:01 +0000 |
676 | +++ plugins/LightDM/plugin.cpp 2016-06-30 19:05:07 +0000 |
677 | @@ -19,9 +19,11 @@ |
678 | #include "DBusGreeter.h" |
679 | #include "DBusGreeterList.h" |
680 | #include "Greeter.h" |
681 | +#include "SessionsModel.h" |
682 | #include "UsersModel.h" |
683 | #include <libusermetricsoutput/ColorTheme.h> |
684 | #include <libusermetricsoutput/UserMetrics.h> |
685 | +#include <QLightDM/SessionsModel> |
686 | #include <QLightDM/UsersModel> |
687 | |
688 | #include <QAbstractItemModel> |
689 | @@ -40,6 +42,13 @@ |
690 | return greeter; |
691 | } |
692 | |
693 | +static QObject *sessions_provider(QQmlEngine *engine, QJSEngine *scriptEngine) |
694 | +{ |
695 | + Q_UNUSED(engine) |
696 | + Q_UNUSED(scriptEngine) |
697 | + return new SessionsModel(); |
698 | +} |
699 | + |
700 | static QObject *users_provider(QQmlEngine *engine, QJSEngine *scriptEngine) |
701 | { |
702 | Q_UNUSED(engine) |
703 | @@ -61,21 +70,22 @@ |
704 | |
705 | #if defined INTEGRATED_LIGHTDM |
706 | Q_ASSERT(uri == QLatin1String("LightDM.IntegratedLightDM")); |
707 | + qmlRegisterSingletonType<Greeter>(uri, 0, 1, "Greeter", greeter_provider); |
708 | #elif defined FULL_LIGHTDM |
709 | Q_ASSERT(uri == QLatin1String("LightDM.FullLightDM")); |
710 | -#endif |
711 | - qRegisterMetaType<QLightDM::Greeter::MessageType>("QLightDM::Greeter::MessageType"); |
712 | - qRegisterMetaType<QLightDM::Greeter::PromptType>("QLightDM::Greeter::PromptType"); |
713 | - |
714 | -#if defined INTEGRATED_LIGHTDM |
715 | - qmlRegisterSingletonType<Greeter>(uri, 0, 1, "Greeter", greeter_provider); |
716 | -#elif defined FULL_LIGHTDM |
717 | qmlRegisterSingletonType<QLightDM::Greeter>(uri, 0, 1, "Greeter", greeter_provider); |
718 | #else |
719 | #error No library defined in LightDM plugin |
720 | #endif |
721 | |
722 | + qRegisterMetaType<QLightDM::Greeter::MessageType>("QLightDM::Greeter::MessageType"); |
723 | + qRegisterMetaType<QLightDM::Greeter::PromptType>("QLightDM::Greeter::PromptType"); |
724 | + |
725 | + qmlRegisterSingletonType<SessionsModel>(uri, 0, 1, "Sessions", sessions_provider); |
726 | + qmlRegisterUncreatableType<SessionsModel>(uri, 0, 1, "SessionRoles", QStringLiteral("Type is not instantiable")); |
727 | + |
728 | qmlRegisterSingletonType<UsersModel>(uri, 0, 1, "Users", users_provider); |
729 | qmlRegisterUncreatableType<QLightDM::UsersModel>(uri, 0, 1, "UserRoles", QStringLiteral("Type is not instantiable")); |
730 | + |
731 | qmlRegisterSingletonType<UserMetricsOutput::UserMetrics>(uri, 0, 1, "Infographic", infographic_provider); |
732 | } |
733 | |
734 | === modified file 'qml/Greeter/Greeter.qml' |
735 | --- qml/Greeter/Greeter.qml 2016-06-30 19:05:01 +0000 |
736 | +++ qml/Greeter/Greeter.qml 2016-06-30 19:05:07 +0000 |
737 | @@ -163,35 +163,41 @@ |
738 | return -1; |
739 | } |
740 | |
741 | - function selectUser(uid, reset) { |
742 | - if (uid < 0) |
743 | + function selectUser(index, reset) { |
744 | + if (index < 0 || index >= LightDMService.users.count) |
745 | return; |
746 | d.waiting = true; |
747 | if (reset) { |
748 | loader.item.reset(); |
749 | } |
750 | - currentIndex = uid; |
751 | - var user = LightDMService.users.data(uid, LightDMService.userRoles.NameRole); |
752 | + currentIndex = index; |
753 | + var user = LightDMService.users.data(index, LightDMService.userRoles.NameRole); |
754 | AccountsService.user = user; |
755 | LauncherModel.setUser(user); |
756 | LightDMService.greeter.authenticate(user); // always resets auth state |
757 | } |
758 | |
759 | + function hideView() { |
760 | + if (loader.item) { |
761 | + loader.item.enabled = false; // drop OSK and prevent interaction |
762 | + loader.item.notifyAuthenticationSucceeded(false /* showFakePassword */); |
763 | + loader.item.hide(); |
764 | + } |
765 | + } |
766 | + |
767 | function login() { |
768 | - enabled = false; |
769 | + d.waiting = true; |
770 | if (LightDMService.greeter.startSessionSync()) { |
771 | sessionStarted(); |
772 | - if (loader.item) { |
773 | - loader.item.notifyAuthenticationSucceeded(false /* showFakePassword */); |
774 | - } |
775 | + hideView(); |
776 | } else if (loader.item) { |
777 | loader.item.notifyAuthenticationFailed(); |
778 | } |
779 | - enabled = true; |
780 | + d.waiting = false; |
781 | } |
782 | |
783 | function startUnlock(toTheRight) { |
784 | - if (loader.item) { |
785 | + if (loader.item && !d.waiting) { |
786 | return loader.item.tryToUnlock(toTheRight); |
787 | } else { |
788 | return false; |
789 | @@ -199,10 +205,8 @@ |
790 | } |
791 | |
792 | function checkForcedUnlock(hideNow) { |
793 | - if (forcedUnlock && shown && loader.item) { |
794 | - // pretend we were just authenticated |
795 | - loader.item.notifyAuthenticationSucceeded(false /* showFakePassword */); |
796 | - loader.item.hide(); |
797 | + if (forcedUnlock && shown) { |
798 | + hideView(); |
799 | if (hideNow) { |
800 | root.hideNow(); // skip hide animation |
801 | } |
802 | @@ -323,7 +327,7 @@ |
803 | |
804 | onLoaded: { |
805 | root.lockedApp = ""; |
806 | - root.forceActiveFocus(); |
807 | + item.forceActiveFocus(); |
808 | d.selectUser(d.currentIndex, true); |
809 | LightDMService.infographic.readyForDataChange(); |
810 | } |
811 | @@ -333,13 +337,11 @@ |
812 | onSelected: { |
813 | d.selectUser(index, true); |
814 | } |
815 | - onPromptlessLogin: d.login(); |
816 | onResponded: { |
817 | if (root.locked) { |
818 | LightDMService.greeter.respond(response); |
819 | } else { |
820 | d.login(); |
821 | - loader.item.hide(); |
822 | } |
823 | } |
824 | onTease: root.tease() |
825 | @@ -389,6 +391,12 @@ |
826 | |
827 | Binding { |
828 | target: loader.item |
829 | + property: "waiting" |
830 | + value: d.waiting |
831 | + } |
832 | + |
833 | + Binding { |
834 | + target: loader.item |
835 | property: "alphanumeric" |
836 | value: d.alphanumeric |
837 | } |
838 | @@ -417,10 +425,7 @@ |
839 | |
840 | onShowGreeter: root.forceShow() |
841 | |
842 | - onHideGreeter: { |
843 | - d.login(); |
844 | - loader.item.hide(); |
845 | - } |
846 | + onHideGreeter: d.login() |
847 | |
848 | onShowMessage: { |
849 | // inefficient, but we only rarely deal with messages |
850 | @@ -438,11 +443,11 @@ |
851 | } |
852 | |
853 | onShowPrompt: { |
854 | - d.waiting = false; |
855 | - |
856 | if (loader.item) { |
857 | loader.item.showPrompt(text, isSecret, isDefaultPrompt); |
858 | } |
859 | + |
860 | + d.waiting = false; |
861 | } |
862 | |
863 | onAuthenticationComplete: { |
864 | @@ -451,7 +456,6 @@ |
865 | if (LightDMService.greeter.authenticated) { |
866 | if (!LightDMService.greeter.promptless) { |
867 | d.login(); |
868 | - loader.item.hide(); |
869 | } |
870 | } else { |
871 | if (!LightDMService.greeter.promptless) { |
872 | |
873 | === modified file 'qml/Greeter/GreeterPrompt.qml' |
874 | --- qml/Greeter/GreeterPrompt.qml 2016-06-06 18:21:22 +0000 |
875 | +++ qml/Greeter/GreeterPrompt.qml 2016-06-30 19:05:07 +0000 |
876 | @@ -16,6 +16,7 @@ |
877 | |
878 | import QtQuick 2.4 |
879 | import Ubuntu.Components 1.3 |
880 | +import "../Components" |
881 | |
882 | FocusScope { |
883 | id: root |
884 | @@ -33,6 +34,7 @@ |
885 | |
886 | function reset() { |
887 | passwordInput.text = ""; |
888 | + fakeLabel.text = ""; |
889 | d.enabled = true; |
890 | } |
891 | |
892 | @@ -62,10 +64,14 @@ |
893 | objectName: "promptButton" |
894 | anchors.fill: parent |
895 | visible: !root.isPrompt |
896 | - enabled: d.enabled |
897 | focus: visible |
898 | |
899 | - onClicked: root.clicked() |
900 | + onClicked: { |
901 | + if (d.enabled) { |
902 | + d.enabled = false; |
903 | + root.clicked(); |
904 | + } |
905 | + } |
906 | |
907 | Label { |
908 | anchors.centerIn: parent |
909 | @@ -79,10 +85,22 @@ |
910 | objectName: "promptField" |
911 | anchors.fill: parent |
912 | visible: root.isPrompt |
913 | - enabled: d.enabled |
914 | - focus: visible |
915 | - |
916 | - inputMethodHints: root.isAlphanumeric ? Qt.ImhNone : Qt.ImhDigitsOnly |
917 | + opacity: fakeLabel.visible ? 0 : 1 |
918 | + |
919 | + // Oddly, a simple "focus: visible" does not stick -- the binding |
920 | + // gets lost when switching between buttons and prompts. But this |
921 | + // explicit binding does work. |
922 | + Binding on focus { |
923 | + value: passwordInput.visible |
924 | + } |
925 | + |
926 | + validator: RegExpValidator { |
927 | + regExp: root.isAlphanumeric ? /^.*$/ : /^\d{4}$/ |
928 | + } |
929 | + |
930 | + inputMethodHints: Qt.ImhSensitiveData | Qt.ImhNoPredictiveText | |
931 | + Qt.ImhMultiLine | // so OSK doesn't close on Enter |
932 | + (root.isAlphanumeric ? Qt.ImhNone : Qt.ImhDigitsOnly) |
933 | echoMode: root.isSecret ? TextInput.Password : TextInput.Normal |
934 | hasClearButton: false |
935 | |
936 | @@ -107,17 +125,35 @@ |
937 | width: units.gu(3) |
938 | color: d.textColor |
939 | visible: root.isSecret && false // TODO: detect when caps lock is on |
940 | + readonly property real visibleWidth: visible ? width + passwordInput.frameSpacing : 0 |
941 | } |
942 | ] |
943 | |
944 | + onDisplayTextChanged: { |
945 | + // We use onDisplayTextChanged instead of onTextChanged because |
946 | + // displayText changes after text and if we did this before it |
947 | + // updated, we would use the wrong displayText for fakeLabel. |
948 | + if (!isAlphanumeric && text.length >= 4) { |
949 | + // hard limit of 4 for passcodes right now |
950 | + respond(); |
951 | + } |
952 | + } |
953 | + |
954 | onAccepted: { |
955 | - if (!enabled) |
956 | - return; |
957 | + if (d.enabled) |
958 | + respond(); |
959 | + } |
960 | + |
961 | + function respond() { |
962 | d.enabled = false; |
963 | + fakeLabel.text = displayText; |
964 | root.responded(text); |
965 | } |
966 | |
967 | - Keys.onEscapePressed: root.canceled() |
968 | + Keys.onEscapePressed: { |
969 | + root.canceled(); |
970 | + event.accepted = true; |
971 | + } |
972 | |
973 | // We use our own custom placeholder label instead of the standard |
974 | // TextField one because the standard one hardcodes baseText as the |
975 | @@ -129,9 +165,7 @@ |
976 | right: parent.right |
977 | verticalCenter: parent.verticalCenter |
978 | leftMargin: units.gu(1.5) |
979 | - rightMargin: anchors.leftMargin + |
980 | - (capsIcon.visible ? capsIcon.width + passwordInput.frameSpacing |
981 | - : 0) |
982 | + rightMargin: anchors.leftMargin + capsIcon.visibleWidth |
983 | } |
984 | text: root.text |
985 | visible: passwordInput.text == "" && !passwordInput.inputMethodComposing |
986 | @@ -139,4 +173,22 @@ |
987 | elide: Text.ElideRight |
988 | } |
989 | } |
990 | + |
991 | + // Have a fake label that covers the text field after the user presses |
992 | + // enter. What we *really* want is a disabled mode that doesn't lose |
993 | + // focus. Because our goal here is simply to keep the OSK up while |
994 | + // we wait for PAM to get back to us, and while waiting, we don't want |
995 | + // the user to be able to edit the field (simply because it would look |
996 | + // weird if we allowed that). But until we have such a disabled mode, |
997 | + // we'll fake it by covering the real text field with a label. |
998 | + FadingLabel { |
999 | + id: fakeLabel |
1000 | + anchors.verticalCenter: parent.verticalCenter |
1001 | + anchors.left: parent.left |
1002 | + anchors.right: parent.right |
1003 | + anchors.leftMargin: passwordInput.frameSpacing * 2 |
1004 | + anchors.rightMargin: passwordInput.frameSpacing * 2 + capsIcon.visibleWidth |
1005 | + color: d.drawColor |
1006 | + visible: root.isPrompt && !d.enabled |
1007 | + } |
1008 | } |
1009 | |
1010 | === modified file 'qml/Greeter/LoginList.qml' |
1011 | --- qml/Greeter/LoginList.qml 2016-06-30 19:05:01 +0000 |
1012 | +++ qml/Greeter/LoginList.qml 2016-06-30 19:05:07 +0000 |
1013 | @@ -21,11 +21,13 @@ |
1014 | |
1015 | StyledItem { |
1016 | id: root |
1017 | + focus: true |
1018 | |
1019 | property alias model: userList.model |
1020 | property bool alphanumeric: true |
1021 | property int currentIndex |
1022 | property bool locked |
1023 | + property bool waiting |
1024 | |
1025 | readonly property int numAboveBelow: 4 |
1026 | readonly property int cellHeight: units.gu(5) |
1027 | @@ -36,7 +38,6 @@ |
1028 | |
1029 | signal selected(int index) |
1030 | signal responded(string response) |
1031 | - signal promptlessLogin() |
1032 | |
1033 | function tryToUnlock() { |
1034 | if (wasPrompted) { |
1035 | @@ -45,7 +46,6 @@ |
1036 | if (root.locked) { |
1037 | root.selected(currentIndex); |
1038 | } else { |
1039 | - promptlessLogin(); |
1040 | root.responded(""); |
1041 | } |
1042 | } |
1043 | @@ -60,20 +60,18 @@ |
1044 | } |
1045 | |
1046 | function showPrompt(text, isSecret, isDefaultPrompt) { |
1047 | - d.promptText = text; |
1048 | - passwordInput.reset(); |
1049 | + passwordInput.text = isDefaultPrompt ? alphanumeric ? i18n.tr("Passphrase") |
1050 | + : i18n.tr("Passcode") |
1051 | + : text; |
1052 | + passwordInput.isPrompt = true; |
1053 | passwordInput.isSecret = isSecret; |
1054 | - if (wasPrompted) // stay in text field if second prompt |
1055 | - passwordInput.focus = true; |
1056 | + passwordInput.reset(); |
1057 | wasPrompted = true; |
1058 | } |
1059 | |
1060 | function showError() { |
1061 | wrongPasswordAnimation.start(); |
1062 | root.resetAuthentication(); |
1063 | - if (wasPrompted) { |
1064 | - passwordInput.focus = true; |
1065 | - } |
1066 | } |
1067 | |
1068 | function reset() { |
1069 | @@ -83,15 +81,33 @@ |
1070 | QtObject { |
1071 | id: d |
1072 | |
1073 | - property string promptText |
1074 | + function checkIfPromptless() { |
1075 | + if (!waiting && !wasPrompted) { |
1076 | + passwordInput.isPrompt = false; |
1077 | + passwordInput.text = root.locked ? i18n.tr("Retry") |
1078 | + : i18n.tr("Log In") |
1079 | + } |
1080 | + } |
1081 | } |
1082 | |
1083 | + onWaitingChanged: d.checkIfPromptless() |
1084 | + onLockedChanged: d.checkIfPromptless() |
1085 | + |
1086 | theme: ThemeSettings { |
1087 | name: "Ubuntu.Components.Themes.Ambiance" |
1088 | } |
1089 | |
1090 | + Keys.onUpPressed: { |
1091 | + selected(currentIndex - 1); |
1092 | + event.accepted = true; |
1093 | + } |
1094 | + Keys.onDownPressed: { |
1095 | + selected(currentIndex + 1); |
1096 | + event.accepted = true; |
1097 | + } |
1098 | Keys.onEscapePressed: { |
1099 | selected(currentIndex); |
1100 | + event.accepted = true; |
1101 | } |
1102 | |
1103 | onCurrentIndexChanged: { |
1104 | @@ -137,6 +153,7 @@ |
1105 | highlightRangeMode: ListView.StrictlyEnforceRange |
1106 | highlightMoveDuration: root.moveDuration |
1107 | flickDeceleration: 10000 |
1108 | + interactive: count > 1 |
1109 | |
1110 | readonly property bool movingInternally: moveTimer.running || userList.moving |
1111 | onMovingInternallyChanged: { |
1112 | @@ -254,13 +271,8 @@ |
1113 | width: highlightItem.width - anchors.margins * 2 |
1114 | opacity: userList.movingInternally ? 0 : 1 |
1115 | |
1116 | - isPrompt: root.wasPrompted |
1117 | isAlphanumeric: root.alphanumeric |
1118 | |
1119 | - text: root.wasPrompted ? d.promptText |
1120 | - : (root.locked ? i18n.tr("Retry") |
1121 | - : i18n.tr("Log In")) |
1122 | - |
1123 | onClicked: root.tryToUnlock() |
1124 | onResponded: root.responded(text) |
1125 | onCanceled: root.selected(currentIndex) |
1126 | @@ -280,7 +292,6 @@ |
1127 | return; |
1128 | } |
1129 | infoLabel.text = ""; |
1130 | - d.promptText = ""; |
1131 | passwordInput.reset(); |
1132 | root.wasPrompted = false; |
1133 | } |
1134 | |
1135 | === modified file 'qml/Greeter/NarrowView.qml' |
1136 | --- qml/Greeter/NarrowView.qml 2016-06-20 20:23:28 +0000 |
1137 | +++ qml/Greeter/NarrowView.qml 2016-06-30 19:05:07 +0000 |
1138 | @@ -31,6 +31,7 @@ |
1139 | property bool alphanumeric |
1140 | property var userModel // unused |
1141 | property alias infographicModel: coverPage.infographicModel |
1142 | + property bool waiting |
1143 | readonly property bool fullyShown: coverPage.showProgress === 1 || lockscreen.shown |
1144 | readonly property bool required: coverPage.required || lockscreen.required |
1145 | readonly property bool animating: coverPage.showAnimation.running || coverPage.hideAnimation.running |
1146 | @@ -71,7 +72,6 @@ |
1147 | if (!alphanumeric && showFakePassword) { |
1148 | lockscreen.showText("...."); // actual text doesn't matter, we show bullets |
1149 | } |
1150 | - lockscreen.hide(); |
1151 | } |
1152 | |
1153 | function notifyAuthenticationFailed() { |
1154 | @@ -172,6 +172,7 @@ |
1155 | height: parent.height |
1156 | width: parent.width |
1157 | background: root.background |
1158 | + draggable: !root.waiting |
1159 | onTease: root.tease() |
1160 | onClicked: hide() |
1161 | |
1162 | |
1163 | === modified file 'qml/Greeter/WideView.qml' |
1164 | --- qml/Greeter/WideView.qml 2016-06-30 19:05:01 +0000 |
1165 | +++ qml/Greeter/WideView.qml 2016-06-30 19:05:07 +0000 |
1166 | @@ -19,6 +19,7 @@ |
1167 | |
1168 | FocusScope { |
1169 | id: root |
1170 | + focus: true |
1171 | |
1172 | property alias dragHandleLeftMargin: coverPage.dragHandleLeftMargin |
1173 | property alias launcherOffset: coverPage.launcherOffset |
1174 | @@ -30,6 +31,7 @@ |
1175 | property alias alphanumeric: loginList.alphanumeric |
1176 | property alias userModel: loginList.model |
1177 | property alias infographicModel: coverPage.infographicModel |
1178 | + property bool waiting |
1179 | readonly property bool fullyShown: coverPage.showProgress === 1 |
1180 | readonly property bool required: coverPage.required |
1181 | readonly property bool animating: coverPage.showAnimation.running || coverPage.hideAnimation.running |
1182 | @@ -37,7 +39,6 @@ |
1183 | // so that it can be replaced in tests with a mock object |
1184 | property var inputMethod: Qt.inputMethod |
1185 | |
1186 | - signal promptlessLogin() |
1187 | signal selected(int index) |
1188 | signal responded(string response) |
1189 | signal tease() |
1190 | @@ -102,7 +103,7 @@ |
1191 | objectName: "coverPage" |
1192 | height: parent.height |
1193 | width: parent.width |
1194 | - draggable: !root.locked |
1195 | + draggable: !root.locked && !root.waiting |
1196 | |
1197 | infographics { |
1198 | height: 0.75 * parent.height |
1199 | @@ -132,8 +133,8 @@ |
1200 | Behavior on height { UbuntuNumberAnimation {} } |
1201 | |
1202 | locked: root.locked |
1203 | + waiting: root.waiting |
1204 | |
1205 | - onPromptlessLogin: root.promptlessLogin() |
1206 | onSelected: root.selected(index) |
1207 | onResponded: root.responded(response) |
1208 | } |
1209 | |
1210 | === modified file 'qml/Shell.qml' |
1211 | --- qml/Shell.qml 2016-06-30 19:05:01 +0000 |
1212 | +++ qml/Shell.qml 2016-06-30 19:05:07 +0000 |
1213 | @@ -137,9 +137,9 @@ |
1214 | // For autopilot consumption |
1215 | readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId |
1216 | |
1217 | - // Disable everything while greeter is waiting, so that the user can't swipe |
1218 | - // the greeter or launcher until we know whether the session is locked. |
1219 | - enabled: greeter && !greeter.waiting |
1220 | + // Note when greeter is waiting on PAM, so that we can disable edges until |
1221 | + // we know which user data to show and whether the session is locked. |
1222 | + readonly property bool waitingOnGreeter: greeter && greeter.waiting |
1223 | |
1224 | property real edgeSize: units.gu(settings.edgeDragWidth) |
1225 | |
1226 | @@ -528,6 +528,7 @@ |
1227 | available: tutorial.panelEnabled |
1228 | && ((!greeter || !greeter.locked) || AccountsService.enableIndicatorsWhileLocked) |
1229 | && (!greeter || !greeter.hasLockedApp) |
1230 | + && !shell.waitingOnGreeter |
1231 | width: parent.width > units.gu(60) ? units.gu(40) : parent.width |
1232 | |
1233 | minimizedPanelHeight: units.gu(3) |
1234 | @@ -578,6 +579,7 @@ |
1235 | available: tutorial.launcherEnabled |
1236 | && (!greeter.locked || AccountsService.enableLauncherWhileLocked) |
1237 | && !greeter.hasLockedApp |
1238 | + && !shell.waitingOnGreeter |
1239 | inverted: shell.usageScenario !== "desktop" |
1240 | superPressed: physicalKeysMapper.superPressed |
1241 | superTabPressed: physicalKeysMapper.superTabPressed |
1242 | |
1243 | === modified file 'tests/mocks/LightDM/IntegratedLightDM/CMakeLists.txt' |
1244 | --- tests/mocks/LightDM/IntegratedLightDM/CMakeLists.txt 2016-06-30 19:05:01 +0000 |
1245 | +++ tests/mocks/LightDM/IntegratedLightDM/CMakeLists.txt 2016-06-30 19:05:07 +0000 |
1246 | @@ -19,9 +19,11 @@ |
1247 | ${CMAKE_SOURCE_DIR}/plugins/LightDM/DBusGreeter.cpp |
1248 | ${CMAKE_SOURCE_DIR}/plugins/LightDM/DBusGreeterList.cpp |
1249 | ${CMAKE_SOURCE_DIR}/plugins/LightDM/Greeter.cpp |
1250 | + ${CMAKE_SOURCE_DIR}/plugins/LightDM/SessionsModel.cpp |
1251 | ${CMAKE_SOURCE_DIR}/plugins/LightDM/UsersModel.cpp |
1252 | ${CMAKE_SOURCE_DIR}/plugins/Utils/unitysortfilterproxymodelqml.cpp |
1253 | MockGreeter.cpp |
1254 | + MockSessionsModel.cpp |
1255 | MockUsersModel.cpp |
1256 | plugin.cpp |
1257 | ) |
1258 | |
1259 | === added file 'tests/mocks/LightDM/IntegratedLightDM/MockSessionsModel.cpp' |
1260 | --- tests/mocks/LightDM/IntegratedLightDM/MockSessionsModel.cpp 1970-01-01 00:00:00 +0000 |
1261 | +++ tests/mocks/LightDM/IntegratedLightDM/MockSessionsModel.cpp 2016-06-30 19:05:07 +0000 |
1262 | @@ -0,0 +1,37 @@ |
1263 | +/* |
1264 | + * Copyright (C) 2015 Canonical, Ltd. |
1265 | + * |
1266 | + * This program is free software; you can redistribute it and/or modify |
1267 | + * it under the terms of the GNU General Public License as published by |
1268 | + * the Free Software Foundation; version 3. |
1269 | + * |
1270 | + * This program is distributed in the hope that it will be useful, |
1271 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1272 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1273 | + * GNU General Public License for more details. |
1274 | + * |
1275 | + * You should have received a copy of the GNU General Public License |
1276 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1277 | + * |
1278 | + */ |
1279 | + |
1280 | +#include "MockSessionsModel.h" |
1281 | +#include <QLightDM/SessionsModel> |
1282 | + |
1283 | +QString MockSessionsModel::testScenario() const |
1284 | +{ |
1285 | + QLightDM::SessionsModel* qSessionsModel = |
1286 | + static_cast<QLightDM::SessionsModel*>(sourceModel()); |
1287 | + |
1288 | + return qSessionsModel->testScenario(); |
1289 | +} |
1290 | + |
1291 | +void MockSessionsModel::setTestScenario(const QString testScenario) |
1292 | +{ |
1293 | + QLightDM::SessionsModel* qSessionsModel = |
1294 | + static_cast<QLightDM::SessionsModel*>(sourceModel()); |
1295 | + |
1296 | + if (qSessionsModel->testScenario() != testScenario) { |
1297 | + qSessionsModel->setTestScenario(testScenario); |
1298 | + } |
1299 | +} |
1300 | |
1301 | === added file 'tests/mocks/LightDM/IntegratedLightDM/MockSessionsModel.h' |
1302 | --- tests/mocks/LightDM/IntegratedLightDM/MockSessionsModel.h 1970-01-01 00:00:00 +0000 |
1303 | +++ tests/mocks/LightDM/IntegratedLightDM/MockSessionsModel.h 2016-06-30 19:05:07 +0000 |
1304 | @@ -0,0 +1,34 @@ |
1305 | +/* |
1306 | + * Copyright (C) 2015 Canonical, Ltd. |
1307 | + * |
1308 | + * This program is free software; you can redistribute it and/or modify |
1309 | + * it under the terms of the GNU General Public License as published by |
1310 | + * the Free Software Foundation; version 3. |
1311 | + * |
1312 | + * This program is distributed in the hope that it will be useful, |
1313 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1314 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1315 | + * GNU General Public License for more details. |
1316 | + * |
1317 | + * You should have received a copy of the GNU General Public License |
1318 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1319 | + * |
1320 | + */ |
1321 | + |
1322 | +#ifndef MOCK_UNITY_SESSIONSMODEL_H |
1323 | +#define MOCK_UNITY_SESSIONSMODEL_H |
1324 | + |
1325 | +#include <SessionsModel.h> |
1326 | + |
1327 | +class MockSessionsModel : public SessionsModel |
1328 | +{ |
1329 | + Q_OBJECT |
1330 | + |
1331 | + Q_PROPERTY(QString testScenario READ testScenario WRITE setTestScenario) |
1332 | + |
1333 | +public: |
1334 | + QString testScenario() const; |
1335 | + void setTestScenario(QString testScenario); |
1336 | +}; |
1337 | + |
1338 | +#endif // MOCK_UNITY_SESSIONSMODEL_H |
1339 | |
1340 | === added file 'tests/mocks/LightDM/IntegratedLightDM/QLightDM/SessionsModel' |
1341 | --- tests/mocks/LightDM/IntegratedLightDM/QLightDM/SessionsModel 1970-01-01 00:00:00 +0000 |
1342 | +++ tests/mocks/LightDM/IntegratedLightDM/QLightDM/SessionsModel 2016-06-30 19:05:07 +0000 |
1343 | @@ -0,0 +1,17 @@ |
1344 | +/* |
1345 | + * Copyright (C) 2015 Canonical, Ltd. |
1346 | + * |
1347 | + * This program is free software; you can redistribute it and/or modify |
1348 | + * it under the terms of the GNU General Public License as published by |
1349 | + * the Free Software Foundation; version 3. |
1350 | + * |
1351 | + * This program is distributed in the hope that it will be useful, |
1352 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1353 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1354 | + * GNU General Public License for more details. |
1355 | + * |
1356 | + * You should have received a copy of the GNU General Public License |
1357 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1358 | + */ |
1359 | + |
1360 | +#include "../liblightdm/SessionsModel.h" |
1361 | |
1362 | === modified file 'tests/mocks/LightDM/IntegratedLightDM/liblightdm/CMakeLists.txt' |
1363 | --- tests/mocks/LightDM/IntegratedLightDM/liblightdm/CMakeLists.txt 2016-06-30 19:05:01 +0000 |
1364 | +++ tests/mocks/LightDM/IntegratedLightDM/liblightdm/CMakeLists.txt 2016-06-30 19:05:07 +0000 |
1365 | @@ -1,7 +1,9 @@ |
1366 | set(LibLightDM_SOURCES |
1367 | Greeter.cpp |
1368 | + SessionsModel.cpp |
1369 | UsersModel.cpp |
1370 | GreeterPrivate.cpp |
1371 | + SessionsModelPrivate.cpp |
1372 | UsersModelPrivate.cpp |
1373 | ${CMAKE_SOURCE_DIR}/plugins/Utils/qvariantlistmodel.cpp |
1374 | ) |
1375 | |
1376 | === modified file 'tests/mocks/LightDM/IntegratedLightDM/liblightdm/Greeter.cpp' |
1377 | --- tests/mocks/LightDM/IntegratedLightDM/liblightdm/Greeter.cpp 2016-06-30 19:05:01 +0000 |
1378 | +++ tests/mocks/LightDM/IntegratedLightDM/liblightdm/Greeter.cpp 2016-06-30 19:05:07 +0000 |
1379 | @@ -51,7 +51,7 @@ |
1380 | |
1381 | QString Greeter::defaultSessionHint() const |
1382 | { |
1383 | - return "ubuntu"; |
1384 | + return QStringLiteral("ubuntu"); |
1385 | } |
1386 | |
1387 | bool Greeter::hideUsersHint() const |
1388 | |
1389 | === added file 'tests/mocks/LightDM/IntegratedLightDM/liblightdm/SessionsModel.cpp' |
1390 | --- tests/mocks/LightDM/IntegratedLightDM/liblightdm/SessionsModel.cpp 1970-01-01 00:00:00 +0000 |
1391 | +++ tests/mocks/LightDM/IntegratedLightDM/liblightdm/SessionsModel.cpp 2016-06-30 19:05:07 +0000 |
1392 | @@ -0,0 +1,99 @@ |
1393 | +/* |
1394 | + * Copyright (C) 2015 Canonical, Ltd. |
1395 | + * |
1396 | + * This program is free software; you can redistribute it and/or modify |
1397 | + * it under the terms of the GNU General Public License as published by |
1398 | + * the Free Software Foundation; version 3. |
1399 | + * |
1400 | + * This program is distributed in the hope that it will be useful, |
1401 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1402 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1403 | + * GNU General Public License for more details. |
1404 | + * |
1405 | + * You should have received a copy of the GNU General Public License |
1406 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1407 | + * |
1408 | + */ |
1409 | + |
1410 | + |
1411 | +// LightDM currently is Qt4 compatible, and so doesn't define setRoleNames. |
1412 | +// To use the same method of setting role name that it does, we |
1413 | +// set our compatibility to Qt4 here too. |
1414 | +#define QT_DISABLE_DEPRECATED_BEFORE QT_VERSION_CHECK(4, 0, 0) |
1415 | + |
1416 | +#include "SessionsModel.h" |
1417 | +#include "SessionsModelPrivate.h" |
1418 | +#include <QtCore/QDir> |
1419 | +#include <QtCore/QString> |
1420 | + |
1421 | +namespace QLightDM |
1422 | +{ |
1423 | + |
1424 | +SessionsModel::SessionsModel(QObject* parent) : |
1425 | + QAbstractListModel(parent), |
1426 | + d_ptr(new SessionsModelPrivate(this)) |
1427 | +{ |
1428 | + Q_D(SessionsModel); |
1429 | + m_roleNames = QAbstractListModel::roleNames(); |
1430 | + m_roleNames[KeyRole] = "key"; |
1431 | + m_roleNames[TypeRole] = "type"; |
1432 | +} |
1433 | + |
1434 | +SessionsModel::~SessionsModel() |
1435 | +{ |
1436 | + delete d_ptr; |
1437 | +} |
1438 | + |
1439 | +QVariant SessionsModel::data(const QModelIndex& index, int role) const |
1440 | +{ |
1441 | + Q_D(const SessionsModel); |
1442 | + |
1443 | + if(!index.isValid()) { |
1444 | + return QVariant(); |
1445 | + } |
1446 | + |
1447 | + int row = index.row(); |
1448 | + |
1449 | + switch (role) { |
1450 | + case QLightDM::SessionsModel::KeyRole: |
1451 | + return d->sessionItems[row].key; |
1452 | + case Qt::DisplayRole: |
1453 | + return d->sessionItems[row].name; |
1454 | + default: |
1455 | + return QVariant(); |
1456 | + } |
1457 | +} |
1458 | + |
1459 | +QHash<int, QByteArray> SessionsModel::roleNames() const |
1460 | +{ |
1461 | + return m_roleNames; |
1462 | +} |
1463 | + |
1464 | +int SessionsModel::rowCount(const QModelIndex& parent) const |
1465 | +{ |
1466 | + Q_D(const SessionsModel); |
1467 | + |
1468 | + if (parent.isValid()) { |
1469 | + return 0; |
1470 | + } else { // parent is root |
1471 | + return d->sessionItems.size(); |
1472 | + } |
1473 | +} |
1474 | + |
1475 | +QString SessionsModel::testScenario() const |
1476 | +{ |
1477 | + Q_D(const SessionsModel); |
1478 | + return d->testScenario; |
1479 | +} |
1480 | + |
1481 | +void SessionsModel::setTestScenario(QString testScenario) |
1482 | +{ |
1483 | + Q_D(SessionsModel); |
1484 | + |
1485 | + if (d->testScenario != testScenario) { |
1486 | + d->testScenario = testScenario; |
1487 | + d->resetEntries(); |
1488 | + } |
1489 | +} |
1490 | + |
1491 | +} // namespace QLightDM |
1492 | |
1493 | === added file 'tests/mocks/LightDM/IntegratedLightDM/liblightdm/SessionsModel.h' |
1494 | --- tests/mocks/LightDM/IntegratedLightDM/liblightdm/SessionsModel.h 1970-01-01 00:00:00 +0000 |
1495 | +++ tests/mocks/LightDM/IntegratedLightDM/liblightdm/SessionsModel.h 2016-06-30 19:05:07 +0000 |
1496 | @@ -0,0 +1,72 @@ |
1497 | +/* |
1498 | + * Copyright (C) 2015 Canonical, Ltd. |
1499 | + * |
1500 | + * This program is free software; you can redistribute it and/or modify |
1501 | + * it under the terms of the GNU General Public License as published by |
1502 | + * the Free Software Foundation; version 3. |
1503 | + * |
1504 | + * This program is distributed in the hope that it will be useful, |
1505 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1506 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1507 | + * GNU General Public License for more details. |
1508 | + * |
1509 | + * You should have received a copy of the GNU General Public License |
1510 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1511 | + * |
1512 | + */ |
1513 | + |
1514 | +#ifndef UNITY_MOCK_SESSIONSMODEL_H |
1515 | +#define UNITY_MOCK_SESSIONSMODEL_H |
1516 | + |
1517 | +#include <QtCore/QAbstractListModel> |
1518 | +#include <QtCore/QString> |
1519 | + |
1520 | +namespace QLightDM |
1521 | +{ |
1522 | +class SessionsModelPrivate; |
1523 | + |
1524 | +class Q_DECL_EXPORT SessionsModel : public QAbstractListModel |
1525 | + { |
1526 | + Q_OBJECT |
1527 | + |
1528 | + Q_ENUMS(SessionModelRoles SessionType) |
1529 | + |
1530 | + // Mock-only API for testing purposes |
1531 | + Q_PROPERTY(QString testScenario READ testScenario WRITE setTestScenario) |
1532 | + |
1533 | + public: |
1534 | + |
1535 | + enum SessionModelRoles { |
1536 | + //name is exposed as Qt::DisplayRole |
1537 | + //comment is exposed as Qt::TooltipRole |
1538 | + KeyRole = Qt::UserRole, |
1539 | + IdRole = KeyRole, /** Deprecated */ |
1540 | + TypeRole |
1541 | + }; |
1542 | + |
1543 | + enum SessionType { |
1544 | + LocalSessions, |
1545 | + RemoteSessions |
1546 | + }; |
1547 | + |
1548 | + explicit SessionsModel(QObject* parent=nullptr); /** Deprecated. Loads local sessions*/ |
1549 | + explicit SessionsModel(SessionsModel::SessionType, QObject* parent=nullptr); |
1550 | + virtual ~SessionsModel(); |
1551 | + |
1552 | + QHash<int, QByteArray> roleNames() const override; |
1553 | + int rowCount(const QModelIndex& parent) const override; |
1554 | + QVariant data(const QModelIndex& index, int role) const override; |
1555 | + |
1556 | + QString testScenario() const; |
1557 | + void setTestScenario(QString testScenario); |
1558 | + |
1559 | + protected: |
1560 | + SessionsModelPrivate* const d_ptr; |
1561 | + |
1562 | + private: |
1563 | + QHash<int, QByteArray> m_roleNames; |
1564 | + Q_DECLARE_PRIVATE(SessionsModel) |
1565 | + }; |
1566 | +} |
1567 | + |
1568 | +#endif // UNITY_MOCK_SESSIONSMODEL_H |
1569 | |
1570 | === added file 'tests/mocks/LightDM/IntegratedLightDM/liblightdm/SessionsModelPrivate.cpp' |
1571 | --- tests/mocks/LightDM/IntegratedLightDM/liblightdm/SessionsModelPrivate.cpp 1970-01-01 00:00:00 +0000 |
1572 | +++ tests/mocks/LightDM/IntegratedLightDM/liblightdm/SessionsModelPrivate.cpp 2016-06-30 19:05:07 +0000 |
1573 | @@ -0,0 +1,73 @@ |
1574 | +/* |
1575 | + * Copyright (C) 2015 Canonical, Ltd. |
1576 | + * |
1577 | + * This program is free software; you can redistribute it and/or modify |
1578 | + * it under the terms of the GNU General Public License as published by |
1579 | + * the Free Software Foundation; version 3. |
1580 | + * |
1581 | + * This program is distributed in the hope that it will be useful, |
1582 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1583 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1584 | + * GNU General Public License for more details. |
1585 | + * |
1586 | + * You should have received a copy of the GNU General Public License |
1587 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1588 | + */ |
1589 | + |
1590 | +#include "SessionsModel.h" |
1591 | +#include "SessionsModelPrivate.h" |
1592 | + |
1593 | +namespace QLightDM |
1594 | +{ |
1595 | + |
1596 | +SessionsModelPrivate::SessionsModelPrivate(SessionsModel* parent) |
1597 | + : testScenario("singleSession") |
1598 | + , q_ptr(parent) |
1599 | +{ |
1600 | + resetEntries(); |
1601 | +} |
1602 | + |
1603 | +void SessionsModelPrivate::resetEntries() |
1604 | +{ |
1605 | + Q_Q(SessionsModel); |
1606 | + |
1607 | + q->beginResetModel(); |
1608 | + if (testScenario == "multipleSessions") { |
1609 | + resetEntries_multipleSessions(); |
1610 | + } else if (testScenario == "noSessions") { |
1611 | + resetEntries_noSessions(); |
1612 | + } else { |
1613 | + resetEntries_singleSession(); |
1614 | + } |
1615 | + q->endResetModel(); |
1616 | +} |
1617 | + |
1618 | +void SessionsModelPrivate::resetEntries_multipleSessions() |
1619 | +{ |
1620 | + sessionItems = |
1621 | + { |
1622 | + {"ubuntu", "", "Ubuntu", ""}, |
1623 | + {"ubuntu-2d", "", "Ubuntu 2D", ""}, |
1624 | + {"gnome", "", "GNOME", ""}, |
1625 | + {"gnome-classic", "", "GNOME Classic", ""}, |
1626 | + {"gnome-flashback-compiz", "", "GNOME Flashback (Compiz)", ""}, |
1627 | + {"gnome-flashback-metacity", "", "GNOME Flashback (Metacity)", ""}, |
1628 | + {"gnome-wayland", "", "GNOME on Wayland", ""}, |
1629 | + {"plasma", "", "Plasma", ""}, |
1630 | + {"kde", "", "KDE" , ""}, |
1631 | + {"xterm", "", "Recovery Console", ""}, |
1632 | + {"", "", "Unknown?", ""} |
1633 | + }; |
1634 | +} |
1635 | + |
1636 | +void SessionsModelPrivate::resetEntries_noSessions() |
1637 | +{ |
1638 | + sessionItems = {}; |
1639 | +} |
1640 | + |
1641 | +void SessionsModelPrivate::resetEntries_singleSession() |
1642 | +{ |
1643 | + sessionItems = {{"ubuntu", "", "Ubuntu", ""}}; |
1644 | +} |
1645 | + |
1646 | +} // namespace QLightDM |
1647 | |
1648 | === added file 'tests/mocks/LightDM/IntegratedLightDM/liblightdm/SessionsModelPrivate.h' |
1649 | --- tests/mocks/LightDM/IntegratedLightDM/liblightdm/SessionsModelPrivate.h 1970-01-01 00:00:00 +0000 |
1650 | +++ tests/mocks/LightDM/IntegratedLightDM/liblightdm/SessionsModelPrivate.h 2016-06-30 19:05:07 +0000 |
1651 | @@ -0,0 +1,59 @@ |
1652 | +/* |
1653 | + * Copyright (C) 2015 Canonical, Ltd. |
1654 | + * |
1655 | + * This program is free software; you can redistribute it and/or modify |
1656 | + * it under the terms of the GNU General Public License as published by |
1657 | + * the Free Software Foundation; version 3. |
1658 | + * |
1659 | + * This program is distributed in the hope that it will be useful, |
1660 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1661 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1662 | + * GNU General Public License for more details. |
1663 | + * |
1664 | + * You should have received a copy of the GNU General Public License |
1665 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1666 | + * |
1667 | + */ |
1668 | + |
1669 | +#ifndef UNITY_MOCK_SESSIONSMODEL_PRIVATE_H |
1670 | +#define UNITY_MOCK_SESSIONSMODEL_PRIVATE_H |
1671 | + |
1672 | +#include <QtCore/QList> |
1673 | +#include <QtCore/QString> |
1674 | + |
1675 | +namespace QLightDM |
1676 | +{ |
1677 | +class SessionsModel; |
1678 | + |
1679 | +class SessionItem |
1680 | +{ |
1681 | +public: |
1682 | + QString key; |
1683 | + QString type; // unused |
1684 | + QString name; |
1685 | + QString comment; // unused |
1686 | +}; |
1687 | + |
1688 | +class SessionsModelPrivate |
1689 | +{ |
1690 | +public: |
1691 | + explicit SessionsModelPrivate(SessionsModel* parent=0); |
1692 | + virtual ~SessionsModelPrivate() = default; |
1693 | + |
1694 | + QList<SessionItem> sessionItems; |
1695 | + QString testScenario; |
1696 | + |
1697 | + void resetEntries(); |
1698 | +protected: |
1699 | + SessionsModel* const q_ptr; |
1700 | + |
1701 | +private: |
1702 | + void resetEntries_multipleSessions(); |
1703 | + void resetEntries_noSessions(); |
1704 | + void resetEntries_singleSession(); |
1705 | + Q_DECLARE_PUBLIC(SessionsModel) |
1706 | +}; |
1707 | + |
1708 | +} // namespace QLightDM |
1709 | + |
1710 | +#endif // UNITY_MOCK_SESSIONSMODEL_PRIVATE_H |
1711 | |
1712 | === modified file 'tests/mocks/LightDM/IntegratedLightDM/liblightdm/UsersModelPrivate.cpp' |
1713 | --- tests/mocks/LightDM/IntegratedLightDM/liblightdm/UsersModelPrivate.cpp 2016-06-18 22:37:48 +0000 |
1714 | +++ tests/mocks/LightDM/IntegratedLightDM/liblightdm/UsersModelPrivate.cpp 2016-06-30 19:05:07 +0000 |
1715 | @@ -60,7 +60,7 @@ |
1716 | { |
1717 | entries = |
1718 | { |
1719 | - { "single", "Single User", 0, 0, false, false, 0, 0, 0 }, |
1720 | + { "single", "Single User", 0, 0, false, false, "ubuntu", 0 }, |
1721 | }; |
1722 | } |
1723 | |
1724 | @@ -68,7 +68,7 @@ |
1725 | { |
1726 | entries = |
1727 | { |
1728 | - { "single", "Single User", 0, 0, false, false, 0, 0, 0 }, |
1729 | + { "single", "Single User", 0, 0, false, false, "ubuntu", 0 }, |
1730 | }; |
1731 | } |
1732 | |
1733 | @@ -76,7 +76,7 @@ |
1734 | { |
1735 | entries = |
1736 | { |
1737 | - { "has-pin", "Has PIN", 0, 0, false, false, 0, 0, 0 }, |
1738 | + { "has-pin", "Has PIN", 0, 0, false, false, "ubuntu", 0 }, |
1739 | }; |
1740 | } |
1741 | |
1742 | @@ -84,26 +84,26 @@ |
1743 | { |
1744 | entries = |
1745 | { |
1746 | - { "has-password", "Has Password", 0, 0, false, false, 0, 0, 0 }, |
1747 | - { "has-pin", "Has PIN", 0, 0, false, false, 0, 0, 0 }, |
1748 | - { "different-prompt", "Different Prompt", 0, 0, false, false, 0, 0, 0 }, |
1749 | - { "no-password", "No Password", 0, 0, false, false, 0, 0, 0 }, |
1750 | - { "auth-error", "Auth Error", 0, 0, false, false, 0, 0, 0 }, |
1751 | - { "two-factor", "Two Factor", 0, 0, false, false, 0, 0, 0 }, |
1752 | - { "info-prompt", "Info Prompt", 0, 0, false, false, 0, 0, 0 }, |
1753 | - { "html-info-prompt", "HTML Info Prompt", 0, 0, false, false, 0, 0, 0 }, |
1754 | - { "long-info-prompt", "Long Info Prompt", 0, 0, false, false, 0, 0, 0 }, |
1755 | - { "wide-info-prompt", "Wide Info Prompt", 0, 0, false, false, 0, 0, 0 }, |
1756 | - { "multi-info-prompt", "Multi Info Prompt", 0, 0, false, false, 0, 0, 0 }, |
1757 | - { "long-name", "Long name (far far too long to fit, seriously this would never fit on the screen, you will never see this part of the name)", 0, 0, false, false, 0, 0, 0 }, |
1758 | - { "color-background", "Color Background", "#dd4814", 0, false, false, 0, 0, 0 }, |
1759 | + { "has-password", "Has Password", 0, 0, false, false, "ubuntu", 0 }, |
1760 | + { "has-pin", "Has PIN", 0, 0, false, false, "ubuntu", 0 }, |
1761 | + { "different-prompt", "Different Prompt", 0, 0, false, false, "ubuntu", 0 }, |
1762 | + { "no-password", "No Password", 0, 0, false, false, "ubuntu", 0 }, |
1763 | + { "auth-error", "Auth Error", 0, 0, false, false, "ubuntu", 0 }, |
1764 | + { "two-factor", "Two Factor", 0, 0, false, false, "ubuntu", 0 }, |
1765 | + { "info-prompt", "Info Prompt", 0, 0, false, false, "ubuntu", 0 }, |
1766 | + { "html-info-prompt", "HTML Info Prompt", 0, 0, false, false, "ubuntu", 0 }, |
1767 | + { "long-info-prompt", "Long Info Prompt", 0, 0, false, false, "ubuntu", 0 }, |
1768 | + { "wide-info-prompt", "Wide Info Prompt", 0, 0, false, false, "ubuntu", 0 }, |
1769 | + { "multi-info-prompt", "Multi Info Prompt", 0, 0, false, false, "ubuntu", 0 }, |
1770 | + { "long-name", "Long name (far far too long to fit, seriously this would never fit on the screen, you will never see this part of the name)", 0, 0, false, false, "ubuntu", 0 }, |
1771 | + { "color-background", "Color Background", "#dd4814", 0, false, false, "ubuntu", 0 }, |
1772 | // white and black are a bit redundant, but useful for manually testing if UI is still readable |
1773 | - { "white-background", "White Background", "#ffffff", 0, false, false, 0, 0, 0 }, |
1774 | - { "black-background", "Black Background", "#000000", 0, false, false, 0, 0, 0 }, |
1775 | - { "no-background", "No Background", "", 0, false, false, 0, 0, 0 }, |
1776 | - { "unicode", "가나다라마", 0, 0, false, false, 0, 0, 0 }, |
1777 | - { "no-response", "No Response", 0, 0, false, false, 0, 0, 0 }, |
1778 | - { "empty-name", "", 0, 0, false, false, 0, 0, 0 }, |
1779 | + { "white-background", "White Background", "#ffffff", 0, false, false, "ubuntu", 0 }, |
1780 | + { "black-background", "Black Background", "#000000", 0, false, false, "ubuntu", 0 }, |
1781 | + { "no-background", "No Background", "", 0, false, false, "ubuntu", 0 }, |
1782 | + { "unicode", "가나다라마", 0, 0, false, false, "ubuntu", 0 }, |
1783 | + { "no-response", "No Response", 0, 0, false, false, "ubuntu", 0 }, |
1784 | + { "empty-name", "", 0, 0, false, false, "ubuntu", 0 }, |
1785 | }; |
1786 | } |
1787 | |
1788 | |
1789 | === modified file 'tests/mocks/LightDM/IntegratedLightDM/plugin.cpp' |
1790 | --- tests/mocks/LightDM/IntegratedLightDM/plugin.cpp 2016-06-30 19:05:01 +0000 |
1791 | +++ tests/mocks/LightDM/IntegratedLightDM/plugin.cpp 2016-06-30 19:05:07 +0000 |
1792 | @@ -18,7 +18,9 @@ |
1793 | #include <DBusGreeter.h> |
1794 | #include <DBusGreeterList.h> |
1795 | #include "MockGreeter.h" |
1796 | +#include "MockSessionsModel.h" |
1797 | #include "MockUsersModel.h" |
1798 | +#include <QLightDM/SessionsModel> |
1799 | #include "ColorTheme.h" |
1800 | #include "UserMetrics.h" |
1801 | #include <QLightDM/UsersModel> |
1802 | @@ -39,6 +41,13 @@ |
1803 | return greeter; |
1804 | } |
1805 | |
1806 | +static QObject *sessions_provider(QQmlEngine *engine, QJSEngine *scriptEngine) |
1807 | +{ |
1808 | + Q_UNUSED(engine) |
1809 | + Q_UNUSED(scriptEngine) |
1810 | + return new MockSessionsModel; |
1811 | +} |
1812 | + |
1813 | static QObject *users_provider(QQmlEngine *engine, QJSEngine *scriptEngine) |
1814 | { |
1815 | Q_UNUSED(engine) |
1816 | @@ -62,6 +71,8 @@ |
1817 | qRegisterMetaType<QLightDM::Greeter::MessageType>("QLightDM::Greeter::MessageType"); |
1818 | qRegisterMetaType<QLightDM::Greeter::PromptType>("QLightDM::Greeter::PromptType"); |
1819 | qmlRegisterSingletonType<MockGreeter>(uri, 0, 1, "Greeter", greeter_provider); |
1820 | + qmlRegisterSingletonType<MockSessionsModel>(uri, 0, 1, "Sessions", sessions_provider); |
1821 | + qmlRegisterUncreatableType<SessionsModel>(uri, 0, 1, "SessionRoles", "Type is not instantiable"); |
1822 | qmlRegisterSingletonType<MockUsersModel>(uri, 0, 1, "Users", users_provider); |
1823 | qmlRegisterUncreatableType<QLightDM::UsersModel>(uri, 0, 1, "UserRoles", "Type is not instantiable"); |
1824 | qmlRegisterSingletonType<UserMetricsOutput::UserMetrics>(uri, 0, 1, "Infographic", infographic_provider); |
1825 | |
1826 | === modified file 'tests/plugins/LightDM/IntegratedLightDM/CMakeLists.txt' |
1827 | --- tests/plugins/LightDM/IntegratedLightDM/CMakeLists.txt 2016-06-30 19:05:01 +0000 |
1828 | +++ tests/plugins/LightDM/IntegratedLightDM/CMakeLists.txt 2016-06-30 19:05:07 +0000 |
1829 | @@ -44,6 +44,29 @@ |
1830 | ) |
1831 | add_qmltest_target(testGreeterPam GreeterPamTestExec COMMAND $<TARGET_FILE:GreeterPamTestExec>) |
1832 | |
1833 | +# SessionsModelTest |
1834 | +add_executable(GreeterSessionsModelTestExec |
1835 | + sessionsmodel.cpp |
1836 | + ${CMAKE_SOURCE_DIR}/plugins/LightDM/SessionsModel.cpp |
1837 | + ${CMAKE_SOURCE_DIR}/plugins/Utils/unitysortfilterproxymodelqml.cpp |
1838 | + ) |
1839 | +add_dependencies(GreeterSessionsModelTestExec MockLightDM) |
1840 | +qt5_use_modules(GreeterSessionsModelTestExec Core Test) |
1841 | +target_link_libraries(GreeterSessionsModelTestExec |
1842 | + MockLightDM |
1843 | + ) |
1844 | +target_include_directories(GreeterSessionsModelTestExec PUBLIC |
1845 | + ${CMAKE_SOURCE_DIR}/plugins/LightDM |
1846 | + ${CMAKE_SOURCE_DIR}/plugins/Utils |
1847 | + ${CMAKE_SOURCE_DIR}/tests/mocks/LightDM/IntegratedLightDM |
1848 | + ) |
1849 | +add_unity8_uitest(GreeterSessions GreeterSessionsModelTestExec |
1850 | + ENVIRONMENT LIBLIGHTDM_MOCK_MODE=full |
1851 | + DEPENDS MockLightDM |
1852 | + LIGHTDM |
1853 | + ) |
1854 | + |
1855 | +# UsersModelTest |
1856 | add_executable(GreeterUsersModelTestExec |
1857 | usersmodel.cpp |
1858 | ${CMAKE_SOURCE_DIR}/plugins/LightDM/UsersModel.cpp |
1859 | |
1860 | === added file 'tests/plugins/LightDM/IntegratedLightDM/sessionsmodel.cpp' |
1861 | --- tests/plugins/LightDM/IntegratedLightDM/sessionsmodel.cpp 1970-01-01 00:00:00 +0000 |
1862 | +++ tests/plugins/LightDM/IntegratedLightDM/sessionsmodel.cpp 2016-06-30 19:05:07 +0000 |
1863 | @@ -0,0 +1,96 @@ |
1864 | +/* |
1865 | + * Copyright (C) 2015 Canonical, Ltd. |
1866 | + * |
1867 | + * This program is free software; you can redistribute it and/or modify |
1868 | + * it under the terms of the GNU General Public License as published by |
1869 | + * the Free Software Foundation; version 3. |
1870 | + * |
1871 | + * This program is distributed in the hope that it will be useful, |
1872 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1873 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1874 | + * GNU General Public License for more details. |
1875 | + * |
1876 | + * You should have received a copy of the GNU General Public License |
1877 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1878 | + */ |
1879 | + |
1880 | +#include "SessionsModel.h" |
1881 | + |
1882 | +#include <QLightDM/SessionsModel> |
1883 | +#include <QtCore/QModelIndex> |
1884 | +#include <QtTest> |
1885 | +#include <QString> |
1886 | + |
1887 | +class GreeterSessionsModelTest : public QObject |
1888 | +{ |
1889 | + Q_OBJECT |
1890 | + |
1891 | +private Q_SLOTS: |
1892 | + |
1893 | + void init() |
1894 | + { |
1895 | + model = new SessionsModel(); |
1896 | + QVERIFY(model); |
1897 | + sourceModel = new QLightDM::SessionsModel(); |
1898 | + QVERIFY(sourceModel); |
1899 | + } |
1900 | + |
1901 | + void cleanup() |
1902 | + { |
1903 | + delete model; |
1904 | + delete sourceModel; |
1905 | + } |
1906 | + |
1907 | + static QModelIndex findByKey(QAbstractItemModel *model, const QString& key) |
1908 | + { |
1909 | + for (int i = 0; i < model->rowCount(QModelIndex()); i++) { |
1910 | + if (model->data(model->index(i, 0), QLightDM::SessionsModel::KeyRole).toString() == key) |
1911 | + return model->index(i, 0); |
1912 | + } |
1913 | + |
1914 | + return QModelIndex(); |
1915 | + } |
1916 | + |
1917 | + void testIconDirectoriesAreValid() |
1918 | + { |
1919 | + Q_FOREACH(const QUrl& searchDirectory, model->iconSearchDirectories()) |
1920 | + { |
1921 | + QVERIFY(searchDirectory.isValid()); |
1922 | + } |
1923 | + } |
1924 | + |
1925 | + void testMultipleSessionsCountIsCorrect() |
1926 | + { |
1927 | + sourceModel->setTestScenario("multipleSessions"); |
1928 | + QVERIFY(sourceModel->rowCount(QModelIndex()) > 1); |
1929 | + } |
1930 | + |
1931 | + void testNoSessionsCountIsCorrect() |
1932 | + { |
1933 | + sourceModel->setTestScenario("noSessions"); |
1934 | + QVERIFY(sourceModel->rowCount(QModelIndex()) == 0); |
1935 | + } |
1936 | + |
1937 | + void testSingleSessionCountIsCorrect() |
1938 | + { |
1939 | + sourceModel->setTestScenario("singleSession"); |
1940 | + QVERIFY(sourceModel->rowCount(QModelIndex()) == 1); |
1941 | + } |
1942 | + |
1943 | + void testSessionNameIsCorrect() |
1944 | + { |
1945 | + // This is testing the lookup, not the correctness of the strings, |
1946 | + // so one test should be sufficient |
1947 | + sourceModel->setTestScenario("multipleSessions"); |
1948 | + QVERIFY(model->data(findByKey(sourceModel, "ubuntu"), |
1949 | + Qt::DisplayRole).toString() == "Ubuntu"); |
1950 | + } |
1951 | + |
1952 | +private: |
1953 | + SessionsModel *model; |
1954 | + QLightDM::SessionsModel *sourceModel; |
1955 | +}; |
1956 | + |
1957 | +QTEST_MAIN(GreeterSessionsModelTest) |
1958 | + |
1959 | +#include "sessionsmodel.moc" |
1960 | |
1961 | === modified file 'tests/qmltests/Greeter/TestView.qml' |
1962 | --- tests/qmltests/Greeter/TestView.qml 2016-06-30 19:05:01 +0000 |
1963 | +++ tests/qmltests/Greeter/TestView.qml 2016-05-25 19:25:51 +0000 |
1964 | @@ -43,7 +43,6 @@ |
1965 | signal responded(string response) |
1966 | signal tease() |
1967 | signal emergencyCall() |
1968 | - signal promptlessLogin() |
1969 | |
1970 | signal _showMessageCalled(string html) |
1971 | signal _showPromptCalled(string text, bool isSecret, bool isDefaultPrompt) |
1972 | |
1973 | === modified file 'tests/qmltests/Greeter/tst_Greeter.qml' |
1974 | --- tests/qmltests/Greeter/tst_Greeter.qml 2016-06-30 19:05:01 +0000 |
1975 | +++ tests/qmltests/Greeter/tst_Greeter.qml 2016-06-30 19:05:07 +0000 |
1976 | @@ -194,6 +194,8 @@ |
1977 | var i = getIndexOf(name); |
1978 | view.selected(i); |
1979 | verifySelected(name); |
1980 | + compare(greeter.waiting, true); |
1981 | + tryCompare(greeter, "waiting", false); |
1982 | return i; |
1983 | } |
1984 | |
1985 | @@ -325,18 +327,6 @@ |
1986 | compare(viewShowMessageSpy.signalArguments[2][0], "You should have seen three messages"); |
1987 | } |
1988 | |
1989 | - function test_waiting() { |
1990 | - // Make sure we unset 'waiting' on prompt |
1991 | - selectUser("has-password"); |
1992 | - compare(greeter.waiting, true); |
1993 | - tryCompare(greeter, "waiting", false); |
1994 | - |
1995 | - // Make sure we unset 'waiting' on authentication |
1996 | - selectUser("no-password"); |
1997 | - compare(greeter.waiting, true); |
1998 | - tryCompare(greeter, "waiting", false); |
1999 | - } |
2000 | - |
2001 | function test_locked() { |
2002 | selectUser("has-password"); |
2003 | compare(view.locked, true); |
2004 | |
2005 | === modified file 'tests/qmltests/Greeter/tst_WideView.qml' |
2006 | --- tests/qmltests/Greeter/tst_WideView.qml 2016-06-30 19:05:01 +0000 |
2007 | +++ tests/qmltests/Greeter/tst_WideView.qml 2016-06-30 19:05:07 +0000 |
2008 | @@ -63,7 +63,8 @@ |
2009 | } |
2010 | |
2011 | onSelected: { |
2012 | - currentIndexField.text = index; |
2013 | + if (index >= 0) |
2014 | + currentIndexField.text = index; |
2015 | } |
2016 | |
2017 | QtObject { |
2018 | @@ -392,7 +393,7 @@ |
2019 | |
2020 | function test_respondedWithPassword() { |
2021 | view.locked = true; |
2022 | - view.showPrompt("Prompt", true, true); |
2023 | + view.showPrompt("Prompt", true, false); |
2024 | var passwordInput = findChild(view, "passwordInput"); |
2025 | compare(passwordInput.text, "Prompt"); |
2026 | verify(passwordInput.isSecret); |
2027 | @@ -454,13 +455,13 @@ |
2028 | view.showPrompt("Prompt", true, true); |
2029 | var promptField = findChild(view, "promptField"); |
2030 | tap(promptField); |
2031 | - compare(promptField.focus, true); |
2032 | - compare(promptField.enabled, true); |
2033 | + verify(promptField.activeFocus); |
2034 | + compare(promptField.opacity, 1); |
2035 | |
2036 | typeString("password"); |
2037 | keyClick(Qt.Key_Enter); |
2038 | - compare(promptField.focus, true); |
2039 | - compare(promptField.enabled, false); |
2040 | + verify(promptField.activeFocus); |
2041 | + compare(promptField.opacity, 0); // hidden by fakeLabel |
2042 | |
2043 | compare(selectedSpy.count, 0); |
2044 | keyClick(Qt.Key_Escape); |
2045 | @@ -468,8 +469,8 @@ |
2046 | compare(selectedSpy.signalArguments[0][0], 1); |
2047 | |
2048 | view.reset(); |
2049 | - compare(promptField.focus, false); |
2050 | - compare(promptField.enabled, true); |
2051 | + verify(promptField.activeFocus); |
2052 | + compare(promptField.opacity, 1); |
2053 | } |
2054 | |
2055 | function test_unicode() { |
2056 | @@ -489,6 +490,7 @@ |
2057 | compare(selectedSpy.signalArguments[0][0], 0); |
2058 | selectedSpy.clear(); |
2059 | |
2060 | + view.reset(); |
2061 | view.locked = false; |
2062 | compare(passwordInput.text, "Log In"); |
2063 | tap(passwordInput); |
2064 | @@ -518,13 +520,89 @@ |
2065 | tryCompare(loginList, "height", view.height); |
2066 | } |
2067 | |
2068 | - function test_alphanumeric() { |
2069 | - var passwordInput = findChild(view, "passwordInput"); |
2070 | + function test_passphrase() { |
2071 | + var promptField = findChild(view, "promptField"); |
2072 | + view.showPrompt("", true, true); |
2073 | |
2074 | verify(view.alphanumeric); |
2075 | - verify(passwordInput.isAlphanumeric); |
2076 | + compare(promptField.inputMethodHints & Qt.ImhDigitsOnly, 0); |
2077 | + |
2078 | + keyClick(Qt.Key_D); |
2079 | + compare(promptField.text, "d"); |
2080 | + } |
2081 | + |
2082 | + function test_passcode() { |
2083 | + var promptField = findChild(view, "promptField"); |
2084 | + view.showPrompt("", true, true); |
2085 | + |
2086 | view.alphanumeric = false; |
2087 | - verify(!passwordInput.isAlphanumeric); |
2088 | + compare(promptField.inputMethodHints & Qt.ImhDigitsOnly, Qt.ImhDigitsOnly); |
2089 | + |
2090 | + keyClick(Qt.Key_D); |
2091 | + compare(promptField.text, ""); |
2092 | + |
2093 | + keyClick(Qt.Key_0); |
2094 | + keyClick(Qt.Key_0); |
2095 | + keyClick(Qt.Key_0); |
2096 | + keyClick(Qt.Key_0); |
2097 | + compare(promptField.text, "0000"); |
2098 | + |
2099 | + compare(respondedSpy.count, 1); |
2100 | + compare(respondedSpy.signalArguments[0][0], "0000"); |
2101 | + |
2102 | + compare(promptField.opacity, 0); |
2103 | + } |
2104 | + |
2105 | + function test_loginListMovement_data() { |
2106 | + return [ |
2107 | + {tag: "up", key: Qt.Key_Up, result: -1}, |
2108 | + {tag: "down", key: Qt.Key_Down, result: 1}, |
2109 | + ] |
2110 | + } |
2111 | + |
2112 | + function test_loginListMovement(data) { |
2113 | + keyClick(data.key); |
2114 | + compare(selectedSpy.count, 1); |
2115 | + compare(selectedSpy.signalArguments[0][0], data.result); |
2116 | + } |
2117 | + |
2118 | + function test_focusStaysActive() { |
2119 | + var promptField = findChild(view, "promptField"); |
2120 | + var promptButton = findChild(view, "promptButton"); |
2121 | + |
2122 | + verify(promptButton.activeFocus); |
2123 | + keyClick(Qt.Key_Enter); |
2124 | + compare(selectedSpy.count, 0); |
2125 | + compare(respondedSpy.count, 1); |
2126 | + compare(respondedSpy.signalArguments[0][0], ""); |
2127 | + verify(promptButton.activeFocus); |
2128 | + keyClick(Qt.Key_Enter); |
2129 | + compare(respondedSpy.count, 1); |
2130 | + |
2131 | + view.showPrompt("", true, true); |
2132 | + verify(promptField.activeFocus); |
2133 | + keyClick(Qt.Key_D); |
2134 | + keyClick(Qt.Key_Enter); |
2135 | + compare(selectedSpy.count, 0); |
2136 | + compare(respondedSpy.count, 2); |
2137 | + compare(respondedSpy.signalArguments[1][0], "d"); |
2138 | + verify(promptField.activeFocus); |
2139 | + keyClick(Qt.Key_Enter); |
2140 | + compare(respondedSpy.count, 2); |
2141 | + |
2142 | + view.reset(); |
2143 | + view.locked = true; |
2144 | + verify(promptButton.activeFocus); |
2145 | + keyClick(Qt.Key_Enter); |
2146 | + compare(respondedSpy.count, 2); |
2147 | + compare(selectedSpy.count, 1); |
2148 | + compare(selectedSpy.signalArguments[0][0], 0); |
2149 | + verify(promptButton.activeFocus); |
2150 | + keyClick(Qt.Key_Enter); |
2151 | + compare(selectedSpy.count, 1); |
2152 | + |
2153 | + view.showPrompt("", true, true); |
2154 | + verify(promptField.activeFocus); |
2155 | } |
2156 | } |
2157 | } |
2158 | |
2159 | === modified file 'tests/qmltests/Tutorial/tst_Tutorial.qml' |
2160 | --- tests/qmltests/Tutorial/tst_Tutorial.qml 2016-06-30 19:05:01 +0000 |
2161 | +++ tests/qmltests/Tutorial/tst_Tutorial.qml 2016-06-30 19:05:07 +0000 |
2162 | @@ -296,7 +296,7 @@ |
2163 | } |
2164 | |
2165 | function prepareShell() { |
2166 | - tryCompare(shell, "enabled", true); // enabled by greeter when ready |
2167 | + tryCompare(shell, "waitingOnGreeter", false); // reset by greeter when ready |
2168 | |
2169 | WindowStateStorage.clear(); |
2170 | SurfaceManager.inputMethodSurface.setState(Mir.MinimizedState); |
2171 | |
2172 | === modified file 'tests/qmltests/tst_OrientedShell.qml' |
2173 | --- tests/qmltests/tst_OrientedShell.qml 2016-06-30 19:05:01 +0000 |
2174 | +++ tests/qmltests/tst_OrientedShell.qml 2016-06-30 19:05:07 +0000 |
2175 | @@ -493,7 +493,7 @@ |
2176 | } |
2177 | |
2178 | function cleanup() { |
2179 | - tryCompare(shell, "enabled", true); // make sure greeter didn't leave us in disabled state |
2180 | + tryCompare(shell, "waitingOnGreeter", false); // make sure greeter didn't leave us in disabled state |
2181 | shell = null; |
2182 | topLevelSurfaceList = null; |
2183 | |
2184 | @@ -1583,7 +1583,7 @@ |
2185 | var stageLoader = findChild(shell, "applicationsDisplayLoader"); |
2186 | verify(stageLoader); |
2187 | |
2188 | - tryCompare(shell, "enabled", true); // enabled by greeter when ready |
2189 | + tryCompare(shell, "waitingOnGreeter", false); // reset by greeter when ready |
2190 | |
2191 | waitUntilShellIsInOrientation(root.physicalOrientation0); |
2192 | |
2193 | |
2194 | === modified file 'tests/qmltests/tst_Shell.qml' |
2195 | --- tests/qmltests/tst_Shell.qml 2016-06-30 19:05:01 +0000 |
2196 | +++ tests/qmltests/tst_Shell.qml 2016-06-30 19:05:07 +0000 |
2197 | @@ -456,7 +456,7 @@ |
2198 | function cleanup() { |
2199 | waitForRendering(shell); |
2200 | mouseEmulation.checked = true; |
2201 | - tryCompare(shell, "enabled", true); // make sure greeter didn't leave us in disabled state |
2202 | + tryCompare(shell, "waitingOnGreeter", false); // make sure greeter didn't leave us in disabled state |
2203 | tearDown(); |
2204 | WindowStateStorage.clear(); |
2205 | } |
2206 | @@ -466,7 +466,7 @@ |
2207 | shellLoader.active = true; |
2208 | tryCompare(shellLoader, "status", Loader.Ready); |
2209 | removeTimeConstraintsFromSwipeAreas(shellLoader.item); |
2210 | - tryCompare(shell, "enabled", true); // enabled by greeter when ready |
2211 | + tryCompare(shell, "waitingOnGreeter", false); // reset by greeter when ready |
2212 | |
2213 | sessionSpy.target = findChild(shell, "greeter") |
2214 | dashCommunicatorSpy.target = findInvisibleChild(shell, "dashCommunicator"); |
2215 | @@ -818,7 +818,7 @@ |
2216 | tryCompare(userlist, "currentIndex", next) |
2217 | tryCompare(userlist, "movingInternally", false) |
2218 | } |
2219 | - tryCompare(shell, "enabled", true); // wait for PAM to settle |
2220 | + tryCompare(shell, "waitingOnGreeter", false); // wait for PAM to settle |
2221 | } |
2222 | |
2223 | function selectUser(name) { |
2224 | |
2225 | === modified file 'tests/qmltests/tst_ShellWithPin.qml' |
2226 | --- tests/qmltests/tst_ShellWithPin.qml 2016-06-30 19:05:01 +0000 |
2227 | +++ tests/qmltests/tst_ShellWithPin.qml 2016-06-30 19:05:07 +0000 |
2228 | @@ -150,7 +150,7 @@ |
2229 | property Item shell: shellLoader.status === Loader.Ready ? shellLoader.item : null |
2230 | |
2231 | function init() { |
2232 | - tryCompare(shell, "enabled", true); // will be enabled when greeter is all ready |
2233 | + tryCompare(shell, "waitingOnGreeter", false); // will be set when greeter is all ready |
2234 | var greeter = findChild(shell, "greeter"); |
2235 | sessionSpy.target = greeter; |
2236 | swipeAwayGreeter(true); |
2237 | @@ -165,7 +165,7 @@ |
2238 | } |
2239 | |
2240 | function cleanup() { |
2241 | - tryCompare(shell, "enabled", true); // make sure greeter didn't leave us in disabled state |
2242 | + tryCompare(shell, "waitingOnGreeter", false); // make sure greeter didn't leave us in disabled state |
2243 | |
2244 | shellLoader.itemDestroyed = false |
2245 | |
2246 | @@ -533,10 +533,12 @@ |
2247 | |
2248 | // Confirm that we start disabled |
2249 | compare(promptSpy.count, 0); |
2250 | - verify(!shell.enabled); |
2251 | + verify(shell.waitingOnGreeter); |
2252 | + var coverPageDragHandle = findChild(shell, "coverPageDragHandle"); |
2253 | + verify(!coverPageDragHandle.enabled); |
2254 | |
2255 | // And that we only become enabled once the lockscreen is up |
2256 | - tryCompare(shell, "enabled", true); |
2257 | + tryCompare(shell, "waitingOnGreeter", false); |
2258 | verify(promptSpy.count > 0); |
2259 | var lockscreen = findChild(shell, "lockscreen"); |
2260 | verify(lockscreen.shown); |
I'm going to work on some qmltests now, but this branch can be reviewed and tested in meantime.