File indexing completed on 2024-07-21 07:58:03

0001 /*
0002     SPDX-FileCopyrightText: 2013 Lukas Tinkl <ltinkl@redhat.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #include "bridgewidget.h"
0008 #include "connectioneditordialog.h"
0009 #include "plasma_nm_editor.h"
0010 #include "ui_bridge.h"
0011 
0012 #include <QDBusPendingReply>
0013 
0014 #include <NetworkManagerQt/Connection>
0015 #include <NetworkManagerQt/ConnectionSettings>
0016 #include <NetworkManagerQt/GenericTypes>
0017 #include <NetworkManagerQt/Settings>
0018 
0019 #include <KLocalizedString>
0020 #include <KMessageBox>
0021 #include <kwidgetsaddons_version.h>
0022 
0023 BridgeWidget::BridgeWidget(const QString &masterUuid, const QString &masterId, const NetworkManager::Setting::Ptr &setting, QWidget *parent, Qt::WindowFlags f)
0024     : SettingWidget(setting, parent, f)
0025     , m_uuid(masterUuid)
0026     , m_id(masterId)
0027     , m_ui(new Ui::BridgeWidget)
0028     , m_menu(new QMenu(this))
0029 {
0030     m_ui->setupUi(this);
0031 
0032     // Action buttons and menu
0033     auto action = new QAction(i18n("Ethernet"), this);
0034     action->setData(NetworkManager::ConnectionSettings::Wired);
0035     m_menu->addAction(action);
0036     action = new QAction(i18n("VLAN"), this);
0037     action->setData(NetworkManager::ConnectionSettings::Vlan);
0038     m_menu->addAction(action);
0039     action = new QAction(i18n("Wi-Fi"), this);
0040     action->setData(NetworkManager::ConnectionSettings::Wireless);
0041     m_menu->addAction(action);
0042     m_ui->btnAdd->setMenu(m_menu);
0043     connect(m_menu, &QMenu::triggered, this, &BridgeWidget::addBridge);
0044     connect(m_ui->btnEdit, &QPushButton::clicked, this, &BridgeWidget::editBridge);
0045     connect(m_ui->btnDelete, &QPushButton::clicked, this, &BridgeWidget::deleteBridge);
0046 
0047     // bridges
0048     populateBridges();
0049     connect(m_ui->bridges, &QListWidget::currentItemChanged, this, &BridgeWidget::currentBridgeChanged);
0050     connect(m_ui->bridges, &QListWidget::itemDoubleClicked, this, &BridgeWidget::editBridge);
0051 
0052     connect(m_ui->ifaceName, &KLineEdit::textChanged, this, &BridgeWidget::slotWidgetChanged);
0053 
0054     // Connect for setting check
0055     watchChangedSetting();
0056 
0057     KAcceleratorManager::manage(this);
0058     KAcceleratorManager::manage(m_menu);
0059 
0060     if (setting) {
0061         loadConfig(setting);
0062     }
0063 }
0064 
0065 BridgeWidget::~BridgeWidget()
0066 {
0067     delete m_ui;
0068 }
0069 
0070 void BridgeWidget::loadConfig(const NetworkManager::Setting::Ptr &setting)
0071 {
0072     NetworkManager::BridgeSetting::Ptr bridgeSetting = setting.staticCast<NetworkManager::BridgeSetting>();
0073 
0074     m_ui->ifaceName->setText(bridgeSetting->interfaceName());
0075     m_ui->agingTime->setValue(bridgeSetting->agingTime());
0076 
0077     const bool stp = bridgeSetting->stp();
0078     m_ui->stpGroup->setChecked(stp);
0079     if (stp) {
0080         m_ui->priority->setValue(bridgeSetting->priority());
0081         m_ui->forwardDelay->setValue(bridgeSetting->forwardDelay());
0082         m_ui->helloTime->setValue(bridgeSetting->helloTime());
0083         m_ui->maxAge->setValue(bridgeSetting->maxAge());
0084     }
0085 }
0086 
0087 QVariantMap BridgeWidget::setting() const
0088 {
0089     NetworkManager::BridgeSetting setting;
0090     setting.setInterfaceName(m_ui->ifaceName->text());
0091     setting.setAgingTime(m_ui->agingTime->value());
0092 
0093     const bool stp = m_ui->stpGroup->isChecked();
0094     setting.setStp(stp);
0095     if (stp) {
0096         setting.setPriority(m_ui->priority->value());
0097         setting.setForwardDelay(m_ui->forwardDelay->value());
0098         setting.setHelloTime(m_ui->helloTime->value());
0099         setting.setMaxAge(m_ui->maxAge->value());
0100     }
0101 
0102     return setting.toMap();
0103 }
0104 
0105 void BridgeWidget::addBridge(QAction *action)
0106 {
0107     qCDebug(PLASMA_NM_EDITOR_LOG) << "Adding bridged connection:" << action->data();
0108     qCDebug(PLASMA_NM_EDITOR_LOG) << "Master UUID:" << m_uuid;
0109     qCDebug(PLASMA_NM_EDITOR_LOG) << "Slave type:" << type();
0110 
0111     NetworkManager::ConnectionSettings::ConnectionType connectionType = static_cast<NetworkManager::ConnectionSettings::ConnectionType>(action->data().toInt());
0112     NetworkManager::ConnectionSettings::Ptr connectionSettings =
0113         NetworkManager::ConnectionSettings::Ptr(new NetworkManager::ConnectionSettings(connectionType));
0114     connectionSettings->setUuid(NetworkManager::ConnectionSettings::createNewUuid());
0115     connectionSettings->setMaster(m_uuid);
0116     connectionSettings->setSlaveType(type());
0117     connectionSettings->setAutoconnect(false);
0118 
0119     QPointer<ConnectionEditorDialog> bridgeEditor = new ConnectionEditorDialog(connectionSettings);
0120     bridgeEditor->setAttribute(Qt::WA_DeleteOnClose);
0121     connect(bridgeEditor.data(), &ConnectionEditorDialog::accepted, [bridgeEditor, this]() {
0122         qCDebug(PLASMA_NM_EDITOR_LOG) << "Saving slave connection";
0123         // qCDebug(PLASMA_NM_EDITOR_LOG) << bridgeEditor->setting();
0124         QDBusPendingReply<QDBusObjectPath> reply = NetworkManager::addConnection(bridgeEditor->setting());
0125         auto watcher = new QDBusPendingCallWatcher(reply, this);
0126         connect(watcher, &QDBusPendingCallWatcher::finished, this, &BridgeWidget::bridgeAddComplete);
0127     });
0128     bridgeEditor->setModal(true);
0129     bridgeEditor->show();
0130 }
0131 
0132 void BridgeWidget::currentBridgeChanged(QListWidgetItem *current, QListWidgetItem *previous)
0133 {
0134     Q_UNUSED(previous)
0135 
0136     m_ui->btnEdit->setEnabled(current);
0137     m_ui->btnDelete->setEnabled(current);
0138 }
0139 
0140 void BridgeWidget::bridgeAddComplete(QDBusPendingCallWatcher *watcher)
0141 {
0142     QDBusPendingReply<QDBusObjectPath> reply = *watcher;
0143 
0144     if (reply.isValid()) {
0145         // find the slave connection with matching UUID
0146         NetworkManager::Connection::Ptr connection = NetworkManager::findConnection(reply.value().path());
0147         if (connection && connection->settings()->master() == m_uuid) {
0148             const QString label =
0149                 QStringLiteral("%1 (%2)").arg(connection->name()).arg(connection->settings()->typeAsString(connection->settings()->connectionType()));
0150             auto slaveItem = new QListWidgetItem(label, m_ui->bridges);
0151             slaveItem->setData(Qt::UserRole, connection->uuid());
0152             slotWidgetChanged();
0153         }
0154     } else {
0155         qCWarning(PLASMA_NM_EDITOR_LOG) << "Bridged connection not added:" << reply.error().message();
0156     }
0157 }
0158 
0159 void BridgeWidget::editBridge()
0160 {
0161     QListWidgetItem *currentItem = m_ui->bridges->currentItem();
0162     if (!currentItem)
0163         return;
0164 
0165     const QString uuid = currentItem->data(Qt::UserRole).toString();
0166     NetworkManager::Connection::Ptr connection = NetworkManager::findConnectionByUuid(uuid);
0167 
0168     if (connection) {
0169         qCDebug(PLASMA_NM_EDITOR_LOG) << "Editing bridged connection" << currentItem->text() << uuid;
0170         QPointer<ConnectionEditorDialog> bridgeEditor = new ConnectionEditorDialog(connection->settings());
0171         bridgeEditor->setAttribute(Qt::WA_DeleteOnClose);
0172         connect(bridgeEditor.data(), &ConnectionEditorDialog::accepted, [connection, bridgeEditor, this]() {
0173             connection->update(bridgeEditor->setting());
0174             connect(connection.data(), &NetworkManager::Connection::updated, this, &BridgeWidget::populateBridges);
0175         });
0176         bridgeEditor->setModal(true);
0177         bridgeEditor->show();
0178     }
0179 }
0180 
0181 void BridgeWidget::deleteBridge()
0182 {
0183     QListWidgetItem *currentItem = m_ui->bridges->currentItem();
0184     if (!currentItem)
0185         return;
0186 
0187     const QString uuid = currentItem->data(Qt::UserRole).toString();
0188     NetworkManager::Connection::Ptr connection = NetworkManager::findConnectionByUuid(uuid);
0189 
0190     if (connection) {
0191         // qCDebug(PLASMA_NM_EDITOR_LOG) << "About to delete bridged connection" << currentItem->text() << uuid;
0192         if (KMessageBox::questionTwoActions(this,
0193                                             i18n("Do you want to remove the connection '%1'?", connection->name()),
0194                                             i18n("Remove Connection"),
0195                                             KStandardGuiItem::remove(),
0196                                             KStandardGuiItem::cancel(),
0197                                             QString(),
0198                                             KMessageBox::Dangerous)
0199             == KMessageBox::ButtonCode::PrimaryAction) {
0200             connection->remove();
0201             delete currentItem;
0202             slotWidgetChanged();
0203         }
0204     }
0205 }
0206 
0207 void BridgeWidget::populateBridges()
0208 {
0209     m_ui->bridges->clear();
0210 
0211     for (const NetworkManager::Connection::Ptr &connection : NetworkManager::listConnections()) {
0212         NetworkManager::ConnectionSettings::Ptr settings = connection->settings();
0213         // The mapping from slave to master may be by uuid or name, try our best to
0214         // figure out if we are master to the slave.
0215         const QString master = settings->master();
0216         bool isSlave = ((master == m_uuid) || // by-uuid
0217                         (!m_id.isEmpty() && master == m_id)); // by-name
0218         if (isSlave && (settings->slaveType() == type())) {
0219             const QString label =
0220                 QStringLiteral("%1 (%2)").arg(connection->name()).arg(connection->settings()->typeAsString(connection->settings()->connectionType()));
0221             auto slaveItem = new QListWidgetItem(label, m_ui->bridges);
0222             slaveItem->setData(Qt::UserRole, connection->uuid());
0223         }
0224     }
0225 }
0226 
0227 bool BridgeWidget::isValid() const
0228 {
0229     return !m_ui->ifaceName->text().isEmpty() && m_ui->bridges->count() > 0;
0230 }
0231 
0232 #include "moc_bridgewidget.cpp"