1 /***************************************************************************
2 * Copyright (C) 2005-2016 by the Quassel Project *
3 * devel@quassel-irc.org *
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. *
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. *
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 ***************************************************************************/
21 #include <QHeaderView>
23 #include <QMessageBox>
26 #include "networkssettingspage.h"
31 #include "presetnetworks.h"
32 #include "settingspagedlg.h"
38 #include "settingspages/identitiessettingspage.h"
40 NetworksSettingsPage::NetworksSettingsPage(QWidget *parent)
41 : SettingsPage(tr("IRC"), tr("Networks"), parent)
48 // hide SASL options for older cores
49 if (!(Client::coreFeatures() & Quassel::SaslAuthentication))
51 if (!(Client::coreFeatures() & Quassel::SaslExternal))
52 ui.saslExtInfo->hide();
54 ui.saslExtInfo->hide();
58 ui.renameNetwork->setIcon(QIcon::fromTheme("edit-rename"));
59 ui.addNetwork->setIcon(QIcon::fromTheme("list-add"));
60 ui.deleteNetwork->setIcon(QIcon::fromTheme("edit-delete"));
61 ui.addServer->setIcon(QIcon::fromTheme("list-add"));
62 ui.deleteServer->setIcon(QIcon::fromTheme("edit-delete"));
63 ui.editServer->setIcon(QIcon::fromTheme("configure"));
64 ui.upServer->setIcon(QIcon::fromTheme("go-up"));
65 ui.downServer->setIcon(QIcon::fromTheme("go-down"));
66 ui.editIdentities->setIcon(QIcon::fromTheme("configure"));
68 _ignoreWidgetChanges = false;
70 connectedIcon = QIcon::fromTheme("network-connect");
71 connectingIcon = QIcon::fromTheme("network-wired"); // FIXME network-connecting
72 disconnectedIcon = QIcon::fromTheme("network-disconnect");
74 foreach(int mib, QTextCodec::availableMibs()) {
75 QByteArray codec = QTextCodec::codecForMib(mib)->name();
76 ui.sendEncoding->addItem(codec);
77 ui.recvEncoding->addItem(codec);
78 ui.serverEncoding->addItem(codec);
80 ui.sendEncoding->model()->sort(0);
81 ui.recvEncoding->model()->sort(0);
82 ui.serverEncoding->model()->sort(0);
84 setEnabled(Client::isConnected()); // need a core connection!
86 connect(Client::instance(), SIGNAL(coreConnectionStateChanged(bool)), this, SLOT(coreConnectionStateChanged(bool)));
87 connect(Client::instance(), SIGNAL(networkCreated(NetworkId)), this, SLOT(clientNetworkAdded(NetworkId)));
88 connect(Client::instance(), SIGNAL(networkRemoved(NetworkId)), this, SLOT(clientNetworkRemoved(NetworkId)));
89 connect(Client::instance(), SIGNAL(identityCreated(IdentityId)), this, SLOT(clientIdentityAdded(IdentityId)));
90 connect(Client::instance(), SIGNAL(identityRemoved(IdentityId)), this, SLOT(clientIdentityRemoved(IdentityId)));
92 connect(ui.identityList, SIGNAL(currentIndexChanged(int)), this, SLOT(widgetHasChanged()));
93 //connect(ui.randomServer, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
94 connect(ui.performEdit, SIGNAL(textChanged()), 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.autoIdentify, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
99 connect(ui.autoIdentifyService, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
100 connect(ui.autoIdentifyPassword, SIGNAL(textEdited(const QString &)), this, SLOT(widgetHasChanged()));
101 connect(ui.useCustomEncodings, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
102 connect(ui.sendEncoding, SIGNAL(currentIndexChanged(int)), this, SLOT(widgetHasChanged()));
103 connect(ui.recvEncoding, SIGNAL(currentIndexChanged(int)), this, SLOT(widgetHasChanged()));
104 connect(ui.serverEncoding, SIGNAL(currentIndexChanged(int)), this, SLOT(widgetHasChanged()));
105 connect(ui.autoReconnect, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
106 connect(ui.reconnectInterval, SIGNAL(valueChanged(int)), this, SLOT(widgetHasChanged()));
107 connect(ui.reconnectRetries, SIGNAL(valueChanged(int)), this, SLOT(widgetHasChanged()));
108 connect(ui.unlimitedRetries, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
109 connect(ui.rejoinOnReconnect, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
111 // Core features can change during a reconnect. Always connect these here, delaying testing for
112 // the core feature flag in load().
113 connect(ui.useCustomMessageRate, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
114 connect(ui.messageRateBurstSize, SIGNAL(valueChanged(int)), this, SLOT(widgetHasChanged()));
115 connect(ui.messageRateDelay, SIGNAL(valueChanged(double)), this, SLOT(widgetHasChanged()));
116 connect(ui.unlimitedMessageRate, SIGNAL(clicked(bool)), this, SLOT(widgetHasChanged()));
118 // Add additional widgets here
119 //connect(ui., SIGNAL(), this, SLOT(widgetHasChanged()));
120 //connect(ui., SIGNAL(), this, SLOT(widgetHasChanged()));
122 foreach(IdentityId id, Client::identityIds()) {
123 clientIdentityAdded(id);
128 void NetworksSettingsPage::save()
131 if (currentId != 0) saveToNetworkInfo(networkInfos[currentId]);
133 QList<NetworkInfo> toCreate, toUpdate;
134 QList<NetworkId> toRemove;
135 QHash<NetworkId, NetworkInfo>::iterator i = networkInfos.begin();
136 while (i != networkInfos.end()) {
137 NetworkId id = (*i).networkId;
140 //if(id == currentId) currentId = 0;
141 //QList<QListWidgetItem *> items = ui.networkList->findItems((*i).networkName, Qt::MatchExactly);
142 //if(items.count()) {
143 // Q_ASSERT(items[0]->data(Qt::UserRole).value<NetworkId>() == id);
146 //i = networkInfos.erase(i);
150 if ((*i) != Client::network((*i).networkId)->networkInfo()) {
156 foreach(NetworkId id, Client::networkIds()) {
157 if (!networkInfos.contains(id)) toRemove.append(id);
159 SaveNetworksDlg dlg(toCreate, toUpdate, toRemove, this);
160 int ret = dlg.exec();
161 if (ret == QDialog::Rejected) {
162 // canceled -> reload everything to be safe
165 setChangedState(false);
170 void NetworksSettingsPage::load()
174 // Handle UI dependent on core feature flags here
175 if (Client::coreFeatures() & Quassel::CustomRateLimits) {
176 // Custom rate limiting supported, allow toggling
177 ui.useCustomMessageRate->setEnabled(true);
178 // Reset tooltip to default.
179 ui.useCustomMessageRate->setToolTip(QString("%1").arg(
180 tr("<p>Override default message rate limiting.</p>"
181 "<p><b>Setting limits too low may get you disconnected"
182 " from the server!</b></p>")));
183 // If changed, update the message below!
185 // Custom rate limiting not supported, disallow toggling
186 ui.useCustomMessageRate->setEnabled(false);
187 // Split up the message to allow re-using translations:
188 // [Original tool-tip]
189 // [Bold 'does not support feature' message]
190 // [Specific version needed and feature details]
191 ui.useCustomMessageRate->setToolTip(QString("%1<br/><b>%2</b><br/>%3").arg(
192 tr("<p>Override default message rate limiting.</p>"
193 "<p><b>Setting limits too low may get you disconnected"
194 " from the server!</b></p>"),
195 tr("Your Quassel core does not support this feature"),
196 tr("You need a Quassel core v0.13.0 or newer in order to "
197 "modify message rate limits.")));
201 // Hide the SASL EXTERNAL notice until a network's shown. Stops it from showing while loading
202 // backlog from the core.
206 foreach(NetworkId netid, Client::networkIds()) {
207 clientNetworkAdded(netid);
209 ui.networkList->setCurrentRow(0);
211 setChangedState(false);
215 void NetworksSettingsPage::reset()
218 ui.networkList->clear();
219 networkInfos.clear();
223 bool NetworksSettingsPage::aboutToSave()
225 if (currentId != 0) saveToNetworkInfo(networkInfos[currentId]);
227 foreach(NetworkInfo info, networkInfos.values()) {
228 if (!info.serverList.count()) errors.append(1);
230 if (!errors.count()) return true;
231 QString error(tr("<b>The following problems need to be corrected before your changes can be applied:</b><ul>"));
232 if (errors.contains(1)) error += tr("<li>All networks need at least one server defined</li>");
233 error += tr("</ul>");
234 QMessageBox::warning(this, tr("Invalid Network Settings"), error);
239 void NetworksSettingsPage::widgetHasChanged()
241 if (_ignoreWidgetChanges) return;
242 bool changed = testHasChanged();
243 if (changed != hasChanged()) setChangedState(changed);
247 bool NetworksSettingsPage::testHasChanged()
249 if (currentId != 0) {
250 saveToNetworkInfo(networkInfos[currentId]);
252 if (Client::networkIds().count() != networkInfos.count()) return true;
253 foreach(NetworkId id, networkInfos.keys()) {
254 if (id < 0) return true;
255 if (Client::network(id)->networkInfo() != networkInfos[id]) return true;
261 void NetworksSettingsPage::setWidgetStates()
264 if (ui.networkList->selectedItems().count()) {
265 ui.detailsBox->setEnabled(true);
266 ui.renameNetwork->setEnabled(true);
267 ui.deleteNetwork->setEnabled(true);
269 /* button disabled for now
270 NetworkId id = ui.networkList->selectedItems()[0]->data(Qt::UserRole).value<NetworkId>();
271 const Network *net = id > 0 ? Client::network(id) : 0;
272 ui.connectNow->setEnabled(net);
273 // && (Client::network(id)->connectionState() == Network::Initialized
274 // || Client::network(id)->connectionState() == Network::Disconnected));
276 if(net->connectionState() == Network::Disconnected) {
277 ui.connectNow->setIcon(connectedIcon);
278 ui.connectNow->setText(tr("Connect"));
280 ui.connectNow->setIcon(disconnectedIcon);
281 ui.connectNow->setText(tr("Disconnect"));
284 ui.connectNow->setIcon(QIcon());
285 ui.connectNow->setText(tr("Apply first!"));
289 ui.renameNetwork->setEnabled(false);
290 ui.deleteNetwork->setEnabled(false);
291 //ui.connectNow->setEnabled(false);
292 ui.detailsBox->setEnabled(false);
295 if (ui.serverList->selectedItems().count()) {
296 ui.editServer->setEnabled(true);
297 ui.deleteServer->setEnabled(true);
298 ui.upServer->setEnabled(ui.serverList->currentRow() > 0);
299 ui.downServer->setEnabled(ui.serverList->currentRow() < ui.serverList->count() - 1);
302 ui.editServer->setEnabled(false);
303 ui.deleteServer->setEnabled(false);
304 ui.upServer->setEnabled(false);
305 ui.downServer->setEnabled(false);
310 void NetworksSettingsPage::setItemState(NetworkId id, QListWidgetItem *item)
312 if (!item && !(item = networkItem(id))) return;
313 const Network *net = Client::network(id);
314 if (!net || net->isInitialized()) item->setFlags(item->flags() | Qt::ItemIsEnabled);
315 else item->setFlags(item->flags() & ~Qt::ItemIsEnabled);
316 if (net && net->connectionState() == Network::Initialized) {
317 item->setIcon(connectedIcon);
319 else if (net && net->connectionState() != Network::Disconnected) {
320 item->setIcon(connectingIcon);
323 item->setIcon(disconnectedIcon);
327 // check if we already have another net of this name in the list, and replace it
328 QList<QListWidgetItem *> items = ui.networkList->findItems(net->networkName(), Qt::MatchExactly);
330 foreach(QListWidgetItem *i, items) {
331 NetworkId oldid = i->data(Qt::UserRole).value<NetworkId>();
332 if (oldid > 0) continue; // only locally created nets should be replaced
333 if (oldid == currentId) {
336 ui.networkList->clearSelection();
338 int row = ui.networkList->row(i);
340 QListWidgetItem *olditem = ui.networkList->takeItem(row);
344 networkInfos.remove(oldid);
348 item->setText(net->networkName());
349 if (select) item->setSelected(true);
354 void NetworksSettingsPage::setNetworkCapStates(NetworkId id)
356 const Network *net = Client::network(id);
357 if ((Client::coreFeatures() & Quassel::CapNegotiation)
358 && net && net->connectionState() != Network::Disconnected) {
359 // If Capability Negotiation isn't supported by the core, no capabilities are active.
360 // If we're here, the network exists and is connected, check available capabilities...
361 // Don't use net->isConnected() as that won't be true during capability negotiation when
362 // capabilities are added and removed.
365 if (net->saslMaybeSupports(IrcCap::SaslMech::PLAIN)) {
366 // The network advertises support for SASL PLAIN. Encourage using it! Unfortunately we
367 // don't know for sure if it's desired or functional.
368 ui.sasl->setTitle(QString("%1 (%2)").arg(tr("Use SASL Authentication"),
371 // The network doesn't advertise support for SASL PLAIN. Here be dragons.
372 ui.sasl->setTitle(QString("%1 (%2)").arg(tr("Use SASL Authentication"),
373 tr("might not work")));
375 // Split up the messages to ease translation and re-use existing "Use SASL Authentication"
376 // translations. If some languages rearrange phrases such that this would not make sense,
377 // these strings can be merged into one.
379 // Add additional capability-dependent interface updates here
381 // We're not connected or the network doesn't yet exist. Don't assume anything and reset
382 // all capability-dependent interface elements to neutral.
384 ui.sasl->setTitle(tr("Use SASL Authentication"));
386 // Add additional capability-dependent interface updates here
391 void NetworksSettingsPage::coreConnectionStateChanged(bool state)
393 this->setEnabled(state);
404 void NetworksSettingsPage::clientIdentityAdded(IdentityId id)
406 const Identity *identity = Client::identity(id);
407 connect(identity, SIGNAL(updatedRemotely()), this, SLOT(clientIdentityUpdated()));
409 QString name = identity->identityName();
410 for (int j = 0; j < ui.identityList->count(); j++) {
411 if ((j > 0 || ui.identityList->itemData(0).toInt() != 1) && name.localeAwareCompare(ui.identityList->itemText(j)) < 0) {
412 ui.identityList->insertItem(j, name, id.toInt());
418 ui.identityList->insertItem(ui.identityList->count(), name, id.toInt());
423 void NetworksSettingsPage::clientIdentityUpdated()
425 const Identity *identity = qobject_cast<const Identity *>(sender());
427 qWarning() << "NetworksSettingsPage: Invalid identity to update!";
430 int row = ui.identityList->findData(identity->id().toInt());
432 qWarning() << "NetworksSettingsPage: Invalid identity to update!";
435 if (ui.identityList->itemText(row) != identity->identityName()) {
436 ui.identityList->setItemText(row, identity->identityName());
441 void NetworksSettingsPage::clientIdentityRemoved(IdentityId id)
443 IdentityId defaultId = defaultIdentity();
444 if (currentId != 0) saveToNetworkInfo(networkInfos[currentId]);
445 foreach(NetworkInfo info, networkInfos.values()) {
446 if (info.identity == id) {
447 if (info.networkId == currentId)
448 ui.identityList->setCurrentIndex(0);
449 info.identity = defaultId;
450 networkInfos[info.networkId] = info;
451 if (info.networkId > 0) Client::updateNetwork(info);
454 ui.identityList->removeItem(ui.identityList->findData(id.toInt()));
459 QListWidgetItem *NetworksSettingsPage::networkItem(NetworkId id) const
461 for (int i = 0; i < ui.networkList->count(); i++) {
462 QListWidgetItem *item = ui.networkList->item(i);
463 if (item->data(Qt::UserRole).value<NetworkId>() == id) return item;
469 void NetworksSettingsPage::clientNetworkAdded(NetworkId id)
472 //connect(Client::network(id), SIGNAL(updatedRemotely()), this, SLOT(clientNetworkUpdated()));
473 connect(Client::network(id), SIGNAL(configChanged()), this, SLOT(clientNetworkUpdated()));
475 connect(Client::network(id), SIGNAL(connectionStateSet(Network::ConnectionState)), this, SLOT(networkConnectionStateChanged(Network::ConnectionState)));
476 connect(Client::network(id), SIGNAL(connectionError(const QString &)), this, SLOT(networkConnectionError(const QString &)));
478 // Handle capability changes in case a server dis/connects with the settings window open.
479 connect(Client::network(id), SIGNAL(capAdded(const QString &)), this, SLOT(clientNetworkCapsUpdated()));
480 connect(Client::network(id), SIGNAL(capRemoved(const QString &)), this, SLOT(clientNetworkCapsUpdated()));
484 void NetworksSettingsPage::clientNetworkUpdated()
486 const Network *net = qobject_cast<const Network *>(sender());
488 qWarning() << "Update request for unknown network received!";
491 networkInfos[net->networkId()] = net->networkInfo();
492 setItemState(net->networkId());
493 if (net->networkId() == currentId) displayNetwork(net->networkId());
499 void NetworksSettingsPage::clientNetworkRemoved(NetworkId id)
501 if (!networkInfos.contains(id)) return;
502 if (id == currentId) displayNetwork(0);
503 NetworkInfo info = networkInfos.take(id);
504 QList<QListWidgetItem *> items = ui.networkList->findItems(info.networkName, Qt::MatchExactly);
505 foreach(QListWidgetItem *item, items) {
506 if (item->data(Qt::UserRole).value<NetworkId>() == id)
507 delete ui.networkList->takeItem(ui.networkList->row(item));
514 void NetworksSettingsPage::networkConnectionStateChanged(Network::ConnectionState state)
517 const Network *net = qobject_cast<const Network *>(sender());
520 if(net->networkId() == currentId) {
521 ui.connectNow->setEnabled(state == Network::Initialized || state == Network::Disconnected);
524 setItemState(net->networkId());
525 if (net->networkId() == currentId) {
526 // Network is currently shown. Update the capability-dependent UI in case capabilities have
528 setNetworkCapStates(currentId);
534 void NetworksSettingsPage::networkConnectionError(const QString &)
539 QListWidgetItem *NetworksSettingsPage::insertNetwork(NetworkId id)
541 NetworkInfo info = Client::network(id)->networkInfo();
542 networkInfos[id] = info;
543 return insertNetwork(info);
547 QListWidgetItem *NetworksSettingsPage::insertNetwork(const NetworkInfo &info)
549 QListWidgetItem *item = 0;
550 QList<QListWidgetItem *> items = ui.networkList->findItems(info.networkName, Qt::MatchExactly);
551 if (!items.count()) item = new QListWidgetItem(disconnectedIcon, info.networkName, ui.networkList);
553 // we overwrite an existing net if it a) has the same name and b) has a negative ID meaning we created it locally before
554 // -> then we can be sure that this is the core-side replacement for the net we created
555 foreach(QListWidgetItem *i, items) {
556 NetworkId id = i->data(Qt::UserRole).value<NetworkId>();
557 if (id < 0) { item = i; break; }
559 if (!item) item = new QListWidgetItem(disconnectedIcon, info.networkName, ui.networkList);
561 item->setData(Qt::UserRole, QVariant::fromValue<NetworkId>(info.networkId));
562 setItemState(info.networkId, item);
568 void NetworksSettingsPage::displayNetwork(NetworkId id)
570 _ignoreWidgetChanges = true;
572 NetworkInfo info = networkInfos[id];
575 // this is only needed when the core supports SASL EXTERNAL
576 if (Client::coreFeatures() & Quassel::SaslExternal) {
578 disconnect(_cid, SIGNAL(sslSettingsUpdated()), this, SLOT(sslUpdated()));
581 _cid = new CertIdentity(*Client::identity(info.identity), this);
582 _cid->enableEditSsl(true);
583 connect(_cid, SIGNAL(sslSettingsUpdated()), this, SLOT(sslUpdated()));
587 ui.identityList->setCurrentIndex(ui.identityList->findData(info.identity.toInt()));
588 ui.serverList->clear();
589 foreach(Network::Server server, info.serverList) {
590 QListWidgetItem *item = new QListWidgetItem(QString("%1:%2").arg(server.host).arg(server.port));
592 item->setIcon(QIcon::fromTheme("document-encrypt"));
593 ui.serverList->addItem(item);
596 //ui.randomServer->setChecked(info.useRandomServer);
597 // Update the capability-dependent UI in case capabilities have changed.
598 setNetworkCapStates(id);
599 ui.performEdit->setPlainText(info.perform.join("\n"));
600 ui.autoIdentify->setChecked(info.useAutoIdentify);
601 ui.autoIdentifyService->setText(info.autoIdentifyService);
602 ui.autoIdentifyPassword->setText(info.autoIdentifyPassword);
603 ui.sasl->setChecked(info.useSasl);
604 ui.saslAccount->setText(info.saslAccount);
605 ui.saslPassword->setText(info.saslPassword);
606 if (info.codecForEncoding.isEmpty()) {
607 ui.sendEncoding->setCurrentIndex(ui.sendEncoding->findText(Network::defaultCodecForEncoding()));
608 ui.recvEncoding->setCurrentIndex(ui.recvEncoding->findText(Network::defaultCodecForDecoding()));
609 ui.serverEncoding->setCurrentIndex(ui.serverEncoding->findText(Network::defaultCodecForServer()));
610 ui.useCustomEncodings->setChecked(false);
613 ui.sendEncoding->setCurrentIndex(ui.sendEncoding->findText(info.codecForEncoding));
614 ui.recvEncoding->setCurrentIndex(ui.recvEncoding->findText(info.codecForDecoding));
615 ui.serverEncoding->setCurrentIndex(ui.serverEncoding->findText(info.codecForServer));
616 ui.useCustomEncodings->setChecked(true);
618 ui.autoReconnect->setChecked(info.useAutoReconnect);
619 ui.reconnectInterval->setValue(info.autoReconnectInterval);
620 ui.reconnectRetries->setValue(info.autoReconnectRetries);
621 ui.unlimitedRetries->setChecked(info.unlimitedReconnectRetries);
622 ui.rejoinOnReconnect->setChecked(info.rejoinChannels);
623 // Custom rate limiting
624 ui.unlimitedMessageRate->setChecked(info.unlimitedMessageRate);
625 // Set 'ui.useCustomMessageRate' after 'ui.unlimitedMessageRate' so if the latter is
626 // disabled, 'ui.messageRateDelayFrame' will remain disabled.
627 ui.useCustomMessageRate->setChecked(info.useCustomMessageRate);
628 ui.messageRateBurstSize->setValue(info.messageRateBurstSize);
629 // Convert milliseconds (integer) into seconds (double)
630 ui.messageRateDelay->setValue(info.messageRateDelay / 1000.0f);
633 // just clear widgets
636 disconnect(_cid, SIGNAL(sslSettingsUpdated()), this, SLOT(sslUpdated()));
640 ui.identityList->setCurrentIndex(-1);
641 ui.serverList->clear();
642 ui.performEdit->clear();
643 ui.autoIdentifyService->clear();
644 ui.autoIdentifyPassword->clear();
645 ui.saslAccount->clear();
646 ui.saslPassword->clear();
649 _ignoreWidgetChanges = false;
654 void NetworksSettingsPage::saveToNetworkInfo(NetworkInfo &info)
656 info.identity = ui.identityList->itemData(ui.identityList->currentIndex()).toInt();
657 //info.useRandomServer = ui.randomServer->isChecked();
658 info.perform = ui.performEdit->toPlainText().split("\n");
659 info.useAutoIdentify = ui.autoIdentify->isChecked();
660 info.autoIdentifyService = ui.autoIdentifyService->text();
661 info.autoIdentifyPassword = ui.autoIdentifyPassword->text();
662 info.useSasl = ui.sasl->isChecked();
663 info.saslAccount = ui.saslAccount->text();
664 info.saslPassword = ui.saslPassword->text();
665 if (!ui.useCustomEncodings->isChecked()) {
666 info.codecForEncoding.clear();
667 info.codecForDecoding.clear();
668 info.codecForServer.clear();
671 info.codecForEncoding = ui.sendEncoding->currentText().toLatin1();
672 info.codecForDecoding = ui.recvEncoding->currentText().toLatin1();
673 info.codecForServer = ui.serverEncoding->currentText().toLatin1();
675 info.useAutoReconnect = ui.autoReconnect->isChecked();
676 info.autoReconnectInterval = ui.reconnectInterval->value();
677 info.autoReconnectRetries = ui.reconnectRetries->value();
678 info.unlimitedReconnectRetries = ui.unlimitedRetries->isChecked();
679 info.rejoinChannels = ui.rejoinOnReconnect->isChecked();
680 // Custom rate limiting
681 info.useCustomMessageRate = ui.useCustomMessageRate->isChecked();
682 info.messageRateBurstSize = ui.messageRateBurstSize->value();
683 // Convert seconds (double) into milliseconds (integer)
684 info.messageRateDelay = static_cast<quint32>((ui.messageRateDelay->value() * 1000));
685 info.unlimitedMessageRate = ui.unlimitedMessageRate->isChecked();
689 void NetworksSettingsPage::clientNetworkCapsUpdated()
691 // Grab the updated network
692 const Network *net = qobject_cast<const Network *>(sender());
694 qWarning() << "Update request for unknown network received!";
697 if (net->networkId() == currentId) {
698 // Network is currently shown. Update the capability-dependent UI in case capabilities have
700 setNetworkCapStates(currentId);
706 void NetworksSettingsPage::sslUpdated()
708 if (_cid && !_cid->sslKey().isNull()) {
709 ui.saslAccount->setDisabled(true);
710 ui.saslAccountLabel->setDisabled(true);
711 ui.saslPassword->setDisabled(true);
712 ui.saslPasswordLabel->setDisabled(true);
713 ui.saslExtInfo->setHidden(false);
715 ui.saslAccount->setDisabled(false);
716 ui.saslAccountLabel->setDisabled(false);
717 ui.saslPassword->setDisabled(false);
718 ui.saslPasswordLabel->setDisabled(false);
719 ui.saslExtInfo->setHidden(true);
725 /*** Network list ***/
727 void NetworksSettingsPage::on_networkList_itemSelectionChanged()
729 if (currentId != 0) {
730 saveToNetworkInfo(networkInfos[currentId]);
732 if (ui.networkList->selectedItems().count()) {
733 NetworkId id = ui.networkList->selectedItems()[0]->data(Qt::UserRole).value<NetworkId>();
736 ui.serverList->setCurrentRow(0);
745 void NetworksSettingsPage::on_addNetwork_clicked()
747 QStringList existing;
748 for (int i = 0; i < ui.networkList->count(); i++) existing << ui.networkList->item(i)->text();
749 NetworkAddDlg dlg(existing, this);
750 if (dlg.exec() == QDialog::Accepted) {
751 NetworkInfo info = dlg.networkInfo();
752 if (info.networkName.isEmpty())
753 return; // sanity check
756 for (id = 1; id <= networkInfos.count(); id++) {
758 if (!networkInfos.keys().contains(-id.toInt())) break;
762 info.identity = defaultIdentity();
763 networkInfos[id] = info;
764 QListWidgetItem *item = insertNetwork(info);
765 ui.networkList->setCurrentItem(item);
771 void NetworksSettingsPage::on_deleteNetwork_clicked()
773 if (ui.networkList->selectedItems().count()) {
774 NetworkId netid = ui.networkList->selectedItems()[0]->data(Qt::UserRole).value<NetworkId>();
775 int ret = QMessageBox::question(this, tr("Delete Network?"),
776 tr("Do you really want to delete the network \"%1\" and all related settings, including the backlog?").arg(networkInfos[netid].networkName),
777 QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
778 if (ret == QMessageBox::Yes) {
780 networkInfos.remove(netid);
781 delete ui.networkList->takeItem(ui.networkList->row(ui.networkList->selectedItems()[0]));
782 ui.networkList->setCurrentRow(qMin(ui.networkList->currentRow()+1, ui.networkList->count()-1));
790 void NetworksSettingsPage::on_renameNetwork_clicked()
792 if (!ui.networkList->selectedItems().count()) return;
793 QString old = ui.networkList->selectedItems()[0]->text();
794 QStringList existing;
795 for (int i = 0; i < ui.networkList->count(); i++) existing << ui.networkList->item(i)->text();
796 NetworkEditDlg dlg(old, existing, this);
797 if (dlg.exec() == QDialog::Accepted) {
798 ui.networkList->selectedItems()[0]->setText(dlg.networkName());
799 NetworkId netid = ui.networkList->selectedItems()[0]->data(Qt::UserRole).value<NetworkId>();
800 networkInfos[netid].networkName = dlg.networkName();
807 void NetworksSettingsPage::on_connectNow_clicked() {
808 if(!ui.networkList->selectedItems().count()) return;
809 NetworkId id = ui.networkList->selectedItems()[0]->data(Qt::UserRole).value<NetworkId>();
810 const Network *net = Client::network(id);
812 if(net->connectionState() == Network::Disconnected) net->requestConnect();
813 else net->requestDisconnect();
817 /*** Server list ***/
819 void NetworksSettingsPage::on_serverList_itemSelectionChanged()
825 void NetworksSettingsPage::on_addServer_clicked()
827 if (currentId == 0) return;
828 ServerEditDlg dlg(Network::Server(), this);
829 if (dlg.exec() == QDialog::Accepted) {
830 networkInfos[currentId].serverList.append(dlg.serverData());
831 displayNetwork(currentId);
832 ui.serverList->setCurrentRow(ui.serverList->count()-1);
838 void NetworksSettingsPage::on_editServer_clicked()
840 if (currentId == 0) return;
841 int cur = ui.serverList->currentRow();
842 ServerEditDlg dlg(networkInfos[currentId].serverList[cur], this);
843 if (dlg.exec() == QDialog::Accepted) {
844 networkInfos[currentId].serverList[cur] = dlg.serverData();
845 displayNetwork(currentId);
846 ui.serverList->setCurrentRow(cur);
852 void NetworksSettingsPage::on_deleteServer_clicked()
854 if (currentId == 0) return;
855 int cur = ui.serverList->currentRow();
856 networkInfos[currentId].serverList.removeAt(cur);
857 displayNetwork(currentId);
858 ui.serverList->setCurrentRow(qMin(cur, ui.serverList->count()-1));
863 void NetworksSettingsPage::on_upServer_clicked()
865 int cur = ui.serverList->currentRow();
866 Network::Server server = networkInfos[currentId].serverList.takeAt(cur);
867 networkInfos[currentId].serverList.insert(cur-1, server);
868 displayNetwork(currentId);
869 ui.serverList->setCurrentRow(cur-1);
874 void NetworksSettingsPage::on_downServer_clicked()
876 int cur = ui.serverList->currentRow();
877 Network::Server server = networkInfos[currentId].serverList.takeAt(cur);
878 networkInfos[currentId].serverList.insert(cur+1, server);
879 displayNetwork(currentId);
880 ui.serverList->setCurrentRow(cur+1);
885 void NetworksSettingsPage::on_editIdentities_clicked()
887 SettingsPageDlg dlg(new IdentitiesSettingsPage(this), this);
892 IdentityId NetworksSettingsPage::defaultIdentity() const
894 IdentityId defaultId = 0;
895 QList<IdentityId> ids = Client::identityIds();
896 foreach(IdentityId id, ids) {
897 if (defaultId == 0 || id < defaultId)
904 /**************************************************************************
906 *************************************************************************/
908 NetworkAddDlg::NetworkAddDlg(const QStringList &exist, QWidget *parent) : QDialog(parent), existing(exist)
911 ui.useSSL->setIcon(QIcon::fromTheme("document-encrypt"));
913 // Whenever useSSL is toggled, update the port number if not changed from the default
914 connect(ui.useSSL, SIGNAL(toggled(bool)), SLOT(updateSslPort(bool)));
915 // Do NOT call updateSslPort when loading settings, otherwise port settings may be overriden.
916 // If useSSL is later changed to be checked by default, change port's default value, too.
918 if (Client::coreFeatures() & Quassel::VerifyServerSSL) {
919 // Synchronize requiring SSL with the use SSL checkbox
920 ui.sslVerify->setEnabled(ui.useSSL->isChecked());
921 connect(ui.useSSL, SIGNAL(toggled(bool)), ui.sslVerify, SLOT(setEnabled(bool)));
923 // Core isn't new enough to allow requiring SSL; disable checkbox and uncheck
924 ui.sslVerify->setEnabled(false);
925 ui.sslVerify->setChecked(false);
926 // Split up the message to allow re-using translations:
927 // [Original tool-tip]
928 // [Bold 'does not support feature' message]
929 // [Specific version needed and feature details]
930 ui.sslVerify->setToolTip(QString("%1<br/><b>%2</b><br/>%3").arg(
931 ui.sslVerify->toolTip(),
932 tr("Your Quassel core does not support this feature"),
933 tr("You need a Quassel core v0.13.0 or newer in order to "
934 "verify connection security.")));
937 // read preset networks
938 QStringList networks = PresetNetworks::names();
939 foreach(QString s, existing)
940 networks.removeAll(s);
941 if (networks.count())
942 ui.presetList->addItems(networks);
944 ui.useManual->setChecked(true);
945 ui.usePreset->setEnabled(false);
947 connect(ui.networkName, SIGNAL(textChanged(const QString &)), SLOT(setButtonStates()));
948 connect(ui.serverAddress, SIGNAL(textChanged(const QString &)), SLOT(setButtonStates()));
953 NetworkInfo NetworkAddDlg::networkInfo() const
955 if (ui.useManual->isChecked()) {
957 info.networkName = ui.networkName->text().trimmed();
958 info.serverList << Network::Server(ui.serverAddress->text().trimmed(), ui.port->value(),
959 ui.serverPassword->text(), ui.useSSL->isChecked(),
960 ui.sslVerify->isChecked());
964 return PresetNetworks::networkInfo(ui.presetList->currentText());
968 void NetworkAddDlg::setButtonStates()
971 if (ui.usePreset->isChecked() && ui.presetList->count())
973 else if (ui.useManual->isChecked()) {
974 ok = !ui.networkName->text().trimmed().isEmpty() && !existing.contains(ui.networkName->text().trimmed())
975 && !ui.serverAddress->text().isEmpty();
977 ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ok);
981 void NetworkAddDlg::updateSslPort(bool isChecked)
983 // "Use encrypted connection" was toggled, check the state...
984 if (isChecked && ui.port->value() == Network::PORT_PLAINTEXT) {
985 // Had been using the plain-text port, use the SSL default
986 ui.port->setValue(Network::PORT_SSL);
987 } else if (!isChecked && ui.port->value() == Network::PORT_SSL) {
988 // Had been using the SSL port, use the plain-text default
989 ui.port->setValue(Network::PORT_PLAINTEXT);
994 /**************************************************************************
996 *************************************************************************/
998 NetworkEditDlg::NetworkEditDlg(const QString &old, const QStringList &exist, QWidget *parent) : QDialog(parent), existing(exist)
1002 if (old.isEmpty()) {
1004 setWindowTitle(tr("Add Network"));
1005 on_networkEdit_textChanged(""); // disable ok button
1007 else ui.networkEdit->setText(old);
1011 QString NetworkEditDlg::networkName() const
1013 return ui.networkEdit->text().trimmed();
1017 void NetworkEditDlg::on_networkEdit_textChanged(const QString &text)
1019 ui.buttonBox->button(QDialogButtonBox::Ok)->setDisabled(text.isEmpty() || existing.contains(text.trimmed()));
1023 /**************************************************************************
1025 *************************************************************************/
1026 ServerEditDlg::ServerEditDlg(const Network::Server &server, QWidget *parent) : QDialog(parent)
1029 ui.useSSL->setIcon(QIcon::fromTheme("document-encrypt"));
1030 ui.host->setText(server.host);
1031 ui.host->setFocus();
1032 ui.port->setValue(server.port);
1033 ui.password->setText(server.password);
1034 ui.useSSL->setChecked(server.useSsl);
1035 ui.sslVerify->setChecked(server.sslVerify);
1036 ui.sslVersion->setCurrentIndex(server.sslVersion);
1037 ui.useProxy->setChecked(server.useProxy);
1038 ui.proxyType->setCurrentIndex(server.proxyType == QNetworkProxy::Socks5Proxy ? 0 : 1);
1039 ui.proxyHost->setText(server.proxyHost);
1040 ui.proxyPort->setValue(server.proxyPort);
1041 ui.proxyUsername->setText(server.proxyUser);
1042 ui.proxyPassword->setText(server.proxyPass);
1044 // This is a dirty hack to display the core->IRC SSL protocol dropdown
1045 // only if the core won't use autonegotiation to determine the best
1046 // protocol. When autonegotiation was introduced, it would have been
1047 // a good idea to use the CoreFeatures enum to accomplish this.
1048 // However, since multiple versions have been released since then, that
1049 // is no longer possible. Instead, we rely on the fact that the
1050 // Datastream protocol was introduced in the same version (0.10) as SSL
1051 // autonegotiation. Because of that, we can display the dropdown only
1052 // if the Legacy protocol is in use. If any other RemotePeer protocol
1053 // is in use, that means a newer protocol is in use and therefore the
1054 // core will use autonegotiation.
1055 if (Client::coreConnection()->peer()->protocol() != Protocol::LegacyProtocol) {
1057 ui.sslVersion->hide();
1060 // Whenever useSSL is toggled, update the port number if not changed from the default
1061 connect(ui.useSSL, SIGNAL(toggled(bool)), SLOT(updateSslPort(bool)));
1062 // Do NOT call updateSslPort when loading settings, otherwise port settings may be overriden.
1063 // If useSSL is later changed to be checked by default, change port's default value, too.
1065 if (Client::coreFeatures() & Quassel::VerifyServerSSL) {
1066 // Synchronize requiring SSL with the use SSL checkbox
1067 ui.sslVerify->setEnabled(ui.useSSL->isChecked());
1068 connect(ui.useSSL, SIGNAL(toggled(bool)), ui.sslVerify, SLOT(setEnabled(bool)));
1070 // Core isn't new enough to allow requiring SSL; disable checkbox and uncheck
1071 ui.sslVerify->setEnabled(false);
1072 ui.sslVerify->setChecked(false);
1073 // Split up the message to allow re-using translations:
1074 // [Original tool-tip]
1075 // [Bold 'does not support feature' message]
1076 // [Specific version needed and feature details]
1077 ui.sslVerify->setToolTip(QString("%1<br/><b>%2</b><br/>%3").arg(
1078 ui.sslVerify->toolTip(),
1079 tr("Your Quassel core does not support this feature"),
1080 tr("You need a Quassel core v0.13.0 or newer in order to "
1081 "verify connection security.")));
1084 on_host_textChanged();
1088 Network::Server ServerEditDlg::serverData() const
1090 Network::Server server(ui.host->text().trimmed(), ui.port->value(), ui.password->text(),
1091 ui.useSSL->isChecked(), ui.sslVerify->isChecked());
1092 server.sslVersion = ui.sslVersion->currentIndex();
1093 server.useProxy = ui.useProxy->isChecked();
1094 server.proxyType = ui.proxyType->currentIndex() == 0 ? QNetworkProxy::Socks5Proxy : QNetworkProxy::HttpProxy;
1095 server.proxyHost = ui.proxyHost->text();
1096 server.proxyPort = ui.proxyPort->value();
1097 server.proxyUser = ui.proxyUsername->text();
1098 server.proxyPass = ui.proxyPassword->text();
1103 void ServerEditDlg::on_host_textChanged()
1105 ui.buttonBox->button(QDialogButtonBox::Ok)->setDisabled(ui.host->text().trimmed().isEmpty());
1109 void ServerEditDlg::updateSslPort(bool isChecked)
1111 // "Use encrypted connection" was toggled, check the state...
1112 if (isChecked && ui.port->value() == Network::PORT_PLAINTEXT) {
1113 // Had been using the plain-text port, use the SSL default
1114 ui.port->setValue(Network::PORT_SSL);
1115 } else if (!isChecked && ui.port->value() == Network::PORT_SSL) {
1116 // Had been using the SSL port, use the plain-text default
1117 ui.port->setValue(Network::PORT_PLAINTEXT);
1122 /**************************************************************************
1124 *************************************************************************/
1126 SaveNetworksDlg::SaveNetworksDlg(const QList<NetworkInfo> &toCreate, const QList<NetworkInfo> &toUpdate, const QList<NetworkId> &toRemove, QWidget *parent) : QDialog(parent)
1130 numevents = toCreate.count() + toUpdate.count() + toRemove.count();
1133 ui.progressBar->setMaximum(numevents);
1134 ui.progressBar->setValue(0);
1136 connect(Client::instance(), SIGNAL(networkCreated(NetworkId)), this, SLOT(clientEvent()));
1137 connect(Client::instance(), SIGNAL(networkRemoved(NetworkId)), this, SLOT(clientEvent()));
1139 foreach(NetworkId id, toRemove) {
1140 Client::removeNetwork(id);
1142 foreach(NetworkInfo info, toCreate) {
1143 Client::createNetwork(info);
1145 foreach(NetworkInfo info, toUpdate) {
1146 const Network *net = Client::network(info.networkId);
1148 qWarning() << "Invalid client network!";
1152 // FIXME this only checks for one changed item rather than all!
1153 connect(net, SIGNAL(updatedRemotely()), this, SLOT(clientEvent()));
1154 Client::updateNetwork(info);
1158 qWarning() << "Sync dialog called without stuff to change!";
1164 void SaveNetworksDlg::clientEvent()
1166 ui.progressBar->setValue(++rcvevents);
1167 if (rcvevents >= numevents) accept();