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