@@ -39,29 +39,63 @@ public:
3939 QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
4040
4141private:
42− int guestRow() const;
42+ struct CustomRow {
43+ QString name;
44+ QString realName;
45+ };
46+
47+ int sourceRowCount() const;
48+
49+ void updateGuestRow();
50+ void updateManualRow();
51+ void updateCustomRows();
52+
53+ void addCustomRow(const CustomRow &newRow);
54+ void removeCustomRow(const QString &rowName);
55+
56+ QList<CustomRow> m_customRows;
57+ bool m_updatingCustomRows;
4358};
4459
4560MangleModel::MangleModel(QObject* parent)
4661 : QIdentityProxyModel(parent)
62+ , m_updatingCustomRows(false)
4763{
4864 setSourceModel(new QLightDM::UsersModel(this));
65+
66+ updateCustomRows();
67+
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);
4979}
5080
5181QVariant MangleModel::data(const QModelIndex &index, int role) const
5282{
5383 QVariant variantData;
5484
55− if (index.row() == guestRow() && index.column() == 0) {
56− switch (role) {
57− case QLightDM::UsersModel::NameRole:
58− variantData = QStringLiteral("*guest"); break;
59− case QLightDM::UsersModel::RealNameRole:
60− variantData = gettext("Guest Session"); break;
61− case QLightDM::UsersModel::LoggedInRole:
62− variantData = false; break;
63− case QLightDM::UsersModel::SessionRole:
64− variantData = Greeter::instance()->defaultSessionHint(); break;
85+ if (index.row() >= rowCount())
86+ return QVariant();
87+
88+ bool isCustomRow = index.row() >= sourceRowCount();
89+ if (isCustomRow && index.column() == 0) {
90+ int customIndex = index.row() - sourceRowCount();
91+ if (role == QLightDM::UsersModel::NameRole) {
92+ variantData = m_customRows[customIndex].name;
93+ } else if (role == QLightDM::UsersModel::RealNameRole) {
94+ variantData = m_customRows[customIndex].realName;
95+ } else if (role == QLightDM::UsersModel::LoggedInRole) {
96+ variantData = false;
97+ } else if (role == QLightDM::UsersModel::SessionRole) {
98+ variantData = Greeter::instance()->defaultSessionHint();
6599 }
66100 } else {
67101 variantData = QIdentityProxyModel::data(index, role);
@@ -69,7 +103,7 @@ QVariant MangleModel::data(const QModelIndex &index, int role) const
69103
70104 // If user's real name is empty, switch to unix name
71105 if (role == QLightDM::UsersModel::RealNameRole && variantData.toString().isEmpty()) {
72− variantData = QIdentityProxyModel::data(index, QLightDM::UsersModel::NameRole);
106+ variantData = data(index, QLightDM::UsersModel::NameRole);
73107 } else if (role == QLightDM::UsersModel::BackgroundPathRole && variantData.toString().startsWith('#')) {
74108 const QString stringData = "data:image/svg+xml,<svg><rect width='100%' height='100%' fill='" + variantData.toString() + "'/></svg>";
75109 variantData = stringData;
@@ -78,25 +112,89 @@ QVariant MangleModel::data(const QModelIndex &index, int role) const
78112 return variantData;
79113}
80114
81−int MangleModel::guestRow() const
115+void MangleModel::addCustomRow(const CustomRow &newRow)
82116{
83− return Greeter::instance()->hasGuestAccount() ?
84− QIdentityProxyModel::rowCount() : -1;
117+ for (int i = 0; i < m_customRows.size(); i++) {
118+ if (m_customRows[i].name == newRow.name) {
119+ return; // we don't have custom rows that change content yet
120+ }
121+ }
122+
123+ beginInsertRows(QModelIndex(), rowCount(), rowCount());
124+ m_customRows << newRow;
125+ endInsertRows();
85126}
86127
87−int MangleModel::rowCount(const QModelIndex &parent) const
128+void MangleModel::removeCustomRow(const QString &rowName)
88129{
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);
135+ endRemoveRows();
136+ break;
137+ }
138+ }
139+}
90140
91− if (Greeter::instance()->hasGuestAccount() && !parent.isValid())
92− count++;
141+void MangleModel::updateManualRow()
142+{
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;
147+ }
148+ }
93149
94− return count;
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")});
153+ else
154+ removeCustomRow(QStringLiteral("*other"));
155+}
156+
157+void MangleModel::updateGuestRow()
158+{
159+ if (Greeter::instance()->hasGuestAccount())
160+ addCustomRow({QStringLiteral("*guest"), gettext("Guest Session")});
161+ else
162+ removeCustomRow(QStringLiteral("*guest"));
163+}
164+
165+void MangleModel::updateCustomRows()
166+{
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)
170+ return;
171+
172+ m_updatingCustomRows = true;
173+ updateGuestRow();
174+ updateManualRow();
175+ m_updatingCustomRows = false;
176+}
177+
178+int MangleModel::rowCount(const QModelIndex &parent) const
179+{
180+ if (parent.isValid())
181+ return 0;
182+ else
183+ return sourceRowCount() + m_customRows.size();
184+}
185+
186+int MangleModel::sourceRowCount() const
187+{
188+ return Greeter::instance()->hideUsersHint() ? 0 : sourceModel()->rowCount();
95189}
96190
97191QModelIndex MangleModel::index(int row, int column, const QModelIndex &parent) const
98192{
99− if (row == guestRow() && !parent.isValid()) {
193+ if (row >= rowCount())
194+ return QModelIndex();
195+
196+ bool isCustomRow = row >= sourceRowCount();
197+ if (isCustomRow && !parent.isValid()) {
100198 return createIndex(row, column);
101199 } else {
102200 return QIdentityProxyModel::index(row, column, parent);
@@ -124,6 +222,10 @@ bool UsersModel::lessThan(const QModelIndex &source_left, const QModelIndex &sou
124222 return false;
125223 if (rightName == QStringLiteral("*guest"))
126224 return true;
225+ if (leftName == QStringLiteral("*other"))
226+ return false;
227+ if (rightName == QStringLiteral("*other"))
228+ return true;
127229
128230 return UnitySortFilterProxyModelQML::lessThan(source_left, source_right);
129231}