Handle removal of accounts a bit better
[quassel.git] / src / client / coreaccountmodel.cpp
1 /***************************************************************************
2  *   Copyright (C) 2009 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  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, 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 void CoreAccountModel::update(const CoreAccountModel *other) {
41   clear();
42   beginInsertRows(QModelIndex(), 0, other->_accounts.count() -1);
43   _internalAccount = other->internalAccount();
44   _accounts = other->_accounts;
45   _removedAccounts = other->_removedAccounts;
46   endInsertRows();
47 }
48
49 void CoreAccountModel::load() {
50   clear();
51   CoreAccountSettings s;
52   foreach(AccountId accId, s.knownAccounts()) {
53     QVariantMap map = s.retrieveAccountData(accId);
54     CoreAccount acc;
55     acc.fromVariantMap(map);  // TODO Hook into kwallet/password saving stuff
56     insertAccount(acc);
57   }
58   if(Quassel::runMode() == Quassel::Monolithic && !internalAccount().isValid()) {
59     // Make sure we have an internal account in monolithic mode
60     CoreAccount intAcc;
61     intAcc.setInternal(true);
62     intAcc.setAccountName(tr("Internal Core"));
63     _internalAccount = createOrUpdateAccount(intAcc);
64   }
65 }
66
67 void CoreAccountModel::save() {
68   CoreAccountSettings s;
69   foreach(AccountId id, _removedAccounts) {
70     s.removeAccount(id);
71   }
72   _removedAccounts.clear();
73   foreach(const CoreAccount &acc, accounts()) {
74     QVariantMap map = acc.toVariantMap(false);  // TODO Hook into kwallet/password saving stuff
75     s.storeAccountData(acc.accountId(), map);
76   }
77 }
78
79 void CoreAccountModel::clear() {
80   if(rowCount()) {
81     beginRemoveRows(QModelIndex(), 0, rowCount()-1);
82     _internalAccount = 0;
83     _accounts.clear();
84     endRemoveRows();
85   }
86 }
87
88 QVariant CoreAccountModel::data(const QModelIndex &index, int role) const {
89   if(!index.isValid() || index.row() >= rowCount() || index.column() >= 1)
90     return QVariant();
91
92   const CoreAccount &acc = accounts().at(index.row());
93
94   switch(role) {
95   case Qt::DisplayRole:
96     return acc.accountName();
97   case AccountIdRole:
98     return QVariant::fromValue<AccountId>(acc.accountId());
99   case UuidRole:
100     return acc.uuid().toString();
101
102     default:
103       return QVariant();
104
105   }
106 }
107
108 CoreAccount CoreAccountModel::account(AccountId id) const {
109   int idx = findAccountIdx(id);
110   if(idx >= 0)
111     return _accounts.value(idx);
112   return CoreAccount();
113 }
114
115 CoreAccount CoreAccountModel::account(const QModelIndex &idx) const {
116   if(idx.isValid() && idx.row() < _accounts.count())
117     return _accounts.value(idx.row());
118   return CoreAccount();
119 }
120
121 QList<CoreAccount> CoreAccountModel::accounts() const {
122   return _accounts;
123 }
124
125 QList<AccountId> CoreAccountModel::accountIds() const {
126   QList<AccountId> list;
127   foreach(const CoreAccount &acc, accounts())
128     list << acc.accountId();
129   return list;
130 }
131
132 bool CoreAccountModel::operator==(const CoreAccountModel &other) const {
133   return _accounts == other._accounts;
134 }
135
136 // TODO with Qt 4.6, use QAbstractItemModel move semantics to properly do this
137 AccountId CoreAccountModel::createOrUpdateAccount(const CoreAccount &newAcc) {
138   CoreAccount acc = newAcc;
139
140   if(acc.uuid().isNull())
141     acc.setUuid(QUuid::createUuid());
142
143   if(!acc.accountId().isValid()) {
144     // find free Id
145     AccountId newId = 0;
146     const QList<AccountId> &ids = accountIds();
147     for(int i = 1; ; i++) {
148       if(!_removedAccounts.contains(i) && !ids.contains(i)) {
149         newId = i;
150         break;
151       }
152     }
153     acc.setAccountId(newId);
154     insertAccount(acc);
155   } else {
156     int idx = findAccountIdx(acc.accountId());
157     if(idx >= 0) {
158       if(acc.accountName() == accounts().at(idx).accountName()) {
159         _accounts[idx] = acc;
160         emit dataChanged(index(idx, 0), index(idx, 0));
161       } else {
162         takeAccount(acc.accountId());
163         insertAccount(acc);
164       }
165     } else
166       insertAccount(acc);
167   }
168   return acc.accountId();
169 }
170
171 void CoreAccountModel::insertAccount(const CoreAccount &acc) {
172   if(acc.isInternal()) {
173     if(internalAccount().isValid()) {
174       qWarning() << "Trying to insert a second internal account in CoreAccountModel, ignoring";
175       return;
176     }
177     _internalAccount = acc.accountId();
178   }
179
180   // check for Quuid
181   int idx = 0;
182   while(idx < _accounts.count() && acc.accountName() > _accounts.at(idx).accountName() && !acc.isInternal())
183     ++idx;
184
185   beginInsertRows(QModelIndex(), idx, idx);
186   _accounts.insert(idx, acc);
187   endInsertRows();
188 }
189
190 CoreAccount CoreAccountModel::takeAccount(AccountId accId) {
191   int idx = findAccountIdx(accId);
192   if(idx < 0)
193     return CoreAccount();
194
195   beginRemoveRows(QModelIndex(), idx, idx);
196   CoreAccount acc = _accounts.takeAt(idx);
197   endRemoveRows();
198
199   if(acc.isInternal())
200     _internalAccount = 0;
201
202   return acc;
203 }
204
205 void CoreAccountModel::removeAccount(AccountId accId) {
206   takeAccount(accId);
207   _removedAccounts.insert(accId);
208 }
209
210 QModelIndex CoreAccountModel::accountIndex(AccountId accId) const {
211   for(int i = 0; i < _accounts.count(); i++) {
212     if(_accounts.at(i).accountId() == accId)
213       return index(i, 0);
214   }
215   return QModelIndex();
216 }
217
218 int CoreAccountModel::findAccountIdx(AccountId id) const {
219   QModelIndex idx = accountIndex(id);
220   return idx.isValid() ? idx.row() : -1;
221 }