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