230263028130d90d32e582dab81f3a39c279bb9d
[quassel.git] / src / qtui / settingspages / networkssettingspage.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-09 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) version 3.                                           *
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 <QHeaderView>
22 #include <QMessageBox>
23 #include <QTextCodec>
24
25 #include "networkssettingspage.h"
26
27 #include "client.h"
28 #include "iconloader.h"
29 #include "identity.h"
30 #include "network.h"
31 #include "settingspagedlg.h"
32 #include "util.h"
33
34 #include "settingspages/identitiessettingspage.h"
35
36 NetworksSettingsPage::NetworksSettingsPage(QWidget *parent) : SettingsPage(tr("General"), tr("Networks"), parent) {
37   ui.setupUi(this);
38
39   // set up icons
40   ui.renameNetwork->setIcon(SmallIcon("edit-rename"));
41   ui.addNetwork->setIcon(SmallIcon("list-add"));
42   ui.deleteNetwork->setIcon(SmallIcon("edit-delete"));
43   ui.addServer->setIcon(SmallIcon("list-add"));
44   ui.deleteServer->setIcon(SmallIcon("edit-delete"));
45   ui.editServer->setIcon(SmallIcon("configure"));
46   ui.upServer->setIcon(SmallIcon("go-up"));
47   ui.downServer->setIcon(SmallIcon("go-down"));
48   ui.editIdentities->setIcon(SmallIcon("configure"));
49
50   _ignoreWidgetChanges = false;
51
52   connectedIcon = SmallIcon("network-connect");
53   connectingIcon = SmallIcon("network-wired");  // FIXME network-connecting
54   disconnectedIcon = SmallIcon("network-disconnect");
55
56   foreach(int mib, QTextCodec::availableMibs()) {
57     QByteArray codec = QTextCodec::codecForMib(mib)->name();
58     ui.sendEncoding->addItem(codec);
59     ui.recvEncoding->addItem(codec);
60     ui.serverEncoding->addItem(codec);
61   }
62   ui.sendEncoding->model()->sort(0);
63   ui.recvEncoding->model()->sort(0);
64   ui.serverEncoding->model()->sort(0);
65   currentId = 0;
66   setEnabled(Client::isConnected());  // need a core connection!
67   setWidgetStates();
68   connect(Client::instance(), SIGNAL(coreConnectionStateChanged(bool)), this, SLOT(coreConnectionStateChanged(bool)));
69   connect(Client::instance(), SIGNAL(networkCreated(NetworkId)), this, SLOT(clientNetworkAdded(NetworkId)));
70   connect(Client::instance(), SIGNAL(networkRemoved(NetworkId)), this, SLOT(clientNetworkRemoved(NetworkId)));
71   connect(Client::instance(), SIGNAL(identityCreated(IdentityId)), this, SLOT(clientIdentityAdded(IdentityId)));
72   connect(Client::instance(), SIGNAL(identityRemoved(IdentityId)), this, SLOT(clientIdentityRemoved(IdentityId)));
73
74   connect(ui.identityList, SIGNAL(currentIndexChanged(int)), this, SLOT(widgetHasChanged()));
75   //connect(ui.randomServer, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
76   connect(ui.performEdit, SIGNAL(textChanged()), this, SLOT(widgetHasChanged()));
77   connect(ui.autoIdentify, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
78   connect(ui.autoIdentifyService, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
79   connect(ui.autoIdentifyPassword, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
80   connect(ui.useCustomEncodings, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
81   connect(ui.sendEncoding, SIGNAL(currentIndexChanged(int)), this, SLOT(widgetHasChanged()));
82   connect(ui.recvEncoding, SIGNAL(currentIndexChanged(int)), this, SLOT(widgetHasChanged()));
83   connect(ui.serverEncoding, SIGNAL(currentIndexChanged(int)), this, SLOT(widgetHasChanged()));
84   connect(ui.autoReconnect, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
85   connect(ui.reconnectInterval, SIGNAL(valueChanged(int)), this, SLOT(widgetHasChanged()));
86   connect(ui.reconnectRetries, SIGNAL(valueChanged(int)), this, SLOT(widgetHasChanged()));
87   connect(ui.unlimitedRetries, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
88   connect(ui.rejoinOnReconnect, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
89   //connect(ui., SIGNAL(), this, SLOT(widgetHasChanged()));
90   //connect(ui., SIGNAL(), this, SLOT(widgetHasChanged()));
91
92   foreach(IdentityId id, Client::identityIds()) {
93     clientIdentityAdded(id);
94   }
95 }
96
97 void NetworksSettingsPage::save() {
98   setEnabled(false);
99   if(currentId != 0) saveToNetworkInfo(networkInfos[currentId]);
100
101   QList<NetworkInfo> toCreate, toUpdate;
102   QList<NetworkId> toRemove;
103   QHash<NetworkId, NetworkInfo>::iterator i = networkInfos.begin();
104   while(i != networkInfos.end()) {
105     NetworkId id = (*i).networkId;
106     if(id < 0) {
107       toCreate.append(*i);
108       //if(id == currentId) currentId = 0;
109       //QList<QListWidgetItem *> items = ui.networkList->findItems((*i).networkName, Qt::MatchExactly);
110       //if(items.count()) {
111       //  Q_ASSERT(items[0]->data(Qt::UserRole).value<NetworkId>() == id);
112       //  delete items[0];
113       //}
114       //i = networkInfos.erase(i);
115       ++i;
116     } else {
117       if((*i) != Client::network((*i).networkId)->networkInfo()) {
118         toUpdate.append(*i);
119       }
120       ++i;
121     }
122   }
123   foreach(NetworkId id, Client::networkIds()) {
124     if(!networkInfos.contains(id)) toRemove.append(id);
125   }
126   SaveNetworksDlg dlg(toCreate, toUpdate, toRemove, this);
127   int ret = dlg.exec();
128   if(ret == QDialog::Rejected) {
129     // canceled -> reload everything to be safe
130     load();
131   }
132   setChangedState(false);
133   setEnabled(true);
134 }
135
136 void NetworksSettingsPage::load() {
137   reset();
138   foreach(NetworkId netid, Client::networkIds()) {
139     clientNetworkAdded(netid);
140   }
141   ui.networkList->setCurrentRow(0);
142   setChangedState(false);
143 }
144
145 void NetworksSettingsPage::reset() {
146   currentId = 0;
147   ui.networkList->clear();
148   networkInfos.clear();
149
150 }
151
152 bool NetworksSettingsPage::aboutToSave() {
153   if(currentId != 0) saveToNetworkInfo(networkInfos[currentId]);
154   QList<int> errors;
155   foreach(NetworkInfo info, networkInfos.values()) {
156     if(!info.serverList.count()) errors.append(1);
157   }
158   if(!errors.count()) return true;
159   QString error(tr("<b>The following problems need to be corrected before your changes can be applied:</b><ul>"));
160   if(errors.contains(1)) error += tr("<li>All networks need at least one server defined</li>");
161   error += tr("</ul>");
162   QMessageBox::warning(this, tr("Invalid Network Settings"), error);
163   return false;
164 }
165
166 void NetworksSettingsPage::widgetHasChanged() {
167   if(_ignoreWidgetChanges) return;
168   bool changed = testHasChanged();
169   if(changed != hasChanged()) setChangedState(changed);
170 }
171
172 bool NetworksSettingsPage::testHasChanged() {
173   if(currentId != 0) {
174     saveToNetworkInfo(networkInfos[currentId]);
175   }
176   if(Client::networkIds().count() != networkInfos.count()) return true;
177   foreach(NetworkId id, networkInfos.keys()) {
178     if(id < 0) return true;
179     if(Client::network(id)->networkInfo() != networkInfos[id]) return true;
180   }
181   return false;
182 }
183
184 void NetworksSettingsPage::setWidgetStates() {
185   // network list
186   if(ui.networkList->selectedItems().count()) {
187     NetworkId id = ui.networkList->selectedItems()[0]->data(Qt::UserRole).value<NetworkId>();
188     const Network *net = 0;
189     if(id > 0) net = Client::network(id);
190     ui.detailsBox->setEnabled(true);
191     ui.renameNetwork->setEnabled(true);
192     ui.deleteNetwork->setEnabled(true);
193     /* button disabled for now
194     ui.connectNow->setEnabled(net);
195     //    && (Client::network(id)->connectionState() == Network::Initialized
196     //    || Client::network(id)->connectionState() == Network::Disconnected));
197     if(net) {
198       if(net->connectionState() == Network::Disconnected) {
199         ui.connectNow->setIcon(connectedIcon);
200         ui.connectNow->setText(tr("Connect"));
201       } else {
202         ui.connectNow->setIcon(disconnectedIcon);
203         ui.connectNow->setText(tr("Disconnect"));
204       }
205     } else {
206       ui.connectNow->setIcon(QIcon());
207       ui.connectNow->setText(tr("Apply first!"));
208     } */
209   } else {
210     ui.renameNetwork->setEnabled(false);
211     ui.deleteNetwork->setEnabled(false);
212     //ui.connectNow->setEnabled(false);
213     ui.detailsBox->setEnabled(false);
214   }
215   // network details
216   if(ui.serverList->selectedItems().count()) {
217     ui.editServer->setEnabled(true);
218     ui.deleteServer->setEnabled(true);
219     ui.upServer->setEnabled(ui.serverList->currentRow() > 0);
220     ui.downServer->setEnabled(ui.serverList->currentRow() < ui.serverList->count() - 1);
221   } else {
222     ui.editServer->setEnabled(false);
223     ui.deleteServer->setEnabled(false);
224     ui.upServer->setEnabled(false);
225     ui.downServer->setEnabled(false);
226   }
227 }
228
229 void NetworksSettingsPage::setItemState(NetworkId id, QListWidgetItem *item) {
230   if(!item && !(item = networkItem(id))) return;
231   const Network *net = Client::network(id);
232   if(!net || net->isInitialized()) item->setFlags(item->flags() | Qt::ItemIsEnabled);
233   else item->setFlags(item->flags() & ~Qt::ItemIsEnabled);
234   if(net && net->connectionState() == Network::Initialized) {
235     item->setIcon(connectedIcon);
236   } else if(net && net->connectionState() != Network::Disconnected) {
237     item->setIcon(connectingIcon);
238   } else {
239     item->setIcon(disconnectedIcon);
240   }
241   if(net) {
242     bool select = false;
243     // check if we already have another net of this name in the list, and replace it
244     QList<QListWidgetItem *> items = ui.networkList->findItems(net->networkName(), Qt::MatchExactly);
245     if(items.count()) {
246       foreach(QListWidgetItem *i, items) {
247         NetworkId oldid = i->data(Qt::UserRole).value<NetworkId>();
248         if(oldid > 0) continue;  // only locally created nets should be replaced
249         if(oldid == currentId) {
250           select = true;
251           currentId = 0;
252           ui.networkList->clearSelection();
253         }
254         int row = ui.networkList->row(i);
255         if(row >= 0) {
256           QListWidgetItem *olditem = ui.networkList->takeItem(row);
257           Q_ASSERT(olditem);
258           delete olditem;
259         }
260         networkInfos.remove(oldid);
261         break;
262       }
263     }
264     item->setText(net->networkName());
265     if(select) item->setSelected(true);
266   }
267 }
268
269 void NetworksSettingsPage::coreConnectionStateChanged(bool state) {
270   this->setEnabled(state);
271   if(state) {
272     load();
273   } else {
274     // reset
275     //currentId = 0;
276   }
277 }
278
279 void NetworksSettingsPage::clientIdentityAdded(IdentityId id) {
280   const Identity * identity = Client::identity(id);
281   connect(identity, SIGNAL(updatedRemotely()), this, SLOT(clientIdentityUpdated()));
282
283   if(id == 1) {
284     // default identity is always the first one!
285     ui.identityList->insertItem(0, identity->identityName(), id.toInt());
286   } else {
287     QString name = identity->identityName();
288     for(int j = 0; j < ui.identityList->count(); j++) {
289       if((j>0 || ui.identityList->itemData(0).toInt() != 1) && name.localeAwareCompare(ui.identityList->itemText(j)) < 0) {
290         ui.identityList->insertItem(j, name, id.toInt());
291         widgetHasChanged();
292         return;
293       }
294     }
295     // append
296     ui.identityList->insertItem(ui.identityList->count(), name, id.toInt());
297     widgetHasChanged();
298   }
299 }
300
301 void NetworksSettingsPage::clientIdentityUpdated() {
302   const Identity *identity = qobject_cast<const Identity *>(sender());
303   if(!identity) {
304     qWarning() << "NetworksSettingsPage: Invalid identity to update!";
305     return;
306   }
307   int row = ui.identityList->findData(identity->id().toInt());
308   if(row < 0) {
309     qWarning() << "NetworksSettingsPage: Invalid identity to update!";
310     return;
311   }
312   if(ui.identityList->itemText(row) != identity->identityName()) {
313     ui.identityList->setItemText(row, identity->identityName());
314   }
315 }
316
317 void NetworksSettingsPage::clientIdentityRemoved(IdentityId id) {
318   if(currentId != 0) saveToNetworkInfo(networkInfos[currentId]);
319   //ui.identityList->removeItem(ui.identityList->findData(id.toInt()));
320   foreach(NetworkInfo info, networkInfos.values()) {
321     //qDebug() << info.networkName << info.networkId << info.identity;
322     if(info.identity == id) {
323       if(info.networkId == currentId) ui.identityList->setCurrentIndex(0);
324       info.identity = 1; // set to default
325       networkInfos[info.networkId] = info;
326       if(info.networkId > 0) Client::updateNetwork(info);
327     }
328   }
329   ui.identityList->removeItem(ui.identityList->findData(id.toInt()));
330   widgetHasChanged();
331 }
332
333 QListWidgetItem *NetworksSettingsPage::networkItem(NetworkId id) const {
334   for(int i = 0; i < ui.networkList->count(); i++) {
335     QListWidgetItem *item = ui.networkList->item(i);
336     if(item->data(Qt::UserRole).value<NetworkId>() == id) return item;
337   }
338   return 0;
339 }
340
341 void NetworksSettingsPage::clientNetworkAdded(NetworkId id) {
342   insertNetwork(id);
343   //connect(Client::network(id), SIGNAL(updatedRemotely()), this, SLOT(clientNetworkUpdated()));
344   connect(Client::network(id), SIGNAL(identitySet(IdentityId)), this, SLOT(clientNetworkUpdated()));
345   connect(Client::network(id), SIGNAL(networkNameSet(const QString &)), this, SLOT(clientNetworkUpdated()));
346   connect(Client::network(id), SIGNAL(serverListSet(QVariantList)), this, SLOT(clientNetworkUpdated()));
347   connect(Client::network(id), SIGNAL(useRandomServerSet(bool)), this, SLOT(clientNetworkUpdated()));
348   connect(Client::network(id), SIGNAL(performSet(const QStringList &)), this, SLOT(clientNetworkUpdated()));
349   connect(Client::network(id), SIGNAL(useAutoIdentifySet(bool)), this, SLOT(clientNetworkUpdated()));
350   connect(Client::network(id), SIGNAL(autoIdentifyServiceSet(const QString &)), this, SLOT(clientNetworkUpdated()));
351   connect(Client::network(id), SIGNAL(autoIdentifyPasswordSet(const QString &)), this, SLOT(clientNetworkUpdated()));
352   connect(Client::network(id), SIGNAL(useAutoReconnectSet(bool)), this, SLOT(clientNetworkUpdated()));
353   connect(Client::network(id), SIGNAL(autoReconnectIntervalSet(quint32)), this, SLOT(clientNetworkUpdated()));
354   connect(Client::network(id), SIGNAL(autoReconnectRetriesSet(quint16)), this, SLOT(clientNetworkUpdated()));
355   connect(Client::network(id), SIGNAL(unlimitedReconnectRetriesSet(bool)), this, SLOT(clientNetworkUpdated()));
356   connect(Client::network(id), SIGNAL(rejoinChannelsSet(bool)), this, SLOT(clientNetworkUpdated()));
357   connect(Client::network(id), SIGNAL(codecForServerSet(const QByteArray &)), this, SLOT(clientNetworkUpdated()));
358   connect(Client::network(id), SIGNAL(codecForEncodingSet(const QByteArray &)), this, SLOT(clientNetworkUpdated()));
359   connect(Client::network(id), SIGNAL(codecForDecodingSet(const QByteArray &)), this, SLOT(clientNetworkUpdated()));
360
361   connect(Client::network(id), SIGNAL(connectionStateSet(Network::ConnectionState)), this, SLOT(networkConnectionStateChanged(Network::ConnectionState)));
362   connect(Client::network(id), SIGNAL(connectionError(const QString &)), this, SLOT(networkConnectionError(const QString &)));
363 }
364
365 void NetworksSettingsPage::clientNetworkUpdated() {
366   const Network *net = qobject_cast<const Network *>(sender());
367   if(!net) {
368     qWarning() << "Update request for unknown network received!";
369     return;
370   }
371   networkInfos[net->networkId()] = net->networkInfo();
372   setItemState(net->networkId());
373   if(net->networkId() == currentId) displayNetwork(net->networkId());
374   setWidgetStates();
375   widgetHasChanged();
376 }
377
378 void NetworksSettingsPage::clientNetworkRemoved(NetworkId id) {
379   if(!networkInfos.contains(id)) return;
380   if(id == currentId) displayNetwork(0);
381   NetworkInfo info = networkInfos.take(id);
382   QList<QListWidgetItem *> items = ui.networkList->findItems(info.networkName, Qt::MatchExactly);
383   foreach(QListWidgetItem *item, items) {
384     if(item->data(Qt::UserRole).value<NetworkId>() == id)
385       delete ui.networkList->takeItem(ui.networkList->row(item));
386   }
387   setWidgetStates();
388   widgetHasChanged();
389 }
390
391 void NetworksSettingsPage::networkConnectionStateChanged(Network::ConnectionState state) {
392   Q_UNUSED(state);
393   const Network *net = qobject_cast<const Network *>(sender());
394   if(!net) return;
395   /*
396   if(net->networkId() == currentId) {
397     ui.connectNow->setEnabled(state == Network::Initialized || state == Network::Disconnected);
398   }
399   */
400   setItemState(net->networkId());
401   setWidgetStates();
402 }
403
404 void NetworksSettingsPage::networkConnectionError(const QString &) {
405
406 }
407
408 QListWidgetItem *NetworksSettingsPage::insertNetwork(NetworkId id) {
409   NetworkInfo info = Client::network(id)->networkInfo();
410   networkInfos[id] = info;
411   return insertNetwork(info);
412 }
413
414 QListWidgetItem *NetworksSettingsPage::insertNetwork(const NetworkInfo &info) {
415   QListWidgetItem *item = 0;
416   QList<QListWidgetItem *> items = ui.networkList->findItems(info.networkName, Qt::MatchExactly);
417   if(!items.count()) item = new QListWidgetItem(disconnectedIcon, info.networkName, ui.networkList);
418   else {
419     // we overwrite an existing net if it a) has the same name and b) has a negative ID meaning we created it locally before
420     // -> then we can be sure that this is the core-side replacement for the net we created
421     foreach(QListWidgetItem *i, items) {
422       NetworkId id = i->data(Qt::UserRole).value<NetworkId>();
423       if(id < 0) { item = i; break; }
424     }
425     if(!item) item = new QListWidgetItem(disconnectedIcon, info.networkName, ui.networkList);
426   }
427   item->setData(Qt::UserRole, QVariant::fromValue<NetworkId>(info.networkId));
428   setItemState(info.networkId, item);
429   widgetHasChanged();
430   return item;
431 }
432
433 void NetworksSettingsPage::displayNetwork(NetworkId id) {
434   _ignoreWidgetChanges = true;
435   if(id != 0) {
436     NetworkInfo info = networkInfos[id];
437     ui.identityList->setCurrentIndex(ui.identityList->findData(info.identity.toInt()));
438     ui.serverList->clear();
439     foreach(Network::Server server, info.serverList) {
440       QListWidgetItem *item = new QListWidgetItem(QString("%1:%2").arg(server.host).arg(server.port));
441       if(server.useSsl)
442         item->setIcon(SmallIcon("document-encrypt"));
443       ui.serverList->addItem(item);
444     }
445     //setItemState(id);
446     //ui.randomServer->setChecked(info.useRandomServer);
447     ui.performEdit->setPlainText(info.perform.join("\n"));
448     ui.autoIdentify->setChecked(info.useAutoIdentify);
449     ui.autoIdentifyService->setText(info.autoIdentifyService);
450     ui.autoIdentifyPassword->setText(info.autoIdentifyPassword);
451     if(info.codecForEncoding.isEmpty()) {
452       ui.sendEncoding->setCurrentIndex(ui.sendEncoding->findText(Network::defaultCodecForEncoding()));
453       ui.recvEncoding->setCurrentIndex(ui.recvEncoding->findText(Network::defaultCodecForDecoding()));
454       ui.serverEncoding->setCurrentIndex(ui.serverEncoding->findText(Network::defaultCodecForServer()));
455       ui.useCustomEncodings->setChecked(false);
456     } else {
457       ui.sendEncoding->setCurrentIndex(ui.sendEncoding->findText(info.codecForEncoding));
458       ui.recvEncoding->setCurrentIndex(ui.recvEncoding->findText(info.codecForDecoding));
459       ui.serverEncoding->setCurrentIndex(ui.serverEncoding->findText(info.codecForServer));
460       ui.useCustomEncodings->setChecked(true);
461     }
462     ui.autoReconnect->setChecked(info.useAutoReconnect);
463     ui.reconnectInterval->setValue(info.autoReconnectInterval);
464     ui.reconnectRetries->setValue(info.autoReconnectRetries);
465     ui.unlimitedRetries->setChecked(info.unlimitedReconnectRetries);
466     ui.rejoinOnReconnect->setChecked(info.rejoinChannels);
467   } else {
468     // just clear widgets
469     ui.identityList->setCurrentIndex(-1);
470     ui.serverList->clear();
471     ui.performEdit->clear();
472     ui.autoIdentifyService->clear();
473     ui.autoIdentifyPassword->clear();
474     setWidgetStates();
475   }
476   _ignoreWidgetChanges = false;
477   currentId = id;
478 }
479
480 void NetworksSettingsPage::saveToNetworkInfo(NetworkInfo &info) {
481   info.identity = ui.identityList->itemData(ui.identityList->currentIndex()).toInt();
482   //info.useRandomServer = ui.randomServer->isChecked();
483   info.perform = ui.performEdit->toPlainText().split("\n");
484   info.useAutoIdentify = ui.autoIdentify->isChecked();
485   info.autoIdentifyService = ui.autoIdentifyService->text();
486   info.autoIdentifyPassword = ui.autoIdentifyPassword->text();
487   if(!ui.useCustomEncodings->isChecked()) {
488     info.codecForEncoding.clear();
489     info.codecForDecoding.clear();
490     info.codecForServer.clear();
491   } else {
492     info.codecForEncoding = ui.sendEncoding->currentText().toLatin1();
493     info.codecForDecoding = ui.recvEncoding->currentText().toLatin1();
494     info.codecForServer = ui.serverEncoding->currentText().toLatin1();
495   }
496   info.useAutoReconnect = ui.autoReconnect->isChecked();
497   info.autoReconnectInterval = ui.reconnectInterval->value();
498   info.autoReconnectRetries = ui.reconnectRetries->value();
499   info.unlimitedReconnectRetries = ui.unlimitedRetries->isChecked();
500   info.rejoinChannels = ui.rejoinOnReconnect->isChecked();
501 }
502 /*** Network list ***/
503
504 void NetworksSettingsPage::on_networkList_itemSelectionChanged() {
505   if(currentId != 0) {
506     saveToNetworkInfo(networkInfos[currentId]);
507   }
508   if(ui.networkList->selectedItems().count()) {
509     NetworkId id = ui.networkList->selectedItems()[0]->data(Qt::UserRole).value<NetworkId>();
510     currentId = id;
511     displayNetwork(id);
512     ui.serverList->setCurrentRow(0);
513   } else {
514     currentId = 0;
515   }
516   setWidgetStates();
517 }
518
519 void NetworksSettingsPage::on_addNetwork_clicked() {
520   QStringList existing;
521   for(int i = 0; i < ui.networkList->count(); i++) existing << ui.networkList->item(i)->text();
522   NetworkAddDlg dlg(existing, this);
523   if(dlg.exec() == QDialog::Accepted) {
524     NetworkId id;
525     for(id = 1; id <= networkInfos.count(); id++) {
526       widgetHasChanged();
527       if(!networkInfos.keys().contains(-id.toInt())) break;
528     }
529     id = -id.toInt();
530
531     NetworkInfo info = dlg.networkInfo();
532     if(info.networkName.isEmpty())
533       return;  // sanity check
534     info.networkId = id;
535     info.identity = 1;
536
537     // defaults
538     info.useRandomServer = false;
539     info.useAutoReconnect = true;
540     info.autoReconnectInterval = 60;
541     info.autoReconnectRetries = 20;
542     info.unlimitedReconnectRetries = false;
543     info.useAutoIdentify = false;
544     info.autoIdentifyService = "NickServ";
545     info.rejoinChannels = true;
546
547     networkInfos[id] = info;
548     QListWidgetItem *item = insertNetwork(info);
549     ui.networkList->setCurrentItem(item);
550     setWidgetStates();
551   }
552 }
553
554 void NetworksSettingsPage::on_deleteNetwork_clicked() {
555   if(ui.networkList->selectedItems().count()) {
556     NetworkId netid = ui.networkList->selectedItems()[0]->data(Qt::UserRole).value<NetworkId>();
557     int ret = QMessageBox::question(this, tr("Delete Network?"),
558                                     tr("Do you really want to delete the network \"%1\" and all related settings, including the backlog?").arg(networkInfos[netid].networkName),
559                                     QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
560     if(ret == QMessageBox::Yes) {
561       currentId = 0;
562       networkInfos.remove(netid);
563       delete ui.networkList->takeItem(ui.networkList->row(ui.networkList->selectedItems()[0]));
564       ui.networkList->setCurrentRow(qMin(ui.networkList->currentRow()+1, ui.networkList->count()-1));
565       setWidgetStates();
566       widgetHasChanged();
567     }
568   }
569 }
570
571 void NetworksSettingsPage::on_renameNetwork_clicked() {
572   if(!ui.networkList->selectedItems().count()) return;
573   QString old = ui.networkList->selectedItems()[0]->text();
574   QStringList existing;
575   for(int i = 0; i < ui.networkList->count(); i++) existing << ui.networkList->item(i)->text();
576   NetworkEditDlg dlg(old, existing, this);
577   if(dlg.exec() == QDialog::Accepted) {
578     ui.networkList->selectedItems()[0]->setText(dlg.networkName());
579     NetworkId netid = ui.networkList->selectedItems()[0]->data(Qt::UserRole).value<NetworkId>();
580     networkInfos[netid].networkName = dlg.networkName();
581     widgetHasChanged();
582   }
583 }
584
585 /*
586 void NetworksSettingsPage::on_connectNow_clicked() {
587   if(!ui.networkList->selectedItems().count()) return;
588   NetworkId id = ui.networkList->selectedItems()[0]->data(Qt::UserRole).value<NetworkId>();
589   const Network *net = Client::network(id);
590   if(!net) return;
591   if(net->connectionState() == Network::Disconnected) net->requestConnect();
592   else net->requestDisconnect();
593 }
594 */
595
596 /*** Server list ***/
597
598 void NetworksSettingsPage::on_serverList_itemSelectionChanged() {
599   setWidgetStates();
600 }
601
602 void NetworksSettingsPage::on_addServer_clicked() {
603   if(currentId == 0) return;
604   ServerEditDlg dlg(Network::Server(), this);
605   if(dlg.exec() == QDialog::Accepted) {
606     networkInfos[currentId].serverList.append(dlg.serverData());
607     displayNetwork(currentId);
608     ui.serverList->setCurrentRow(ui.serverList->count()-1);
609     widgetHasChanged();
610   }
611 }
612
613 void NetworksSettingsPage::on_editServer_clicked() {
614   if(currentId == 0) return;
615   int cur = ui.serverList->currentRow();
616   ServerEditDlg dlg(networkInfos[currentId].serverList[cur], this);
617   if(dlg.exec() == QDialog::Accepted) {
618     networkInfos[currentId].serverList[cur] = dlg.serverData();
619     displayNetwork(currentId);
620     ui.serverList->setCurrentRow(cur);
621     widgetHasChanged();
622   }
623 }
624
625 void NetworksSettingsPage::on_deleteServer_clicked() {
626   if(currentId == 0) return;
627   int cur = ui.serverList->currentRow();
628   networkInfos[currentId].serverList.removeAt(cur);
629   displayNetwork(currentId);
630   ui.serverList->setCurrentRow(qMin(cur, ui.serverList->count()-1));
631   widgetHasChanged();
632 }
633
634 void NetworksSettingsPage::on_upServer_clicked() {
635   int cur = ui.serverList->currentRow();
636   Network::Server server = networkInfos[currentId].serverList.takeAt(cur);
637   networkInfos[currentId].serverList.insert(cur-1, server);
638   displayNetwork(currentId);
639   ui.serverList->setCurrentRow(cur-1);
640   widgetHasChanged();
641 }
642
643 void NetworksSettingsPage::on_downServer_clicked() {
644   int cur = ui.serverList->currentRow();
645   Network::Server server = networkInfos[currentId].serverList.takeAt(cur);
646   networkInfos[currentId].serverList.insert(cur+1, server);
647   displayNetwork(currentId);
648   ui.serverList->setCurrentRow(cur+1);
649   widgetHasChanged();
650 }
651
652 void NetworksSettingsPage::on_editIdentities_clicked() {
653   SettingsPageDlg dlg(new IdentitiesSettingsPage(this), this);
654   dlg.exec();
655 }
656
657 /**************************************************************************
658 * NetworkAddDlg
659 *************************************************************************/
660
661 NetworkAddDlg::NetworkAddDlg(const QStringList &exist, QWidget *parent) : QDialog(parent), existing(exist) {
662   ui.setupUi(this);
663   ui.useSSL->setIcon(SmallIcon("document-encrypt"));
664
665   // read preset networks
666   networksFilePath = findDataFilePath("networks.ini");
667   if(!networksFilePath.isEmpty()) {
668     QSettings s(networksFilePath, QSettings::IniFormat);
669     QStringList networks = s.childGroups();
670     foreach(QString s, existing)
671       networks.removeAll(s);
672     if(!networks.isEmpty()) {
673       QMap<QString, QString> sorted;
674       foreach(QString net, networks)
675         sorted[net.toLower()] = net;
676       ui.presetList->addItems(sorted.values());
677     }
678   }
679   if(!ui.presetList->count()) {
680     ui.useManual->setChecked(true);
681     ui.usePreset->setEnabled(false);
682   }
683   connect(ui.networkName, SIGNAL(textChanged(const QString &)), SLOT(setButtonStates()));
684   connect(ui.serverAddress, SIGNAL(textChanged(const QString &)), SLOT(setButtonStates()));
685   setButtonStates();
686 }
687
688 NetworkInfo NetworkAddDlg::networkInfo() const {
689   NetworkInfo info;
690
691   if(ui.useManual->isChecked()) {
692     info.networkName = ui.networkName->text().trimmed();
693     info.serverList << Network::Server(ui.serverAddress->text().trimmed(), ui.port->value(), ui.serverPassword->text(), ui.useSSL->isChecked());
694   } else {
695     info.networkName = ui.presetList->currentText();
696     QSettings s(networksFilePath, QSettings::IniFormat);
697     s.beginGroup(info.networkName);
698     foreach(QString server, s.value("Servers").toStringList()) {
699       bool ssl = false;
700       QStringList splitserver = server.split(':', QString::SkipEmptyParts);
701       if(splitserver.count() != 2) {
702         qWarning() << "Invalid server entry in networks.conf:" << server;
703         continue;
704       }
705       if(splitserver[1].at(0) == '+')
706         ssl = true;
707       uint port = splitserver[1].toUInt();
708       if(!port) {
709         qWarning() << "Invalid port entry in networks.conf:" << server;
710         continue;
711       }
712       info.serverList << Network::Server(splitserver[0].trimmed(), port, QString(), ssl);
713     }
714   }
715
716   return info;
717 }
718
719 void NetworkAddDlg::setButtonStates() {
720   bool ok = false;
721   if(ui.usePreset->isChecked() && ui.presetList->count())
722     ok = true;
723   else if(ui.useManual->isChecked()) {
724     ok = !ui.networkName->text().trimmed().isEmpty() && !existing.contains(ui.networkName->text().trimmed())
725       && !ui.serverAddress->text().isEmpty();
726   }
727   ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ok);
728 }
729
730 /**************************************************************************
731  * NetworkEditDlg
732  *************************************************************************/
733
734 NetworkEditDlg::NetworkEditDlg(const QString &old, const QStringList &exist, QWidget *parent) : QDialog(parent), existing(exist) {
735   ui.setupUi(this);
736
737   if(old.isEmpty()) {
738     // new network
739     setWindowTitle(tr("Add Network"));
740     on_networkEdit_textChanged(""); // disable ok button
741   } else ui.networkEdit->setText(old);
742 }
743
744 QString NetworkEditDlg::networkName() const {
745   return ui.networkEdit->text().trimmed();
746
747 }
748
749 void NetworkEditDlg::on_networkEdit_textChanged(const QString &text) {
750   ui.buttonBox->button(QDialogButtonBox::Ok)->setDisabled(text.isEmpty() || existing.contains(text.trimmed()));
751 }
752
753 /**************************************************************************
754  * ServerEditDlg
755  *************************************************************************/
756 ServerEditDlg::ServerEditDlg(const Network::Server &server, QWidget *parent) : QDialog(parent) {
757   ui.setupUi(this);
758   ui.useSSL->setIcon(SmallIcon("document-encrypt"));
759   ui.host->setText(server.host);
760   ui.port->setValue(server.port);
761   ui.password->setText(server.password);
762   ui.useSSL->setChecked(server.useSsl);
763   ui.sslVersion->setCurrentIndex(server.sslVersion);
764   ui.useProxy->setChecked(server.useProxy);
765   ui.proxyType->setCurrentIndex(server.proxyType == QNetworkProxy::Socks5Proxy ? 0 : 1);
766   ui.proxyHost->setText(server.proxyHost);
767   ui.proxyPort->setValue(server.proxyPort);
768   ui.proxyUsername->setText(server.proxyUser);
769   ui.proxyPassword->setText(server.proxyPass);
770   on_host_textChanged();
771 }
772
773 Network::Server ServerEditDlg::serverData() const {
774   Network::Server server(ui.host->text().trimmed(), ui.port->value(), ui.password->text(), ui.useSSL->isChecked());
775   server.sslVersion = ui.sslVersion->currentIndex();
776   server.useProxy = ui.useProxy->isChecked();
777   server.proxyType = ui.proxyType->currentIndex() == 0 ? QNetworkProxy::Socks5Proxy : QNetworkProxy::HttpProxy;
778   server.proxyHost = ui.proxyHost->text();
779   server.proxyPort = ui.proxyPort->value();
780   server.proxyUser = ui.proxyUsername->text();
781   server.proxyPass = ui.proxyPassword->text();
782   return server;
783 }
784
785 void ServerEditDlg::on_host_textChanged() {
786   ui.buttonBox->button(QDialogButtonBox::Ok)->setDisabled(ui.host->text().trimmed().isEmpty());
787 }
788
789 /**************************************************************************
790  * SaveNetworksDlg
791  *************************************************************************/
792
793 SaveNetworksDlg::SaveNetworksDlg(const QList<NetworkInfo> &toCreate, const QList<NetworkInfo> &toUpdate, const QList<NetworkId> &toRemove, QWidget *parent) : QDialog(parent)
794 {
795   ui.setupUi(this);
796
797   numevents = toCreate.count() + toUpdate.count() + toRemove.count();
798   rcvevents = 0;
799   if(numevents) {
800     ui.progressBar->setMaximum(numevents);
801     ui.progressBar->setValue(0);
802
803     connect(Client::instance(), SIGNAL(networkCreated(NetworkId)), this, SLOT(clientEvent()));
804     connect(Client::instance(), SIGNAL(networkRemoved(NetworkId)), this, SLOT(clientEvent()));
805
806     foreach(NetworkId id, toRemove) {
807       Client::removeNetwork(id);
808     }
809     foreach(NetworkInfo info, toCreate) {
810       Client::createNetwork(info);
811     }
812     foreach(NetworkInfo info, toUpdate) {
813       const Network *net = Client::network(info.networkId);
814       if(!net) {
815         qWarning() << "Invalid client network!";
816         numevents--;
817         continue;
818       }
819       // FIXME this only checks for one changed item rather than all!
820       connect(net, SIGNAL(updatedRemotely()), this, SLOT(clientEvent()));
821       Client::updateNetwork(info);
822     }
823   } else {
824     qWarning() << "Sync dialog called without stuff to change!";
825     accept();
826   }
827 }
828
829 void SaveNetworksDlg::clientEvent() {
830   ui.progressBar->setValue(++rcvevents);
831   if(rcvevents >= numevents) accept();
832 }