diff --git a/kcm/kcm.cpp b/kcm/kcm.cpp index abdba2e6..9222440b 100755 --- a/kcm/kcm.cpp +++ b/kcm/kcm.cpp @@ -1,548 +1,548 @@ /* Copyright 2016-2018 Jan Grulich This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "kcm.h" #include "debug.h" #include "settings/connectionsettings.h" // #include "mobileconnectionwizard.h" #include "uiutils.h" // #include "vpnuiplugin.h" // KDE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Qt #include #include #include Q_LOGGING_CATEGORY(KCM_NETWORKMANAGEMENT, "kcm_networkmanagement") K_PLUGIN_FACTORY_WITH_JSON(KCMNetworkmanagementFactory, "kcm_networkmanagement.json", registerPlugin();) KCMNetworkmanagement::KCMNetworkmanagement(QObject *parent, const QVariantList &args) : KQuickAddons::ConfigModule(parent, args) , m_handler(new Handler(this)) { KAboutData* about = new KAboutData(QStringLiteral("kcm_networkmanagement"), i18n("Edit your Network Connections"), QStringLiteral("0.1"), QString(), KAboutLicense::LGPL); about->addAuthor(i18n("Jan Grulich"), QString(), QStringLiteral("jgrulich@redhat.com")); setAboutData(about); setButtons(Apply); // Check if we can use AP mode to identify security type bool useApMode = false; bool foundInactive = false; NetworkManager::WirelessDevice::Ptr wifiDev; for (const NetworkManager::Device::Ptr &device : NetworkManager::networkInterfaces()) { if (device->type() == NetworkManager::Device::Wifi) { wifiDev = device.objectCast(); if (wifiDev) { if (!wifiDev->isActive()) { foundInactive = true; } else { // Prefer previous device if it was inactive if (foundInactive) { break; } } if (wifiDev->wirelessCapabilities().testFlag(NetworkManager::WirelessDevice::ApCap)) { useApMode = true; } // We prefer inactive wireless card with AP capabilities if (foundInactive && useApMode) { break; } } } } // TODO // m_ui->connectionView->rootContext()->setContextProperty("connectionModified", false); // m_ui->connectionView->rootContext()->setContextProperty("useApMode", useApMode); - m_connectionSetting = new ConnectionSetting(this); + m_connectionSettings = new ConnectionSettings(this); // connect(m_connectionSetting, &ConnectionSetting::settingChanged, // [this] () { // if (m_connectionSetting->isInitialized() && m_connectionSetting->isValid()) { // setNeedsSave(true); // } // }); connect(m_connectionSettings, &ConnectionSettings::validityChanged, [this] (bool valid) { if (m_connectionSettings->isInitialized()) { setNeedsSave(true); } }); NetworkManager::Connection::Ptr selectedConnection; // Look in the arguments for a connection ID to preselect static const QLatin1String uuidArgumentMarker { "Uuid=" }; for (QVariant arg : args) { if (arg.canConvert(QMetaType::QString)) { QString uuid = arg.toString(); if (uuid.startsWith(uuidArgumentMarker)) { uuid = uuid.replace(uuidArgumentMarker, QString()); selectedConnection = NetworkManager::findConnectionByUuid(uuid); qDebug() << "Selecting user connection:" << uuid; break; } } } // Pre-select currently active primary connection and if there is none then just select // the very first connection // NetworkManager::ActiveConnection::Ptr activeConnection = NetworkManager::primaryConnection(); // if (activeConnection && activeConnection->isValid()) { // // Also check if the connection type is supported by KCM // const NetworkManager::ConnectionSettings::ConnectionType type = activeConnection->type(); // if (UiUtils::isConnectionTypeSupported(type)) { // QMetaObject::invokeMethod(mainUi(), "selectConnectionInView", Q_ARG(QVariant, activeConnection->id()), Q_ARG(QVariant, activeConnection->connection()->path())); // } // } // // // Select the very first connection as a fallback // if (!selectedConnection || !selectedConnection->isValid()) { // NetworkManager::Connection::List connectionList = NetworkManager::listConnections(); // std::sort(connectionList.begin(), connectionList.end(), [] (const NetworkManager::Connection::Ptr &left, const NetworkManager::Connection::Ptr &right) // { // const QString leftName = left->settings()->id(); // const UiUtils::SortedConnectionType leftType = UiUtils::connectionTypeToSortedType(left->settings()->connectionType()); // const QDateTime leftDate = left->settings()->timestamp(); // // const QString rightName = right->settings()->id(); // const UiUtils::SortedConnectionType rightType = UiUtils::connectionTypeToSortedType(right->settings()->connectionType()); // const QDateTime rightDate = right->settings()->timestamp(); // // if (leftType < rightType) { // return true; // } else if (leftType > rightType) { // return false; // } // // if (leftDate > rightDate) { // return true; // } else if (leftDate < rightDate) { // return false; // } // // if (QString::localeAwareCompare(leftName, rightName) > 0) { // return true; // } else { // return false; // } // }); // // for (const NetworkManager::Connection::Ptr &connection : connectionList) { // const NetworkManager::ConnectionSettings::ConnectionType type = connection->settings()->connectionType(); // if (UiUtils::isConnectionTypeSupported(type)) { // QMetaObject::invokeMethod(mainUi(), "selectConnectionInView", Q_ARG(QVariant, connection->settings()->id()), Q_ARG(QVariant, connection->path())); // break; // } // } // } - if (selectedConnection && selectedConnection->isValid()) { - const NetworkManager::ConnectionSettings::Ptr settings = selectedConnection->settings(); - if (UiUtils::isConnectionTypeSupported(settings->connectionType())) { - QMetaObject::invokeMethod(rootItem, "selectConnection", Q_ARG(QVariant, settings->id()), Q_ARG(QVariant, selectedConnection->path())); - } - } else { - qDebug() << "Cannot preselect a connection"; - } +// if (selectedConnection && selectedConnection->isValid()) { +// const NetworkManager::ConnectionSettings::Ptr settings = selectedConnection->settings(); +// if (UiUtils::isConnectionTypeSupported(settings->connectionType())) { +// QMetaObject::invokeMethod(rootItem, "selectConnection", Q_ARG(QVariant, settings->id()), Q_ARG(QVariant, selectedConnection->path())); +// } +// } else { +// qDebug() << "Cannot preselect a connection"; +// } connect(NetworkManager::settingsNotifier(), &NetworkManager::SettingsNotifier::connectionAdded, this, &KCMNetworkmanagement::onConnectionAdded, Qt::UniqueConnection); // Initialize first scan and then scan every 15 seconds m_handler->requestScan(); m_timer = new QTimer(this); m_timer->setInterval(15000); connect(m_timer, &QTimer::timeout, [this] () { m_handler->requestScan(); }); m_timer->start(); } KCMNetworkmanagement::~KCMNetworkmanagement() { delete m_handler; } void KCMNetworkmanagement::defaults() { KQuickAddons::ConfigModule::defaults(); } void KCMNetworkmanagement::load() { // If there is no loaded connection do nothing if (m_currentConnectionPath.isEmpty()) { return; } NetworkManager::Connection::Ptr connection = NetworkManager::findConnection(m_currentConnectionPath); if (connection) { NetworkManager::ConnectionSettings::Ptr connectionSettings = connection->settings(); // Re-load the connection again to load stored values m_connectionSettings->loadConfig(connectionSettings); } KQuickAddons::ConfigModule::load(); } void KCMNetworkmanagement::save() { // NetworkManager::Connection::Ptr connection = NetworkManager::findConnection(m_currentConnectionPath); // // if (connection) { // m_handler->updateConnection(connection, m_connectionSettings->setting()); // } KQuickAddons::ConfigModule::save(); } void KCMNetworkmanagement::onConnectionAdded(const QString &connection) { if (m_createdConnectionUuid.isEmpty()) { return; } NetworkManager::Connection::Ptr newConnection = NetworkManager::findConnection(connection); if (newConnection) { NetworkManager::ConnectionSettings::Ptr connectionSettings = newConnection->settings(); if (connectionSettings && connectionSettings->uuid() == m_createdConnectionUuid) { loadConnectionSettings(connectionSettings); QMetaObject::invokeMethod(mainUi(), "selectConnectionInView", Q_ARG(QVariant, connectionSettings->id()), Q_ARG(QVariant, newConnection->path())); m_createdConnectionUuid.clear(); } } } void KCMNetworkmanagement::selectConnection(const QString &connectionPath) { if (connectionPath.isEmpty()) { resetSelection(); return; } m_currentConnectionPath = connectionPath; NetworkManager::Connection::Ptr connection = NetworkManager::findConnection(m_currentConnectionPath); if (connection) { NetworkManager::ConnectionSettings::Ptr connectionSettings = connection->settings(); loadConnectionSettings(connectionSettings); } } void KCMNetworkmanagement::requestCreateConnection(int connectionType, const QString &vpnType, const QString &specificType, bool shared) { NetworkManager::ConnectionSettings::ConnectionType type = static_cast(connectionType); if (type == NetworkManager::ConnectionSettings::Vpn && vpnType == "imported") { importVpn(); } else if (type == NetworkManager::ConnectionSettings::Gsm) { // launch the mobile broadband wizard, both gsm/cdma // #if WITH_MODEMMANAGER_SUPPORT // QPointer wizard = new MobileConnectionWizard(NetworkManager::ConnectionSettings::Unknown, this); // connect(wizard.data(), &MobileConnectionWizard::accepted, // [wizard, this] () { // if (wizard->getError() == MobileProviders::Success) { // qCDebug(KCM_NETWORKMANAGEMENT) << "Mobile broadband wizard finished:" << wizard->type() << wizard->args(); // // if (wizard->args().count() == 2) { // QVariantMap tmp = qdbus_cast(wizard->args().value(1)); // // NetworkManager::ConnectionSettings::Ptr connectionSettings; // connectionSettings = NetworkManager::ConnectionSettings::Ptr(new NetworkManager::ConnectionSettings(wizard->type())); // connectionSettings->setId(wizard->args().value(0).toString()); // if (wizard->type() == NetworkManager::ConnectionSettings::Gsm) { // NetworkManager::GsmSetting::Ptr gsmSetting = connectionSettings->setting(NetworkManager::Setting::Gsm).staticCast(); // gsmSetting->fromMap(tmp); // gsmSetting->setPasswordFlags(NetworkManager::Setting::NotRequired); // gsmSetting->setPinFlags(NetworkManager::Setting::NotRequired); // } else if (wizard->type() == NetworkManager::ConnectionSettings::Cdma) { // connectionSettings->setting(NetworkManager::Setting::Cdma)->fromMap(tmp); // } else { // qCWarning(KCM_NETWORKMANAGEMENT) << Q_FUNC_INFO << "Unhandled setting type"; // } // // Generate new UUID // connectionSettings->setUuid(NetworkManager::ConnectionSettings::createNewUuid()); // addConnection(connectionSettings); // } else { // qCWarning(KCM_NETWORKMANAGEMENT) << Q_FUNC_INFO << "Unexpected number of args to parse"; // } // } // }); // connect(wizard.data(), &MobileConnectionWizard::finished, // [wizard] () { // if (wizard) { // wizard->deleteLater(); // } // }); // wizard->setModal(true); // wizard->show(); // #endif } else { NetworkManager::ConnectionSettings::Ptr connectionSettings; connectionSettings = NetworkManager::ConnectionSettings::Ptr(new NetworkManager::ConnectionSettings(type)); if (type == NetworkManager::ConnectionSettings::Vpn) { NetworkManager::VpnSetting::Ptr vpnSetting = connectionSettings->setting(NetworkManager::Setting::Vpn).dynamicCast(); vpnSetting->setServiceType(vpnType); // Set VPN subtype in case of Openconnect to add support for juniper if (vpnType == QLatin1String("org.freedesktop.NetworkManager.openconnect")) { NMStringMap data = vpnSetting->data(); data.insert(QLatin1String("protocol"), specificType); vpnSetting->setData(data); } } if (type == NetworkManager::ConnectionSettings::Wired || type == NetworkManager::ConnectionSettings::Wireless) { // Set auto-negotiate to true, NM sets it to false by default, but we used to have this before and also // I don't think it's wise to request users to specify speed and duplex as most of them don't know what is that // and what to set if (type == NetworkManager::ConnectionSettings::Wired) { NetworkManager::WiredSetting::Ptr wiredSetting = connectionSettings->setting(NetworkManager::Setting::Wired).dynamicCast(); wiredSetting->setAutoNegotiate(true); } if (shared) { if (type == NetworkManager::ConnectionSettings::Wireless) { NetworkManager::WirelessSetting::Ptr wifiSetting = connectionSettings->setting(NetworkManager::Setting::Wireless).dynamicCast(); wifiSetting->setMode(NetworkManager::WirelessSetting::Adhoc); wifiSetting->setSsid(i18n("my_shared_connection").toUtf8()); for (const NetworkManager::Device::Ptr & device : NetworkManager::networkInterfaces()) { if (device->type() == NetworkManager::Device::Wifi) { NetworkManager::WirelessDevice::Ptr wifiDev = device.objectCast(); if (wifiDev) { if (wifiDev->wirelessCapabilities().testFlag(NetworkManager::WirelessDevice::ApCap)) { wifiSetting->setMode(NetworkManager::WirelessSetting::Ap); wifiSetting->setMacAddress(NetworkManager::macAddressFromString(wifiDev->permanentHardwareAddress())); } } } } } NetworkManager::Ipv4Setting::Ptr ipv4Setting = connectionSettings->setting(NetworkManager::Setting::Ipv4).dynamicCast(); ipv4Setting->setMethod(NetworkManager::Ipv4Setting::Shared); connectionSettings->setAutoconnect(false); } } if (type == NetworkManager::ConnectionSettings::WireGuard) { NetworkManager::WireGuardSetting::Ptr wireguardSetting = connectionSettings->setting(NetworkManager::Setting::WireGuard).dynamicCast(); NetworkManager::Ipv4Setting::Ptr ipv4Setting = connectionSettings->setting(NetworkManager::Setting::Ipv4).dynamicCast(); NetworkManager::Ipv6Setting::Ptr ipv6Setting = connectionSettings->setting(NetworkManager::Setting::Ipv6).dynamicCast(); connectionSettings->setAutoconnect(false); ipv4Setting->setMethod(NetworkManager::Ipv4Setting::Disabled); ipv6Setting->setMethod(NetworkManager::Ipv6Setting::Ignored); } // Generate new UUID connectionSettings->setUuid(NetworkManager::ConnectionSettings::createNewUuid()); addConnection(connectionSettings); } } void KCMNetworkmanagement::requestExportConnection(const QString &connectionPath) { NetworkManager::Connection::Ptr connection = NetworkManager::findConnection(connectionPath); if (!connection) { return; } NetworkManager::ConnectionSettings::Ptr connSettings = connection->settings(); if (connSettings->connectionType() != NetworkManager::ConnectionSettings::Vpn) return; NetworkManager::VpnSetting::Ptr vpnSetting = connSettings->setting(NetworkManager::Setting::Vpn).dynamicCast(); qCDebug(KCM_NETWORKMANAGEMENT) << "Exporting VPN connection" << connection->name() << "type:" << vpnSetting->serviceType(); QString error; // VpnUiPlugin * vpnPlugin = KServiceTypeTrader::createInstanceFromQuery(QStringLiteral("PlasmaNetworkManagement/VpnUiPlugin"), // QStringLiteral("[X-NetworkManager-Services]=='%1'").arg(vpnSetting->serviceType()), // this, QVariantList(), &error); // if (vpnPlugin) { // if (vpnPlugin->suggestedFileName(connSettings).isEmpty()) { // this VPN doesn't support export // qCWarning(KCM_NETWORKMANAGEMENT) << "This VPN doesn't support export"; // return; // } // // const QString url = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + QDir::separator() + vpnPlugin->suggestedFileName(connSettings); // const QString filename = QFileDialog::getSaveFileName(this, i18n("Export VPN Connection"), url, vpnPlugin->supportedFileExtensions()); // if (!filename.isEmpty()) { // if (!vpnPlugin->exportConnectionSettings(connSettings, filename)) { // // TODO display failure // qCWarning(KCM_NETWORKMANAGEMENT) << "Failed to export VPN connection"; // } else { // // TODO display success // } // } // delete vpnPlugin; // } else { // qCWarning(KCM_NETWORKMANAGEMENT) << "Error getting VpnUiPlugin for export:" << error; // } } QObject * KCMNetworkmanagement::connectionSettings() const { return m_connectionSettings; } void KCMNetworkmanagement::addConnection(const NetworkManager::ConnectionSettings::Ptr &connectionSettings) { // QPointer editor = new ConnectionEditorDialog(connectionSettings); // connect(editor.data(), &ConnectionEditorDialog::accepted, // [connectionSettings, editor, this] () { // // We got confirmation so watch this connection and select it once it is created // m_createdConnectionUuid = connectionSettings->uuid(); // m_handler->addConnection(editor->setting()); // }); // connect(editor.data(), &ConnectionEditorDialog::finished, // [editor] () { // if (editor) { // editor->deleteLater(); // } // }); // editor->setModal(true); // editor->show(); } void KCMNetworkmanagement::loadConnectionSettings(const NetworkManager::ConnectionSettings::Ptr& connectionSettings) { m_connectionSettings->loadConfig(connectionSettings); QMetaObject::invokeMethod(mainUi(), "loadConnectionSetting"); setNeedsSave(false); } void KCMNetworkmanagement::importVpn() { // get the list of supported extensions // const KService::List services = KServiceTypeTrader::self()->query("PlasmaNetworkManagement/VpnUiPlugin"); // QString extensions; // for (const KService::Ptr &service : services) { // VpnUiPlugin * vpnPlugin = service->createInstance(this); // if (vpnPlugin) { // extensions += vpnPlugin->supportedFileExtensions() % QStringLiteral(" "); // delete vpnPlugin; // } // } // // const QString &filename = QFileDialog::getOpenFileName(this, i18n("Import VPN Connection"), QDir::homePath(), extensions.simplified()); // // if (!filename.isEmpty()) { // const KService::List services = KServiceTypeTrader::self()->query("PlasmaNetworkManagement/VpnUiPlugin"); // // QFileInfo fi(filename); // const QString ext = QStringLiteral("*.") % fi.suffix(); // qCDebug(PLASMA_NM) << "Importing VPN connection " << filename << "extension:" << ext; // // // Handle WireGuard separately because it is different than all the other VPNs // if (WireGuardInterfaceWidget::supportedFileExtensions().contains(ext)) { // NMVariantMapMap connection = WireGuardInterfaceWidget::importConnectionSettings(filename); // NetworkManager::ConnectionSettings connectionSettings; // connectionSettings.fromMap(connection); // connectionSettings.setUuid(NetworkManager::ConnectionSettings::createNewUuid()); // // // qCDebug(PLASMA_NM) << "Converted connection:" << connectionSettings; // // m_handler->addConnection(connectionSettings.toMap()); // // qCDebug(PLASMA_NM) << "Adding imported connection under id:" << conId; // // if (!connection.isEmpty()) { // return; // get out if the import produced at least some output // } // } // for (const KService::Ptr &service : services) { // VpnUiPlugin * vpnPlugin = service->createInstance(this); // if (vpnPlugin && vpnPlugin->supportedFileExtensions().contains(ext)) { // qCDebug(PLASMA_NM) << "Found VPN plugin" << service->name() << ", type:" << service->property("X-NetworkManager-Services", QVariant::String).toString(); // // NMVariantMapMap connection = vpnPlugin->importConnectionSettings(filename); // // // qCDebug(PLASMA_NM) << "Raw connection:" << connection; // // NetworkManager::ConnectionSettings connectionSettings; // connectionSettings.fromMap(connection); // connectionSettings.setUuid(NetworkManager::ConnectionSettings::createNewUuid()); // // // qCDebug(PLASMA_NM) << "Converted connection:" << connectionSettings; // // m_handler->addConnection(connectionSettings.toMap()); // // qCDebug(PLASMA_NM) << "Adding imported connection under id:" << conId; // // if (connection.isEmpty()) { // the "positive" part will arrive with connectionAdded // // TODO display success // } else { // delete vpnPlugin; // break; // stop iterating over the plugins if the import produced at least some output // } // // delete vpnPlugin; // } // } // } } void KCMNetworkmanagement::resetSelection() { // Reset selected connections m_currentConnectionPath.clear(); QMetaObject::invokeMethod(mainUi(), "deselectConnectionsInView"); // if (m_connectionSetting) { // delete m_connectionSetting; // m_connectionSetting = nullptr; // } setNeedsSave(false); } #include "kcm.moc" diff --git a/kcm/kcm.h b/kcm/kcm.h index da9e8169..5a2ce9d7 100755 --- a/kcm/kcm.h +++ b/kcm/kcm.h @@ -1,69 +1,69 @@ /* Copyright 2016-2018 Jan Grulich This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #ifndef PLASMA_NM_KCM_H #define PLASMA_NM_KCM_H #include "handler.h" #include class QQuickView; class ConnectionSettings; class KCMNetworkmanagement : public KQuickAddons::ConfigModule { Q_OBJECT Q_PROPERTY(QObject * connectionSettings READ connectionSettings CONSTANT) public: - explicit KCMNetworkmanagement(QWidget *parent = nullptr, const QVariantList &args = QVariantList()); + KCMNetworkmanagement(QObject *parent = nullptr, const QVariantList &args = QVariantList()); ~KCMNetworkmanagement() override; // Called from QML Q_INVOKABLE void selectConnection(const QString &connectionPath); Q_INVOKABLE void requestCreateConnection(int connectionType, const QString &vpnType, const QString &specificType, bool share); Q_INVOKABLE void requestExportConnection(const QString &connectionPath); QObject *connectionSettings() const; public Q_SLOTS: void defaults() override; void load() override; void save() override; private Q_SLOTS: void onConnectionAdded(const QString &connection); private: void addConnection(const NetworkManager::ConnectionSettings::Ptr &connectionSettings); void importVpn(); void loadConnectionSettings(const NetworkManager::ConnectionSettings::Ptr &connectionSettings); void resetSelection(); QString m_currentConnectionPath; QString m_createdConnectionUuid; Handler *m_handler; QTimer *m_timer; ConnectionSettings *m_connectionSettings = nullptr; }; #endif diff --git a/kcm/package/contents/ui/ConnectionItemDelegate.qml b/kcm/package/contents/ui/ConnectionItemDelegate.qml index 35e9930b..02d4b412 100644 --- a/kcm/package/contents/ui/ConnectionItemDelegate.qml +++ b/kcm/package/contents/ui/ConnectionItemDelegate.qml @@ -1,138 +1,138 @@ /* Copyright 2016-2018 Jan Grulich This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ import QtQuick 2.6 import QtQuick.Layouts 1.2 import QtQuick.Controls 2.5 as QQC2 import org.kde.kirigami 2.9 as Kirigami import org.kde.plasma.networkmanagement 0.2 as PlasmaNM Kirigami.AbstractListItem { id: connectionItem Accessible.role: Accessible.ListItem Accessible.name: model.Name - checked: ConnectionPath === connectionViewPage.currentConnectionPath + checked: ConnectionPath === root.currentConnectionPath highlighted: focus signal aboutToChangeConnection(bool exportable, string name, string path) signal aboutToExportConnection(string path) signal aboutToRemoveConnection(string name, string path) RowLayout { anchors { left: parent.left right: parent.right verticalCenter: parent.verticalCenter leftMargin: Kirigami.Units.largeSpacing } spacing: Kirigami.Units.largeSpacing Kirigami.Icon { id: connectionIcon Layout.minimumHeight: Kirigami.Units.iconSizes.smallMedium Layout.maximumHeight: Layout.minimumHeight Layout.minimumWidth: height source: KcmConnectionIcon } ColumnLayout { spacing: 0 QQC2.Label { id: nameLabel Layout.fillWidth: true height: paintedHeight elide: Text.ElideRight font.weight: ConnectionState == PlasmaNM.Enums.Activated ? Font.DemiBold : Font.Normal font.italic: ConnectionState == PlasmaNM.Enums.Activating ? true : false text: Name textFormat: Text.PlainText } QQC2.Label { id: statusLabel Layout.fillWidth: true height: paintedHeight elide: Text.ElideRight font.pointSize: theme.smallestFont.pointSize text: itemText() textFormat: Text.PlainText opacity: 0.6 } } } QQC.Menu { id: connectionItemMenu QQC.MenuItem { text: ConnectionState == PlasmaNM.Enums.Deactivated ? i18n("Connect") : i18n("Disconnect") visible: ItemType == 1 onTriggered: { if (ConnectionState == PlasmaNM.Enums.Deactivated) { handler.activateConnection(ConnectionPath, DevicePath, SpecificPath); } else { handler.deactivateConnection(ConnectionPath, DevicePath); } } } QQC.MenuItem { iconName: "list-remove" text: i18n("Delete"); onTriggered: { aboutToRemoveConnection(Name, ConnectionPath) } } QQC.MenuItem { iconName: "document-export" visible: KcmVpnConnectionExportable text: i18n("Export"); onTriggered: aboutToExportConnection(ConnectionPath) } } onClicked: { if (mouse.button === Qt.LeftButton) { aboutToChangeConnection(KcmVpnConnectionExportable, Name, ConnectionPath) } else if (mouse.button == Qt.RightButton) { connectionItemMenu.popup() } } /* This generates the status description under each connection in the list at the left side of the applet. */ function itemText() { if (ConnectionState == PlasmaNM.Enums.Activated) { return i18n("Connected") } else if (ConnectionState == PlasmaNM.Enums.Activating) { return i18n("Connecting") } else { return LastUsed } } } diff --git a/kcm/package/contents/ui/editor/ConnectionEditor.qml b/kcm/package/contents/ui/editor/ConnectionEditor.qml index afd9588e..f3b9fcd4 100644 --- a/kcm/package/contents/ui/editor/ConnectionEditor.qml +++ b/kcm/package/contents/ui/editor/ConnectionEditor.qml @@ -1,177 +1,178 @@ /* Copyright 2018 Jan Grulich This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ import QtQuick 2.6 import QtQuick.Layouts 1.3 import QtQuick.Controls 2.2 as QtControls +import org.kde.kcm 1.2 import org.kde.kirigami 2.0 as Kirigami import org.kde.plasma.networkmanagement 0.2 as PlasmaNM -Kirigami.ScrollablePage { +SimpleKCM { id: connectionEditorPage title: connectionNameTextField.text PlasmaNM.Utils { id: nmUtils } - header: MouseArea { - width: connectionEditorPage.width - height: Math.round(Kirigami.Units.gridUnit * 2.5) - enabled: !applicationWindow().wideScreen - - Accessible.role: Accessible.Button - Accessible.name: i18n("Back") - - onClicked: { - root.pageStack.currentIndex = 0 - } - - Item { - id: headerControls - anchors.fill: parent - - QtControls.ToolButton { - id: backButton - anchors.fill: parent - anchors.margins: Kirigami.Units.smallSpacing - visible: !applicationWindow().wideScreen - - onClicked: { - root.pageStack.currentIndex = 0 - } - - RowLayout { - anchors.fill: parent - - Kirigami.Icon { - id: toolButtonIcon - - Layout.alignment: Qt.AlignVCenter - Layout.preferredHeight: Kirigami.Units.iconSizes.small - Layout.preferredWidth: Layout.preferredHeight - - source: LayoutMirroring.enabled ? "go-next" : "go-previous" - } - - QtControls.Label { - Layout.fillWidth: true - Layout.fillHeight: true - - height: toolButtonIcon.height - text: connectionEditorPage.title - verticalAlignment: Text.AlignVCenter - elide: Text.ElideRight - - //FIXME: QtControls bug, why? - Component.onCompleted: { - font.bold = true - } - } - } - } - - QtControls.Label { - anchors.verticalCenter: parent.verticalCenter - x: y - - text: connectionEditorPage.title - elide: Text.ElideRight - visible: !backButton.visible - opacity: 0.3 - //FIXME: QtControls bug, why? - Component.onCompleted: { - font.bold = true - } - } - } - - Kirigami.Separator { - anchors { - left: parent.left - right: parent.right - top: parent.bottom - } - visible: !connectionEditorPage.atYBeginning - } - } +// header: MouseArea { +// width: connectionEditorPage.width +// height: Math.round(Kirigami.Units.gridUnit * 2.5) +// enabled: !applicationWindow().wideScreen +// +// Accessible.role: Accessible.Button +// Accessible.name: i18n("Back") +// +// onClicked: { +// applicationWindow().pageStack.currentIndex = 0 +// } +// +// Item { +// id: headerControls +// anchors.fill: parent +// +// QtControls.ToolButton { +// id: backButton +// anchors.fill: parent +// anchors.margins: Kirigami.Units.smallSpacing +// visible: !applicationWindow().wideScreen +// +// onClicked: { +// applicationWindow().pageStack.currentIndex = 0 +// } +// +// RowLayout { +// anchors.fill: parent +// +// Kirigami.Icon { +// id: toolButtonIcon +// +// Layout.alignment: Qt.AlignVCenter +// Layout.preferredHeight: Kirigami.Units.iconSizes.small +// Layout.preferredWidth: Layout.preferredHeight +// +// source: LayoutMirroring.enabled ? "go-next" : "go-previous" +// } +// +// QtControls.Label { +// Layout.fillWidth: true +// Layout.fillHeight: true +// +// height: toolButtonIcon.height +// text: connectionEditorPage.title +// verticalAlignment: Text.AlignVCenter +// elide: Text.ElideRight +// +// //FIXME: QtControls bug, why? +// Component.onCompleted: { +// font.bold = true +// } +// } +// } +// } +// +// QtControls.Label { +// anchors.verticalCenter: parent.verticalCenter +// x: y +// +// text: connectionEditorPage.title +// elide: Text.ElideRight +// visible: !backButton.visible +// opacity: 0.3 +// //FIXME: QtControls bug, why? +// Component.onCompleted: { +// font.bold = true +// } +// } +// } +// +// Kirigami.Separator { +// anchors { +// left: parent.left +// right: parent.right +// top: parent.bottom +// } +// visible: !connectionEditorPage.atYBeginning +// } +// } ColumnLayout { width: connectionEditorPage.width QtControls.TextField { id: connectionNameTextField Layout.fillWidth: true hoverEnabled: true } QtControls.TabBar { id: tabBar Layout.fillWidth: true QtControls.TabButton { text: connectionSetting.settingName } // FIXME just placeholders for now QtControls.TabButton { text: connectionSpecificSetting.item.settingName } QtControls.TabButton { text: i18n("IP") } } StackLayout { Layout.fillWidth: true currentIndex: tabBar.currentIndex ConnectionSetting { id: connectionSetting } Loader { id: connectionSpecificSetting } } } function loadConnectionSettings() { connectionNameTextField.text = connectionSettingsObject.id // Load general connection setting connectionSetting.loadSettings() // Load connection specific setting if (connectionSettingsObject.connectionType == PlasmaNM.Enums.Wired) { connectionSpecificSetting.source = "WiredSetting.qml" } else if (connectionSettingsObject.connectionType == PlasmaNM.Enums.Wireless) { connectionSpecificSetting.source = "WirelessSetting.qml" } connectionSpecificSetting.item.loadSettings() } } diff --git a/kcm/package/contents/ui/main.qml b/kcm/package/contents/ui/main.qml index cb8a8726..909c7f27 100755 --- a/kcm/package/contents/ui/main.qml +++ b/kcm/package/contents/ui/main.qml @@ -1,259 +1,377 @@ /* Copyright 2016-2018 Jan Grulich This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ import "editor" import QtQuick 2.6 import QtQuick.Dialogs 1.1 +<<<<<<< HEAD import QtQuick.Layouts 1.2 import QtQuick.Controls 2.5 as QQC2 import org.kde.kcm 1.0 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.extras 2.0 as PlasmaExtras +======= +import QtQuick.Layouts 1.3 +import QtQuick.Controls 2.2 as QtControls + +import org.kde.kcm 1.2 +import org.kde.kirigami 2.3 as Kirigami // for Kirigami.Units +>>>>>>> 6cfc42e4... Attempt to use multipage KCM feature import org.kde.plasma.networkmanagement 0.2 as PlasmaNM import org.kde.kirigami 2.9 as Kirigami -Kirigami.ApplicationItem { +ScrollViewKCM { id: root + ConfigModule.quickHelp: i18n("Connections") + + title: i18n("Edit your Network Connections") + + property bool currentConnectionExportable: false + property string currentConnectionName + property string currentConnectionPath + property QtObject connectionSettingsObject: kcm.connectionSettings LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft LayoutMirroring.childrenInherit: true - wideScreen: width >= Kirigami.Units.gridUnit * 50 - - pageStack.defaultColumnWidth: Kirigami.Units.gridUnit * 25 - pageStack.initialPage: connectionView - SystemPalette { id: palette colorGroup: SystemPalette.Active } PlasmaNM.Handler { id: handler } PlasmaNM.KcmIdentityModel { id: connectionModel } PlasmaNM.EditorProxyModel { id: editorProxyModel sourceModel: connectionModel } - PlasmaNM.Configuration { - id: configuration - } + header: Rectangle { + color: Kirigami.Theme.backgroundColor - RowLayout { - anchors.fill: parent + width: root.width + height: Math.round(Kirigami.Units.gridUnit * 2.5) - spacing: units.smallSpacing + RowLayout { + id: searchLayout - ColumnLayout { + spacing: Kirigami.Units.smallSpacing + anchors { + fill: parent + margins: Kirigami.Units.smallSpacing + } - spacing: units.smallSpacing + QQC2.TextField { + id: searchField - ConnectionView { - id: connectionView + Layout.minimumHeight: Layout.maximumHeight + Layout.maximumHeight: Kirigami.Units.iconSizes.smallMedium + Kirigami.Units.smallSpacing * 2 Layout.fillWidth: true - Layout.fillHeight: true - Layout.minimumWidth: 300 - Layout.preferredWidth: 400 - } - RowLayout { - spacing: units.smallSpacing + focus: true + placeholderText: i18n("Type here to search connection...") - QQC2.TextField { - id: searchField + onTextChanged: { + editorProxyModel.setFilterRegExp(text) + } - Layout.fillWidth: true + MouseArea { + anchors { + right: parent.right + verticalCenter: parent.verticalCenter + rightMargin: y + } - placeholderText: i18n("Search...") + opacity: searchField.text.length > 0 ? 1 : 0 + width: Kirigami.Units.iconSizes.small + height: width - onTextChanged: { - editorProxyModel.setFilterRegExp(text) + onClicked: { + searchField.text = "" } - } - QQC2.ToolButton { - id: addConnectionButton + Kirigami.Icon { + anchors.fill: parent + source: LayoutMirroring.enabled ? "edit-clear-rtl" : "edit-clear" + } - width: Kirigami.Units.iconSizes.medium * 3 - height: Kirigami.Units.iconSizes.medium + Behavior on opacity { + OpacityAnimator { + duration: Kirigami.Units.longDuration + easing.type: Easing.InOutQuad + } + } + } + } + } - icon.name: "list-add" + Kirigami.Separator { + visible: !connectionView.atYBeginning + anchors { + left: parent.left + right: parent.right + top: parent.bottom + } + } + } - QQC2.ToolTip.text: i18n("Add new connection") - QQC2.ToolTip.visible: hovered + view: ListView { + id: connectionView + clip: true + model: editorProxyModel + currentIndex: -1 + boundsBehavior: Flickable.StopAtBounds + activeFocusOnTab: true + keyNavigationWraps: true + Accessible.role: Accessible.List + Keys.onTabPressed: { + if (applicationWindow().wideScreen && root.pageStack.depth > 1) { + connectionEditor.focus = true; + } + } - onClicked: { - addNewConnectionDialog.open() - } + section { + property: "KcmConnectionType" + delegate: Kirigami.AbstractListItem { + supportsMouseEvents: false + background: Rectangle { + color: palette.window } + QQC2.Label { + id: headerLabel + anchors.centerIn: parent + font.weight: Font.DemiBold + text: section + } + } + } + + delegate: ConnectionItemDelegate { + onAboutToChangeConnection: { +// // Shouldn't be problem to set this in advance +// root.currentConnectionExportable = exportable +// if (kcm.needsSave) { +// confirmSaveDialog.connectionName = name +// confirmSaveDialog.connectionPath = path +// confirmSaveDialog.open() +// } else { + root.currentConnectionName = name + root.currentConnectionPath = path + +// } + } + + onAboutToExportConnection: { + requestExportConnection(path) + } + + onAboutToRemoveConnection: { + deleteConfirmationDialog.connectionName = name + deleteConfirmationDialog.connectionPath = path + deleteConfirmationDialog.open() + } + } + } - QQC2.ToolButton { - id: removeConnectionButton + footer: Row { + layoutDirection: Qt.RightToLeft + spacing: Kirigami.Units.smallSpacing + padding: Kirigami.Units.smallSpacing - height: Kirigami.Units.iconSizes.medium - width: Kirigami.Units.iconSizes.medium + QQC2.Button { + id: exportConnectionButton - enabled: connectionView.currentConnectionPath && connectionView.currentConnectionPath.length - icon.name: "list-remove" + height: Kirigami.Units.iconSizes.medium + width: Kirigami.Units.iconSizes.medium - QQC2.ToolTip.text: i18n("Remove selected connection") - QQC2.ToolTip.visible: hovered - onClicked: { - deleteConfirmationDialog.connectionName = connectionView.currentConnectionName - deleteConfirmationDialog.connectionPath = connectionView.currentConnectionPath - deleteConfirmationDialog.open() - } - } + enabled: root.currentConnectionExportable + icon.name: "document-export" - QQC2.ToolButton { - id: exportConnectionButton + QQC2.ToolTip.text: i18n("Export selected connection") + QQC2.ToolTip.visible: hovered + + onClicked: { + kcm.requestExportConnection(root.currentConnectionPath) + } + } - height: Kirigami.Units.iconSizes.medium - width: Kirigami.Units.iconSizes.medium + QQC2.Button { + id: removeConnectionButton - enabled: connectionView.currentConnectionExportable - icon.name: "document-export" + height: Kirigami.Units.iconSizes.medium + width: Kirigami.Units.iconSizes.medium - QQC2.ToolTip.text: i18n("Export selected connection") - QQC2.ToolTip.visible: hovered + enabled: root.currentConnectionPath && root.currentConnectionPath.length + icon.name: "list-remove" - onClicked: { - kcm.requestExportConnection(connectionView.currentConnectionPath) - } - } + QQC2.ToolTip.text: i18n("Remove selected connection") + QQC2.ToolTip.visible: hovered + + onClicked: { + deleteConfirmationDialog.connectionName = root.currentConnectionName + deleteConfirmationDialog.connectionPath = root.currentConnectionPath + deleteConfirmationDialog.open() + } + } + + QQC2.Button { + id: addConnectionButton + + width: Kirigami.Units.iconSizes.medium + height: Kirigami.Units.iconSizes.medium + + icon.name: "list-add" + + QQC2.ToolTip.text: i18n("Add new connection") + QQC2.ToolTip.visible: hovered + + onClicked: { + addNewConnectionDialog.open() } } } ConnectionEditor { id: connectionEditor + opacity: applicationWindow().pageStack.currentIndex == 1 } Row { id: leftButtonRow anchors { bottom: parent.bottom left: parent.left margins: units.smallSpacing } spacing: units.smallSpacing QQC2.ToolButton { id: configureButton icon.name: "configure" QQC2.ToolTip.text: i18n("Configuration") QQC2.ToolTip.visible: hovered onClicked: { configurationDialog.open() } } } MessageDialog { id: deleteConfirmationDialog property string connectionName property string connectionPath icon: StandardIcon.Question standardButtons: StandardButton.Ok | StandardButton.Cancel title: i18nc("@title:window", "Remove Connection") text: i18n("Do you want to remove the connection '%1'?", connectionName) onAccepted: { if (connectionPath == connectionView.currentConnectionPath) { // Deselect now non-existing connection deselectConnectionsInView() } handler.removeConnection(connectionPath) } } MessageDialog { id: deleteConfirmationDialog property string connectionName property string connectionPath /* Like QString::toHtmlEscaped */ function toHtmlEscaped(s) { return s.replace(/[&<>]/g, function (tag) { return { '&': '&', '<': '<', '>': '>' }[tag] || tag }); } icon: StandardIcon.Question standardButtons: StandardButton.Ok | StandardButton.Cancel title: i18nc("@title:window", "Remove Connection") text: i18n("Do you want to remove the connection '%1'?", toHtmlEscaped(connectionName)) onAccepted: { if (connectionPath == connectionView.currentConnectionPath) { // Deselect now non-existing connection deselectConnections() } handler.removeConnection(connectionPath) } } AddConnectionDialog { id: addNewConnectionDialog onRequestCreateConnection: { root.requestCreateConnection(type, vpnType, specificType, shared) } } ConfigurationDialog { id: configurationDialog } + onCurrentConnectionPathChanged: { + if (currentConnectionPath) { + if (applicationWindow().pageStack.depth < 2) { + applicationWindow().pageStack.push(connectionEditor) + } else { + applicationWindow().pageStack.currentIndex = 1 + } + kcm.selectConnection(root.currentConnectionPath) + } + } + function loadConnectionSetting() { connectionEditor.loadConnectionSettings() } function deselectConnectionsInView() { connectionView.currentConnectionPath = "" } function selectConnectionInView(connectionName, connectionPath) { connectionView.currentConnectionName = connectionName connectionView.currentConnectionPath = connectionPath } } diff --git a/libs/declarative/qmlplugins.cpp b/libs/declarative/qmlplugins.cpp index 491c9889..3b22db19 100644 --- a/libs/declarative/qmlplugins.cpp +++ b/libs/declarative/qmlplugins.cpp @@ -1,73 +1,73 @@ /* Copyright 2013 Jan Grulich This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "qmlplugins.h" #include #include "availabledevices.h" #include "connectionicon.h" #include "enabledconnections.h" #include "networkstatus.h" #include "appletproxymodel.h" #include "configuration.h" #include "creatableconnectionsmodel.h" #include "editorproxymodel.h" #include "kcmidentitymodel.h" #include "networkmodel.h" -#include "mobileproxymodel.h" +// #include "mobileproxymodel.h" #include "utils.h" #include "handler.h" #include "enums.h" void QmlPlugins::registerTypes(const char* uri) { // @uri org.kde.plasma.networkmanagement.AvailableDevices qmlRegisterType(uri, 0, 2, "AvailableDevices"); // @uri org.kde.plasma.networkmanagement.ConnectionIcon qmlRegisterType(uri, 0, 2, "ConnectionIcon"); // @uri org.kde.plasma.networkmanagement.Configuration qmlRegisterType(uri, 0, 2, "Configuration"); // @uri org.kde.plasma.networkmanagement.EnabledConnections qmlRegisterType(uri, 0, 2, "EnabledConnections"); // @uri org.kde.plasma.networkmanagement.Enums qmlRegisterUncreatableType(uri, 0, 2, "Enums", "You cannot create Enums on yourself"); // @uri org.kde.plasma.networkmanagement.NetworkStatus qmlRegisterType(uri, 0, 2, "NetworkStatus"); // @uri org.kde.plasma.networkmanagement.Handler qmlRegisterType(uri, 0, 2, "Handler"); // @uri org.kde.plasma.networkmanagement.NetworkModel qmlRegisterType(uri, 0, 2, "NetworkModel"); // @uri org.kde.plasma.networkmanagement.AppletProxyModel qmlRegisterType(uri, 0, 2, "AppletProxyModel"); // @uri org.kde.plasma.networkmanagement.EditorProxyModel qmlRegisterType(uri, 0, 2, "EditorProxyModel"); // @uri org.kde.plasma.networkmanagement.KcmIdentityModel qmlRegisterType(uri, 0, 2, "KcmIdentityModel"); // @uri org.kde.plasma.networkmanagement.CreatableConnectionsModel qmlRegisterType(uri, 0, 2, "CreatableConnectionsModel"); // @uri org.kde.plasma.networkmanagement.MobileProxyModel - qmlRegisterType(uri, 0, 2, "MobileProxyModel"); +// qmlRegisterType(uri, 0, 2, "MobileProxyModel"); // @uri org.kde.plasma.networkmanagement.Utils qmlRegisterType(uri, 0, 2, "Utils"); } diff --git a/libs/handler.h b/libs/handler.h index 39a44e8c..a8f58152 100644 --- a/libs/handler.h +++ b/libs/handler.h @@ -1,157 +1,157 @@ /* Copyright 2013-2018 Jan Grulich This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #ifndef PLASMA_NM_HANDLER_H #define PLASMA_NM_HANDLER_H #include #include #include #include #include #include #if WITH_MODEMMANAGER_SUPPORT #include #endif class Q_DECL_EXPORT Handler : public QObject { Q_OBJECT public: enum HandlerAction { ActivateConnection, AddAndActivateConnection, AddConnection, DeactivateConnection, RemoveConnection, RequestScan, UpdateConnection, CreateHotspot, }; explicit Handler(QObject* parent = nullptr); ~Handler() override; Q_PROPERTY(bool hotspotSupported READ hotspotSupported NOTIFY hotspotSupportedChanged); public: bool hotspotSupported() const { return m_hotspotSupported; }; /** * Activates given connection * @connection - d-bus path of the connection you want to activate * @device - d-bus path of the device where the connection should be activated * @specificParameter - d-bus path of the specific object you want to use for this activation, i.e access point */ Q_INVOKABLE void activateConnection(const QString &connection, const QString &device, const QString &specificParameter); /** * Adds and activates a new wireless connection * @device - d-bus path of the wireless device where the connection should be activated * @specificParameter - d-bus path of the accesspoint you want to connect to * @password - pre-filled password which should be used for the new wireless connection * @autoConnect - boolean value whether this connection should be activated automatically when it's available * * Works automatically for wireless connections with WEP/WPA security, for wireless connections with WPA/WPA * it will open the connection editor for advanced configuration. * */ Q_INVOKABLE void addAndActivateConnection(const QString &device, const QString &specificParameter, const QString &password = QString()); /** * Returns a code that includes the credentials to a said wifi connection * Here's some information on how this information is created, it's generally used to put in QR codes to share. * https://github.com/zxing/zxing/wiki/Barcode-Contents#wi-fi-network-config-android-ios-11 * * @param connectionPath the d-bus path to the connection we want to read * @param ssid the name of the network being displayed * @param securityType the authentication protocol used for this specific ssid */ QString wifiCode(const QString& connectionPath, const QString& ssid, /*NetworkManager::WirelessSecurityType*/ int securityType) const; /** * Adds a new connection * @map - NMVariantMapMap with connection settings */ Q_INVOKABLE void addConnection(const NMVariantMapMap &map); /** * Deactivates given connection * @connection - d-bus path of the connection you want to deactivate * @device - d-bus path of the connection where the connection is activated */ Q_INVOKABLE void deactivateConnection(const QString &connection, const QString &device); /** * Disconnects all connections */ Q_INVOKABLE void disconnectAll(); Q_INVOKABLE void enableAirplaneMode(bool enable); Q_INVOKABLE void enableNetworking(bool enable); Q_INVOKABLE void enableWireless(bool enable); Q_INVOKABLE void enableWwan(bool enable); /** * Removes given connection * @connection - d-bus path of the connection you want to edit */ Q_INVOKABLE void removeConnection(const QString & connection); /** * Updates given connection * @connection - connection which should be updated * @map - NMVariantMapMap with new connection settings */ Q_INVOKABLE void updateConnection(const NetworkManager::Connection::Ptr &connection, const NMVariantMapMap &map); - Q_INVOKABLE void requestScan(const QString &interface); + Q_INVOKABLE void requestScan(const QString &interface = QString()); Q_INVOKABLE void createHotspot(); Q_INVOKABLE void stopHotspot(); private Q_SLOTS: void secretAgentError(const QString &connectionPath, const QString &message); void replyFinished(QDBusPendingCallWatcher *watcher); void hotspotCreated(QDBusPendingCallWatcher *watcher); void primaryConnectionTypeChanged(NetworkManager::ConnectionSettings::ConnectionType type); #if WITH_MODEMMANAGER_SUPPORT void unlockRequiredChanged(MMModemLock modemLock); #endif Q_SIGNALS: void connectionActivationFailed(const QString &connectionPath, const QString &message); void hotspotCreated(); void hotspotDisabled(); void hotspotSupportedChanged(bool hotspotSupported); private: bool m_hotspotSupported; bool m_tmpWirelessEnabled; bool m_tmpWwanEnabled; #if WITH_MODEMMANAGER_SUPPORT QString m_tmpConnectionPath; #endif QString m_tmpConnectionUuid; QString m_tmpDevicePath; QString m_tmpSpecificPath; QMap m_bluetoothAdapters; QMap m_wirelessScanRetryTimer; void enableBluetooth(bool enable); void scanRequestFailed(const QString &interface); bool checkRequestScanRateLimit(const NetworkManager::WirelessDevice::Ptr &wifiDevice); bool checkHotspotSupported(); void scheduleRequestScan(const QString &interface, int timeout); }; #endif // PLASMA_NM_HANDLER_H