1 /*
2 * SPDX-FileCopyrightText: 2012 Alejandro Fiestas Olivares <afiestas@kde.org>
3 * SPDX-FileCopyrightText: 2020 Dan Leinir Turthra Jensen <admin@leinir.dk>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8 #include "accountsmodel.h"
9
10 #include "core.h"
11 #include "servicesmodel.h"
12
13 #include <QDebug>
14
15 #include <QIcon>
16 #include <klocalizedstring.h>
17
18 #include <SignOn/Identity>
19
20 #include <Accounts/Account>
21 #include <Accounts/Manager>
22
23 class AccountsModel::Private : public QObject
24 {
25 public:
Private(AccountsModel * model)26 Private(AccountsModel *model)
27 : accountsManager(KAccounts::accountsManager())
28 , q(model)
29 {
30 accountIDs = accountsManager->accountList();
31
32 connect(accountsManager, &Accounts::Manager::accountCreated, q, [this](Accounts::AccountId accountId) {
33 int row = accountIDs.count();
34 q->beginInsertRows(QModelIndex(), row, row);
35 accountIDs.insert(row, accountId);
36 q->endInsertRows();
37 });
38 connect(accountsManager, &Accounts::Manager::accountRemoved, q, [this](Accounts::AccountId accountId) {
39 q->beginRemoveRows(QModelIndex(), accountIDs.indexOf(accountId), accountIDs.indexOf(accountId));
40 removeAccount(accountId);
41 q->endRemoveRows();
42 });
43 };
~Private()44 virtual ~Private()
45 {
46 qDeleteAll(accounts);
47 };
48
49 Accounts::Manager *accountsManager;
50 Accounts::AccountIdList accountIDs;
51 QHash<int, Accounts::Account *> accounts;
52 QHash<Accounts::Account *, ServicesModel *> servicesModels;
53
54 Accounts::Account *accountById(int id);
55 void removeAccount(Accounts::AccountId accountId);
56
57 private:
58 AccountsModel *q;
59 };
60
accountById(int id)61 Accounts::Account *AccountsModel::Private::accountById(int id)
62 {
63 if (accounts.contains(id)) {
64 return accounts.value(id);
65 }
66
67 // If we don't yet have this account cached, get it and connect it up to the model
68 Accounts::Account *account = accountsManager->account(id);
69 if (!account) {
70 qDebug() << "\t Failed to get the account from manager";
71 return nullptr;
72 }
73
74 connect(account, &Accounts::Account::displayNameChanged, q, [this, account]() {
75 QModelIndex accountIndex = q->index(accountIDs.indexOf(account->id()));
76 Q_EMIT q->dataChanged(accountIndex, accountIndex, QVector<int>() << AccountsModel::DisplayNameRole);
77 });
78
79 accounts[id] = account;
80 return account;
81 }
82
removeAccount(Accounts::AccountId accountId)83 void AccountsModel::Private::removeAccount(Accounts::AccountId accountId)
84 {
85 accountIDs.removeOne(accountId);
86 delete accounts.take(accountId);
87 }
88
AccountsModel(QObject * parent)89 AccountsModel::AccountsModel(QObject *parent)
90 : QAbstractListModel(parent)
91 , d(new AccountsModel::Private(this))
92 {
93 }
94
~AccountsModel()95 AccountsModel::~AccountsModel()
96 {
97 delete d;
98 }
99
roleNames() const100 QHash<int, QByteArray> AccountsModel::roleNames() const
101 {
102 static QHash<int, QByteArray> roles{{IdRole, "id"},
103 {ServicesRole, "services"},
104 {EnabledRole, "enabled"},
105 {CredentialsIdRole, "credentialsId"},
106 {DisplayNameRole, "displayName"},
107 {ProviderNameRole, "providerName"},
108 {IconNameRole, "iconName"},
109 {DataObjectRole, "dataObject"}};
110 return roles;
111 }
112
rowCount(const QModelIndex & parent) const113 int AccountsModel::rowCount(const QModelIndex &parent) const
114 {
115 if (parent.isValid()) {
116 return 0;
117 }
118
119 return d->accountIDs.count();
120 }
121
data(const QModelIndex & index,int role) const122 QVariant AccountsModel::data(const QModelIndex &index, int role) const
123 {
124 QVariant data;
125 if (checkIndex(index)) {
126 Accounts::AccountId accountId = d->accountIDs.value(index.row());
127 Accounts::Account *account = d->accountById(accountId);
128 if (account) {
129 switch (role) {
130 case IdRole:
131 data.setValue(account->id());
132 break;
133 case ServicesRole: {
134 ServicesModel *servicesModel{nullptr};
135 if (d->servicesModels.contains(account)) {
136 servicesModel = d->servicesModels.value(account);
137 } else {
138 // Not parenting to the account itself, so we can avoid it suddenly
139 // disappearing. Just to be on the safe side
140 servicesModel = new ServicesModel(d->accountsManager);
141 servicesModel->setAccount(account);
142 d->servicesModels[account] = servicesModel;
143 }
144 data.setValue(servicesModel);
145 break;
146 }
147 case EnabledRole:
148 data.setValue(account->enabled());
149 break;
150 case CredentialsIdRole:
151 data.setValue(account->credentialsId());
152 break;
153 case DisplayNameRole:
154 data.setValue(account->displayName());
155 break;
156 case ProviderNameRole:
157 data.setValue(account->providerName());
158 break;
159 case IconNameRole: {
160 QString iconName = QStringLiteral("user-identity");
161 if (account->provider().isValid() && !account->provider().iconName().isEmpty()) {
162 iconName = account->provider().iconName();
163 }
164 data.setValue(iconName);
165 break;
166 }
167 case DataObjectRole:
168 data.setValue<QObject *>(account);
169 break;
170 }
171 }
172 }
173
174 return data;
175 }
176