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