qtui: Add keyboard/mouse access to version links
[quassel.git] / src / qtui / settingspages / networkssettingspage.cpp
index 6a36d0e..0f67de2 100644 (file)
@@ -67,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();
@@ -89,7 +91,8 @@ NetworksSettingsPage::NetworksSettingsPage(QWidget* parent)
                                     ui.sendEncoding,         ui.recvEncoding,         ui.serverEncoding,
                                     ui.autoReconnect,        ui.reconnectInterval,    ui.reconnectRetries,
                                     ui.unlimitedRetries,     ui.rejoinOnReconnect,    ui.useCustomMessageRate,
-                                    ui.messageRateBurstSize, ui.messageRateDelay,     ui.unlimitedMessageRate},
+                                    ui.messageRateBurstSize, ui.messageRateDelay,     ui.unlimitedMessageRate,
+                                    ui.enableCapServerTime},
                                    this,
                                    &NetworksSettingsPage::widgetHasChanged);
 
@@ -177,6 +180,20 @@ void NetworksSettingsPage::load()
                                                         "modify message rate limits.")));
     }
 
+    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();
@@ -625,6 +642,8 @@ void NetworksSettingsPage::displayNetwork(NetworkId id)
         ui.messageRateBurstSize->setValue(info.messageRateBurstSize);
         // Convert milliseconds (integer) into seconds (double)
         ui.messageRateDelay->setValue(info.messageRateDelay / 1000.0f);
+        // Skipped IRCv3 capabilities
+        ui.enableCapServerTime->setChecked(!info.skipCaps.contains(IrcCap::SERVER_TIME));
     }
     else {
         // just clear widgets
@@ -677,6 +696,14 @@ void NetworksSettingsPage::saveToNetworkInfo(NetworkInfo& info)
     // Convert seconds (double) into milliseconds (integer)
     info.messageRateDelay = static_cast<quint32>((ui.messageRateDelay->value() * 1000));
     info.unlimitedMessageRate = ui.unlimitedMessageRate->isChecked();
+    // Skipped IRCv3 capabilities
+    if (ui.enableCapServerTime->isChecked()) {
+        // Capability enabled, remove it from the skip list
+        info.skipCaps.removeAll(IrcCap::SERVER_TIME);
+    } else if (!info.skipCaps.contains(IrcCap::SERVER_TIME)) {
+        // Capability disabled and not in the skip list, add it
+        info.skipCaps.append(IrcCap::SERVER_TIME);
+    }
 }
 
 void NetworksSettingsPage::clientNetworkCapsUpdated()
@@ -706,23 +733,23 @@ 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;
         }
     }
@@ -981,6 +1008,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;
@@ -1212,6 +1306,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
  *************************************************************************/