YES! We finally have dynamic signals between Core and Client, meaning that arbitrary
[quassel.git] / src / qtgui / serverlist.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-07 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 "identities.h"
23 #include "client.h"
24 //#include "clientproxy.h"
25 #include "signalproxy.h"
26
27 /* NOTE: This dialog holds not only the server list, but also the identities.
28  *       This makes perfect sense given the fact that connections are initiated from
29  *       this dialog, and that the dialog exists during the lifetime of the program.
30  */
31
32 ServerListDlg::ServerListDlg(QWidget *parent) : QDialog(parent) {
33   ui.setupUi(this);
34
35   QSettings settings;
36   settings.beginGroup("GUI");
37   ui.showOnStartup->setChecked(settings.value("ShowServerListOnStartup", true).toBool());
38
39   updateNetworkTree();
40   connect(ui.networkTree, SIGNAL(itemSelectionChanged()), this, SLOT(updateButtons()));
41   connect(Client::instance(), SIGNAL(sessionDataChanged(const QString &)), this, SLOT(updateNetworkTree()));
42
43   settings.endGroup();
44
45   //connect(this, SIGNAL(requestConnect(QStringList)), ClientProxy::instance(), SLOT(gsRequestConnect(QStringList)));
46   Client::signalProxy()->attachSignal(this, SIGNAL(requestConnect(QString)));
47
48   // Autoconnect
49   /* Should not be the client's task... :-P
50   QStringList list;
51   QVariantMap networks = Client::retrieveSessionData("Networks").toMap();
52   foreach(QString net, networks.keys()) {
53     if(networks[net].toMap()["AutoConnect"].toBool()) {
54       list << net;
55     }
56   }
57   if(!list.isEmpty()) emit requestConnect(list);
58   */
59 }
60
61 ServerListDlg::~ServerListDlg() {
62
63 }
64
65 void ServerListDlg::updateNetworkTree() {
66   QVariantMap networks = Client::retrieveSessionData("Networks").toMap();
67   //QStringList headers;
68   //headers << "Network" << "Autoconnect";
69   ui.networkTree->clear();
70   //ui.networkTree->setHeaderLabels(headers);
71   ui.networkTree->setHeaderLabel("Networks");
72   QHash<QString, QTreeWidgetItem *> groups;
73   foreach(QString net, networks.keys()) {
74     QVariantMap s = networks[net].toMap();
75     QString gr = s["Group"].toString();
76     QTreeWidgetItem *item = 0;
77     if(gr.isEmpty()) {
78       item = new QTreeWidgetItem(ui.networkTree);
79     } else {
80       if(groups.contains(gr)) {
81         item = new QTreeWidgetItem(groups[gr]);
82       } else {
83         QTreeWidgetItem *newgr = new QTreeWidgetItem(ui.networkTree);
84         //ui.networkTree->addTopLevelItem(newgr);
85         newgr->setText(0, gr);
86         newgr->setFlags(newgr->flags() & ~Qt::ItemIsSelectable);
87         groups[gr] = newgr;
88         item = new QTreeWidgetItem(newgr);
89         newgr->setExpanded(true);
90         ui.networkTree->addTopLevelItem(newgr);
91         //ui.networkTree->expandItem(newgr); //<-- buggy Qt?
92       }
93     }
94     item->setText(0, net);
95     item->setToolTip(0, s["Description"].toString());
96     //item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
97     //item->setCheckState(1, Qt::Unchecked);
98   }
99   ui.networkTree->sortItems(0, Qt::AscendingOrder);
100   updateButtons();
101 }
102
103 void ServerListDlg::updateButtons() {
104   QList<QTreeWidgetItem *> selected = ui.networkTree->selectedItems();
105   ui.editButton->setEnabled(selected.size() == 1);
106   ui.deleteButton->setEnabled(selected.size() >= 1);
107   ui.connectButton->setEnabled(selected.size() >= 1);
108
109 }
110
111 bool ServerListDlg::showOnStartup() {
112   return ui.showOnStartup->isChecked();
113 }
114
115 void ServerListDlg::on_addButton_clicked() {
116   NetworkEditDlg dlg(this, QVariantMap());
117   if(dlg.exec() == QDialog::Accepted) {
118     QVariantMap networks = Client::retrieveSessionData("Networks").toMap();
119     QVariantMap net = dlg.getNetwork();
120     networks[net["Name"].toString()] = net;
121     Client::storeSessionData("Networks", networks);
122     updateNetworkTree();
123   }
124 }
125
126 void ServerListDlg::on_editButton_clicked() {
127   QString curnet = ui.networkTree->currentItem()->text(0);
128   QVariantMap networks = Client::retrieveSessionData("Networks").toMap();
129   NetworkEditDlg dlg(this, networks[curnet].toMap());
130   if(dlg.exec() == QDialog::Accepted) {
131     QVariantMap net = dlg.getNetwork();
132     networks.remove(curnet);
133     networks[net["Name"].toString()] = net;
134     Client::storeSessionData("Networks", networks);
135     updateNetworkTree();
136   }
137 }
138
139 void ServerListDlg::on_deleteButton_clicked() {
140   if(QMessageBox::warning(this, tr("Remove Network?"), tr("Are you sure you want to delete the selected network(s)?"),
141                         QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
142     QVariantMap networks = Client::retrieveSessionData("Networks").toMap();
143     QList<QTreeWidgetItem *> sel = ui.networkTree->selectedItems();
144     foreach(QTreeWidgetItem *item, sel) {
145       networks.remove(item->text(0));
146     }
147     Client::storeSessionData("Networks", networks);
148     updateNetworkTree();
149   }
150 }
151
152 void ServerListDlg::editIdentities(bool end) {
153   IdentitiesDlg dlg(this);
154   if(dlg.exec() == QDialog::Accepted) {
155     /* Should now all be handled within the dialog class. Global settings rulez0rs. */
156     //identities = dlg.getIdentities();
157     //QMap<QString, QString> mapping = dlg.getNameMapping();
158     // add mapping here  <-- well, I don't fucking know anymore what I meant by this back in 2005...
159
160     //
161     //storeIdentities();
162     //storeNetworks();  // ? how to treat mapping and NOT save changes not yet applied to the server list?
163   }
164   else if(end) exit(0);
165 }
166
167 void ServerListDlg::on_showOnStartup_stateChanged(int) {
168   QSettings s;
169   s.setValue("GUI/ShowServerListOnStartup", ui.showOnStartup->isChecked());
170 }
171
172 void ServerListDlg::accept() {
173   QStringList nets;
174   QList<QTreeWidgetItem *> list = ui.networkTree->selectedItems();
175   foreach(QTreeWidgetItem *item, list) {
176     nets << item->text(0);
177   }
178   emit requestConnect(nets[0]); // FIXME
179   QDialog::accept();
180 }
181
182 /***************************************************************************/
183
184 NetworkEditDlg::NetworkEditDlg(QWidget *parent, QVariantMap _network) : QDialog(parent) {
185   ui.setupUi(this);
186   network = _network;
187   oldName = network["Name"].toString();
188
189   connect(ui.serverList, SIGNAL(itemSelectionChanged()), this, SLOT(updateServerButtons()));
190
191   QVariantMap identities = Client::retrieveSessionData("Identities").toMap();
192
193   ui.identityList->addItem(tr("Default Identity"));
194   foreach(QString id, identities.keys()) {
195     if(id != "Default") ui.identityList->addItem(id);
196   }
197   QStringList groups; groups << "";
198   QVariantMap nets = Client::retrieveSessionData("Networks").toMap();
199   foreach(QString net, nets.keys()) {
200     QString gr = nets[net].toMap()["Group"].toString();
201     if(!groups.contains(gr) && !gr.isEmpty()) {
202       groups.append(gr);
203     }
204   }
205   ui.networkGroup->addItems(groups);
206   if(network.size() == 0) network = createDefaultNetwork();
207
208   ui.networkName->setText(network["Name"].toString());
209   if(network["Group"].toString().isEmpty()) ui.networkGroup->setCurrentIndex(0);
210   else ui.networkGroup->setCurrentIndex(ui.networkGroup->findText(network["Group"].toString()));
211   if(network["Identity"].toString().isEmpty() || network["Identity"].toString() == "Default") ui.identityList->setCurrentIndex(0);
212   else ui.identityList->setCurrentIndex(ui.identityList->findText(network["Identity"].toString()));
213   ui.enableAutoConnect->setChecked(network["AutoConnect"].toBool());
214   updateWidgets();
215
216   on_networkName_textChanged(ui.networkName->text());
217   ui.networkName->setFocus();
218 }
219
220 QVariantMap NetworkEditDlg::createDefaultNetwork() {
221   QVariantMap net;
222
223   net["Name"] = QString();
224   net["Group"] = QString();
225   net["Identity"] = QString("Default");
226
227   return net;
228 }
229
230 void NetworkEditDlg::updateWidgets() {
231   ui.serverList->clear();
232   foreach(QVariant s, network["Servers"].toList()) {
233     QVariantMap server = s.toMap();
234     QString entry = QString("%1:%2").arg(server["Address"].toString()).arg(server["Port"].toInt());
235     QListWidgetItem *item = new QListWidgetItem(entry);
236     //if(server["Exclude"].toBool()) item->setCheckState(Qt::Checked);
237     ui.serverList->addItem(item);
238   }
239   ui.performEdit->clear();
240   ui.performEdit->setText( network["Perform"].toString() );
241   updateServerButtons();
242 }
243
244 void NetworkEditDlg::updateServerButtons() {
245   Q_ASSERT(ui.serverList->selectedItems().size() <= 1);
246   int curidx;
247   if(ui.serverList->selectedItems().isEmpty()) curidx = -1;
248   else curidx = ui.serverList->row(ui.serverList->selectedItems()[0]);
249   ui.editServer->setEnabled(curidx >= 0);
250   ui.deleteServer->setEnabled(curidx >= 0);
251   ui.upServer->setEnabled(curidx > 0);
252   ui.downServer->setEnabled(curidx >= 0 && curidx < ui.serverList->count() - 1);
253
254 }
255
256 void NetworkEditDlg::on_networkName_textChanged(QString text) {
257   ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!text.isEmpty());
258 }
259
260 void NetworkEditDlg::accept() {
261   QString reason = checkValidity();
262   if(reason.isEmpty()) {
263     network["Name"] = ui.networkName->text();
264     network["Description"] = ui.networkDesc->text();
265     /*if(ui.networkGroup->currentText() == "<none>") network["Group"] = "";
266     else */ network["Group"] = ui.networkGroup->currentText();
267     network["AutoConnect"] = ui.enableAutoConnect->isChecked();
268     network["Perform"] = ui.performEdit->toPlainText();
269     if(ui.identityList->currentIndex()) network["Identity"] = ui.identityList->currentText();
270     else network["Identity"] = "Default";
271     QDialog::accept();
272   } else {
273     QMessageBox::warning(this, tr("Invalid Network Settings!"),
274                          tr("<b>Your network settings are invalid!</b><br>%1").arg(reason));
275   }
276
277 }
278
279 QString NetworkEditDlg::checkValidity() {
280   QString r;
281   QVariantMap nets = Client::retrieveSessionData("Networks").toMap();
282   if(ui.networkName->text() != oldName && nets.keys().contains(ui.networkName->text())) {
283     r += tr(" Network name already exists.");
284   }
285   if(network["Servers"].toList().isEmpty()) {
286     r += tr(" You need to enter at least one server for this network.");
287   }
288   return r;
289 }
290
291 void NetworkEditDlg::on_addServer_clicked() {
292   ServerEditDlg dlg(this);
293   if(dlg.exec() == QDialog::Accepted) {
294     QList<QVariant> list = network["Servers"].toList();
295     list.append(dlg.getServer());
296     network["Servers"] = list;
297     updateWidgets();
298   }
299 }
300
301 void NetworkEditDlg::on_editServer_clicked() {
302   int idx = ui.serverList->currentRow();
303   ServerEditDlg dlg(this, network["Servers"].toList()[idx].toMap());
304   if(dlg.exec() == QDialog::Accepted) {
305     QList<QVariant> list = network["Servers"].toList();
306     list[idx] = dlg.getServer();
307     network["Servers"] = list;
308     updateWidgets();
309   }
310 }
311
312 void NetworkEditDlg::on_deleteServer_clicked() {
313   int idx = ui.serverList->currentRow();
314   QList<QVariant> list = network["Servers"].toList();
315   list.removeAt(idx);
316   network["Servers"] = list;
317   updateWidgets();
318   if(idx < ui.serverList->count()) ui.serverList->setCurrentRow(idx);
319   else if(ui.serverList->count()) ui.serverList->setCurrentRow(ui.serverList->count()-1);
320 }
321
322 void NetworkEditDlg::on_upServer_clicked() {
323   int idx = ui.serverList->currentRow();
324   QList<QVariant> list = network["Servers"].toList();
325   list.swap(idx, idx-1);
326   network["Servers"] = list;
327   updateWidgets();
328   ui.serverList->setCurrentRow(idx-1);
329 }
330
331 void NetworkEditDlg::on_downServer_clicked() {
332   int idx = ui.serverList->currentRow();
333   QList<QVariant> list = network["Servers"].toList();
334   list.swap(idx, idx+1);
335   network["Servers"] = list;
336   updateWidgets();
337   ui.serverList->setCurrentRow(idx+1);
338 }
339
340 void NetworkEditDlg::on_editIdentities_clicked() {
341   QString id;
342   if(ui.identityList->currentIndex() > 0) id = ui.identityList->currentText();
343   else id = "Default";
344   IdentitiesDlg dlg(this, id);
345   if(dlg.exec() == QDialog::Accepted) {
346     QVariantMap identities = Client::retrieveSessionData("Identities").toMap();
347     ui.identityList->clear();
348     ui.identityList->addItem(tr("Default Identity"));
349     foreach(QString i, identities.keys()) {
350       if(i != "Default") ui.identityList->addItem(i);
351     }
352     QMap<QString, QString> mapping = dlg.getNameMapping();
353     if(mapping.contains(id)) id = mapping[id];
354     else id = "Default";
355     if(id != "Default") ui.identityList->setCurrentIndex(ui.identityList->findText(id));
356     else ui.identityList->setCurrentIndex(0);
357     network["Identity"] = id;
358   }
359 }
360
361 /***************************************************************************/
362
363 ServerEditDlg::ServerEditDlg(QWidget *parent, QVariantMap server) : QDialog(parent) {
364   ui.setupUi(this);
365
366   if(!server.isEmpty()) {
367     ui.serverAddress->setText(server["Address"].toString());
368     ui.serverPort->setValue(server["Port"].toInt());
369   } else {
370     ui.serverAddress->setText(QString());
371     ui.serverPort->setValue(6667);
372   }
373   on_serverAddress_textChanged();
374 }
375
376 void ServerEditDlg::on_serverAddress_textChanged() {
377   ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!ui.serverAddress->text().isEmpty());
378 }
379
380 QVariantMap ServerEditDlg::getServer() {
381   QVariantMap s;
382   s["Address"] = ui.serverAddress->text();
383   s["Port"] = ui.serverPort->text();
384   return s;
385 }
386
387
388 /***************************************************************************/