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