test: Add build system support and a main function for unit tests
[quassel.git] / src / client / coreaccountmodel.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-2018 by the Quassel Project                        *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) version 3.                                           *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
19  ***************************************************************************/
20
21 #include "coreaccountmodel.h"
22
23 #include "clientsettings.h"
24 #include "quassel.h"
25
26 CoreAccountModel::CoreAccountModel(QObject *parent)
27     : QAbstractListModel(parent),
28     _internalAccount(0)
29 {
30 }
31
32
33 CoreAccountModel::CoreAccountModel(const CoreAccountModel *other, QObject *parent)
34     : QAbstractListModel(parent),
35     _internalAccount(0)
36 {
37     update(other);
38 }
39
40
41 void CoreAccountModel::update(const CoreAccountModel *other)
42 {
43     clear();
44     if (other->_accounts.count() > 0) {
45         beginInsertRows(QModelIndex(), 0, other->_accounts.count() -1);
46         _accounts = other->_accounts;
47         endInsertRows();
48     }
49     _internalAccount = other->internalAccount();
50     _removedAccounts = other->_removedAccounts;
51 }
52
53
54 void CoreAccountModel::load()
55 {
56     clear();
57     CoreAccountSettings s;
58     foreach(AccountId accId, s.knownAccounts()) {
59         QVariantMap map = s.retrieveAccountData(accId);
60         CoreAccount acc;
61         acc.fromVariantMap(map); // TODO Hook into kwallet/password saving stuff
62         insertAccount(acc);
63     }
64     if (Quassel::runMode() == Quassel::Monolithic && !internalAccount().isValid()) {
65         // Make sure we have an internal account in monolithic mode
66         CoreAccount intAcc;
67         intAcc.setInternal(true);
68         intAcc.setAccountName(tr("Internal Core"));
69         _internalAccount = createOrUpdateAccount(intAcc);
70     }
71 }
72
73
74 void CoreAccountModel::save()
75 {
76     CoreAccountSettings s;
77     foreach(AccountId id, _removedAccounts) {
78         s.removeAccount(id);
79     }
80     _removedAccounts.clear();
81     foreach(const CoreAccount &acc, accounts()) {
82         QVariantMap map = acc.toVariantMap(false); // TODO Hook into kwallet/password saving stuff
83         s.storeAccountData(acc.accountId(), map);
84     }
85 }
86
87
88 void CoreAccountModel::clear()
89 {
90     beginResetModel();
91     _internalAccount = 0;
92     _accounts.clear();
93     endResetModel();
94 }
95
96
97 QVariant CoreAccountModel::data(const QModelIndex &index, int role) const
98 {
99     if (!index.isValid() || index.row() >= rowCount() || index.column() >= 1)
100         return QVariant();
101
102     const CoreAccount &acc = accounts().at(index.row());
103
104     switch (role) {
105     case Qt::DisplayRole:
106         return acc.accountName();
107     case AccountIdRole:
108         return QVariant::fromValue<AccountId>(acc.accountId());
109     case UuidRole:
110         return acc.uuid().toString();
111
112     default:
113         return QVariant();
114     }
115 }
116
117
118 CoreAccount CoreAccountModel::account(AccountId id) const
119 {
120     int idx = findAccountIdx(id);
121     if (idx >= 0)
122         return _accounts.value(idx);
123     return CoreAccount();
124 }
125
126
127 CoreAccount CoreAccountModel::account(const QModelIndex &idx) const
128 {
129     if (idx.isValid() && idx.row() < _accounts.count())
130         return _accounts.value(idx.row());
131     return CoreAccount();
132 }
133
134
135 QList<CoreAccount> CoreAccountModel::accounts() const
136 {
137     return _accounts;
138 }
139
140
141 QList<AccountId> CoreAccountModel::accountIds() const
142 {
143     QList<AccountId> list;
144     foreach(const CoreAccount &acc, accounts())
145     list << acc.accountId();
146     return list;
147 }
148
149
150 bool CoreAccountModel::operator==(const CoreAccountModel &other) const
151 {
152     return _accounts == other._accounts;
153 }
154
155
156 bool CoreAccountModel::operator!=(const CoreAccountModel &other) const
157 {
158     return !(*this == other);
159 }
160
161
162 // TODO with Qt 4.6, use QAbstractItemModel move semantics to properly do this
163 AccountId CoreAccountModel::createOrUpdateAccount(const CoreAccount &newAcc)
164 {
165     CoreAccount acc = newAcc;
166
167     if (acc.uuid().isNull())
168         acc.setUuid(QUuid::createUuid());
169
170     if (!acc.accountId().isValid()) {
171         // find free Id
172         AccountId newId = 0;
173         const QList<AccountId> &ids = accountIds();
174         for (int i = 1;; i++) {
175             if (!_removedAccounts.contains(i) && !ids.contains(i)) {
176                 newId = i;
177                 break;
178             }
179         }
180         acc.setAccountId(newId);
181         insertAccount(acc);
182     }
183     else {
184         int idx = findAccountIdx(acc.accountId());
185         if (idx >= 0) {
186             if (acc.accountName() == accounts().at(idx).accountName()) {
187                 _accounts[idx] = acc;
188                 emit dataChanged(index(idx, 0), index(idx, 0));
189             }
190             else {
191                 takeAccount(acc.accountId());
192                 insertAccount(acc);
193             }
194         }
195         else
196             insertAccount(acc);
197     }
198     return acc.accountId();
199 }
200
201
202 void CoreAccountModel::insertAccount(const CoreAccount &acc)
203 {
204     if (acc.isInternal()) {
205         if (internalAccount().isValid()) {
206             qWarning() << "Trying to insert a second internal account in CoreAccountModel, ignoring";
207             return;
208         }
209         _internalAccount = acc.accountId();
210     }
211
212     // check for Quuid
213     int idx = 0;
214     while (idx<_accounts.count() && acc.accountName()> _accounts.at(idx).accountName() && !acc.isInternal())
215         ++idx;
216
217     beginInsertRows(QModelIndex(), idx, idx);
218     _accounts.insert(idx, acc);
219     endInsertRows();
220 }
221
222
223 CoreAccount CoreAccountModel::takeAccount(AccountId accId)
224 {
225     int idx = findAccountIdx(accId);
226     if (idx < 0)
227         return CoreAccount();
228
229     beginRemoveRows(QModelIndex(), idx, idx);
230     CoreAccount acc = _accounts.takeAt(idx);
231     endRemoveRows();
232
233     if (acc.isInternal())
234         _internalAccount = 0;
235
236     return acc;
237 }
238
239
240 void CoreAccountModel::removeAccount(AccountId accId)
241 {
242     takeAccount(accId);
243     _removedAccounts.insert(accId);
244 }
245
246
247 QModelIndex CoreAccountModel::accountIndex(AccountId accId) const
248 {
249     for (int i = 0; i < _accounts.count(); i++) {
250         if (_accounts.at(i).accountId() == accId)
251             return index(i, 0);
252     }
253     return {};
254 }
255
256
257 int CoreAccountModel::findAccountIdx(AccountId id) const
258 {
259     QModelIndex idx = accountIndex(id);
260     return idx.isValid() ? idx.row() : -1;
261 }