@@ -39,29 +39,63 @@ public:
39 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
39 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
42− int guestRow() const;
42+ struct CustomRow {
47+ int sourceRowCount() const;
49+ void updateGuestRow();
50+ void updateManualRow();
51+ void updateCustomRows();
53+ void addCustomRow(const CustomRow &newRow);
54+ void removeCustomRow(const QString &rowName);
56+ QList<CustomRow> m_customRows;
57+ bool m_updatingCustomRows;
45MangleModel::MangleModel(QObject* parent)
60MangleModel::MangleModel(QObject* parent)
46 : QIdentityProxyModel(parent)
61 : QIdentityProxyModel(parent)
62+ , m_updatingCustomRows(false)
48 setSourceModel(new QLightDM::UsersModel(this));
64 setSourceModel(new QLightDM::UsersModel(this));
68+ // Would be nice if there were a rowCountChanged signal in the base class.
69+ // We redo all custom rows on any row count change, because (A) some of
70+ // custom rows (manual login) use row count information and (B) when
71+ // testing, we use a modelReset signal as a way to indicate that a custom
72+ // row has been toggled off or on.
73+ connect(this, &QIdentityProxyModel::modelReset,
74+ this, &MangleModel::updateCustomRows);
75+ connect(this, &QIdentityProxyModel::rowsInserted,
76+ this, &MangleModel::updateCustomRows);
77+ connect(this, &QIdentityProxyModel::rowsRemoved,
78+ this, &MangleModel::updateCustomRows);
51QVariant MangleModel::data(const QModelIndex &index, int role) const
81QVariant MangleModel::data(const QModelIndex &index, int role) const
53 QVariant variantData;
83 QVariant variantData;
85+ if (index.row() >= rowCount())
88+ bool isCustomRow = index.row() >= sourceRowCount();
55− if (index.row() == guestRow() && index.column() == 0) {
89+ if (isCustomRow && index.column() == 0) {
56− switch (role) {
90+ int customIndex = index.row() - sourceRowCount();
57− case QLightDM::UsersModel::NameRole:
91+ if (role == QLightDM::UsersModel::NameRole) {
58− variantData = QStringLiteral("*guest"); break;
92+ variantData = m_customRows[customIndex].name;
59− case QLightDM::UsersModel::RealNameRole:
93+ } else if (role == QLightDM::UsersModel::RealNameRole) {
60− variantData = gettext("Guest Session"); break;
94+ variantData = m_customRows[customIndex].realName;
61− case QLightDM::UsersModel::LoggedInRole:
95+ } else if (role == QLightDM::UsersModel::LoggedInRole) {
62− variantData = false; break;
96+ variantData = false;
63− case QLightDM::UsersModel::SessionRole:
97+ } else if (role == QLightDM::UsersModel::SessionRole) {
64− variantData = Greeter::instance()->defaultSessionHint(); break;
98+ variantData = Greeter::instance()->defaultSessionHint();
67 variantData = QIdentityProxyModel::data(index, role);
101 variantData = QIdentityProxyModel::data(index, role);
@@ -69,7 +103,7 @@ QVariant MangleModel::data(const QModelIndex &index, int role) const
70 // If user's real name is empty, switch to unix name
104 // If user's real name is empty, switch to unix name
71 if (role == QLightDM::UsersModel::RealNameRole && variantData.toString().isEmpty()) {
105 if (role == QLightDM::UsersModel::RealNameRole && variantData.toString().isEmpty()) {
72− variantData = QIdentityProxyModel::data(index, QLightDM::UsersModel::NameRole);
106+ variantData = data(index, QLightDM::UsersModel::NameRole);
73 } else if (role == QLightDM::UsersModel::BackgroundPathRole && variantData.toString().startsWith('#')) {
107 } else if (role == QLightDM::UsersModel::BackgroundPathRole && variantData.toString().startsWith('#')) {
74 const QString stringData = "data:image/svg+xml,<svg><rect width='100%' height='100%' fill='" + variantData.toString() + "'/></svg>";
108 const QString stringData = "data:image/svg+xml,<svg><rect width='100%' height='100%' fill='" + variantData.toString() + "'/></svg>";
75 variantData = stringData;
109 variantData = stringData;
@@ -78,25 +112,89 @@ QVariant MangleModel::data(const QModelIndex &index, int role) const
78 return variantData;
112 return variantData;
81−int MangleModel::guestRow() const
115+void MangleModel::addCustomRow(const CustomRow &newRow)
83− return Greeter::instance()->hasGuestAccount() ?
117+ for (int i = 0; i < m_customRows.size(); i++) {
84− QIdentityProxyModel::rowCount() : -1;
118+ if (m_customRows[i].name == newRow.name) {
119+ return; // we don't have custom rows that change content yet
123+ beginInsertRows(QModelIndex(), rowCount(), rowCount());
124+ m_customRows << newRow;
87−int MangleModel::rowCount(const QModelIndex &parent) const
128+void MangleModel::removeCustomRow(const QString &rowName)
89− auto count = QIdentityProxyModel::rowCount(parent);
130+ for (int i = 0; i < m_customRows.size(); i++) {
131+ if (m_customRows[i].name == rowName) {
132+ int rowNum = sourceRowCount() + i;
133+ beginRemoveRows(QModelIndex(), rowNum, rowNum);
134+ m_customRows.removeAt(i);
91− if (Greeter::instance()->hasGuestAccount() && !parent.isValid())
141+void MangleModel::updateManualRow()
143+ bool hasAnotherEntry = sourceRowCount() > 0;
144+ for (int i = 0; !hasAnotherEntry && i < m_customRows.size(); i++) {
145+ if (m_customRows[i].name != QStringLiteral("*other")) {
146+ hasAnotherEntry = true;
150+ // Show manual login if we are asked to OR if no other entry exists
151+ if (Greeter::instance()->showManualLoginHint() || !hasAnotherEntry)
152+ addCustomRow({QStringLiteral("*other"), gettext("Login")});
154+ removeCustomRow(QStringLiteral("*other"));
157+void MangleModel::updateGuestRow()
159+ if (Greeter::instance()->hasGuestAccount())
160+ addCustomRow({QStringLiteral("*guest"), gettext("Guest Session")});
162+ removeCustomRow(QStringLiteral("*guest"));
165+void MangleModel::updateCustomRows()
167+ // We update when rowCount changes, but we also insert/remove rows here.
168+ // So guard this function to avoid recursion.
169+ if (m_updatingCustomRows)
94− return count;
170+ return;
172+ m_updatingCustomRows = true;
175+ m_updatingCustomRows = false;
178+int MangleModel::rowCount(const QModelIndex &parent) const
180+ if (parent.isValid())
183+ return sourceRowCount() + m_customRows.size();
186+int MangleModel::sourceRowCount() const
188+ return Greeter::instance()->hideUsersHint() ? 0 : sourceModel()->rowCount();
97QModelIndex MangleModel::index(int row, int column, const QModelIndex &parent) const
191QModelIndex MangleModel::index(int row, int column, const QModelIndex &parent) const
193+ if (row >= rowCount())
194+ return QModelIndex();
196+ bool isCustomRow = row >= sourceRowCount();
99− if (row == guestRow() && !parent.isValid()) {
197+ if (isCustomRow && !parent.isValid()) {
100 return createIndex(row, column);
198 return createIndex(row, column);
102 return QIdentityProxyModel::index(row, column, parent);
200 return QIdentityProxyModel::index(row, column, parent);
@@ -124,6 +222,10 @@ bool UsersModel::lessThan(const QModelIndex &source_left, const QModelIndex &sou
124 return false;
222 return false;
125 if (rightName == QStringLiteral("*guest"))
223 if (rightName == QStringLiteral("*guest"))
126 return true;
224 return true;
225+ if (leftName == QStringLiteral("*other"))
227+ if (rightName == QStringLiteral("*other"))
128 return UnitySortFilterProxyModelQML::lessThan(source_left, source_right);
230 return UnitySortFilterProxyModelQML::lessThan(source_left, source_right);