on xenial help sign in
Merge greeter-guest
ea4893eMichael Terry
plugins/LightDM/UsersModel.cpp+85−58
@@ -12,23 +12,22 @@
12 *
12 *
13 * You should have received a copy of the GNU General Public License
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Author: Michael Terry <michael.terry@canonical.com>
17 */
15 */
18
16
19#include "Greeter.h"
17#include "Greeter.h"
20#include "UsersModel.h"
18#include "UsersModel.h"
19+#include <QIdentityProxyModel>
21#include <QLightDM/UsersModel>
20#include <QLightDM/UsersModel>
22−#include <QtCore/QSortFilterProxyModel>
23
21
24#include <libintl.h>
22#include <libintl.h>
25
23
26// First, we define an internal class that wraps LightDM's UsersModel. This
24// First, we define an internal class that wraps LightDM's UsersModel. This
27// class will modify some of the data coming from LightDM. For example, we
25// class will modify some of the data coming from LightDM. For example, we
28−// modify any empty Real Names into just normal Names.
26+// modify any empty Real Names into just normal Names. We also add optional
27+// rows, depending on configuration.
29// (We can't modify the data directly in UsersModel below because it won't sort
28// (We can't modify the data directly in UsersModel below because it won't sort
30// using the modified data.)
29// using the modified data.)
31−class MangleModel : public QSortFilterProxyModel
30+class MangleModel : public QIdentityProxyModel
32{
31{
33 Q_OBJECT
32 Q_OBJECT
34
33
@@ -36,21 +35,66 @@ public:
36 explicit MangleModel(QObject* parent=0);
35 explicit MangleModel(QObject* parent=0);
37
36
38 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
37 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
38+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
39+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
40+
41+private:
42+ int manualRow() const;
43+ int guestRow() const;
44+
45+ void updateShowManual();
46+
47+ bool m_showManual;
39};
48};
40
49
41MangleModel::MangleModel(QObject* parent)
50MangleModel::MangleModel(QObject* parent)
42− : QSortFilterProxyModel(parent)
51+ : QIdentityProxyModel(parent)
52+ , m_showManual(false)
43{
53{
54+ if (!Greeter::instance()->hideUsersHint()) {
44− setSourceModel(new QLightDM::UsersModel(this));
55+ setSourceModel(new QLightDM::UsersModel(this));
56+ }
57+
58+ updateShowManual();
59+
60+ connect(this, &QIdentityProxyModel::modelReset,
61+ this, &MangleModel::updateShowManual);
62+ connect(this, &QIdentityProxyModel::rowsInserted,
63+ this, &MangleModel::updateShowManual);
64+ connect(this, &QIdentityProxyModel::rowsRemoved,
65+ this, &MangleModel::updateShowManual);
45}
66}
46
67
47QVariant MangleModel::data(const QModelIndex &index, int role) const
68QVariant MangleModel::data(const QModelIndex &index, int role) const
48{
69{
49− QVariant variantData = QSortFilterProxyModel::data(index, role);
70+ QVariant variantData;
71+
72+ if (index.row() == manualRow() && index.column() == 0) {
73+ switch (role) {
74+ case QLightDM::UsersModel::NameRole: return QStringLiteral("*other");
75+ case QLightDM::UsersModel::RealNameRole: return gettext("Login");
76+ case QLightDM::UsersModel::LoggedInRole: return false;
77+ case QLightDM::UsersModel::SessionRole: return Greeter::instance()->defaultSessionHint();
78+ default: return QVariant();
79+ }
80+ } else if (index.row() == guestRow() && index.column() == 0) {
81+ switch (role) {
82+ case QLightDM::UsersModel::NameRole:
83+ variantData = QStringLiteral("*guest"); break;
84+ case QLightDM::UsersModel::RealNameRole:
85+ variantData = gettext("Guest Session"); break;
86+ case QLightDM::UsersModel::LoggedInRole:
87+ variantData = false; break;
88+ case QLightDM::UsersModel::SessionRole:
89+ variantData = Greeter::instance()->defaultSessionHint(); break;
90+ }
91+ } else {
92+ variantData = QIdentityProxyModel::data(index, role);
93+ }
50
94
51 // If user's real name is empty, switch to unix name
95 // If user's real name is empty, switch to unix name
52 if (role == QLightDM::UsersModel::RealNameRole && variantData.toString().isEmpty()) {
96 if (role == QLightDM::UsersModel::RealNameRole && variantData.toString().isEmpty()) {
53− variantData = QSortFilterProxyModel::data(index, QLightDM::UsersModel::NameRole);
97+ variantData = QIdentityProxyModel::data(index, QLightDM::UsersModel::NameRole);
54 } else if (role == QLightDM::UsersModel::BackgroundPathRole && variantData.toString().startsWith('#')) {
98 } else if (role == QLightDM::UsersModel::BackgroundPathRole && variantData.toString().startsWith('#')) {
55 const QString stringData = "data:image/svg+xml,<svg><rect width='100%' height='100%' fill='" + variantData.toString() + "'/></svg>";
99 const QString stringData = "data:image/svg+xml,<svg><rect width='100%' height='100%' fill='" + variantData.toString() + "'/></svg>";
56 variantData = stringData;
100 variantData = stringData;
@@ -59,34 +103,15 @@ QVariant MangleModel::data(const QModelIndex &index, int role) const
59 return variantData;
103 return variantData;
60}
104}
61
105
62−// **** Now we continue with actual UsersModel class ****
63−
64−UsersModel::UsersModel(QObject* parent)
65− : UnitySortFilterProxyModelQML(parent)
66− , m_showManual(false)
67−{
68− if (!Greeter::instance()->hideUsersHint()) {
69− setModel(new MangleModel(this));
70− }
71− setSortCaseSensitivity(Qt::CaseInsensitive);
72− setSortLocaleAware(true);
73− setSortRole(QLightDM::UsersModel::RealNameRole);
74− sort(0);
75−
76− connect(this, &UnitySortFilterProxyModelQML::countChanged,
77− this, &UsersModel::updateShowManual);
78− updateShowManual();
79−}
80−
81−void UsersModel::updateShowManual()
106+void MangleModel::updateShowManual()
82{
107{
83 // Show manual login if we are asked to OR if no other entry exists
108 // Show manual login if we are asked to OR if no other entry exists
84 bool showManual = Greeter::instance()->showManualLoginHint() ||
109 bool showManual = Greeter::instance()->showManualLoginHint() ||
85− (QSortFilterProxyModel::rowCount() == 0 &&
110+ (QIdentityProxyModel::rowCount() == 0 &&
86 !Greeter::instance()->hasGuestAccount());
111 !Greeter::instance()->hasGuestAccount());
87
112
88 if (m_showManual != showManual) {
113 if (m_showManual != showManual) {
89− int row = QSortFilterProxyModel::rowCount();
114+ int row = QIdentityProxyModel::rowCount();
90 if (showManual)
115 if (showManual)
91 beginInsertRows(QModelIndex(), row, row);
116 beginInsertRows(QModelIndex(), row, row);
92 else
117 else
@@ -101,29 +126,29 @@ void UsersModel::updateShowManual()
101 }
126 }
102}
127}
103
128
104−int UsersModel::manualRow() const
129+int MangleModel::manualRow() const
105{
130{
106 if (!m_showManual)
131 if (!m_showManual)
107 return -1;
132 return -1;
108
133
109− return QSortFilterProxyModel::rowCount();
134+ return QIdentityProxyModel::rowCount();
110}
135}
111
136
112−int UsersModel::guestRow() const
137+int MangleModel::guestRow() const
113{
138{
114 if (!Greeter::instance()->hasGuestAccount())
139 if (!Greeter::instance()->hasGuestAccount())
115 return -1;
140 return -1;
116
141
117− int row = QSortFilterProxyModel::rowCount();
142+ int row = QIdentityProxyModel::rowCount();
118 if (m_showManual)
143 if (m_showManual)
119 row++;
144 row++;
120
145
121 return row;
146 return row;
122}
147}
123
148
124−int UsersModel::rowCount(const QModelIndex &parent) const
149+int MangleModel::rowCount(const QModelIndex &parent) const
125{
150{
126− auto count = UnitySortFilterProxyModelQML::rowCount(parent);
151+ auto count = QIdentityProxyModel::rowCount(parent);
127
152
128 if (m_showManual && !parent.isValid())
153 if (m_showManual && !parent.isValid())
129 count++;
154 count++;
@@ -133,36 +158,38 @@ int UsersModel::rowCount(const QModelIndex &parent) const
133 return count;
158 return count;
134}
159}
135
160
136−QModelIndex UsersModel::index(int row, int column, const QModelIndex &parent) const
161+QModelIndex MangleModel::index(int row, int column, const QModelIndex &parent) const
137{
162{
138 if ((row == manualRow() || row == guestRow()) && !parent.isValid()) {
163 if ((row == manualRow() || row == guestRow()) && !parent.isValid()) {
139 return createIndex(row, column);
164 return createIndex(row, column);
140 } else {
165 } else {
141− return UnitySortFilterProxyModelQML::index(row, column, parent);
166+ return QIdentityProxyModel::index(row, column, parent);
142 }
167 }
143}
168}
144
169
145−QVariant UsersModel::data(const QModelIndex &index, int role) const
170+// **** Now we continue with actual UsersModel class ****
171+
172+UsersModel::UsersModel(QObject* parent)
173+ : UnitySortFilterProxyModelQML(parent)
146{
174{
147− if (index.row() == manualRow() && index.column() == 0) {
175+ setModel(new MangleModel(this));
148− switch (role) {
176+ setSortCaseSensitivity(Qt::CaseInsensitive);
149− case QLightDM::UsersModel::NameRole: return QStringLiteral("*other");
177+ setSortLocaleAware(true);
150− case QLightDM::UsersModel::RealNameRole: return gettext("Login");
178+ setSortRole(QLightDM::UsersModel::RealNameRole);
151− case QLightDM::UsersModel::LoggedInRole: return false;
179+ sort(0);
152− case QLightDM::UsersModel::SessionRole: return Greeter::instance()->defaultSessionHint();
153− default: return QVariant();
154− }
180+}
155− } else if (index.row() == guestRow() && index.column() == 0) {
181+
156− switch (role) {
182+bool UsersModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
183+{
157− case QLightDM::UsersModel::NameRole: return QStringLiteral("*guest");
184+ auto leftName = source_left.data(QLightDM::UsersModel::NameRole);
158− case QLightDM::UsersModel::RealNameRole: return gettext("Guest Session");
185+ auto rightName = source_right.data(QLightDM::UsersModel::NameRole);
159− case QLightDM::UsersModel::LoggedInRole: return false;
186+
160− case QLightDM::UsersModel::SessionRole: return Greeter::instance()->defaultSessionHint();
187+ if (leftName == QStringLiteral("*guest"))
161− default: return QVariant();
188+ return false;
162− }
189+ if (rightName == QStringLiteral("*guest"))
163− }
190+ return true;
164
191
165− return QSortFilterProxyModel::data(index, role);
192+ return UnitySortFilterProxyModelQML::lessThan(source_left, source_right);
166}
193}
167
194
168#include "UsersModel.moc"
195#include "UsersModel.moc"
plugins/LightDM/UsersModel.h+2−11
@@ -30,15 +30,6 @@ class UsersModel : public UnitySortFilterProxyModelQML
30public:
30public:
31 explicit UsersModel(QObject* parent=0);
31 explicit UsersModel(QObject* parent=0);
32
32
33− int rowCount(const QModelIndex &parent = QModelIndex()) const override;
33+protected:
34− QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
34+ bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
35− QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
36−
37−private:
38− int manualRow() const;
39− int guestRow() const;
40−
41− void updateShowManual();
42−
43− bool m_showManual;
44};
35};
tests/mocks/AccountsService/AccountsService.cpp+2−2
@@ -121,8 +121,8 @@ QString AccountsService::backgroundFile() const
121
121
122 // Check if our mock user has a background set in liblightdm
122 // Check if our mock user has a background set in liblightdm
123 for (int i = 0; i < m_usersModel->count(); i++) {
123 for (int i = 0; i < m_usersModel->count(); i++) {
124− if (m_usersModel->data(m_usersModel->index(i, 0), QLightDM::UsersModel::NameRole) == m_user) {
124+ if (m_usersModel->data(i, QLightDM::UsersModel::NameRole) == m_user) {
125− return m_usersModel->data(m_usersModel->index(i, 0), QLightDM::UsersModel::BackgroundPathRole).toString();
125+ return m_usersModel->data(i, QLightDM::UsersModel::BackgroundPathRole).toString();
126 }
126 }
127 }
127 }
128
128
tests/mocks/liblightdm/MockUsersModel.cpp+2
@@ -65,6 +65,8 @@ UsersModel::UsersModel(QObject *parent)
65 roles[UidRole] = "uid";
65 roles[UidRole] = "uid";
66 setRoleNames(roles);
66 setRoleNames(roles);
67
67
68+ connect(MockController::instance(), &MockController::hasGuestAccountHintChanged,
69+ this, &UsersModel::resetEntries);
68 connect(MockController::instance(), &MockController::userModeChanged,
70 connect(MockController::instance(), &MockController::userModeChanged,
69 this, &UsersModel::resetEntries);
71 this, &UsersModel::resetEntries);
70 resetEntries();
72 resetEntries();
tests/plugins/LightDM/IntegratedLightDM/CMakeLists.txt+1−3
@@ -20,7 +20,6 @@ target_link_libraries(GreeterDBusTestExec
20 )
20 )
21target_include_directories(GreeterDBusTestExec PUBLIC
21target_include_directories(GreeterDBusTestExec PUBLIC
22 ${CMAKE_SOURCE_DIR}/plugins/LightDM
22 ${CMAKE_SOURCE_DIR}/plugins/LightDM
23− ${CMAKE_SOURCE_DIR}/tests/mocks/LightDM/IntegratedLightDM
24 )
23 )
25add_unity8_uitest(GreeterDBus dbus-test-runner
24add_unity8_uitest(GreeterDBus dbus-test-runner
26 ARG_PREFIX "--parameter"
25 ARG_PREFIX "--parameter"
@@ -57,7 +56,6 @@ target_link_libraries(GreeterSessionsModelTestExec
57target_include_directories(GreeterSessionsModelTestExec PUBLIC
56target_include_directories(GreeterSessionsModelTestExec PUBLIC
58 ${CMAKE_SOURCE_DIR}/plugins/LightDM
57 ${CMAKE_SOURCE_DIR}/plugins/LightDM
59 ${CMAKE_SOURCE_DIR}/plugins/Utils
58 ${CMAKE_SOURCE_DIR}/plugins/Utils
60− ${CMAKE_SOURCE_DIR}/tests/mocks/LightDM/IntegratedLightDM
61 ${CMAKE_SOURCE_DIR}/tests/mocks/liblightdm/
59 ${CMAKE_SOURCE_DIR}/tests/mocks/liblightdm/
62 )
60 )
63add_unity8_uitest(GreeterSessions GreeterSessionsModelTestExec
61add_unity8_uitest(GreeterSessions GreeterSessionsModelTestExec
@@ -81,7 +79,7 @@ target_link_libraries(GreeterUsersModelTestExec
81target_include_directories(GreeterUsersModelTestExec PUBLIC
79target_include_directories(GreeterUsersModelTestExec PUBLIC
82 ${CMAKE_SOURCE_DIR}/plugins/LightDM
80 ${CMAKE_SOURCE_DIR}/plugins/LightDM
83 ${CMAKE_SOURCE_DIR}/plugins/Utils
81 ${CMAKE_SOURCE_DIR}/plugins/Utils
84− ${CMAKE_SOURCE_DIR}/tests/mocks/LightDM/IntegratedLightDM
82+ ${CMAKE_SOURCE_DIR}/tests/mocks/liblightdm
85 )
83 )
86add_unity8_uitest(GreeterUsers GreeterUsersModelTestExec
84add_unity8_uitest(GreeterUsers GreeterUsersModelTestExec
87 DEPENDS MockLightDM
85 DEPENDS MockLightDM
tests/plugins/LightDM/IntegratedLightDM/usersmodel.cpp+34−4
@@ -14,6 +14,8 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
15 */
16
16
17+#include "Greeter.h"
18+#include "MockController.h"
17#include "UsersModel.h"
19#include "UsersModel.h"
18
20
19#include <QLightDM/UsersModel>
21#include <QLightDM/UsersModel>
@@ -40,17 +42,23 @@ private:
40 return model->data(model->index(i, 0), role).toString();
42 return model->data(model->index(i, 0), role).toString();
41 }
43 }
42
44
45+ void recreateModel()
46+ {
47+ delete model;
48+ model = new UsersModel();
49+ QVERIFY(model);
50+ }
51+
43private Q_SLOTS:
52private Q_SLOTS:
44
53
45 void init()
54 void init()
46 {
55 {
47− model = new UsersModel();
56+ recreateModel();
48− QVERIFY(model);
49 }
57 }
50
58
51 void cleanup()
59 void cleanup()
52 {
60 {
53− delete model;
61+ QLightDM::MockController::instance()->reset();
54 }
62 }
55
63
56 void testMangleColor()
64 void testMangleColor()
@@ -65,8 +73,30 @@ private Q_SLOTS:
65 QVERIFY(name == "empty-name");
73 QVERIFY(name == "empty-name");
66 }
74 }
67
75
76+ void testHasGuest()
77+ {
78+ // sanity check that it doesn't start already present
79+ QCOMPARE(findName(model, QStringLiteral("*guest")), -1);
80+
81+ QLightDM::MockController::instance()->setHasGuestAccountHint(true);
82+ recreateModel();
83+
84+ int i = findName(model, QStringLiteral("*guest"));
85+ QVERIFY(i >= 0);
86+ QCOMPARE(i, model->count() - 1);
87+
88+ auto realName = model->data(i, QLightDM::UsersModel::RealNameRole).toString();
89+ QCOMPARE(realName, QStringLiteral("Guest Session"));
90+
91+ auto loggedIn = model->data(i, QLightDM::UsersModel::LoggedInRole).toBool();
92+ QVERIFY(!loggedIn);
93+
94+ auto session = model->data(i, QLightDM::UsersModel::SessionRole).toString();
95+ QCOMPARE(session, Greeter::instance()->defaultSessionHint());
96+ }
97+
68private:
98private:
69− UsersModel *model;
99+ UsersModel *model = nullptr;
70};
100};
71
101
72QTEST_MAIN(GreeterUsersModelTest)
102QTEST_MAIN(GreeterUsersModelTest)