settings: Add Features tab to Network for skipCaps
[quassel.git] / src / qtui / settingspages / networkssettingspage.cpp
index 592c197..c9de1ac 100644 (file)
@@ -50,9 +50,6 @@ NetworksSettingsPage::NetworksSettingsPage(QWidget* parent)
         ui.sasl->hide();
     if (!Client::isCoreFeatureEnabled(Quassel::Feature::SaslExternal))
         ui.saslExtInfo->hide();
-#ifndef HAVE_SSL
-    ui.saslExtInfo->hide();
-#endif
 
     // set up icons
     ui.renameNetwork->setIcon(icon::get("edit-rename"));
@@ -70,8 +67,10 @@ NetworksSettingsPage::NetworksSettingsPage(QWidget* parent)
     disconnectedIcon = icon::get("network-disconnect");
 
     // Status icons
-    infoIcon = icon::get("dialog-information");
-    warningIcon = icon::get("dialog-warning");
+    infoIcon = icon::get({"emblem-information", "dialog-information"});
+    successIcon = icon::get({"emblem-success", "dialog-information"});
+    unavailableIcon = icon::get({"emblem-unavailable", "dialog-warning"});
+    questionIcon = icon::get({"emblem-question", "dialog-question", "dialog-information"});
 
     foreach (int mib, QTextCodec::availableMibs()) {
         QByteArray codec = QTextCodec::codecForMib(mib)->name();
@@ -180,11 +179,23 @@ void NetworksSettingsPage::load()
                                                         "modify message rate limits.")));
     }
 
-#ifdef HAVE_SSL
+    if (!Client::isConnected() || Client::isCoreFeatureEnabled(Quassel::Feature::SkipIrcCaps)) {
+        // Either disconnected or IRCv3 capability skippping supported, enable configuration and
+        // hide warning.  Don't show the warning needlessly when disconnected.
+        ui.enableCapsConfigWidget->setEnabled(true);
+        ui.enableCapsStatusLabel->setText(tr("These features require support from the network"));
+        ui.enableCapsStatusIcon->setPixmap(infoIcon.pixmap(16));
+    }
+    else {
+        // Core does not IRCv3 capability skipping, show warning and disable configuration
+        ui.enableCapsConfigWidget->setEnabled(false);
+        ui.enableCapsStatusLabel->setText(tr("Your Quassel core is too old to configure IRCv3 features"));
+        ui.enableCapsStatusIcon->setPixmap(unavailableIcon.pixmap(16));
+    }
+
     // Hide the SASL EXTERNAL notice until a network's shown.  Stops it from showing while loading
     // backlog from the core.
     sslUpdated();
-#endif
 
     // Reset network capability status in case no valid networks get selected (a rare situation)
     resetNetworkCapStates();
@@ -575,7 +586,6 @@ void NetworksSettingsPage::displayNetwork(NetworkId id)
     if (id != 0) {
         NetworkInfo info = networkInfos[id];
 
-#ifdef HAVE_SSL
         // this is only needed when the core supports SASL EXTERNAL
         if (Client::isCoreFeatureEnabled(Quassel::Feature::SaslExternal)) {
             if (_cid) {
@@ -586,7 +596,6 @@ void NetworksSettingsPage::displayNetwork(NetworkId id)
             _cid->enableEditSsl(true);
             connect(_cid, &CertIdentity::sslSettingsUpdated, this, &NetworksSettingsPage::sslUpdated);
         }
-#endif
 
         ui.identityList->setCurrentIndex(ui.identityList->findData(info.identity.toInt()));
         ui.serverList->clear();
@@ -635,12 +644,10 @@ void NetworksSettingsPage::displayNetwork(NetworkId id)
     }
     else {
         // just clear widgets
-#ifdef HAVE_SSL
         if (_cid) {
             disconnect(_cid, &CertIdentity::sslSettingsUpdated, this, &NetworksSettingsPage::sslUpdated);
             delete _cid;
         }
-#endif
         ui.identityList->setCurrentIndex(-1);
         ui.serverList->clear();
         ui.performEdit->clear();
@@ -715,29 +722,28 @@ void NetworksSettingsPage::setSASLStatus(const CapSupportStatus saslStatus)
             // There's no capability negotiation or network doesn't exist.  Don't assume
             // anything.
             ui.saslStatusLabel->setText(QString("<i>%1</i>").arg(tr("Could not check if supported by network")));
-            ui.saslStatusIcon->setPixmap(infoIcon.pixmap(16));
+            ui.saslStatusIcon->setPixmap(questionIcon.pixmap(16));
             break;
         case CapSupportStatus::Disconnected:
             // Disconnected from network, no way to check.
             ui.saslStatusLabel->setText(QString("<i>%1</i>").arg(tr("Cannot check if supported when disconnected")));
-            ui.saslStatusIcon->setPixmap(infoIcon.pixmap(16));
+            ui.saslStatusIcon->setPixmap(questionIcon.pixmap(16));
             break;
         case CapSupportStatus::MaybeUnsupported:
             // The network doesn't advertise support for SASL PLAIN.  Here be dragons.
             ui.saslStatusLabel->setText(QString("<i>%1</i>").arg(tr("Not currently supported by network")));
-            ui.saslStatusIcon->setPixmap(warningIcon.pixmap(16));
+            ui.saslStatusIcon->setPixmap(unavailableIcon.pixmap(16));
             break;
         case CapSupportStatus::MaybeSupported:
             // The network advertises support for SASL PLAIN.  Encourage using it!
             // Unfortunately we don't know for sure if it's desired or functional.
             ui.saslStatusLabel->setText(QString("<i>%1</i>").arg(tr("Supported by network")));
-            ui.saslStatusIcon->setPixmap(infoIcon.pixmap(16));
+            ui.saslStatusIcon->setPixmap(successIcon.pixmap(16));
             break;
         }
     }
 }
 
