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