2817b84b471f312f918068e753c35407001e7fcd
[quassel.git] / src / qtui / settingspages / identitiessettingspage.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-08 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) any later version.                                   *
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 <QMessageBox>
22
23 #include "identitiessettingspage.h"
24
25 #include "client.h"
26
27 IdentitiesSettingsPage::IdentitiesSettingsPage(QWidget *parent)
28   : SettingsPage(tr("General"), tr("Identities"), parent) {
29
30   ui.setupUi(this);
31   setEnabled(false);  // need a core connection!
32   connect(Client::instance(), SIGNAL(coreConnectionStateChanged(bool)), this, SLOT(coreConnectionStateChanged(bool)));
33   connect(Client::instance(), SIGNAL(identityCreated(IdentityId)), this, SLOT(clientIdentityCreated(IdentityId)));
34   connect(Client::instance(), SIGNAL(identityRemoved(IdentityId)), this, SLOT(clientIdentityRemoved(IdentityId)));
35
36   currentId = 0;
37
38   // We need to know whenever the state of input widgets changes...
39   //connect(ui.identityList, SIGNAL(editTextChanged(const QString &)), this, SLOT(widgetHasChanged()));
40   connect(ui.realName, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
41   connect(ui.nicknameList, SIGNAL(itemChanged(QListWidgetItem *)), this, SLOT(widgetHasChanged()));
42   connect(ui.awayNick, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
43   connect(ui.awayNickEnabled, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
44   connect(ui.awayReason, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
45   connect(ui.awayReasonEnabled, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
46   connect(ui.returnMessage, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
47   connect(ui.returnMessageEnabled, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
48   connect(ui.autoAwayEnabled, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
49   connect(ui.autoAwayTime, SIGNAL(valueChanged(int)), this, SLOT(widgetHasChanged()));
50   connect(ui.autoAwayReason, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
51   connect(ui.autoAwayReasonEnabled, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
52   connect(ui.autoReturnMessage, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
53   connect(ui.autoReturnMessageEnabled, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
54   connect(ui.ident, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
55   connect(ui.kickReason, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
56   connect(ui.partReason, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
57   connect(ui.quitReason, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
58
59 }
60
61 void IdentitiesSettingsPage::coreConnectionStateChanged(bool state) {
62   this->setEnabled(state);
63   if(state) {
64     load();
65   } else {
66     // reset
67     currentId = 0;
68   }
69 }
70
71 void IdentitiesSettingsPage::save() {
72   setEnabled(false);
73   QList<Identity *> toCreate, toUpdate;
74   // we need to remove our temporarily created identities.
75   // these are going to be re-added after the core has propagated them back...
76   for(QHash<IdentityId, Identity *>::iterator i = identities.begin(); i != identities.end(); ++i) {
77     if((*i)->id() < 0) {
78       Identity *temp = *i;
79       i = identities.erase(i);
80       toCreate.append(temp);
81       ui.identityList->removeItem(ui.identityList->findData(temp->id()));
82     } else {
83       if(**i != *Client::identity((*i)->id())) {
84         toUpdate.append(*i);
85       }
86     }
87   }
88   SaveIdentitiesDlg dlg(toCreate, toUpdate, deletedIdentities, this);
89   int ret = dlg.exec();
90   if(ret == QDialog::Rejected) {
91     // canceled -> reload everything to be safe
92     load();
93   }
94   foreach(Identity *id, toCreate) {
95     id->deleteLater();
96   }
97   changeState(false);
98   setEnabled(true);
99
100 }
101
102 void IdentitiesSettingsPage::load() {
103   currentId = 0;
104   foreach(Identity *identity, identities.values()) {
105     identity->deleteLater();
106   }
107   identities.clear();
108   deletedIdentities.clear();
109   changedIdentities.clear();
110   ui.identityList->clear();
111   foreach(IdentityId id, Client::identityIds()) {
112     clientIdentityCreated(id);
113   }
114   changeState(false);
115 }
116
117 void IdentitiesSettingsPage::defaults() {
118   // TODO implement bool hasDefaults()
119 }
120
121 void IdentitiesSettingsPage::widgetHasChanged() {
122   bool changed = testHasChanged();
123   if(changed != hasChanged()) changeState(changed);
124 }
125
126 bool IdentitiesSettingsPage::testHasChanged() {
127   if(deletedIdentities.count()) return true;
128   if(currentId < 0) {
129     return true; // new identity
130   } else {
131     changedIdentities.removeAll(currentId);
132     Identity temp(currentId, this);
133     saveToIdentity(&temp);
134     if(temp != *identities[currentId]) changedIdentities.append(currentId);
135     return changedIdentities.count();
136   }
137 }
138
139 bool IdentitiesSettingsPage::aboutToSave() {
140   saveToIdentity(identities[currentId]);
141   QList<int> errors;
142   foreach(Identity *id, identities.values()) {
143     if(id->identityName().isEmpty()) errors.append(1);
144     if(!id->nicks().count()) errors.append(2);
145     if(id->realName().isEmpty()) errors.append(3);
146     if(id->ident().isEmpty()) errors.append(4);
147   }
148   if(!errors.count()) return true;
149   QString error(tr("<b>The following problems need to be corrected before your changes can be applied:</b><ul>"));
150   if(errors.contains(1)) error += tr("<li>All identities need an identity name set</li>");
151   if(errors.contains(2)) error += tr("<li>Every identity needs at least one nickname defined</li>");
152   if(errors.contains(3)) error += tr("<li>You need to specify a real name for every identity</li>");
153   if(errors.contains(4)) error += tr("<li>You need to specify an ident for every identity</li>");
154   error += tr("</ul>");
155   QMessageBox::warning(this, tr("One or more identities are invalid"), error);
156   return false;
157 }
158
159 void IdentitiesSettingsPage::clientIdentityCreated(IdentityId id) {
160   insertIdentity(new Identity(*Client::identity(id), this));
161   connect(Client::identity(id), SIGNAL(updatedRemotely()), this, SLOT(clientIdentityUpdated()));
162 }
163
164 void IdentitiesSettingsPage::clientIdentityUpdated() {
165   Identity *identity = qobject_cast<Identity *>(sender());
166   if(!identity) {
167     qWarning() << "Invalid identity to update!";
168     return;
169   }
170   if(!identities.contains(identity->id())) {
171     qWarning() << "Unknown identity to update:" << identity->identityName();
172     return;
173   }
174   identities[identity->id()]->update(*identity);
175   ui.identityList->setItemText(ui.identityList->findData(identity->id()), identity->identityName());
176   if(identity->id() == currentId) displayIdentity(identity, true);
177 }
178
179 void IdentitiesSettingsPage::clientIdentityRemoved(IdentityId id) {
180   if(identities.contains(id)) {
181     removeIdentity(identities[id]);
182     changedIdentities.removeAll(id);
183     deletedIdentities.removeAll(id);
184   }
185 }
186
187 void IdentitiesSettingsPage::insertIdentity(Identity *identity) {
188   IdentityId id = identity->id();
189   identities[id] = identity;
190   if(id == 1) {
191     // default identity is always the first one!
192     ui.identityList->insertItem(0, identity->identityName(), id);
193   } else {
194     QString name = identity->identityName();
195     for(int j = 0; j < ui.identityList->count(); j++) {
196       if((j>0 || ui.identityList->itemData(0).toInt() != 1) && name.localeAwareCompare(ui.identityList->itemText(j)) < 0) {
197         ui.identityList->insertItem(j, name, id);
198         widgetHasChanged();
199         return;
200       }
201     }
202     // append
203     ui.identityList->insertItem(ui.identityList->count(), name, id);
204     widgetHasChanged();
205   }
206 }
207
208 void IdentitiesSettingsPage::removeIdentity(Identity *id) {
209   ui.identityList->removeItem(ui.identityList->findData(id->id()));
210   identities.remove(id->id());
211   id->deleteLater();
212   widgetHasChanged();
213 }
214
215 void IdentitiesSettingsPage::on_identityList_currentIndexChanged(int index) {
216   if(index < 0) {
217     //ui.identityList->setEditable(false);
218     displayIdentity(0);
219   } else {
220     IdentityId id = ui.identityList->itemData(index).toInt();
221     if(identities.contains(id)) displayIdentity(identities[id]);
222     ui.deleteIdentity->setEnabled(id != 1); // default identity cannot be deleted
223     //ui.identityList->setEditable(id != 1);  // ...or renamed
224   }
225 }
226
227 void IdentitiesSettingsPage::displayIdentity(Identity *id, bool dontsave) {
228   if(currentId != 0 && !dontsave && identities.contains(currentId)) {
229     saveToIdentity(identities[currentId]);
230   }
231   if(id) {
232     currentId = id->id();
233     ui.realName->setText(id->realName());
234     ui.nicknameList->clear();
235     ui.nicknameList->addItems(id->nicks());
236     //for(int i = 0; i < ui.nicknameList->count(); i++) {
237     //  ui.nicknameList->item(i)->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEditable|Qt::ItemIsEnabled);
238     //}
239     if(ui.nicknameList->count()) ui.nicknameList->setCurrentRow(0);
240     ui.awayNick->setText(id->awayNick());
241     ui.awayNickEnabled->setChecked(id->awayNickEnabled());
242     ui.awayReason->setText(id->awayReason());
243     ui.awayReasonEnabled->setChecked(id->awayReasonEnabled());
244     ui.returnMessage->setText(id->returnMessage());
245     ui.returnMessageEnabled->setChecked(id->returnMessageEnabled());
246     ui.autoAwayEnabled->setChecked(id->autoAwayEnabled());
247     ui.autoAwayTime->setValue(id->autoAwayTime());
248     ui.autoAwayReason->setText(id->autoAwayReason());
249     ui.autoAwayReasonEnabled->setChecked(id->autoAwayReasonEnabled());
250     ui.autoReturnMessage->setText(id->autoReturnMessage());
251     ui.autoReturnMessageEnabled->setChecked(id->autoReturnMessageEnabled());
252     ui.ident->setText(id->ident());
253     ui.kickReason->setText(id->kickReason());
254     ui.partReason->setText(id->partReason());
255     ui.quitReason->setText(id->quitReason());
256   }
257 }
258
259 void IdentitiesSettingsPage::saveToIdentity(Identity *id) {
260   id->setIdentityName(ui.identityList->currentText());
261   id->setRealName(ui.realName->text());
262   QStringList nicks;
263   for(int i = 0; i < ui.nicknameList->count(); i++) {
264     nicks << ui.nicknameList->item(i)->text();
265   }
266   id->setNicks(nicks);
267   id->setAwayNick(ui.awayNick->text());
268   id->setAwayNickEnabled(ui.awayNickEnabled->isChecked());
269   id->setAwayReason(ui.awayReason->text());
270   id->setAwayReasonEnabled(ui.awayReasonEnabled->isChecked());
271   id->setReturnMessage(ui.returnMessage->text());
272   id->setReturnMessageEnabled(ui.returnMessageEnabled->isChecked());
273   id->setAutoAwayEnabled(ui.autoAwayEnabled->isChecked());
274   id->setAutoAwayTime(ui.autoAwayTime->value());
275   id->setAutoAwayReason(ui.autoAwayReason->text());
276   id->setAutoAwayReasonEnabled(ui.autoAwayReasonEnabled->isChecked());
277   id->setAutoReturnMessage(ui.autoReturnMessage->text());
278   id->setAutoReturnMessageEnabled(ui.autoReturnMessageEnabled->isChecked());
279   id->setIdent(ui.ident->text());
280   id->setKickReason(ui.kickReason->text());
281   id->setPartReason(ui.partReason->text());
282   id->setQuitReason(ui.quitReason->text());
283 }
284
285 void IdentitiesSettingsPage::on_addIdentity_clicked() {
286   CreateIdentityDlg dlg(ui.identityList->model(), this);
287   if(dlg.exec() == QDialog::Accepted) {
288     // find a free (negative) ID
289     IdentityId id;
290     for(id = 1; id <= identities.count(); id++) {
291       if(!identities.keys().contains(-id)) break;
292     }
293     id *= -1;
294     Identity *newId = new Identity(id, this);
295     if(dlg.duplicateId() != 0) {
296       // duplicate
297       newId->update(*identities[dlg.duplicateId()]);
298       newId->setId(id);
299     }
300     newId->setIdentityName(dlg.identityName());
301     identities[id] = newId;
302     insertIdentity(newId);
303     ui.identityList->setCurrentIndex(ui.identityList->findData(id));
304     widgetHasChanged();
305   }
306 }
307
308 void IdentitiesSettingsPage::on_deleteIdentity_clicked() {
309   Identity *id = identities[currentId];
310   int ret = QMessageBox::question(this, tr("Delete Identity?"),
311                                   tr("Do you really want to delete identity \"%1\"?").arg(id->identityName()),
312                                   QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
313   if(ret != QMessageBox::Yes) return;
314   if(id->id() > 0) deletedIdentities.append(id->id());
315   removeIdentity(id);
316 }
317
318 void IdentitiesSettingsPage::on_identityList_editTextChanged(const QString &text) {
319   ui.identityList->setItemText(ui.identityList->currentIndex(), text);
320 }
321
322 /*****************************************************************************************/
323
324 CreateIdentityDlg::CreateIdentityDlg(QAbstractItemModel *model, QWidget *parent) : QDialog(parent) {
325   ui.setupUi(this);
326
327   ui.identityList->setModel(model);  // now we use the identity list of the main page... Trolltech <3
328   on_identityName_textChanged("");   // disable ok button :)
329 }
330
331 QString CreateIdentityDlg::identityName() const {
332   return ui.identityName->text();
333 }
334
335 IdentityId CreateIdentityDlg::duplicateId() const {
336   if(!ui.duplicateIdentity->isChecked()) return 0;
337   if(ui.identityList->currentIndex() >= 0) {
338     return ui.identityList->itemData(ui.identityList->currentIndex()).toInt();
339   }
340   return 0;
341 }
342
343 void CreateIdentityDlg::on_identityName_textChanged(const QString &text) {
344   ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(text.count());
345
346 }
347
348 /*********************************************************************************************/
349
350 SaveIdentitiesDlg::SaveIdentitiesDlg(QList<Identity *> tocreate, QList<Identity *> toupdate, QList<IdentityId> toremove, QWidget *parent)
351   : QDialog(parent), toCreate(tocreate), toUpdate(toupdate), toRemove(toremove) {
352   ui.setupUi(this);
353   numevents = toCreate.count() + toUpdate.count() + toRemove.count();
354   rcvevents = 0;
355   if(numevents) {
356     ui.progressBar->setMaximum(numevents);
357     ui.progressBar->setValue(0);
358
359     connect(Client::instance(), SIGNAL(identityCreated(IdentityId)), this, SLOT(clientEvent()));
360     connect(Client::instance(), SIGNAL(identityRemoved(IdentityId)), this, SLOT(clientEvent()));
361
362     foreach(Identity *id, toCreate) {
363       Client::createIdentity(*id);
364     }
365     foreach(Identity *id, toUpdate) {
366       const Identity *cid = Client::identity(id->id());
367       if(!cid) {
368         qWarning() << "Invalid client identity!";
369         numevents--;
370         continue;
371       }
372       connect(cid, SIGNAL(updatedRemotely()), this, SLOT(clientEvent()));
373       Client::updateIdentity(*id);
374     }
375     foreach(IdentityId id, toRemove) {
376       Client::removeIdentity(id);
377     }
378   } else {
379     qWarning() << "Sync dialog called without stuff to change!";
380     accept();
381   }
382 }
383
384 void SaveIdentitiesDlg::clientEvent() {
385   ui.progressBar->setValue(++rcvevents);
386   if(rcvevents >= numevents) accept();
387 }