Lots of additions again. Working on implementing commands and prettifying the output.
[quassel.git] / gui / identities.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005/06 by The Quassel Team                             *
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 "identities.h"
22
23 IdentitiesDlg::IdentitiesDlg(QWidget *parent, QString selected) : QDialog(parent) {
24   ui.setupUi(this);
25   connect(global, SIGNAL(dataUpdatedRemotely(QString)), this, SLOT(globalDataUpdated(QString)));
26
27   connect(ui.enableAutoAway, SIGNAL(stateChanged(int)), this, SLOT(autoAwayChecked()));
28
29   identities = global->getData("Identities").toMap();
30   foreach(QString name, identities.keys()) {
31     nameMapping[name] = name;
32   }
33   if(identities.size() == 0) {
34     VarMap id = createDefaultIdentity();
35     id["IdName"] = "Default";
36     identities["Default"] = id;
37     nameMapping["Default"] = "Default";
38   }
39   ui.identityList->addItem(tr("Default Identity"));
40
41   foreach(QString id, identities.keys()) {
42     if(id != "Default") ui.identityList->addItem(id);
43     if(id == selected) ui.identityList->setCurrentIndex(ui.identityList->count()-1);
44   }
45   updateWidgets();
46   lastIdentity = getCurIdentity();
47   connect(ui.identityList, SIGNAL(activated(QString)), this, SLOT(identityChanged(QString)));
48   connect(ui.editIdentitiesButton, SIGNAL(clicked()), this, SLOT(editIdentities()));
49   connect(ui.nickList, SIGNAL(itemSelectionChanged()), this, SLOT(nickSelectionChanged()));
50   connect(ui.addNickButton, SIGNAL(clicked()), this, SLOT(addNick()));
51   connect(ui.editNickButton, SIGNAL(clicked()), this, SLOT(editNick()));
52   connect(ui.delNickButton, SIGNAL(clicked()), this, SLOT(delNick()));
53   connect(ui.upNickButton, SIGNAL(clicked()), this, SLOT(upNick()));
54   connect(ui.downNickButton, SIGNAL(clicked()), this, SLOT(downNick()));
55 }
56
57 /* this needs more work! mapping? */
58 void IdentitiesDlg::globalDataUpdated(QString key) {
59   if(key == "Identities") {
60     if(QMessageBox::warning(this, tr("Data changed remotely!"), tr("<b>Some other GUI client changed the identities data!</b><br>"
61        "Apply updated settings, losing all changes done locally?"),
62        QMessageBox::Apply|QMessageBox::Discard) == QMessageBox::Apply) {
63       //identities = global->getData(key).toMap();
64       //updateWidgets();
65          reject();
66        }
67   }
68 }
69
70 VarMap IdentitiesDlg::createDefaultIdentity() {
71   VarMap id;
72   id["RealName"] = "foo";
73   id["Ident"] = "";
74   id["NickList"] = QStringList();
75   id["enableAwayNick"] = false;
76   id["AwayNick"] = "";
77   id["enableAwayReason"] = false;
78   id["AwayReason"] = "";
79   id["enableReturnMessage"] = false;
80   id["ReturnMessage"] = "";
81   id["enableAutoAway"] = false;
82   id["AutoAwayTime"] = 10;
83   id["enableAutoAwayReason"] = false;
84   id["AutoAwayReason"] = "";
85   id["enableAutoAwayReturn"] = false;
86   id["AutoAwayReturn"] = "";
87   id["PartReason"] = "Quasseling elsewhere.";
88   id["QuitReason"] = "Every Quassel comes to its end.";
89   id["KickReason"] = "No more quasseling for you!";
90
91   return id;
92 }
93
94 QString IdentitiesDlg::getCurIdentity() {
95   if(ui.identityList->currentIndex() == 0) return "Default";
96   return ui.identityList->currentText();
97 }
98
99 void IdentitiesDlg::updateWidgets() {
100   VarMap id = identities[getCurIdentity()].toMap();
101   ui.realNameEdit->setText(id["RealName"].toString());
102   ui.identEdit->setText(id["Ident"].toString());
103   ui.nickList->clear();
104   ui.nickList->addItems(id["NickList"].toStringList());
105   if(ui.nickList->count()>0) ui.nickList->setCurrentRow(0);
106   ui.enableAwayNick->setChecked(id["enableAwayNick"].toBool());
107   ui.awayNickEdit->setText(id["AwayNick"].toString());
108   ui.awayNickEdit->setEnabled(ui.enableAwayNick->isChecked());
109   ui.enableAwayReason->setChecked(id["enableAwayReason"].toBool());
110   ui.awayReasonEdit->setText(id["AwayReason"].toString());
111   ui.awayReasonEdit->setEnabled(ui.enableAwayReason->isChecked());
112   ui.enableReturnMessage->setChecked(id["enableReturnMessage"].toBool());
113   ui.returnMessageEdit->setText(id["ReturnMessage"].toString());
114   ui.returnMessageEdit->setEnabled(ui.enableReturnMessage->isChecked());
115   ui.enableAutoAway->setChecked(id["enableAutoAway"].toBool());
116   ui.autoAwayTime->setValue(id["AutoAwayTime"].toInt());
117   ui.enableAutoAwayReason->setChecked(id["enableAutoAwayReason"].toBool());
118   ui.autoAwayReasonEdit->setText(id["AutoAwayReason"].toString());
119   ui.enableAutoAwayReturn->setChecked(id["enableAutoAwayReturn"].toBool());
120   ui.autoAwayReturnEdit->setText(id["AutoAwayReturn"].toString());
121   ui.partReasonEdit->setText(id["PartReason"].toString());
122   ui.kickReasonEdit->setText(id["KickReason"].toString());
123   ui.quitReasonEdit->setText(id["QuitReason"].toString());
124   // set enabled states correctly
125   autoAwayChecked();
126   nickSelectionChanged();
127 }
128
129 void IdentitiesDlg::updateIdentity(QString idName) {
130   VarMap id;
131   id["RealName"] = ui.realNameEdit->text();
132   id["Ident"] = ui.identEdit->text();
133   QStringList nicks;
134   for(int i = 0; i < ui.nickList->count(); i++) nicks << ui.nickList->item(i)->text();
135   id["NickList"] = nicks;
136   id["enableAwayNick"] = ui.enableAwayNick->isChecked();
137   id["AwayNick"] = ui.awayNickEdit->text();
138   id["enableAwayReason"] = ui.enableAwayReason->isChecked();
139   id["AwayReason"] = ui.awayReasonEdit->text();
140   id["enableReturnMessage"] = ui.enableReturnMessage->isChecked();
141   id["ReturnMessage"] = ui.returnMessageEdit->text();
142   id["enableAutoAway"] = ui.enableAutoAway->isChecked();
143   id["AutoAwayTime"] = ui.autoAwayTime->value();
144   id["enableAutoAwayReason"] = ui.enableAutoAwayReason->isChecked();
145   id["AutoAwayReason"] = ui.autoAwayReasonEdit->text();
146   id["enableAutoAwayReturn"] = ui.enableAutoAwayReturn->isChecked();
147   id["AutoAwayReturn"] = ui.autoAwayReturnEdit->text();
148   id["PartReason"] = ui.partReasonEdit->text();
149   id["KickReason"] = ui.kickReasonEdit->text();
150   id["QuitReason"] = ui.quitReasonEdit->text();
151
152   id["IdName"] = idName;
153   identities[idName] = id;
154 }
155
156 void IdentitiesDlg::identityChanged(QString) {
157   updateIdentity(lastIdentity);
158   lastIdentity = getCurIdentity();
159   updateWidgets();
160 }
161
162 void IdentitiesDlg::autoAwayChecked() {
163   if(ui.enableAutoAway->isChecked()) {
164     ui.autoAwayLabel_1->setEnabled(1);
165     ui.autoAwayLabel_2->setEnabled(1);
166     ui.autoAwayTime->setEnabled(1);
167     ui.enableAutoAwayReason->setEnabled(1);
168     ui.enableAutoAwayReturn->setEnabled(1);
169     ui.autoAwayReasonEdit->setEnabled(ui.enableAutoAwayReason->isChecked());
170     ui.autoAwayReturnEdit->setEnabled(ui.enableAutoAwayReturn->isChecked());
171   } else {
172     ui.autoAwayLabel_1->setEnabled(0);
173     ui.autoAwayLabel_2->setEnabled(0);
174     ui.autoAwayTime->setEnabled(0);
175     ui.enableAutoAwayReason->setEnabled(0);
176     ui.enableAutoAwayReturn->setEnabled(0);
177     ui.autoAwayReasonEdit->setEnabled(0);
178     ui.autoAwayReturnEdit->setEnabled(0);
179   }
180 }
181
182 void IdentitiesDlg::nickSelectionChanged() {
183   Q_ASSERT(ui.nickList->selectedItems().size() <= 1);
184   int curidx;
185   if(ui.nickList->selectedItems().isEmpty()) curidx = -1;
186   else curidx = ui.nickList->row(ui.nickList->selectedItems()[0]);
187   ui.editNickButton->setEnabled(curidx >= 0);
188   ui.delNickButton->setEnabled(curidx >= 0);
189   ui.upNickButton->setEnabled(curidx > 0);
190   ui.downNickButton->setEnabled(curidx >= 0 && curidx < ui.nickList->count() - 1);
191 }
192
193 void IdentitiesDlg::addNick() {
194   NickEditDlg dlg(this);
195   if(dlg.exec() == QDialog::Accepted) {
196     QListWidgetItem *item = new QListWidgetItem(ui.nickList);
197     item->setText(dlg.getNick());
198     item->setFlags(item->flags() | Qt::ItemIsEditable);
199     ui.nickList->setCurrentItem(item);
200     nickSelectionChanged();
201   }
202 }
203
204 void IdentitiesDlg::editNick() {
205   NickEditDlg dlg(this, ui.nickList->currentItem()->text());
206   if(dlg.exec() == QDialog::Accepted) {
207     ui.nickList->currentItem()->setText(dlg.getNick());
208   }
209 }
210
211 void IdentitiesDlg::delNick() {
212   int row = ui.nickList->currentRow();
213   delete ui.nickList->takeItem(row);
214   if(row <= ui.nickList->count() - 1) ui.nickList->setCurrentRow(row);
215   else if(row > 0) ui.nickList->setCurrentRow(ui.nickList->count()-1);
216   nickSelectionChanged();
217 }
218
219 void IdentitiesDlg::upNick() {
220   int row = ui.nickList->currentRow();
221   QListWidgetItem *item = ui.nickList->takeItem(row);
222   ui.nickList->insertItem(row-1, item);
223   ui.nickList->setCurrentRow(row-1);
224   nickSelectionChanged();
225 }
226
227 void IdentitiesDlg::downNick() {
228   int row = ui.nickList->currentRow();
229   QListWidgetItem *item = ui.nickList->takeItem(row);
230   ui.nickList->insertItem(row+1, item);
231   ui.nickList->setCurrentRow(row+1);
232   nickSelectionChanged();
233 }
234
235 void IdentitiesDlg::accept() {
236   updateIdentity(getCurIdentity());
237   QString result = checkValidity();
238   if(result.length() == 0) {
239     global->putData("Identities", identities);
240     // We have to care about renamed identities and update the network list appropriately...
241     VarMap networks = global->getData("Networks").toMap();
242     foreach(QString netname, networks.keys()) {
243       VarMap net = networks[netname].toMap();
244       if(nameMapping.contains(net["Identity"].toString())) {
245         net["Identity"] = nameMapping[net["Identity"].toString()];
246       } else net["Identity"] = "Default";
247       networks[netname] = net;
248     }
249     global->putData("Networks", networks);
250     QDialog::accept();
251   } else {
252     QMessageBox::warning(this, tr("Invalid Identity!"),
253                          tr("One or more of your identities do not contain all necessary information:\n\n%1\n"
254                              "Please fill in any missing information.").arg(result));
255   }
256 }
257
258 QString IdentitiesDlg::checkValidity() {
259   QString reason;
260   foreach(QString name, identities.keys()) {
261     QString r;
262     VarMap id = identities[name].toMap();
263     if(name == "Default") name = tr("Default Identity");
264     if(id["RealName"].toString().isEmpty()) {
265       r += tr(" You have not set a real name.");
266     }
267     if(id["Ident"].toString().isEmpty()) {
268       r += tr(" You have to specify an Ident.");
269     }
270     if(id["NickList"].toStringList().size() == 0) {
271       r += tr(" You haven't entered any nicknames.");
272     }
273     if(r.length()>0) {
274       reason += tr("[%1]%2\n").arg(name).arg(r);
275     }
276   }
277   return reason;
278 }
279
280 void IdentitiesDlg::editIdentities() {
281   updateIdentity(getCurIdentity());
282   IdentitiesEditDlg dlg(this, identities, nameMapping, createDefaultIdentity(), getCurIdentity());
283   if(dlg.exec() == QDialog::Accepted) {
284     identities = dlg.getIdentities();
285     nameMapping = dlg.getMapping();
286     ui.identityList->clear();
287     ui.identityList->addItem(tr("Default Identity"));
288     foreach(QString id, identities.keys()) {
289       if(id != "Default") ui.identityList->addItem(id);
290       if(id == dlg.getSelectedIdentity()) ui.identityList->setCurrentIndex(ui.identityList->count()-1);
291     }
292     lastIdentity = getCurIdentity();
293     updateWidgets();
294   }
295 }
296
297 /******************************************************************************/
298
299 IdentitiesEditDlg::IdentitiesEditDlg(QWidget *parent, VarMap _identities, QMap<QString, QString> _mapping, VarMap templ, QString selected)
300   : QDialog(parent) {
301   ui.setupUi(this);
302   identities = _identities;
303   mapping = _mapping;
304   identTemplate = templ;
305
306   foreach(QString name, identities.keys()) {
307     if(name == "Default") continue;
308     ui.identList->addItem(name);
309     if(name == selected) ui.identList->setCurrentRow(ui.identList->count()-1);
310   }
311   ui.identList->sortItems();
312   ui.identList->insertItem(0, tr("Default Identity"));
313   if(ui.identList->selectedItems().count()!=1) ui.identList->setCurrentRow(0);
314   selectionChanged();
315   connect(ui.identList, SIGNAL(itemSelectionChanged()), this, SLOT(selectionChanged()));
316   connect(ui.addButton, SIGNAL(clicked()), this, SLOT(addIdentity()));
317   connect(ui.duplicateButton, SIGNAL(clicked()), this, SLOT(duplicateIdentity()));
318   connect(ui.renameButton, SIGNAL(clicked()), this, SLOT(renameIdentity()));
319   connect(ui.deleteButton, SIGNAL(clicked()), this, SLOT(deleteIdentity()));
320   }
321
322   void IdentitiesEditDlg::selectionChanged() {
323     Q_ASSERT(ui.identList->selectedItems().size() == 1);
324     int idx = ui.identList->row(ui.identList->selectedItems()[0]);
325     ui.duplicateButton->setEnabled(idx >= 0);
326     ui.renameButton->setEnabled(idx > 0);
327     ui.deleteButton->setEnabled(idx > 0);
328   }
329
330   void IdentitiesEditDlg::addIdentity() {
331     RenameIdentityDlg dlg(this, identities.keys());
332     if(dlg.exec() == QDialog::Accepted) {
333       VarMap id = identTemplate;
334       identities[dlg.getName()] = id;
335       Q_ASSERT(!mapping.contains(dlg.getName()));
336       mapping[dlg.getName()] = dlg.getName();
337       QListWidgetItem *item = new QListWidgetItem(dlg.getName(), ui.identList);
338       sortList();
339       ui.identList->setCurrentItem(item);
340       selectionChanged();
341     }
342   }
343
344   void IdentitiesEditDlg::duplicateIdentity() {
345     RenameIdentityDlg dlg(this, identities.keys());
346     if(dlg.exec() == QDialog::Accepted) {
347       QString curname = ui.identList->currentRow() == 0 ? "Default" : ui.identList->currentItem()->text();
348       QVariant id = identities[curname];
349       identities[dlg.getName()] = id;
350       Q_ASSERT(!mapping.contains(dlg.getName()));
351       mapping[dlg.getName()] = dlg.getName();
352       QListWidgetItem *item = new QListWidgetItem(dlg.getName(), ui.identList);
353       sortList();
354       ui.identList->setCurrentItem(item);
355       selectionChanged();
356     }
357   }
358
359   void IdentitiesEditDlg::renameIdentity() {
360     QList<QString> names;
361     QString curname = ui.identList->currentItem()->text();
362     foreach(QString n, identities.keys()) {
363       if(n != curname) names.append(n);
364     }
365     RenameIdentityDlg dlg(this, names, curname);
366     if(dlg.exec() == QDialog::Accepted) {
367       QString newname = dlg.getName();
368       foreach(QString key, mapping.keys()) {
369         if(mapping[key] == curname) {
370           mapping[key] = newname;
371           break;
372         }
373       }
374       QVariant id = identities.take(curname);
375       identities[newname] = id;
376       QListWidgetItem *item = ui.identList->currentItem();
377       item->setText(newname);
378       sortList();
379       ui.identList->setCurrentItem(item);
380       selectionChanged();
381     }
382   }
383
384   void IdentitiesEditDlg::deleteIdentity() {
385     QString curname = ui.identList->currentItem()->text();
386     if(QMessageBox::question(this, tr("Delete Identity?"),
387        tr("Do you really want to delete identity \"%1\"?\nNetworks using this identity "
388            "will be reset to use the default identity.").arg(curname),
389        tr("&Delete"), tr("&Cancel"), QString(), 1, 1) == 0) {
390          delete ui.identList->takeItem(ui.identList->currentRow());
391          foreach(QString key, mapping.keys()) {
392            if(mapping[key] == curname) {
393              mapping.remove(key); break;
394            }
395          }
396          identities.remove(curname);
397          selectionChanged();
398        }
399   }
400
401   void IdentitiesEditDlg::sortList() {
402     QListWidgetItem *def = ui.identList->takeItem(0);
403     ui.identList->sortItems();
404     ui.identList->insertItem(0, def);
405   }
406
407   /******************************************************************************/
408
409   NickEditDlg::NickEditDlg(QWidget *parent, QString nick) : QDialog(parent) {
410     ui.setupUi(this);
411     ui.lineEdit->setText(nick);
412     connect(ui.lineEdit, SIGNAL(textChanged(QString)), this, SLOT(textChanged(QString)));
413     textChanged(nick);
414   }
415
416   void NickEditDlg::textChanged(QString text) {
417     ui.buttonBox->button(QDialogButtonBox::Ok)->setDisabled(text.isEmpty() || text == "");
418   }
419
420   QString NickEditDlg::getNick() {
421     return ui.lineEdit->text();
422   }
423
424   /*******************************************************************************/
425
426   RenameIdentityDlg::RenameIdentityDlg(QWidget *parent, QList<QString> _reserved, QString name) : QDialog(parent) {
427     ui.setupUi(this);
428     reserved = _reserved;
429     setWindowTitle(tr("Edit Identity Name"));
430     ui.label->setText(tr("Identity:"));
431     ui.lineEdit->setText(name);
432     connect(ui.lineEdit, SIGNAL(textChanged(QString)), this, SLOT(textChanged(QString)));
433     textChanged(name);
434   }
435
436   void RenameIdentityDlg::textChanged(QString text) {
437     if(text.length() == 0) { ui.buttonBox->button(QDialogButtonBox::Ok)->setDisabled(true); return; }
438     ui.buttonBox->button(QDialogButtonBox::Ok)->setDisabled(reserved.contains(text));
439   }
440
441   QString RenameIdentityDlg::getName() {
442     return ui.lineEdit->text();
443   }