-#ifdef HAVE_SSL
 void NetworksSettingsPage::sslUpdated()
 {
     if (_cid && !_cid->sslKey().isNull()) {
@@ -760,7 +766,6 @@ void NetworksSettingsPage::sslUpdated()
         ui.saslExtInfo->setHidden(true);
     }
 }
-#endif
 
 /*** Network list ***/
 
@@ -992,6 +997,73 @@ void NetworksSettingsPage::on_saslStatusDetails_clicked()
     }
 }
 
+void NetworksSettingsPage::on_enableCapsStatusDetails_clicked()
+{
+    if (!Client::isConnected() || Client::isCoreFeatureEnabled(Quassel::Feature::SkipIrcCaps)) {
+        // Either disconnected or IRCv3 capability skippping supported
+
+        // Try to get a list of currently enabled features
+        QStringList sortedCapsEnabled;
+        // Check if a network is selected
+        if (ui.networkList->selectedItems().count()) {
+            // Get the underlying Network from the selected network
+            NetworkId netid = ui.networkList->selectedItems()[0]->data(Qt::UserRole).value<NetworkId>();
+            const Network* net = Client::network(netid);
+            if (net && Client::isCoreFeatureEnabled(Quassel::Feature::CapNegotiation)) {
+                // Capability negotiation is supported, network exists.
+                // If the network is disconnected, the list of enabled capabilities will be empty,
+                // no need to check for that specifically.
+                // Sorting isn't required, but it looks nicer.
+                sortedCapsEnabled = net->capsEnabled();
+                sortedCapsEnabled.sort();
+            }
+        }
+
+        // Try to explain IRCv3 network features in a friendly way, including showing the currently
+        // enabled features if available
+        auto messageText = QString("<p>%1</p></br><p>%2</p>")
+                .arg(tr("Quassel makes use of newer IRC features when supported by the IRC network."
+                        "  If desired, you can disable unwanted or problematic features here."),
+                     tr("The <a href=\"https://ircv3.net/irc/\">IRCv3 website</a> provides more "
+                        "technical details on the IRCv3 capabilities powering these features."));
+
+        if (!sortedCapsEnabled.isEmpty()) {
+            // Format the capabilities within <code></code> blocks
+            auto formattedCaps = QString("<code>%1</code>")
+                    .arg(sortedCapsEnabled.join("</code>, <code>"));
+
+            // Add the currently enabled capabilities to the list
+            // This creates a new QString, but this code is not performance-critical.
+            messageText = messageText.append(QString("<p><i>%1</i></p>").arg(
+                                                 tr("Currently enabled IRCv3 capabilities for this "
+                                                    "network: %1").arg(formattedCaps)));
+        }
+
+        QMessageBox::information(this, tr("Configuring network features"), messageText);
+    }
+    else {
+        // Core does not IRCv3 capability skipping, show warning
+        QMessageBox::warning(this, tr("Configuring network features unsupported"),
+                             QString("<p><b>%1</b></p></br><p>%2</p>")
+                             .arg(tr("Your Quassel core is too old to configure IRCv3 network features"),
+                                  tr("You need a Quassel core v0.14.0 or newer to control what network "
+                                     "features Quassel will use.")));
+    }
+}
+
+void NetworksSettingsPage::on_enableCapsAdvanced_clicked()
+{
+    if (currentId == 0)
+        return;
+
+    CapsEditDlg dlg(networkInfos[currentId].skipCapsToString(), this);
+    if (dlg.exec() == QDialog::Accepted) {
+        networkInfos[currentId].skipCapsFromString(dlg.skipCapsString());
+        displayNetwork(currentId);
+        widgetHasChanged();
+    }
+}
+
 IdentityId NetworksSettingsPage::defaultIdentity() const
 {
     IdentityId defaultId = 0;
@@ -1223,6 +1295,47 @@ void ServerEditDlg::updateSslPort(bool isChecked)
     }
 }
 
+/**************************************************************************
+ * CapsEditDlg
+ *************************************************************************/
+
+CapsEditDlg::CapsEditDlg(const QString& oldSkipCapsString, QWidget* parent)
+    : QDialog(parent)
+    , oldSkipCapsString(oldSkipCapsString)
+{
+    ui.setupUi(this);
+
+    // Connect to the reset button to reset the text
+    // This provides an explicit way to "get back to defaults" in case someone changes settings to
+    // experiment
+    QPushButton* defaultsButton = ui.buttonBox->button(QDialogButtonBox::RestoreDefaults);
+    connect(defaultsButton, &QPushButton::clicked, this, &CapsEditDlg::defaultSkipCaps);
+
+    if (oldSkipCapsString.isEmpty()) {
+        // Disable Reset button
+        on_skipCapsEdit_textChanged("");
+    }
+    else {
+        ui.skipCapsEdit->setText(oldSkipCapsString);
+    }
+}
+
+
+QString CapsEditDlg::skipCapsString() const
+{
+    return ui.skipCapsEdit->text();
+}
+
+void CapsEditDlg::defaultSkipCaps()
+{
+    ui.skipCapsEdit->setText("");
+}
+
+void CapsEditDlg::on_skipCapsEdit_textChanged(const QString& text)
+{
+    ui.buttonBox->button(QDialogButtonBox::RestoreDefaults)->setDisabled(text.isEmpty());
+}
+
 /**************************************************************************
  * SaveNetworksDlg
  *************************************************************************/