Move handling of networks.ini from NetworksSettingsPage in Network
[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     NetworkInfo info = dlg.networkInfo();
525     if(info.networkName.isEmpty())
526       return;  // sanity check
527
528     NetworkId id;
529     for(id = 1; id <= networkInfos.count(); id++) {
530       widgetHasChanged();
531       if(!networkInfos.keys().contains(-id.toInt())) break;
532     }
533     id = -id.toInt();
534     info.networkId = id;
535     networkInfos[id] = info;
536     QListWidgetItem *item = insertNetwork(info);
537     ui.networkList->setCurrentItem(item);
538     setWidgetStates();
539   }
540 }
541
542 void NetworksSettingsPage::on_deleteNetwork_clicked() {
543   if(ui.networkList->selectedItems().count()) {
544     NetworkId netid = ui.networkList->selectedItems()[0]->data(Qt::UserRole).value<NetworkId>();
545     int ret = QMessageBox::question(this, tr("Delete Network?"),
546                                     tr("Do you really want to delete the network \"%1\" and all related settings, including the backlog?").arg(networkInfos[netid].networkName),
547                                     QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
548     if(ret == QMessageBox::Yes) {
549       currentId = 0;
550       networkInfos.remove(netid);
551       delete ui.networkList->takeItem(ui.networkList->row(ui.networkList->selectedItems()[0]));
552       ui.networkList->setCurrentRow(qMin(ui.networkList->currentRow()+1, ui.networkList->count()-1));
553       setWidgetStates();
554       widgetHasChanged();
555     }
556   }
557 }
558
559 void NetworksSettingsPage::on_renameNetwork_clicked() {
560   if(!ui.networkList->selectedItems().count()) return;
561   QString old = ui.networkList->selectedItems()[0]->text();
562   QStringList existing;
563   for(int i = 0; i < ui.networkList->count(); i++) existing << ui.networkList->item(i)->text();
564   NetworkEditDlg dlg(old, existing, this);
565   if(dlg.exec() == QDialog::Accepted) {
566     ui.networkList->selectedItems()[0]->setText(dlg.networkName());
567     NetworkId netid = ui.networkList->selectedItems()[0]->data(Qt::UserRole).value<NetworkId>();
568     networkInfos[netid].networkName = dlg.networkName();
569     widgetHasChanged();
570   }
571 }
572
573 /*
574 void NetworksSettingsPage::on_connectNow_clicked() {
575   if(!ui.networkList->selectedItems().count()) return;
576   NetworkId id = ui.networkList->selectedItems()[0]->data(Qt::UserRole).value<NetworkId>();
577   const Network *net = Client::network(id);
578   if(!net) return;
579   if(net->connectionState() == Network::Disconnected) net->requestConnect();
580   else net->requestDisconnect();
581 }
582 */
583
584 /*** Server list ***/
585
586 void NetworksSettingsPage::on_serverList_itemSelectionChanged() {
587   setWidgetStates();
588 }
589
590 void NetworksSettingsPage::on_addServer_clicked() {
591   if(currentId == 0) return;
592   ServerEditDlg dlg(Network::Server(), this);
593   if(dlg.exec() == QDialog::Accepted) {
594     networkInfos[currentId].serverList.append(dlg.serverData());
595     displayNetwork(currentId);
596     ui.serverList->setCurrentRow(ui.serverList->count()-1);
597     widgetHasChanged();
598   }
599 }
600
601 void NetworksSettingsPage::on_editServer_clicked() {
602   if(currentId == 0) return;
603   int cur = ui.serverList->currentRow();
604   ServerEditDlg dlg(networkInfos[currentId].serverList[cur], this);
605   if(dlg.exec() == QDialog::Accepted) {
606     networkInfos[currentId].serverList[cur] = dlg.serverData();
607     displayNetwork(currentId);
608     ui.serverList->setCurrentRow(cur);
609     widgetHasChanged();
610   }
611 }
612
613 void NetworksSettingsPage::on_deleteServer_clicked() {
614   if(currentId == 0) return;
615   int cur = ui.serverList->currentRow();
616   networkInfos[currentId].serverList.removeAt(cur);
617   displayNetwork(currentId);
618   ui.serverList->setCurrentRow(qMin(cur, ui.serverList->count()-1));
619   widgetHasChanged();
620 }
621
622 void NetworksSettingsPage::on_upServer_clicked() {
623   int cur = ui.serverList->currentRow();
624   Network::Server server = networkInfos[currentId].serverList.takeAt(cur);
625   networkInfos[currentId].serverList.insert(cur-1, server);
626   displayNetwork(currentId);
627   ui.serverList->setCurrentRow(cur-1);
628   widgetHasChanged();
629 }
630
631 void NetworksSettingsPage::on_downServer_clicked() {
632   int cur = ui.serverList->currentRow();
633   Network::Server server = networkInfos[currentId].serverList.takeAt(cur);
634   networkInfos[currentId].serverList.insert(cur+1, server);
635   displayNetwork(currentId);
636   ui.serverList->setCurrentRow(cur+1);
637   widgetHasChanged();
638 }
639
640 void NetworksSettingsPage::on_editIdentities_clicked() {
641   SettingsPageDlg dlg(new IdentitiesSettingsPage(this), this);
642   dlg.exec();
643 }
644
645 /**************************************************************************
646 * NetworkAddDlg
647 *************************************************************************/
648
649 NetworkAddDlg::NetworkAddDlg(const QStringList &exist, QWidget *parent) : QDialog(parent), existing(exist) {
650   ui.setupUi(this);
651   ui.useSSL->setIcon(SmallIcon("document-encrypt"));
652
653   // read preset networks
654   QStringList networks = Network::presetNetworks();
655   foreach(QString s, existing)
656     networks.removeAll(s);
657   if(networks.count())
658     ui.presetList->addItems(networks);
659   else {
660     ui.useManual->setChecked(true);
661     ui.usePreset->setEnabled(false);
662   }
663   connect(ui.networkName, SIGNAL(textChanged(const QString &)), SLOT(setButtonStates()));
664   connect(ui.serverAddress, SIGNAL(textChanged(const QString &)), SLOT(setButtonStates()));
665   setButtonStates();
666 }
667
668 NetworkInfo NetworkAddDlg::networkInfo() const {
669   if(ui.useManual->isChecked()) {
670     NetworkInfo info;
671     info.networkName = ui.networkName->text().trimmed();
672     info.serverList << Network::Server(ui.serverAddress->text().trimmed(), ui.port->value(), ui.serverPassword->text(), ui.useSSL->isChecked());
673     return info;
674   } else
675     return Network::networkInfoFromPreset(ui.presetList->currentText());
676 }
677
678 void NetworkAddDlg::setButtonStates() {
679   bool ok = false;
680   if(ui.usePreset->isChecked() && ui.presetList->count())
681     ok = true;
682   else if(ui.useManual->isChecked()) {
683     ok = !ui.networkName->text().trimmed().isEmpty() && !existing.contains(ui.networkName->text().trimmed())
684       && !ui.serverAddress->text().isEmpty();
685   }
686   ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ok);
687 }
688
689 /**************************************************************************
690  * NetworkEditDlg
691  *************************************************************************/
692
693 NetworkEditDlg::NetworkEditDlg(const QString &old, const QStringList &exist, QWidget *parent) : QDialog(parent), existing(exist) {
694   ui.setupUi(this);
695
696   if(old.isEmpty()) {
697     // new network
698     setWindowTitle(tr("Add Network"));
699     on_networkEdit_textChanged(""); // disable ok button
700   } else ui.networkEdit->setText(old);
701 }
702
703 QString NetworkEditDlg::networkName() const {
704   return ui.networkEdit->text().trimmed();
705
706 }
707
708 void NetworkEditDlg::on_networkEdit_textChanged(const QString &text) {
709   ui.buttonBox->button(QDialogButtonBox::Ok)->setDisabled(text.isEmpty() || existing.contains(text.trimmed()));
710 }
711
712 /**************************************************************************
713  * ServerEditDlg
714  *************************************************************************/
715 ServerEditDlg::ServerEditDlg(const Network::Server &server, QWidget *parent) : QDialog(parent) {
716   ui.setupUi(this);
717   ui.useSSL->setIcon(SmallIcon("document-encrypt"));
718   ui.host->setText(server.host);
719   ui.port->setValue(server.port);
720   ui.password->setText(server.password);
721   ui.useSSL->setChecked(server.useSsl);
722   ui.sslVersion->setCurrentIndex(server.sslVersion);
723   ui.useProxy->setChecked(server.useProxy);
724   ui.proxyType->setCurrentIndex(server.proxyType == QNetworkProxy::Socks5Proxy ? 0 : 1);
725   ui.proxyHost->setText(server.proxyHost);
726   ui.proxyPort->setValue(server.proxyPort);
727   ui.proxyUsername->setText(server.proxyUser);
728   ui.proxyPassword->setText(server.proxyPass);
729   on_host_textChanged();
730 }
731
732 Network::Server ServerEditDlg::serverData() const {
733   Network::Server server(ui.host->text().trimmed(), ui.port->value(), ui.password->text(), ui.useSSL->isChecked());
734   server.sslVersion = ui.sslVersion->currentIndex();
735   server.useProxy = ui.useProxy->isChecked();
736   server.proxyType = ui.proxyType->currentIndex() == 0 ? QNetworkProxy::Socks5Proxy : QNetworkProxy::HttpProxy;
737   server.proxyHost = ui.proxyHost->text();
738   server.proxyPort = ui.proxyPort->value();
739   server.proxyUser = ui.proxyUsername->text();
740   server.proxyPass = ui.proxyPassword->text();
741   return server;
742 }
743
744 void ServerEditDlg::on_host_textChanged() {
745   ui.buttonBox->button(QDialogButtonBox::Ok)->setDisabled(ui.host->text().trimmed().isEmpty());
746 }
747
748 /**************************************************************************
749  * SaveNetworksDlg
750  *************************************************************************/
751
752 SaveNetworksDlg::SaveNetworksDlg(const QList<NetworkInfo> &toCreate, const QList<NetworkInfo> &toUpdate, const QList<NetworkId> &toRemove, QWidget *parent) : QDialog(parent)
753 {
754   ui.setupUi(this);
755
756   numevents = toCreate.count() + toUpdate.count() + toRemove.count();
757   rcvevents = 0;
758   if(numevents) {
759     ui.progressBar->setMaximum(numevents);
760     ui.progressBar->setValue(0);
761
762     connect(Client::instance(), SIGNAL(networkCreated(NetworkId)), this, SLOT(clientEvent()));
763     connect(Client::instance(), SIGNAL(networkRemoved(NetworkId)), this, SLOT(clientEvent()));
764
765     foreach(NetworkId id, toRemove) {
766       Client::removeNetwork(id);
767     }
768     foreach(NetworkInfo info, toCreate) {
769       Client::createNetwork(info);
770     }
771     foreach(NetworkInfo info, toUpdate) {
772       const Network *net = Client::network(info.networkId);
773       if(!net) {
774         qWarning() << "Invalid client network!";
775         numevents--;
776         continue;
777       }
778       // FIXME this only checks for one changed item rather than all!
779       connect(net, SIGNAL(updatedRemotely()), this, SLOT(clientEvent()));
780       Client::updateNetwork(info);
781     }
782   } else {
783     qWarning() << "Sync dialog called without stuff to change!";
784     accept();
785   }
786 }
787
788 void SaveNetworksDlg::clientEvent() {
789   ui.progressBar->setValue(++rcvevents);
790   if(rcvevents >= numevents) accept();
791 }