diff --git a/IconButton.cxx b/IconButton.cxx index ba41bb6..5728cb8 100644 --- a/IconButton.cxx +++ b/IconButton.cxx @@ -1,79 +1,93 @@ // SPDX-License-Identifier: GPL-3.0-or-later /* - Copyright 2018 Martin Koller, kollix@aon.at + Copyright 2018 - 2020 Martin Koller, kollix@aon.at This file is part of liquidshell. liquidshell is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. liquidshell 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 General Public License for more details. You should have received a copy of the GNU General Public License along with liquidshell. If not, see . */ #include #include //-------------------------------------------------------------------------------- IconButton::IconButton(QWidget *parent) : QToolButton(parent) { setAutoRaise(true); setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum); QHBoxLayout *hbox = new QHBoxLayout(this); iconLabel = new QLabel; iconLabel->setFixedSize(iconSize()); iconLabel->setContextMenuPolicy(Qt::PreventContextMenu); hbox->addWidget(iconLabel); + icon2Label = new QLabel; + icon2Label->setFixedSize(iconSize()); + icon2Label->setContextMenuPolicy(Qt::PreventContextMenu); + icon2Label->hide(); // until an icon is set + hbox->addWidget(icon2Label); + textLabel = new QLabel; hbox->addWidget(textLabel); } //-------------------------------------------------------------------------------- IconButton::IconButton(QWidget *parent, const QIcon &icon, int theIconSize, const QString &name) : IconButton(parent) { if ( theIconSize != -1 ) setIconSize(QSize(theIconSize, theIconSize)); iconLabel->setFixedSize(iconSize()); iconLabel->setPixmap(icon.pixmap(iconSize())); textLabel->setText(name); } //-------------------------------------------------------------------------------- void IconButton::setText(const QString &txt) { textLabel->setText(txt); } //-------------------------------------------------------------------------------- void IconButton::setIcon(const QIcon &icon) { iconLabel->setPixmap(icon.pixmap(iconSize())); } //-------------------------------------------------------------------------------- +void IconButton::setIcon2(const QIcon &icon) +{ + icon2Label->setPixmap(icon.pixmap(iconSize())); + icon2Label->show(); +} + +//-------------------------------------------------------------------------------- + QSize IconButton::sizeHint() const { return layout()->sizeHint(); } //-------------------------------------------------------------------------------- diff --git a/IconButton.hxx b/IconButton.hxx index d5ec43b..f72dbd8 100644 --- a/IconButton.hxx +++ b/IconButton.hxx @@ -1,47 +1,49 @@ // SPDX-License-Identifier: GPL-3.0-or-later /* - Copyright 2018 Martin Koller, kollix@aon.at + Copyright 2018 - 2020 Martin Koller, kollix@aon.at This file is part of liquidshell. liquidshell is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. liquidshell 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 General Public License for more details. You should have received a copy of the GNU General Public License along with liquidshell. If not, see . */ #ifndef _IconButton_H_ #define _IconButton_H_ #include #include // button class to ensure the positioning of the icon and text independent of the style class IconButton : public QToolButton { Q_OBJECT public: IconButton(QWidget *parent = nullptr); IconButton(QWidget *parent, const QIcon &icon, int iconSize, const QString &name); void setText(const QString &txt); void setIcon(const QIcon &icon); + void setIcon2(const QIcon &icon); QSize sizeHint() const override; private: QLabel *iconLabel = nullptr; + QLabel *icon2Label = nullptr; QLabel *textLabel = nullptr; }; #endif diff --git a/NetworkList.cxx b/NetworkList.cxx index 6d61590..cc07171 100644 --- a/NetworkList.cxx +++ b/NetworkList.cxx @@ -1,366 +1,424 @@ // SPDX-License-Identifier: GPL-3.0-or-later /* - Copyright 2017 - 2019 Martin Koller, kollix@aon.at + Copyright 2017 - 2020 Martin Koller, kollix@aon.at This file is part of liquidshell. liquidshell is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. liquidshell 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 General Public License for more details. You should have received a copy of the GNU General Public License along with liquidshell. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include +#include + //-------------------------------------------------------------------------------- -NetworkButton::NetworkButton(NetworkManager::Connection::Ptr c, NetworkManager::Device::Ptr dev) +NetworkButton::NetworkButton(NetworkManager::Connection::Ptr c, NetworkManager::Device::Ptr dev, + NetworkManager::AccessPoint::Ptr accessPoint) : connection(c), device(dev) { setCheckable(true); if ( connection ) { for (const NetworkManager::ActiveConnection::Ptr &ac : NetworkManager::activeConnections()) { if ( ac->uuid() == c->uuid() ) { setChecked(true); break; } } - - connect(this, &NetworkButton::toggled, this, &NetworkButton::toggleNetworkStatus); } - else - setEnabled(false); + else if ( accessPoint ) + { + ssid = accessPoint->ssid(); + rawSsid = accessPoint->rawSsid(); + wpaFlags = accessPoint->wpaFlags(); + } + + connect(this, &NetworkButton::toggled, this, &NetworkButton::toggleNetworkStatus); } //-------------------------------------------------------------------------------- void NetworkButton::toggleNetworkStatus(bool on) { if ( on ) { + if ( !connection ) // no connection yet -> create one + { + // the connMap content was "reverse-engineered" by using qdbusviewer and the result of getting + // GetSettings of one of theSettings.Connection elements + + NMVariantMapMap connMap; + QVariantMap map; + map.insert("id", ssid); + + // ensure to not need root password by creating only for the current user + struct passwd *pwd = getpwuid(geteuid()); + if ( pwd ) + map.insert("permissions", QStringList(QString("user:") + QString::fromUtf8(pwd->pw_name))); + + connMap.insert("connection", map); + + QVariantMap wirelessMap; + wirelessMap.insert("ssid", rawSsid); + + if ( wpaFlags ) + { + wirelessMap.insert("security", "802-11-wireless-security"); + + QVariantMap security; + if ( wpaFlags & NetworkManager::AccessPoint::KeyMgmtPsk ) + security.insert("key-mgmt", QString("wpa-psk")); + else if ( wpaFlags & NetworkManager::AccessPoint::KeyMgmtSAE ) + security.insert("key-mgmt", QString("sae")); + else + { + // TODO: other types - find value names + } + + connMap.insert("802-11-wireless-security", security); + } + + connMap.insert("802-11-wireless", wirelessMap); + + QDBusPendingReply call = + NetworkManager::addAndActivateConnection(connMap, device->uni(), QString()); + + /* + QDBusPendingCallWatcher *pendingCallWatcher = new QDBusPendingCallWatcher(call, this); + connect(pendingCallWatcher, &QDBusPendingCallWatcher::finished, this, + [this](QDBusPendingCallWatcher *w) + { + w->deleteLater(); + QDBusPendingReply reply = *w; + qDebug() << reply.error(); + } + ); + */ + + // without closing our popup, the user can not enter the password in the password dialog which appears + window()->close(); + + return; + } + switch ( connection->settings()->connectionType() ) { case NetworkManager::ConnectionSettings::Wired: { NetworkManager::activateConnection(connection->path(), connection->settings()->interfaceName(), QString()); break; } case NetworkManager::ConnectionSettings::Wireless: { NetworkManager::activateConnection(connection->path(), device->uni(), QString()); break; } case NetworkManager::ConnectionSettings::Vpn: { NetworkManager::ActiveConnection::Ptr conn(NetworkManager::primaryConnection()); if ( conn && !conn->devices().isEmpty() ) NetworkManager::activateConnection(connection->path(), conn->devices()[0], QString()); break; } default: ; // TODO } } - else + else if ( connection ) { for (const NetworkManager::ActiveConnection::Ptr &ac : NetworkManager::activeConnections()) { if ( ac->uuid() == connection->uuid() ) { NetworkManager::deactivateConnection(ac->path()); break; } } } } //-------------------------------------------------------------------------------- //-------------------------------------------------------------------------------- //-------------------------------------------------------------------------------- NetworkList::NetworkList(QWidget *parent) : QFrame(parent) { setWindowFlags(windowFlags() | Qt::Popup); setFrameShape(QFrame::StyledPanel); QVBoxLayout *vbox = new QVBoxLayout(this); hbox = new QHBoxLayout; vbox->addLayout(hbox); network = new QToolButton; network->setIcon(QIcon::fromTheme("network-wired")); network->setToolTip(i18n("Enable Networking")); network->setCheckable(true); connect(network, &QToolButton::clicked, [](bool on) { NetworkManager::setNetworkingEnabled(on); }); connect(NetworkManager::notifier(), &NetworkManager::Notifier::networkingEnabledChanged, this, &NetworkList::statusUpdate); hbox->addWidget(network); wireless = new QToolButton; wireless->setIcon(QIcon::fromTheme("network-wireless")); wireless->setToolTip(i18n("Enable Wireless Networking")); wireless->setCheckable(true); connect(wireless, &QToolButton::clicked, [](bool on) { NetworkManager::setWirelessEnabled(on); }); connect(NetworkManager::notifier(), &NetworkManager::Notifier::wirelessEnabledChanged, this, &NetworkList::statusUpdate); hbox->addWidget(wireless); statusUpdate(); hbox->addStretch(); QToolButton *configure = new QToolButton; configure->setIcon(QIcon::fromTheme("configure")); configure->setToolTip(i18n("Configure Network Connections")); connect(configure, &QToolButton::clicked, this, &NetworkList::openConfigureDialog); hbox->addWidget(configure); // show connections QWidget *widget = new QWidget; connectionsVbox = new QVBoxLayout(widget); connectionsVbox->setContentsMargins(QMargins()); connectionsVbox->setSizeConstraint(QLayout::SetMinAndMaxSize); scroll = new QScrollArea; scroll->setWidgetResizable(true); scroll->setWidget(widget); vbox->addWidget(scroll); fillConnections(); QTimer *checkConnectionsTimer = new QTimer(this); checkConnectionsTimer->setInterval(1000); connect(checkConnectionsTimer, &QTimer::timeout, this, &NetworkList::fillConnections); checkConnectionsTimer->start(); } //-------------------------------------------------------------------------------- void NetworkList::openConfigureDialog() { // newer plasma has already a KCM KService::Ptr service = KService::serviceByDesktopName("kcm_networkmanagement"); if ( service ) KRun::runApplication(*service, QList(), this); else KRun::run("kde5-nm-connection-editor", QList(), this); close(); } //-------------------------------------------------------------------------------- void NetworkList::statusUpdate() { network->setChecked(NetworkManager::isNetworkingEnabled()); wireless->setChecked(NetworkManager::isWirelessEnabled()); } //-------------------------------------------------------------------------------- void NetworkList::fillConnections() { if ( underMouse() ) // avoid to delete the widget we are possibly hovering over return; QLayoutItem *child; while ( (child = connectionsVbox->takeAt(0)) ) { delete child->widget(); delete child; } NetworkManager::Connection::List allConnections = NetworkManager::listConnections(); // show VPN networks on top for (const NetworkManager::Connection::Ptr c : allConnections) { if ( !c->isValid() ) continue; if ( c->settings()->connectionType() == NetworkManager::ConnectionSettings::Vpn ) { NetworkButton *vpn = new NetworkButton(c); vpn->setText(c->name()); vpn->setIcon(QIcon::fromTheme("security-high")); connectionsVbox->addWidget(vpn); vpn->show(); } } // wired networks for (const NetworkManager::Connection::Ptr c : allConnections) { if ( !c->isValid() ) continue; if ( (c->settings()->connectionType() == NetworkManager::ConnectionSettings::Wired) && !c->uuid().isEmpty() ) { NetworkButton *net = new NetworkButton(c); net->setText(c->name()); net->setIcon(QIcon::fromTheme("network-wired")); connectionsVbox->addWidget(net); net->show(); } } // show available wifi networks if ( NetworkManager::isWirelessEnabled() ) { for (const NetworkManager::Device::Ptr &device : NetworkManager::networkInterfaces()) { if ( device->type() != NetworkManager::Device::Wifi ) continue; NetworkManager::WirelessDevice::Ptr wifiDevice = device.objectCast(); for (const NetworkManager::WirelessNetwork::Ptr &network : wifiDevice->networks()) { NetworkManager::AccessPoint::Ptr accessPoint = network->referenceAccessPoint(); if ( !accessPoint ) continue; // check if we have a connection for this SSID - bool haveConnection = false; NetworkManager::Connection::Ptr conn; for (const NetworkManager::Connection::Ptr c : allConnections) { if ( c->isValid() && (c->settings()->connectionType() == NetworkManager::ConnectionSettings::Wireless) ) { NetworkManager::Setting::Ptr setting = c->settings()->setting(NetworkManager::Setting::Wireless); NetworkManager::WirelessSetting::Ptr s = setting.staticCast(); if ( s->ssid() == network->ssid() ) { - haveConnection = true; conn = c; break; } } } - if ( haveConnection ) + NetworkButton *net; + + if ( conn ) { - NetworkButton *net = new NetworkButton(conn, device); + net = new NetworkButton(conn, device); net->setText(QString("%1 (%2%)").arg(conn->name()).arg(network->signalStrength())); - net->setIcon(QIcon::fromTheme("network-wireless")); - connectionsVbox->addWidget(net); - net->show(); } else { - NetworkButton *net = new NetworkButton; + net = new NetworkButton(nullptr, device, accessPoint); net->setText(QString("%1 (%2%)").arg(network->ssid()).arg(network->signalStrength())); - net->setIcon(QIcon::fromTheme("network-wireless")); - net->setEnabled(false); // TODO: allow to add a new connection. See NetworkManager::addAndActivateConnection - connectionsVbox->addWidget(net); - net->show(); } - /* - NetworkManager::WirelessSecurityType security = - NetworkManager::findBestWirelessSecurity(wifiDevice->wirelessCapabilities(), true, - wifiDevice->mode() == NetworkManager::WirelessDevice::Adhoc, - accessPoint->capabilities(), accessPoint->wpaFlags(), accessPoint->rsnFlags()); + net->setIcon(QIcon::fromTheme("network-wireless")); - if ( (security != NetworkManager::UnknownSecurity) && (security != NetworkManager::NoneSecurity) ) - net->setIcon(QIcon::fromTheme("object-locked")); + if ( accessPoint->wpaFlags() ) + net->setIcon2(QIcon::fromTheme("object-locked")); else - net->setIcon(QIcon::fromTheme("object-unlocked")); - */ + net->setIcon2(QIcon::fromTheme("object-unlocked")); + + connectionsVbox->addWidget(net); + net->show(); } } } #if 0 // TEST static int count = 15; for (int i = 0; i < count; i++) { NetworkButton *net = new NetworkButton(); net->setText(QString("dummy %1").arg(i)); net->setIcon(QIcon::fromTheme("network-wired")); connectionsVbox->addWidget(net); net->show(); } count -= 3; if ( count <= 0 ) count = 15; #endif connectionsVbox->addStretch(); adjustSize(); emit changed(); } //-------------------------------------------------------------------------------- QSize NetworkList::sizeHint() const { QWidget *w = scroll->widget(); QSize s; s.setHeight(frameWidth() + contentsMargins().top() + layout()->contentsMargins().top() + hbox->sizeHint().height() + ((layout()->spacing() == -1) ? style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing) : layout()->spacing()) + scroll->frameWidth() + scroll->contentsMargins().top() + w->sizeHint().height() + scroll->contentsMargins().bottom() + scroll->frameWidth() + layout()->contentsMargins().bottom() + contentsMargins().bottom() + frameWidth() ); s.setWidth(frameWidth() + contentsMargins().left() + layout()->contentsMargins().left() + scroll->frameWidth() + scroll->contentsMargins().left() + w->sizeHint().width() + scroll->verticalScrollBar()->sizeHint().width() + scroll->contentsMargins().right() + scroll->frameWidth() + layout()->contentsMargins().right() + contentsMargins().right() + frameWidth() ); return s; } //-------------------------------------------------------------------------------- diff --git a/NetworkList.hxx b/NetworkList.hxx index a9c7ecb..b1b6644 100644 --- a/NetworkList.hxx +++ b/NetworkList.hxx @@ -1,75 +1,80 @@ // SPDX-License-Identifier: GPL-3.0-or-later /* Copyright 2017 Martin Koller, kollix@aon.at This file is part of liquidshell. liquidshell is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. liquidshell 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 General Public License for more details. You should have received a copy of the GNU General Public License along with liquidshell. If not, see . */ #ifndef _NetworkList_H_ #define _NetworkList_H_ #include #include #include #include #include class NetworkList : public QFrame { Q_OBJECT public: NetworkList(QWidget *parent); QSize sizeHint() const override; Q_SIGNALS: void changed(); private Q_SLOTS: void statusUpdate(); void fillConnections(); void openConfigureDialog(); private: QToolButton *network, *wireless; QVBoxLayout *connectionsVbox; QHBoxLayout *hbox; QScrollArea *scroll; }; //-------------------------------------------------------------------------------- #include +#include #include class NetworkButton : public IconButton { Q_OBJECT public: - NetworkButton(NetworkManager::Connection::Ptr c = NetworkManager::Connection::Ptr(), - NetworkManager::Device::Ptr dev = NetworkManager::Device::Ptr()); + NetworkButton(NetworkManager::Connection::Ptr c = nullptr, + NetworkManager::Device::Ptr dev = nullptr, + NetworkManager::AccessPoint::Ptr accessPoint = nullptr); private Q_SLOTS: void toggleNetworkStatus(bool on); private: NetworkManager::Connection::Ptr connection; NetworkManager::Device::Ptr device; + QByteArray rawSsid; + QString ssid; + NetworkManager::AccessPoint::WpaFlags wpaFlags; }; #endif