221eb2a51c25ced626acb3436b44d070e75a972a
[quassel.git] / gui / serverlist.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005 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 "serverlist.h"
22
23 /* NOTE: This dialog holds not only the server list, but also the identities.
24  *       This makes perfect sense given the fact that connections are initiated from
25  *       this dialog, and that the dialog exists during the lifetime of the program.
26  *       This data is also only used from within the GUI, which means it shouldn't be
27  *       part of the global Quassel class (me thinks).
28  */
29
30 ServerListDlg::ServerListDlg(QWidget *parent) : QDialog(parent) {
31   ui.setupUi(this);
32
33   QSettings settings;
34   settings.beginGroup("Network");
35   ui.showOnStartup->setChecked(settings.value("ShowServerListOnStartup", true).toBool());
36   // create some default entries
37   VarMap s1, s2, s3, s4;
38
39   s1["group"] = "Private Servers";
40   networks["mindNet"] = s1;
41   s2["group"] = "Private Servers";
42   networks["fooBar"] = s2;
43   s3["group"] = "";
44   networks["Single"] = s3;
45   s4["group"] = "Public Servers";
46   networks["public"] = s4;
47
48   // load networks from QSettings here instead
49   // [...]
50
51   // Construct tree widget (and its items) from networks
52   QStringList headers;
53   headers << "Network" << "Autoconnect";
54   ui.networkTree->setHeaderLabels(headers);
55   QHash<QString, QTreeWidgetItem *> groups;
56   foreach(QString net, networks.keys()) {
57     VarMap s = networks[net].toMap();
58     QString gr = s["group"].toString();
59     QTreeWidgetItem *item = 0;
60     if(gr == "") {
61       item = new QTreeWidgetItem(ui.networkTree);
62     } else {
63       if(groups.contains(gr)) {
64         item = new QTreeWidgetItem(groups[gr]);
65       } else {
66         QTreeWidgetItem *newgr = new QTreeWidgetItem(ui.networkTree);
67         newgr->setText(0, gr);
68         newgr->setFlags(newgr->flags() & ~Qt::ItemIsSelectable);
69         ui.networkTree->expandItem(newgr);
70         groups[gr] = newgr;
71         item = new QTreeWidgetItem(newgr);
72       }
73     }
74     item->setText(0, net);
75     //item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
76     item->setCheckState(1, Qt::Unchecked);
77   }
78   connect(ui.networkTree, SIGNAL(itemSelectionChanged()), this, SLOT(updateButtons()));
79
80   loadIdentities();
81   settings.endGroup();
82 }
83
84 ServerListDlg::~ServerListDlg() {
85
86 }
87
88 void ServerListDlg::updateButtons() {
89   QList<QTreeWidgetItem *> selected = ui.networkTree->selectedItems();
90   ui.editButton->setEnabled(selected.size() == 1);
91   ui.deleteButton->setEnabled(selected.size() >= 1);
92   ui.connectButton->setEnabled(selected.size() >= 1);
93
94 }
95
96 bool ServerListDlg::showOnStartup() {
97   return ui.showOnStartup->isChecked();
98 }
99
100 void ServerListDlg::on_addButton_clicked() {
101   NetworkEditDlg dlg(this, VarMap(), identities);
102   if(dlg.exec() == QDialog::Accepted) {
103
104   }
105 }
106
107 void ServerListDlg::loadNetworks() {
108
109 }
110
111 void ServerListDlg::storeNetworks() {
112
113 }
114
115 void ServerListDlg::loadIdentities() {
116   QSettings s;
117   //s.beginGroup("Identities");
118   identities = s.value("Network/Identities").toMap();
119   while(!identities.contains("Default")) {
120     identities = VarMap();
121     editIdentities();
122   }
123 }
124
125 void ServerListDlg::storeIdentities() {
126   QSettings s;
127   s.setValue("Network/Identities", identities);
128 }
129
130 void ServerListDlg::editIdentities() {
131   IdentitiesDlg dlg(this, identities);
132   if(dlg.exec() == QDialog::Accepted) {
133     identities = dlg.getIdentities();
134     QMap<QString, QString> mapping = dlg.getNameMapping();
135     // add mapping here
136
137     //
138     storeIdentities();
139     storeNetworks();  // ? how to treat mapping and NOT save changes not yet applied to the server list?
140   }
141 }
142
143 void ServerListDlg::on_showOnStartup_stateChanged(int) {
144   QSettings s;
145   s.setValue("Network/ShowServerListOnStartup", ui.showOnStartup->isChecked());
146 }
147
148 /***************************************************************************/
149
150 NetworkEditDlg::NetworkEditDlg(QWidget *parent, VarMap _network, VarMap _identities) : QDialog(parent) {
151   ui.setupUi(this);
152   network = _network;
153   identities = _identities;
154
155   ui.identityList->addItem(tr("Default Identity"));
156
157   foreach(QString id, identities.keys()) {
158     if(id != "Default") ui.identityList->addItem(id);
159   }
160
161 }
162
163 VarMap NetworkEditDlg::createDefaultNetwork() {
164   VarMap net;
165
166   net["group"] = "";
167
168   return net;
169 }
170
171 /***************************************************************************/
172
173 IdentitiesDlg::IdentitiesDlg(QWidget *parent, VarMap _identities) : QDialog(parent) {
174   ui.setupUi(this);
175   connect(ui.enableAutoAway, SIGNAL(stateChanged(int)), this, SLOT(autoAwayChecked()));
176
177   identities = _identities;
178   foreach(QString name, identities.keys()) {
179     nameMapping[name] = name;
180   }
181   if(identities.size() == 0) {
182     VarMap id = createDefaultIdentity();
183     id["IdName"] = "Default";
184     identities["Default"] = id;
185   }
186   ui.identityList->addItem(tr("Default Identity"));
187
188   foreach(QString id, identities.keys()) {
189     if(id != "Default") ui.identityList->addItem(id);
190   }
191   updateWidgets();
192   lastIdentity = getCurIdentity();
193   connect(ui.identityList, SIGNAL(activated(QString)), this, SLOT(identityChanged(QString)));
194   connect(ui.editIdentitiesButton, SIGNAL(clicked()), this, SLOT(editIdentities()));
195   connect(ui.nickList, SIGNAL(itemSelectionChanged()), this, SLOT(nickSelectionChanged()));
196   connect(ui.addNickButton, SIGNAL(clicked()), this, SLOT(addNick()));
197   connect(ui.editNickButton, SIGNAL(clicked()), this, SLOT(editNick()));
198   connect(ui.delNickButton, SIGNAL(clicked()), this, SLOT(delNick()));
199   connect(ui.upNickButton, SIGNAL(clicked()), this, SLOT(upNick()));
200   connect(ui.downNickButton, SIGNAL(clicked()), this, SLOT(downNick()));
201 }
202
203 VarMap IdentitiesDlg::createDefaultIdentity() {
204   VarMap id;
205   id["RealName"] = "foo";
206   id["Ident"] = "";
207   id["NickList"] = QStringList();
208   id["enableAwayNick"] = false;
209   id["AwayNick"] = "";
210   id["enableAwayReason"] = false;
211   id["AwayReason"] = "";
212   id["enableReturnMessage"] = false;
213   id["ReturnMessage"] = "";
214   id["enableAutoAway"] = false;
215   id["AutoAwayTime"] = 10;
216   id["enableAutoAwayReason"] = false;
217   id["AutoAwayReason"] = "";
218   id["enableAutoAwayReturn"] = false;
219   id["AutoAwayReturn"] = "";
220   id["PartReason"] = "Quasseling elsewhere.";
221   id["QuitReason"] = "Every Quassel comes to its end.";
222   id["KickReason"] = "No more quasseling for you!";
223
224   return id;
225 }
226
227 QString IdentitiesDlg::getCurIdentity() {
228   if(ui.identityList->currentIndex() == 0) return "Default";
229   return ui.identityList->currentText();
230 }
231
232 void IdentitiesDlg::updateWidgets() {
233   VarMap id = identities[getCurIdentity()].toMap();
234   ui.realNameEdit->setText(id["RealName"].toString());
235   ui.identEdit->setText(id["Ident"].toString());
236   ui.nickList->clear();
237   ui.nickList->addItems(id["NickList"].toStringList());
238   if(ui.nickList->count()>0) ui.nickList->setCurrentRow(0);
239   ui.enableAwayNick->setChecked(id["enableAwayNick"].toBool());
240   ui.awayNickEdit->setText(id["AwayNick"].toString());
241   ui.awayNickEdit->setEnabled(ui.enableAwayNick->isChecked());
242   ui.enableAwayReason->setChecked(id["enableAwayReason"].toBool());
243   ui.awayReasonEdit->setText(id["AwayReason"].toString());
244   ui.awayReasonEdit->setEnabled(ui.enableAwayReason->isChecked());
245   ui.enableReturnMessage->setChecked(id["enableReturnMessage"].toBool());
246   ui.returnMessageEdit->setText(id["ReturnMessage"].toString());
247   ui.returnMessageEdit->setEnabled(ui.enableReturnMessage->isChecked());
248   ui.enableAutoAway->setChecked(id["enableAutoAway"].toBool());
249   ui.autoAwayTime->setValue(id["AutoAwayTime"].toInt());
250   ui.enableAutoAwayReason->setChecked(id["enableAutoAwayReason"].toBool());
251   ui.autoAwayReasonEdit->setText(id["AutoAwayReason"].toString());
252   ui.enableAutoAwayReturn->setChecked(id["enableAutoAwayReturn"].toBool());
253   ui.autoAwayReturnEdit->setText(id["AutoAwayReturn"].toString());
254   ui.partReasonEdit->setText(id["PartReason"].toString());
255   ui.kickReasonEdit->setText(id["KickReason"].toString());
256   ui.quitReasonEdit->setText(id["QuitReason"].toString());
257   // set enabled states correctly
258   autoAwayChecked();
259   nickSelectionChanged();
260 }
261
262 void IdentitiesDlg::updateIdentity(QString idName) {
263   VarMap id;
264   id["RealName"] = ui.realNameEdit->text();
265   id["Ident"] = ui.identEdit->text();
266   QStringList nicks;
267   for(int i = 0; i < ui.nickList->count(); i++) nicks << ui.nickList->item(i)->text();
268   id["NickList"] = nicks;
269   id["enableAwayNick"] = ui.enableAwayNick->isChecked();
270   id["AwayNick"] = ui.awayNickEdit->text();
271   id["enableAwayReason"] = ui.enableAwayReason->isChecked();
272   id["AwayReason"] = ui.awayReasonEdit->text();
273   id["enableReturnMessage"] = ui.enableReturnMessage->isChecked();
274   id["ReturnMessage"] = ui.returnMessageEdit->text();
275   id["enableAutoAway"] = ui.enableAutoAway->isChecked();
276   id["AutoAwayTime"] = ui.autoAwayTime->value();
277   id["enableAutoAwayReason"] = ui.enableAutoAwayReason->isChecked();
278   id["AutoAwayReason"] = ui.autoAwayReasonEdit->text();
279   id["enableAutoAwayReturn"] = ui.enableAutoAwayReturn->isChecked();
280   id["AutoAwayReturn"] = ui.autoAwayReturnEdit->text();
281   id["PartReason"] = ui.partReasonEdit->text();
282   id["KickReason"] = ui.kickReasonEdit->text();
283   id["QuitReason"] = ui.quitReasonEdit->text();
284
285   id["IdName"] = idName;
286   identities[idName] = id;
287 }
288
289 void IdentitiesDlg::identityChanged(QString) {
290   updateIdentity(lastIdentity);
291   lastIdentity = getCurIdentity();
292   updateWidgets();
293 }
294
295 void IdentitiesDlg::autoAwayChecked() {
296   if(ui.enableAutoAway->isChecked()) {
297     ui.autoAwayLabel_1->setEnabled(1);
298     ui.autoAwayLabel_2->setEnabled(1);
299     ui.autoAwayTime->setEnabled(1);
300     ui.enableAutoAwayReason->setEnabled(1);
301     ui.enableAutoAwayReturn->setEnabled(1);
302     ui.autoAwayReasonEdit->setEnabled(ui.enableAutoAwayReason->isChecked());
303     ui.autoAwayReturnEdit->setEnabled(ui.enableAutoAwayReturn->isChecked());
304   } else {
305     ui.autoAwayLabel_1->setEnabled(0);
306     ui.autoAwayLabel_2->setEnabled(0);
307     ui.autoAwayTime->setEnabled(0);
308     ui.enableAutoAwayReason->setEnabled(0);
309     ui.enableAutoAwayReturn->setEnabled(0);
310     ui.autoAwayReasonEdit->setEnabled(0);
311     ui.autoAwayReturnEdit->setEnabled(0);
312   }
313 }
314
315 void IdentitiesDlg::nickSelectionChanged() {
316   int curidx = ui.nickList->currentRow();
317   ui.editNickButton->setEnabled(curidx >= 0);
318   ui.delNickButton->setEnabled(curidx >= 0);
319   ui.upNickButton->setEnabled(curidx > 0);
320   ui.downNickButton->setEnabled(curidx >= 0 && curidx < ui.nickList->count() - 1);
321 }
322
323 void IdentitiesDlg::addNick() {
324   NickEditDlg dlg(this);
325   if(dlg.exec() == QDialog::Accepted) {
326     QListWidgetItem *item = new QListWidgetItem(ui.nickList);
327     item->setText(dlg.getNick());
328     item->setFlags(item->flags() | Qt::ItemIsEditable);
329     ui.nickList->setCurrentItem(item);
330     nickSelectionChanged();
331   }
332 }
333
334 void IdentitiesDlg::editNick() {
335   NickEditDlg dlg(this, ui.nickList->currentItem()->text());
336   if(dlg.exec() == QDialog::Accepted) {
337     ui.nickList->currentItem()->setText(dlg.getNick());
338   }
339 }
340
341 void IdentitiesDlg::delNick() {
342   int row = ui.nickList->currentRow();
343   delete ui.nickList->takeItem(row);
344   if(row <= ui.nickList->count() - 1) ui.nickList->setCurrentRow(row);
345   else if(row > 0) ui.nickList->setCurrentRow(ui.nickList->count()-1);
346   nickSelectionChanged();
347 }
348
349 void IdentitiesDlg::upNick() {
350   int row = ui.nickList->currentRow();
351   QListWidgetItem *item = ui.nickList->takeItem(row);
352   ui.nickList->insertItem(row-1, item);
353   ui.nickList->setCurrentRow(row-1);
354   nickSelectionChanged();
355 }
356
357 void IdentitiesDlg::downNick() {
358   int row = ui.nickList->currentRow();
359   QListWidgetItem *item = ui.nickList->takeItem(row);
360   ui.nickList->insertItem(row+1, item);
361   ui.nickList->setCurrentRow(row+1);
362   nickSelectionChanged();
363 }
364
365 void IdentitiesDlg::accept() {
366   updateIdentity(getCurIdentity());
367   QString result = checkValidity();
368   if(result.length() == 0) QDialog::accept();
369   else {
370     QMessageBox::warning(this, tr("Invalid Identity!"),
371                          tr("One or more of your identities do not contain all necessary information:\n\n%1\n"
372                              "Please fill in any missing information.").arg(result));
373   }
374 }
375
376 QString IdentitiesDlg::checkValidity() {
377   QString reason;
378   foreach(QString name, identities.keys()) {
379     QString r;
380     VarMap id = identities[name].toMap();
381     if(name == "Default") name = tr("Default Identity");
382     if(id["RealName"].toString().length() == 0) {
383       r += tr(" You have not set a real name.");
384     }
385     if(id["Ident"].toString().length() == 0) {
386       r += tr(" You have to specify an Ident.");
387     }
388     if(id["NickList"].toStringList().size() == 0) {
389       r += tr(" You haven't entered any nicknames.");
390     }
391     if(r.length()>0) {
392       reason += tr("[%1]%2\n").arg(name).arg(r);
393     }
394   }
395   return reason;
396 }
397
398 void IdentitiesDlg::editIdentities() {
399   updateIdentity(getCurIdentity());
400   IdentitiesEditDlg dlg(this, identities, nameMapping, createDefaultIdentity());
401   if(dlg.exec() == QDialog::Accepted) {
402     identities = dlg.getIdentities();
403     nameMapping = dlg.getMapping();
404     ui.identityList->clear();
405     ui.identityList->addItem(tr("Default Identity"));
406     foreach(QString id, identities.keys()) {
407       if(id != "Default") ui.identityList->addItem(id);
408     }
409     lastIdentity = getCurIdentity();
410     updateWidgets();
411   }
412 }
413
414 /******************************************************************************/
415
416 IdentitiesEditDlg::IdentitiesEditDlg(QWidget *parent, VarMap _identities, QMap<QString, QString> _mapping, VarMap templ)
417   : QDialog(parent) {
418   ui.setupUi(this);
419   identities = _identities;
420   mapping = _mapping;
421   identTemplate = templ;
422
423   foreach(QString name, identities.keys()) {
424     if(name == "Default") continue;
425     ui.identList->addItem(name);
426   }
427   ui.identList->sortItems();
428   ui.identList->insertItem(0, tr("Default Identity"));
429   ui.identList->setCurrentRow(0);
430   selectionChanged();
431   connect(ui.identList, SIGNAL(itemSelectionChanged()), this, SLOT(selectionChanged()));
432   connect(ui.addButton, SIGNAL(clicked()), this, SLOT(addIdentity()));
433   connect(ui.duplicateButton, SIGNAL(clicked()), this, SLOT(duplicateIdentity()));
434   connect(ui.renameButton, SIGNAL(clicked()), this, SLOT(renameIdentity()));
435   connect(ui.deleteButton, SIGNAL(clicked()), this, SLOT(deleteIdentity()));
436 }
437
438 void IdentitiesEditDlg::selectionChanged() {
439   int idx = ui.identList->currentRow();
440   ui.duplicateButton->setEnabled(idx >= 0);
441   ui.renameButton->setEnabled(idx > 0);
442   ui.deleteButton->setEnabled(idx > 0);
443
444 }
445
446 void IdentitiesEditDlg::addIdentity() {
447   RenameIdentityDlg dlg(this, identities.keys());
448   if(dlg.exec() == QDialog::Accepted) {
449     VarMap id = identTemplate;
450     identities[dlg.getName()] = id;
451     QListWidgetItem *item = new QListWidgetItem(dlg.getName(), ui.identList);
452     sortList();
453     ui.identList->setCurrentItem(item);
454     selectionChanged();
455   }
456 }
457
458 void IdentitiesEditDlg::duplicateIdentity() {
459   RenameIdentityDlg dlg(this, identities.keys());
460   if(dlg.exec() == QDialog::Accepted) {
461     QString curname = ui.identList->currentRow() == 0 ? "Default" : ui.identList->currentItem()->text();
462     QVariant id = identities[curname];
463     identities[dlg.getName()] = id;
464     QListWidgetItem *item = new QListWidgetItem(dlg.getName(), ui.identList);
465     sortList();
466     ui.identList->setCurrentItem(item);
467     selectionChanged();
468   }
469 }
470
471 void IdentitiesEditDlg::renameIdentity() {
472   QList<QString> names;
473   QString curname = ui.identList->currentItem()->text();
474   foreach(QString n, identities.keys()) {
475     if(n != curname) names.append(n);
476   }
477   RenameIdentityDlg dlg(this, names, curname);
478   if(dlg.exec() == QDialog::Accepted) {
479     QString newname = dlg.getName();
480     foreach(QString key, mapping.keys()) {
481       if(mapping[key] == curname) {
482         mapping[key] = newname;
483         break;
484       }
485     }
486     QVariant id = identities.take(curname);
487     identities[newname] = id;
488     QListWidgetItem *item = ui.identList->currentItem();
489     item->setText(newname);
490     sortList();
491     ui.identList->setCurrentItem(item);
492     selectionChanged();
493   }
494 }
495
496 void IdentitiesEditDlg::deleteIdentity() {
497   QString curname = ui.identList->currentItem()->text();
498   if(QMessageBox::question(this, tr("Delete Identity?"),
499      tr("Do you really want to delete identity \"%1\"?\nNetworks using this identity "
500         "will be reset to use the default identity.").arg(curname),
501     tr("&Delete"), tr("&Cancel"), QString(), 1, 1) == 0) {
502       delete ui.identList->takeItem(ui.identList->currentRow());
503       foreach(QString key, mapping.keys()) {
504         if(mapping[key] == curname) {
505           mapping.remove(key); break;
506         }
507       }
508       identities.remove(curname);
509       selectionChanged();
510   }
511 }
512
513 void IdentitiesEditDlg::sortList() {
514   QListWidgetItem *def = ui.identList->takeItem(0);
515   ui.identList->sortItems();
516   ui.identList->insertItem(0, def);
517 }
518
519 /******************************************************************************/
520
521 NickEditDlg::NickEditDlg(QWidget *parent, QString nick) : QDialog(parent) {
522   ui.setupUi(this);
523   ui.lineEdit->setText(nick);
524   connect(ui.lineEdit, SIGNAL(textChanged(QString)), this, SLOT(textChanged(QString)));
525   textChanged(nick);
526 }
527
528 void NickEditDlg::textChanged(QString text) {
529   ui.okButton->setDisabled(text.isEmpty() || text == "");
530 }
531
532 QString NickEditDlg::getNick() {
533   return ui.lineEdit->text();
534 }
535
536 /*******************************************************************************/
537
538 RenameIdentityDlg::RenameIdentityDlg(QWidget *parent, QList<QString> _reserved, QString name) : QDialog(parent) {
539   ui.setupUi(this);
540   reserved = _reserved;
541   //ui.NickEditDlg->setWindowTitle(tr("Edit Identity Name"));  // why does this not work?
542   ui.label->setText(tr("Identity:"));
543   ui.lineEdit->setText(name);
544   connect(ui.lineEdit, SIGNAL(textChanged(QString)), this, SLOT(textChanged(QString)));
545   textChanged(name);
546 }
547
548 void RenameIdentityDlg::textChanged(QString text) {
549   if(text.length() == 0) { ui.okButton->setEnabled(0); return; }
550   ui.okButton->setDisabled(reserved.contains(text));
551 }
552
553 QString RenameIdentityDlg::getName() {
554   return ui.lineEdit->text();
555 }
556