diff --git a/libs/declarative/networkstatus.cpp b/libs/declarative/networkstatus.cpp index 00913310..b9db3768 100644 --- a/libs/declarative/networkstatus.cpp +++ b/libs/declarative/networkstatus.cpp @@ -1,243 +1,248 @@ /* 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 "networkstatus.h" #include "uiutils.h" #include #include #include #include NetworkStatus::SortedConnectionType NetworkStatus::connectionTypeToSortedType(NetworkManager::ConnectionSettings::ConnectionType type) { switch (type) { case NetworkManager::ConnectionSettings::Adsl: return NetworkStatus::NetworkStatus::Adsl; break; case NetworkManager::ConnectionSettings::Bluetooth: return NetworkStatus::Bluetooth; break; case NetworkManager::ConnectionSettings::Cdma: return NetworkStatus::Cdma; break; case NetworkManager::ConnectionSettings::Gsm: return NetworkStatus::Gsm; break; case NetworkManager::ConnectionSettings::Infiniband: return NetworkStatus::Infiniband; break; case NetworkManager::ConnectionSettings::OLPCMesh: return NetworkStatus::OLPCMesh; break; case NetworkManager::ConnectionSettings::Pppoe: return NetworkStatus::Pppoe; break; case NetworkManager::ConnectionSettings::Vpn: return NetworkStatus::Vpn; break; case NetworkManager::ConnectionSettings::Wired: return NetworkStatus::Wired; break; case NetworkManager::ConnectionSettings::Wireless: return NetworkStatus::Wireless; break; case NetworkManager::ConnectionSettings::WireGuard: return NetworkStatus::Wireguard; break; default: return NetworkStatus::Other; break; } } NetworkStatus::NetworkStatus(QObject* parent) : QObject(parent) { connect(NetworkManager::notifier(), &NetworkManager::Notifier::statusChanged, this, &NetworkStatus::statusChanged); connect(NetworkManager::notifier(), &NetworkManager::Notifier::activeConnectionsChanged, this, QOverload<>::of(&NetworkStatus::activeConnectionsChanged)); activeConnectionsChanged(); statusChanged(NetworkManager::status()); } NetworkStatus::~NetworkStatus() { } QString NetworkStatus::activeConnections() const { return m_activeConnections; } QString NetworkStatus::networkStatus() const { return m_networkStatus; } void NetworkStatus::activeConnectionsChanged() { for (const NetworkManager::ActiveConnection::Ptr & active : NetworkManager::activeConnections()) { connect(active.data(), &NetworkManager::ActiveConnection::default4Changed, this, &NetworkStatus::defaultChanged, Qt::UniqueConnection); connect(active.data(), &NetworkManager::ActiveConnection::default6Changed, this, &NetworkStatus::defaultChanged, Qt::UniqueConnection); connect(active.data(), &NetworkManager::ActiveConnection::stateChanged, this, &NetworkStatus::changeActiveConnections); } changeActiveConnections(); } void NetworkStatus::defaultChanged() { statusChanged(NetworkManager::status()); } void NetworkStatus::statusChanged(NetworkManager::Status status) { + const auto oldNetworkStatus = m_networkStatus; switch (status) { case NetworkManager::ConnectedLinkLocal: m_networkStatus = i18nc("A network device is connected, but there is only link-local connectivity", "Connected"); break; case NetworkManager::ConnectedSiteOnly: m_networkStatus = i18nc("A network device is connected, but there is only site-local connectivity", "Connected"); break; case NetworkManager::Connected: m_networkStatus = i18nc("A network device is connected, with global network connectivity", "Connected"); break; case NetworkManager::Asleep: m_networkStatus = i18nc("Networking is inactive and all devices are disabled", "Inactive"); break; case NetworkManager::Disconnected: m_networkStatus = i18nc("There is no active network connection", "Disconnected"); break; case NetworkManager::Disconnecting: m_networkStatus = i18nc("Network connections are being cleaned up", "Disconnecting"); break; case NetworkManager::Connecting: m_networkStatus = i18nc("A network device is connecting to a network and there is no other available network connection", "Connecting"); break; default: m_networkStatus = checkUnknownReason(); break; } if (status == NetworkManager::ConnectedLinkLocal || status == NetworkManager::ConnectedSiteOnly || status == NetworkManager::Connected) { changeActiveConnections(); - } else { + } else if (m_activeConnections != m_networkStatus) { m_activeConnections = m_networkStatus; Q_EMIT activeConnectionsChanged(m_activeConnections); } - Q_EMIT networkStatusChanged(m_networkStatus); + if (oldNetworkStatus != m_networkStatus) { + Q_EMIT networkStatusChanged(m_networkStatus); + } } void NetworkStatus::changeActiveConnections() { if (NetworkManager::status() != NetworkManager::Connected && NetworkManager::status() != NetworkManager::ConnectedLinkLocal && NetworkManager::status() != NetworkManager::ConnectedSiteOnly) { return; } QString activeConnections; const QString format = QStringLiteral("%1: %2"); QList activeConnectionList = NetworkManager::activeConnections(); std::sort(activeConnectionList.begin(), activeConnectionList.end(), [] (const NetworkManager::ActiveConnection::Ptr &left, const NetworkManager::ActiveConnection::Ptr &right) { return NetworkStatus::connectionTypeToSortedType(left->type()) < NetworkStatus::connectionTypeToSortedType(right->type()); }); for (const NetworkManager::ActiveConnection::Ptr &active : activeConnectionList) { if (!active->devices().isEmpty() && UiUtils::isConnectionTypeSupported(active->type())) { NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(active->devices().first()); if (device && ((device->type() != NetworkManager::Device::Generic && device->type() <= NetworkManager::Device::Team) || device->type() == 29)) { // TODO: Change to WireGuard enum value when it is added bool connecting = false; bool connected = false; QString conType; QString status; NetworkManager::VpnConnection::Ptr vpnConnection; if (active->vpn()) { conType = i18n("VPN"); vpnConnection = active.objectCast(); } else { conType = UiUtils::interfaceTypeLabel(device->type(), device); } if (vpnConnection && active->vpn()) { if (vpnConnection->state() >= NetworkManager::VpnConnection::Prepare && vpnConnection->state() <= NetworkManager::VpnConnection::GettingIpConfig) { connecting = true; } else if (vpnConnection->state() == NetworkManager::VpnConnection::Activated) { connected = true; } } else { if (active->state() == NetworkManager::ActiveConnection::Activated) { connected = true; } else if (active->state() == NetworkManager::ActiveConnection::Activating) { connecting = true; } } if (active->type() == NetworkManager::ConnectionSettings::ConnectionType::WireGuard) { conType = i18n("WireGuard"); connected = true; } NetworkManager::Connection::Ptr connection = active->connection(); if (connecting) { status = i18n("Connecting to %1", connection->name()); } else if (connected) { status = i18n("Connected to %1", connection->name()); } if (!activeConnections.isEmpty()) { activeConnections += '\n'; } activeConnections += format.arg(conType, status); connect(connection.data(), &NetworkManager::Connection::updated, this, &NetworkStatus::changeActiveConnections, Qt::UniqueConnection); } } } - m_activeConnections = activeConnections; - Q_EMIT activeConnectionsChanged(activeConnections); + if (m_activeConnections != activeConnections) { + m_activeConnections = activeConnections; + Q_EMIT activeConnectionsChanged(activeConnections); + } } QString NetworkStatus::checkUnknownReason() const { // Check if NetworkManager is running. if (!QDBusConnection::systemBus().interface()->isServiceRegistered(NM_DBUS_INTERFACE)) { return i18n("NetworkManager not running"); } // Check for compatible NetworkManager version. if (NetworkManager::compareVersion(0, 9, 8) < 0) { return i18n("NetworkManager 0.9.8 required, found %1.", NetworkManager::version()); } return i18nc("global connection state", "Unknown"); } diff --git a/libs/models/networkmodel.cpp b/libs/models/networkmodel.cpp index d1611c5b..350525c4 100644 --- a/libs/models/networkmodel.cpp +++ b/libs/models/networkmodel.cpp @@ -1,1051 +1,1052 @@ /* 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 . */ #include "networkmodel.h" #include "networkmodelitem.h" #include "debug.h" #include "uiutils.h" #if WITH_MODEMMANAGER_SUPPORT #include #include #endif #include #include NetworkModel::NetworkModel(QObject *parent) : QAbstractListModel(parent) { QLoggingCategory::setFilterRules(QStringLiteral("plasma-nm.debug = false")); initialize(); } NetworkModel::~NetworkModel() { } QVariant NetworkModel::data(const QModelIndex &index, int role) const { const int row = index.row(); if (row >= 0 && row < m_list.count()) { NetworkModelItem *item = m_list.itemAt(row); switch (role) { case ConnectionDetailsRole: return item->details(); case ConnectionIconRole: return item->icon(); case ConnectionPathRole: return item->connectionPath(); case ConnectionStateRole: return item->connectionState(); case DeviceName: return item->deviceName(); case DevicePathRole: return item->devicePath(); case DeviceStateRole: return item->deviceState(); case DuplicateRole: return item->duplicate(); case ItemUniqueNameRole: if (m_list.returnItems(NetworkItemsList::Name, item->name()).count() > 1) { return item->originalName(); } else { return item->name(); } case ItemTypeRole: return item->itemType(); case LastUsedRole: return UiUtils::formatLastUsedDateRelative(item->timestamp()); case LastUsedDateOnlyRole: return UiUtils::formatDateRelative(item->timestamp()); case NameRole: return item->name(); case SectionRole: return item->sectionType(); case SignalRole: return item->signal(); case SlaveRole: return item->slave(); case SsidRole: return item->ssid(); case SpecificPathRole: return item->specificPath(); case SecurityTypeRole: return item->securityType(); case SecurityTypeStringRole: return UiUtils::labelFromWirelessSecurity(item->securityType()); case TimeStampRole: return item->timestamp(); case TypeRole: return item->type(); case UniRole: return item->uni(); case UuidRole: return item->uuid(); case VpnState: return item->vpnState(); case VpnType: return item->vpnType(); case RxBytesRole: return item->rxBytes(); case TxBytesRole: return item->txBytes(); default: break; } } return QVariant(); } int NetworkModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); return parent.isValid() ? 0 : m_list.count(); } QHash NetworkModel::roleNames() const { QHash roles = QAbstractListModel::roleNames(); roles[ConnectionDetailsRole] = "ConnectionDetails"; roles[ConnectionIconRole] = "ConnectionIcon"; roles[ConnectionPathRole] = "ConnectionPath"; roles[ConnectionStateRole] = "ConnectionState"; roles[DeviceName] = "DeviceName"; roles[DevicePathRole] = "DevicePath"; roles[DeviceStateRole] = "DeviceState"; roles[DuplicateRole] = "Duplicate"; roles[ItemUniqueNameRole] = "ItemUniqueName"; roles[ItemTypeRole] = "ItemType"; roles[LastUsedRole] = "LastUsed"; roles[LastUsedDateOnlyRole] = "LastUsedDateOnly"; roles[NameRole] = "Name"; roles[SectionRole] = "Section"; roles[SignalRole] = "Signal"; roles[SlaveRole] = "Slave"; roles[SsidRole] = "Ssid"; roles[SpecificPathRole] = "SpecificPath"; roles[SecurityTypeRole] = "SecurityType"; roles[SecurityTypeStringRole] = "SecurityTypeString"; roles[TimeStampRole] = "TimeStamp"; roles[TypeRole] = "Type"; roles[UniRole] = "Uni"; roles[UuidRole] = "Uuid"; roles[VpnState] = "VpnState"; roles[VpnType] = "VpnType"; roles[RxBytesRole] = "RxBytes"; roles[TxBytesRole] = "TxBytes"; return roles; } void NetworkModel::initialize() { // Initialize existing connections for (const NetworkManager::Connection::Ptr &connection : NetworkManager::listConnections()) { addConnection(connection); } // Initialize existing devices for (const NetworkManager::Device::Ptr &dev : NetworkManager::networkInterfaces()) { addDevice(dev); } // Initialize existing active connections for (const NetworkManager::ActiveConnection::Ptr &active : NetworkManager::activeConnections()) { addActiveConnection(active); } initializeSignals(); } void NetworkModel::initializeSignals() { connect(NetworkManager::notifier(), &NetworkManager::Notifier::activeConnectionAdded, this, &NetworkModel::activeConnectionAdded, Qt::UniqueConnection); connect(NetworkManager::notifier(), &NetworkManager::Notifier::activeConnectionRemoved, this, &NetworkModel::activeConnectionRemoved, Qt::UniqueConnection); connect(NetworkManager::settingsNotifier(), &NetworkManager::SettingsNotifier::connectionAdded, this, &NetworkModel::connectionAdded, Qt::UniqueConnection); connect(NetworkManager::settingsNotifier(), &NetworkManager::SettingsNotifier::connectionRemoved, this, &NetworkModel::connectionRemoved, Qt::UniqueConnection); connect(NetworkManager::notifier(), &NetworkManager::Notifier::deviceAdded, this, &NetworkModel::deviceAdded, Qt::UniqueConnection); connect(NetworkManager::notifier(), &NetworkManager::Notifier::deviceRemoved, this, &NetworkModel::deviceRemoved, Qt::UniqueConnection); connect(NetworkManager::notifier(), &NetworkManager::Notifier::statusChanged, this, &NetworkModel::statusChanged, Qt::UniqueConnection); } void NetworkModel::initializeSignals(const NetworkManager::ActiveConnection::Ptr &activeConnection) { if (activeConnection->vpn()) { NetworkManager::VpnConnection::Ptr vpnConnection = activeConnection.objectCast(); if (vpnConnection) { connect(vpnConnection.data(), &NetworkManager::VpnConnection::stateChanged, this, &NetworkModel::activeVpnConnectionStateChanged, Qt::UniqueConnection); } } else { connect(activeConnection.data(), &NetworkManager::ActiveConnection::stateChanged, this, &NetworkModel::activeConnectionStateChanged, Qt::UniqueConnection); } } void NetworkModel::initializeSignals(const NetworkManager::Connection::Ptr &connection) { connect(connection.data(), &NetworkManager::Connection::updated, this, &NetworkModel::connectionUpdated, Qt::UniqueConnection); } void NetworkModel::initializeSignals(const NetworkManager::Device::Ptr &device) { connect(device.data(), &NetworkManager::Device::availableConnectionAppeared, this, &NetworkModel::availableConnectionAppeared, Qt::UniqueConnection); connect(device.data(), &NetworkManager::Device::availableConnectionDisappeared, this, &NetworkModel::availableConnectionDisappeared, Qt::UniqueConnection); connect(device.data(), &NetworkManager::Device::ipV4ConfigChanged, this, &NetworkModel::ipConfigChanged, Qt::UniqueConnection); connect(device.data(), &NetworkManager::Device::ipV6ConfigChanged, this, &NetworkModel::ipConfigChanged, Qt::UniqueConnection); connect(device.data(), &NetworkManager::Device::ipInterfaceChanged, this, &NetworkModel::ipInterfaceChanged); connect(device.data(), &NetworkManager::Device::stateChanged, this, &NetworkModel::deviceStateChanged, Qt::UniqueConnection); auto deviceStatistics = device->deviceStatistics(); connect(deviceStatistics.data(), &NetworkManager::DeviceStatistics::rxBytesChanged, this, [this, device](qulonglong rxBytes) { for (auto *item : m_list.returnItems(NetworkItemsList::Device, device->uni())) { item->setRxBytes(rxBytes); updateItem(item); } }); connect(deviceStatistics.data(), &NetworkManager::DeviceStatistics::txBytesChanged, this, [this, device](qulonglong txBytes) { for (auto *item : m_list.returnItems(NetworkItemsList::Device, device->uni())) { item->setTxBytes(txBytes); updateItem(item); } }); if (device->type() == NetworkManager::Device::Wifi) { NetworkManager::WirelessDevice::Ptr wifiDev = device.objectCast(); connect(wifiDev.data(), &NetworkManager::WirelessDevice::networkAppeared, this, &NetworkModel::wirelessNetworkAppeared, Qt::UniqueConnection); connect(wifiDev.data(), &NetworkManager::WirelessDevice::networkDisappeared, this, &NetworkModel::wirelessNetworkDisappeared, Qt::UniqueConnection); } #if WITH_MODEMMANAGER_SUPPORT else if (device->type() == NetworkManager::Device::Modem) { ModemManager::ModemDevice::Ptr modem = ModemManager::findModemDevice(device->udi()); if (modem) { if (modem->hasInterface(ModemManager::ModemDevice::ModemInterface)) { ModemManager::Modem::Ptr modemNetwork = modem->interface(ModemManager::ModemDevice::ModemInterface).objectCast(); if (modemNetwork) { connect(modemNetwork.data(), &ModemManager::Modem::signalQualityChanged, this, &NetworkModel::gsmNetworkSignalQualityChanged, Qt::UniqueConnection); connect(modemNetwork.data(), &ModemManager::Modem::accessTechnologiesChanged, this, &NetworkModel::gsmNetworkAccessTechnologiesChanged, Qt::UniqueConnection); connect(modemNetwork.data(), &ModemManager::Modem::currentModesChanged, this, &NetworkModel::gsmNetworkCurrentModesChanged, Qt::UniqueConnection); } } } } #endif } void NetworkModel::initializeSignals(const NetworkManager::WirelessNetwork::Ptr &network) { connect(network.data(), &NetworkManager::WirelessNetwork::signalStrengthChanged, this, &NetworkModel::wirelessNetworkSignalChanged, Qt::UniqueConnection); connect(network.data(), &NetworkManager::WirelessNetwork::referenceAccessPointChanged, this, &NetworkModel::wirelessNetworkReferenceApChanged, Qt::UniqueConnection); } void NetworkModel::addActiveConnection(const NetworkManager::ActiveConnection::Ptr &activeConnection) { initializeSignals(activeConnection); NetworkManager::Device::Ptr device; NetworkManager::Connection::Ptr connection = activeConnection->connection(); // Not necessary to have device for VPN connections if (activeConnection && !activeConnection->vpn() && !activeConnection->devices().isEmpty()) { device = NetworkManager::findNetworkInterface(activeConnection->devices().first()); } // Check whether we have a base connection if (!m_list.contains(NetworkItemsList::Uuid, connection->uuid())) { // Active connection appeared before a base connection, so we have to add its base connection first addConnection(connection); } beginResetModel(); for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::NetworkItemsList::Uuid, connection->uuid())) { if (((device && device->uni() == item->devicePath()) || item->devicePath().isEmpty()) || item->type() == NetworkManager::ConnectionSettings::Vpn) { item->setActiveConnectionPath(activeConnection->path()); item->setConnectionState(activeConnection->state()); if (activeConnection->vpn()) { NetworkManager::VpnConnection::Ptr vpnConnection = activeConnection.objectCast(); NetworkManager::VpnConnection::State state = vpnConnection->state(); if (state == NetworkManager::VpnConnection::Prepare || state == NetworkManager::VpnConnection::NeedAuth || state == NetworkManager::VpnConnection::Connecting || state == NetworkManager::VpnConnection::GettingIpConfig) { item->setConnectionState(NetworkManager::ActiveConnection::Activating); } else if (state == NetworkManager::VpnConnection::Activated) { item->setConnectionState(NetworkManager::ActiveConnection::Activated); } else { item->setConnectionState(NetworkManager::ActiveConnection::Deactivated); } item->setVpnState(state); } item->invalidateDetails(); qCDebug(PLASMA_NM) << "Item " << item->name() << ": active connection state changed to " << item->connectionState(); if (device && device->uni() == item->devicePath()) { auto deviceStatistics = device->deviceStatistics(); item->setRxBytes(deviceStatistics->rxBytes()); item->setTxBytes(deviceStatistics->txBytes()); } } } endResetModel(); } void NetworkModel::addAvailableConnection(const QString &connection, const NetworkManager::Device::Ptr &device) { if (!device) { return; } checkAndCreateDuplicate(connection, device->uni()); for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Connection, connection)) { // The item is already associated with another device if (!device || !item->devicePath().isEmpty()) { continue; } if (device->ipInterfaceName().isEmpty()) { item->setDeviceName(device->interfaceName()); } else { item->setDeviceName(device->ipInterfaceName()); } item->setDevicePath(device->uni()); item->setDeviceState(device->state()); qCDebug(PLASMA_NM) << "Item " << item->name() << ": device changed to " << item->devicePath(); #if WITH_MODEMMANAGER_SUPPORT if (device->type() == NetworkManager::Device::Modem) { ModemManager::ModemDevice::Ptr modemDevice = ModemManager::findModemDevice(device->udi()); if (modemDevice) { ModemManager::Modem::Ptr modemInterface = modemDevice->interface(ModemManager::ModemDevice::ModemInterface).objectCast(); if (modemInterface) { item->setSignal(modemInterface->signalQuality().signal); qCDebug(PLASMA_NM) << "Item " << item->name() << ": signal changed to " << item->signal(); } } } #endif if (item->type() == NetworkManager::ConnectionSettings::Wireless && item->mode() == NetworkManager::WirelessSetting::Infrastructure) { // Find an accesspoint which could be removed, because it will be merged with a connection for (NetworkModelItem *secondItem : m_list.returnItems(NetworkItemsList::Ssid, item->ssid())) { if (secondItem->itemType() == NetworkModelItem::AvailableAccessPoint && secondItem->devicePath() == item->devicePath()) { const int row = m_list.indexOf(secondItem); qCDebug(PLASMA_NM) << "Access point " << secondItem->name() << ": merged to " << item->name() << " connection"; if (row >= 0) { beginRemoveRows(QModelIndex(), row, row); m_list.removeItem(secondItem); secondItem->deleteLater(); endRemoveRows(); } break; } } NetworkManager::WirelessDevice::Ptr wifiDevice = device.objectCast(); if (wifiDevice) { NetworkManager::WirelessNetwork::Ptr wifiNetwork = wifiDevice->findNetwork(item->ssid()); if (wifiNetwork) { updateFromWirelessNetwork(item, wifiNetwork, wifiDevice); } } } updateItem(item); break; } } void NetworkModel::addConnection(const NetworkManager::Connection::Ptr &connection) { // Can't add a connection without name or uuid if (connection->name().isEmpty() || connection->uuid().isEmpty()) { return; } initializeSignals(connection); NetworkManager::ConnectionSettings::Ptr settings = connection->settings(); NetworkManager::VpnSetting::Ptr vpnSetting; NetworkManager::WirelessSetting::Ptr wirelessSetting; if (settings->connectionType() == NetworkManager::ConnectionSettings::Vpn) { vpnSetting = settings->setting(NetworkManager::Setting::Vpn).dynamicCast(); } else if (settings->connectionType() == NetworkManager::ConnectionSettings::Wireless) { wirelessSetting = settings->setting(NetworkManager::Setting::Wireless).dynamicCast(); } // Check whether the connection is already in the model to avoid duplicates, but this shouldn't happen if (!m_list.contains(NetworkItemsList::Connection, connection->path())) { NetworkModelItem *item = new NetworkModelItem(); item->setConnectionPath(connection->path()); item->setName(settings->id()); item->setTimestamp(settings->timestamp()); item->setType(settings->connectionType()); item->setUuid(settings->uuid()); item->setSlave(settings->isSlave()); if (item->type() == NetworkManager::ConnectionSettings::Vpn) { item->setVpnType(vpnSetting->serviceType().section('.', -1)); } else if (item->type() == NetworkManager::ConnectionSettings::Wireless) { item->setMode(wirelessSetting->mode()); item->setSecurityType(NetworkManager::securityTypeFromConnectionSetting(settings)); item->setSsid(QString::fromUtf8(wirelessSetting->ssid())); } item->invalidateDetails(); const int index = m_list.count(); beginInsertRows(QModelIndex(), index, index); m_list.insertItem(item); endInsertRows(); qCDebug(PLASMA_NM) << "New connection " << item->name() << " added"; } } void NetworkModel::addDevice(const NetworkManager::Device::Ptr &device) { initializeSignals(device); if (device->type() == NetworkManager::Device::Wifi) { NetworkManager::WirelessDevice::Ptr wifiDev = device.objectCast(); for (const NetworkManager::WirelessNetwork::Ptr &wifiNetwork : wifiDev->networks()) { addWirelessNetwork(wifiNetwork, wifiDev); } } for (const NetworkManager::Connection::Ptr &connection : device->availableConnections()) { addAvailableConnection(connection->path(), device); } } void NetworkModel::addWirelessNetwork(const NetworkManager::WirelessNetwork::Ptr &network, const NetworkManager::WirelessDevice::Ptr &device) { initializeSignals(network); // BUG: 386342 // When creating a new hidden wireless network and attempting to connect to it, NM then later reports that AccessPoint appeared, but // it doesn't know its SSID from some reason, this also makes Wireless device to advertise a new available connection, which we later // attempt to merge with an AP, based on its SSID, but it doesn't find any, because we have AP with empty SSID. After this we get another // AccessPoint appeared signal, this time we know SSID, but we don't attempt any merging, because it's usually the other way around, thus // we need to attempt to merge it here with a connection we guess it's related to this new AP for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Type, NetworkManager::ConnectionSettings::Wireless)) { if (item->itemType() == NetworkModelItem::AvailableConnection) { NetworkManager::ConnectionSettings::Ptr connectionSettings = NetworkManager::findConnection(item->connectionPath())->settings(); if (connectionSettings && connectionSettings->connectionType() == NetworkManager::ConnectionSettings::Wireless) { NetworkManager::WirelessSetting::Ptr wirelessSetting = connectionSettings->setting(NetworkManager::Setting::Wireless).dynamicCast(); if (QString::fromUtf8(wirelessSetting->ssid()) == network->ssid()) { const QString bssid = NetworkManager::macAddressAsString(wirelessSetting->bssid()); const QString restrictedHw = NetworkManager::macAddressAsString(wirelessSetting->macAddress()); if ((bssid.isEmpty() || bssid == network->referenceAccessPoint()->hardwareAddress()) && (restrictedHw.isEmpty() || restrictedHw == device->hardwareAddress())) { updateFromWirelessNetwork(item, network, device); return; } } } } } NetworkManager::WirelessSetting::NetworkMode mode = NetworkManager::WirelessSetting::Infrastructure; NetworkManager::WirelessSecurityType securityType = NetworkManager::UnknownSecurity; NetworkManager::AccessPoint::Ptr ap = network->referenceAccessPoint(); if (ap && ap->capabilities().testFlag(NetworkManager::AccessPoint::Privacy)) { securityType = NetworkManager::findBestWirelessSecurity(device->wirelessCapabilities(), true, (device->mode() == NetworkManager::WirelessDevice::Adhoc), ap->capabilities(), ap->wpaFlags(), ap->rsnFlags()); if (network->referenceAccessPoint()->mode() == NetworkManager::AccessPoint::Infra) { mode = NetworkManager::WirelessSetting::Infrastructure; } else if (network->referenceAccessPoint()->mode() == NetworkManager::AccessPoint::Adhoc) { mode = NetworkManager::WirelessSetting::Adhoc; } else if (network->referenceAccessPoint()->mode() == NetworkManager::AccessPoint::ApMode) { mode = NetworkManager::WirelessSetting::Ap; } } NetworkModelItem *item = new NetworkModelItem(); if (device->ipInterfaceName().isEmpty()) { item->setDeviceName(device->interfaceName()); } else { item->setDeviceName(device->ipInterfaceName()); } item->setDevicePath(device->uni()); item->setMode(mode); item->setName(network->ssid()); item->setSignal(network->signalStrength()); item->setSpecificPath(network->referenceAccessPoint()->uni()); item->setSsid(network->ssid()); item->setType(NetworkManager::ConnectionSettings::Wireless); item->setSecurityType(securityType); item->invalidateDetails(); const int index = m_list.count(); beginInsertRows(QModelIndex(), index, index); m_list.insertItem(item); endInsertRows(); qCDebug(PLASMA_NM) << "New wireless network " << item->name() << " added"; } void NetworkModel::checkAndCreateDuplicate(const QString &connection, const QString &deviceUni) { bool createDuplicate = false; NetworkModelItem *originalItem = nullptr; for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Connection, connection)) { if (!item->duplicate()) { originalItem = item; } if (!item->duplicate() && item->itemType() == NetworkModelItem::AvailableConnection && (item->devicePath() != deviceUni && !item->devicePath().isEmpty())) { createDuplicate = true; } } if (createDuplicate) { NetworkModelItem *duplicatedItem = new NetworkModelItem(originalItem); duplicatedItem->invalidateDetails(); const int index = m_list.count(); beginInsertRows(QModelIndex(), index, index); m_list.insertItem(duplicatedItem); endInsertRows(); } } void NetworkModel::onItemUpdated() { NetworkModelItem *item = static_cast(sender()); if (item) { updateItem(item); } } void NetworkModel::setDeviceStatisticsRefreshRateMs(const QString &devicePath, uint refreshRate) { NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(devicePath); if (device) { device->deviceStatistics()->setRefreshRateMs(refreshRate); } } void NetworkModel::updateItem(NetworkModelItem*item) { const int row = m_list.indexOf(item); if (row >= 0) { item->invalidateDetails(); QModelIndex index = createIndex(row, 0); - Q_EMIT dataChanged(index, index); + Q_EMIT dataChanged(index, index, item->changedRoles()); + item->clearChangedRoles(); } } void NetworkModel::accessPointSignalStrengthChanged(int signal) { NetworkManager::AccessPoint *apPtr = qobject_cast(sender()); if (apPtr) { for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Ssid, apPtr->ssid())) { if (item->specificPath() == apPtr->uni()) { item->setSignal(signal); updateItem(item); qCDebug(PLASMA_NM) << "AccessPoint " << item->name() << ": signal changed to " << item->signal(); } } } } void NetworkModel::activeConnectionAdded(const QString &activeConnection) { NetworkManager::ActiveConnection::Ptr activeCon = NetworkManager::findActiveConnection(activeConnection); if (activeCon) { addActiveConnection(activeCon); } } void NetworkModel::activeConnectionRemoved(const QString &activeConnection) { for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::ActiveConnection, activeConnection)) { item->setActiveConnectionPath(QString()); item->setConnectionState(NetworkManager::ActiveConnection::Deactivated); item->setVpnState(NetworkManager::VpnConnection::Disconnected); updateItem(item); qCDebug(PLASMA_NM) << "Item " << item->name() << ": active connection removed"; } } void NetworkModel::activeConnectionStateChanged(NetworkManager::ActiveConnection::State state) { NetworkManager::ActiveConnection *activePtr = qobject_cast(sender()); if (activePtr) { beginResetModel(); for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::ActiveConnection, activePtr->path())) { item->setConnectionState(state); item->invalidateDetails(); qCDebug(PLASMA_NM) << "Item " << item->name() << ": active connection changed to " << item->connectionState(); } endResetModel(); } } void NetworkModel::activeVpnConnectionStateChanged(NetworkManager::VpnConnection::State state, NetworkManager::VpnConnection::StateChangeReason reason) { Q_UNUSED(reason) NetworkManager::ActiveConnection *activePtr = qobject_cast(sender()); if (activePtr) { for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::ActiveConnection, activePtr->path())) { if (state == NetworkManager::VpnConnection::Prepare || state == NetworkManager::VpnConnection::NeedAuth || state == NetworkManager::VpnConnection::Connecting || state == NetworkManager::VpnConnection::GettingIpConfig) { item->setConnectionState(NetworkManager::ActiveConnection::Activating); } else if (state == NetworkManager::VpnConnection::Activated) { item->setConnectionState(NetworkManager::ActiveConnection::Activated); } else { item->setConnectionState(NetworkManager::ActiveConnection::Deactivated); } item->setVpnState(state); updateItem(item); qCDebug(PLASMA_NM) << "Item " << item->name() << ": active connection changed to " << item->connectionState(); } } } void NetworkModel::availableConnectionAppeared(const QString &connection) { NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(qobject_cast(sender())->uni()); if (device) { beginResetModel(); addAvailableConnection(connection, device); endResetModel(); } } void NetworkModel::availableConnectionDisappeared(const QString &connection) { for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Connection, connection)) { bool available = false; const QString devicePath = item->devicePath(); const QString specificPath = item->specificPath(); // We have to check whether the connection is still available, because it might be // presented in the model for more devices and we don't want to remove it for all of them. // Check whether the device is still available NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(devicePath); if (device) { // Check whether the connection is still listed as available for (const NetworkManager::Connection::Ptr &connection : device->availableConnections()) { if (connection->path() == item->connectionPath()) { available = true; break; } } } if (!available) { item->setDeviceName(QString()); item->setDevicePath(QString()); item->setDeviceState(NetworkManager::Device::UnknownState); item->setSignal(0); item->setSpecificPath(QString()); qCDebug(PLASMA_NM) << "Item " << item->name() << " removed as available connection"; // Check whether the connection is still available as an access point, this happens // when we change its properties, like ssid, bssid, security etc. if (item->type() == NetworkManager::ConnectionSettings::Wireless && !specificPath.isEmpty()) { if (device && device->type() == NetworkManager::Device::Wifi) { NetworkManager::WirelessDevice::Ptr wifiDevice = device.objectCast(); if (wifiDevice) { NetworkManager::AccessPoint::Ptr ap = wifiDevice->findAccessPoint(specificPath); if (ap) { NetworkManager::WirelessNetwork::Ptr network = wifiDevice->findNetwork(ap->ssid()); if (network) { addWirelessNetwork(network, wifiDevice); } } } } } if (item->duplicate()) { const int row = m_list.indexOf(item); if (row >= 0) { qCDebug(PLASMA_NM) << "Duplicate item " << item->name() << " removed completely"; beginRemoveRows(QModelIndex(), row, row); m_list.removeItem(item); item->deleteLater(); endRemoveRows(); } } else { updateItem(item); } } available = false; } } void NetworkModel::connectionAdded(const QString &connection) { NetworkManager::Connection::Ptr newConnection = NetworkManager::findConnection(connection); if (newConnection) { addConnection(newConnection); } } void NetworkModel::connectionRemoved(const QString &connection) { bool remove = false; for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Connection, connection)) { // When the item type is wireless, we can remove only the connection and leave it as an available access point if (item->type() == NetworkManager::ConnectionSettings::Wireless && !item->devicePath().isEmpty()) { for (NetworkModelItem *secondItem : m_list.items()) { // Remove it entirely when there is another connection with the same configuration and for the same device // or it's a shared connection if ((item->mode() != NetworkManager::WirelessSetting::Infrastructure) || (item->connectionPath() != secondItem->connectionPath() && item->devicePath() == secondItem->devicePath() && item->mode() == secondItem->mode() && item->securityType() == secondItem->securityType() && item->ssid() == secondItem->ssid())) { remove = true; break; } } if (!remove) { item->setConnectionPath(QString()); item->setName(item->ssid()); item->setSlave(false); item->setTimestamp(QDateTime()); item->setUuid(QString()); updateItem(item); qCDebug(PLASMA_NM) << "Item " << item->name() << ": connection removed"; } } else { remove = true; } if (remove) { const int row = m_list.indexOf(item); if (row >= 0) { qCDebug(PLASMA_NM) << "Item " << item->name() << " removed completely"; beginRemoveRows(QModelIndex(), row, row); m_list.removeItem(item); item->deleteLater(); endRemoveRows(); } } remove = false; } } void NetworkModel::connectionUpdated() { NetworkManager::Connection *connectionPtr = qobject_cast(sender()); if (connectionPtr) { NetworkManager::ConnectionSettings::Ptr settings = connectionPtr->settings(); for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Connection, connectionPtr->path())) { item->setConnectionPath(connectionPtr->path()); item->setName(settings->id()); item->setTimestamp(settings->timestamp()); item->setType(settings->connectionType()); item->setUuid(settings->uuid()); if (item->type() == NetworkManager::ConnectionSettings::Wireless) { NetworkManager::WirelessSetting::Ptr wirelessSetting; wirelessSetting = settings->setting(NetworkManager::Setting::Wireless).dynamicCast(); item->setMode(wirelessSetting->mode()); item->setSecurityType(NetworkManager::securityTypeFromConnectionSetting(settings)); item->setSsid(QString::fromUtf8(wirelessSetting->ssid())); // TODO check whether BSSID has changed and update the wireless info } updateItem(item); qCDebug(PLASMA_NM) << "Item " << item->name() << ": connection updated"; } } } void NetworkModel::deviceAdded(const QString &device) { NetworkManager::Device::Ptr dev = NetworkManager::findNetworkInterface(device); if (dev) { addDevice(dev); } } void NetworkModel::deviceRemoved(const QString &device) { // Make all items unavailable for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Device, device)) { availableConnectionDisappeared(item->connectionPath()); } } void NetworkModel::deviceStateChanged(NetworkManager::Device::State state, NetworkManager::Device::State oldState, NetworkManager::Device::StateChangeReason reason) { Q_UNUSED(oldState); Q_UNUSED(reason); NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(qobject_cast(sender())->uni()); if (device) { beginResetModel(); for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Device, device->uni())) { item->setDeviceState(state); item->invalidateDetails(); // qCDebug(PLASMA_NM) << "Item " << item->name() << ": device state changed to " << item->deviceState(); } endResetModel(); } } #if WITH_MODEMMANAGER_SUPPORT void NetworkModel::gsmNetworkAccessTechnologiesChanged(QFlags accessTechnologies) { Q_UNUSED(accessTechnologies); ModemManager::Modem *gsmNetwork = qobject_cast(sender()); if (gsmNetwork) { for (const NetworkManager::Device::Ptr &dev : NetworkManager::networkInterfaces()) { if (dev->type() == NetworkManager::Device::Modem) { ModemManager::ModemDevice::Ptr modem = ModemManager::findModemDevice(dev->udi()); if (modem) { if (modem->hasInterface(ModemManager::ModemDevice::ModemInterface)) { ModemManager::Modem::Ptr modemNetwork = modem->interface(ModemManager::ModemDevice::ModemInterface).objectCast(); if (modemNetwork && modemNetwork->device() == gsmNetwork->device()) { // TODO store access technology internally? for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Device, dev->uni())) { updateItem(item); } } } } } } } } void NetworkModel::gsmNetworkCurrentModesChanged() { ModemManager::Modem *gsmNetwork = qobject_cast(sender()); if (gsmNetwork) { for (const NetworkManager::Device::Ptr &dev : NetworkManager::networkInterfaces()) { if (dev->type() == NetworkManager::Device::Modem) { ModemManager::ModemDevice::Ptr modem = ModemManager::findModemDevice(dev->udi()); if (modem) { if (modem->hasInterface(ModemManager::ModemDevice::ModemInterface)) { ModemManager::Modem::Ptr modemNetwork = modem->interface(ModemManager::ModemDevice::ModemInterface).objectCast(); if (modemNetwork && modemNetwork->device() == gsmNetwork->device()) { for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Device, dev->uni())) { updateItem(item); } } } } } } } } void NetworkModel::gsmNetworkSignalQualityChanged(const ModemManager::SignalQualityPair &signalQuality) { ModemManager::Modem *gsmNetwork = qobject_cast(sender()); if (gsmNetwork) { for (const NetworkManager::Device::Ptr &dev : NetworkManager::networkInterfaces()) { if (dev->type() == NetworkManager::Device::Modem) { ModemManager::ModemDevice::Ptr modem = ModemManager::findModemDevice(dev->udi()); if (modem) { if (modem->hasInterface(ModemManager::ModemDevice::ModemInterface)) { ModemManager::Modem::Ptr modemNetwork = modem->interface(ModemManager::ModemDevice::ModemInterface).objectCast(); if (modemNetwork && modemNetwork->device() == gsmNetwork->device()) { for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Device, dev->uni())) { item->setSignal(signalQuality.signal); updateItem(item); } } } } } } } } #endif void NetworkModel::ipConfigChanged() { NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(qobject_cast(sender())->uni()); if (device) { for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Device, device->uni())) { updateItem(item); // qCDebug(PLASMA_NM) << "Item " << item->name() << ": device ipconfig changed"; } } } void NetworkModel::ipInterfaceChanged() { NetworkManager::Device *device = qobject_cast(sender()); if (device) { for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Device, device->uni())) { if (device->ipInterfaceName().isEmpty()) { item->setDeviceName(device->interfaceName()); } else { item->setDeviceName(device->ipInterfaceName()); } } } } void NetworkModel::statusChanged(NetworkManager::Status status) { Q_UNUSED(status); qCDebug(PLASMA_NM) << "NetworkManager state changed to " << status; // This has probably effect only for VPN connections for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Type, NetworkManager::ConnectionSettings::Vpn)) { updateItem(item); } } void NetworkModel::wirelessNetworkAppeared(const QString &ssid) { NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(qobject_cast(sender())->uni()); if (device && device->type() == NetworkManager::Device::Wifi) { NetworkManager::WirelessDevice::Ptr wirelessDevice = device.objectCast(); NetworkManager::WirelessNetwork::Ptr network = wirelessDevice->findNetwork(ssid); addWirelessNetwork(network, wirelessDevice); } } void NetworkModel::wirelessNetworkDisappeared(const QString &ssid) { NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(qobject_cast(sender())->uni()); if (device) { for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Ssid, ssid, device->uni())) { // Remove the entire item, because it's only AP or it's a duplicated available connection if (item->itemType() == NetworkModelItem::AvailableAccessPoint || item->duplicate()) { const int row = m_list.indexOf(item); if (row >= 0) { qCDebug(PLASMA_NM) << "Wireless network " << item->name() << " removed completely"; beginRemoveRows(QModelIndex(), row, row); m_list.removeItem(item); item->deleteLater(); endRemoveRows(); } // Remove only AP and device from the item and leave it as an unavailable connection } else { if (item->mode() == NetworkManager::WirelessSetting::Infrastructure) { item->setDeviceName(QString()); item->setDevicePath(QString()); item->setSpecificPath(QString()); } item->setSignal(0); updateItem(item); qCDebug(PLASMA_NM) << "Item " << item->name() << ": wireless network removed"; } } } } void NetworkModel::wirelessNetworkReferenceApChanged(const QString &accessPoint) { NetworkManager::WirelessNetwork *networkPtr = qobject_cast(sender()); if (networkPtr) { for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Ssid, networkPtr->ssid(), networkPtr->device())) { NetworkManager::Connection::Ptr connection = NetworkManager::findConnection(item->connectionPath()); if (connection) { NetworkManager::WirelessSetting::Ptr wirelessSetting = connection->settings()->setting(NetworkManager::Setting::Wireless).staticCast(); if (wirelessSetting) { if (wirelessSetting->bssid().isEmpty()) { item->setSpecificPath(accessPoint); updateItem(item); } } } } } } void NetworkModel::wirelessNetworkSignalChanged(int signal) { NetworkManager::WirelessNetwork *networkPtr = qobject_cast(sender()); if (networkPtr) { for (NetworkModelItem *item : m_list.returnItems(NetworkItemsList::Ssid, networkPtr->ssid(), networkPtr->device())) { if (item->specificPath() == networkPtr->referenceAccessPoint()->uni()) { item->setSignal(signal); updateItem(item); // qCDebug(PLASMA_NM) << "Wireless network " << item->name() << ": signal changed to " << item->signal(); } } } } NetworkManager::WirelessSecurityType NetworkModel::alternativeWirelessSecurity(const NetworkManager::WirelessSecurityType type) { if (type == NetworkManager::WpaPsk) { return NetworkManager::Wpa2Psk; } else if (type == NetworkManager::WpaEap) { return NetworkManager::Wpa2Eap; } else if (type == NetworkManager::Wpa2Psk) { return NetworkManager::WpaPsk; } else if (type == NetworkManager::Wpa2Eap) { return NetworkManager::WpaEap; } return type; } void NetworkModel::updateFromWirelessNetwork(NetworkModelItem *item, const NetworkManager::WirelessNetwork::Ptr &network, const NetworkManager::WirelessDevice::Ptr &device) { NetworkManager::WirelessSecurityType securityType = NetworkManager::UnknownSecurity; NetworkManager::AccessPoint::Ptr ap = network->referenceAccessPoint(); if (ap && ap->capabilities().testFlag(NetworkManager::AccessPoint::Privacy)) { securityType = NetworkManager::findBestWirelessSecurity(device->wirelessCapabilities(), true, (device->mode() == NetworkManager::WirelessDevice::Adhoc), ap->capabilities(), ap->wpaFlags(), ap->rsnFlags()); } // Check whether the connection is associated with some concrete AP NetworkManager::Connection::Ptr connection = NetworkManager::findConnection(item->connectionPath()); if (connection) { NetworkManager::WirelessSetting::Ptr wirelessSetting = connection->settings()->setting(NetworkManager::Setting::Wireless).staticCast(); if (wirelessSetting) { if (!wirelessSetting->bssid().isEmpty()) { for (const NetworkManager::AccessPoint::Ptr ap : network->accessPoints()) { if (ap->hardwareAddress() == NetworkManager::macAddressAsString(wirelessSetting->bssid())) { item->setSignal(ap->signalStrength()); item->setSpecificPath(ap->uni()); // We need to watch this AP for signal changes connect(ap.data(), &NetworkManager::AccessPoint::signalStrengthChanged, this, &NetworkModel::accessPointSignalStrengthChanged, Qt::UniqueConnection); } } } else { item->setSignal(network->signalStrength()); item->setSpecificPath(network->referenceAccessPoint()->uni()); } } } item->setSecurityType(securityType); updateItem(item); } diff --git a/libs/models/networkmodelitem.cpp b/libs/models/networkmodelitem.cpp index aed326a0..e20fe023 100644 --- a/libs/models/networkmodelitem.cpp +++ b/libs/models/networkmodelitem.cpp @@ -1,590 +1,659 @@ /* 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 . */ #include "networkmodelitem.h" #include "uiutils.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if WITH_MODEMMANAGER_SUPPORT #include #include #include #include #include #endif NetworkModelItem::NetworkModelItem(QObject *parent) : QObject(parent) , m_connectionState(NetworkManager::ActiveConnection::Deactivated) , m_deviceState(NetworkManager::Device::UnknownState) , m_detailsValid(false) , m_duplicate(false) , m_mode(NetworkManager::WirelessSetting::Infrastructure) , m_securityType(NetworkManager::NoneSecurity) , m_signal(0) , m_slave(false) , m_type(NetworkManager::ConnectionSettings::Unknown) , m_vpnState(NetworkManager::VpnConnection::Unknown) , m_rxBytes(0) , m_txBytes(0) { } NetworkModelItem::NetworkModelItem(const NetworkModelItem *item, QObject *parent) : QObject(parent) , m_connectionPath(item->connectionPath()) , m_connectionState(NetworkManager::ActiveConnection::Deactivated) , m_detailsValid(false) , m_duplicate(true) , m_mode(item->mode()) , m_name(item->name()) , m_securityType(item->securityType()) , m_slave(item->slave()) , m_ssid(item->ssid()) , m_timestamp(item->timestamp()) , m_type(item->type()) , m_uuid(item->uuid()) , m_vpnState(NetworkManager::VpnConnection::Unknown) , m_rxBytes(0) , m_txBytes(0) { } NetworkModelItem::~NetworkModelItem() { } QString NetworkModelItem::activeConnectionPath() const { return m_activeConnectionPath; } void NetworkModelItem::setActiveConnectionPath(const QString &path) { m_activeConnectionPath = path; } QString NetworkModelItem::connectionPath() const { return m_connectionPath; } void NetworkModelItem::setConnectionPath(const QString &path) { - m_connectionPath = path; + if (m_connectionPath != path) { + m_connectionPath = path; + m_changedRoles << NetworkModel::ConnectionPathRole << NetworkModel::UniRole; + } } NetworkManager::ActiveConnection::State NetworkModelItem::connectionState() const { return m_connectionState; } void NetworkModelItem::setConnectionState(NetworkManager::ActiveConnection::State state) { - m_connectionState = state; + if (m_connectionState != state) { + m_connectionState = state; + m_changedRoles << NetworkModel::ConnectionStateRole << NetworkModel::SectionRole; + refreshIcon(); + } } QStringList NetworkModelItem::details() const { if (!m_detailsValid) { updateDetails(); } return m_details; } QString NetworkModelItem::devicePath() const { return m_devicePath; } QString NetworkModelItem::deviceName() const { return m_deviceName; } void NetworkModelItem::setDeviceName(const QString &name) { - m_deviceName = name; + if (m_deviceName != name) { + m_deviceName = name; + m_changedRoles << NetworkModel::DeviceName; + } } void NetworkModelItem::setDevicePath(const QString &path) { - m_devicePath = path; + if (m_devicePath != path) { + m_devicePath = path; + m_changedRoles << NetworkModel::DevicePathRole << NetworkModel::ItemTypeRole << NetworkModel::UniRole; + } } QString NetworkModelItem::deviceState() const { return UiUtils::connectionStateToString(m_deviceState); } void NetworkModelItem::setDeviceState(const NetworkManager::Device::State state) { - m_deviceState = state; + if (m_deviceState != state) { + m_deviceState = state; + m_changedRoles << NetworkModel::DeviceStateRole; + } } bool NetworkModelItem::duplicate() const { return m_duplicate; } -QString NetworkModelItem::icon() const +void NetworkModelItem::setIcon(const QString& icon) +{ + if (icon != m_icon) { + m_icon = icon; + m_changedRoles << NetworkModel::ConnectionIconRole; + } +} + +void NetworkModelItem::refreshIcon() +{ + setIcon(computeIcon()); +} + +QString NetworkModelItem::computeIcon() const { switch (m_type) { case NetworkManager::ConnectionSettings::Adsl: return QStringLiteral("network-mobile-100"); break; case NetworkManager::ConnectionSettings::Bluetooth: - if (connectionState() == NetworkManager::ActiveConnection::Activated) { + if (m_connectionState == NetworkManager::ActiveConnection::Activated) { return QStringLiteral("network-bluetooth-activated"); } else { return QStringLiteral("network-bluetooth"); } break; case NetworkManager::ConnectionSettings::Bond: break; case NetworkManager::ConnectionSettings::Bridge: break; case NetworkManager::ConnectionSettings::Cdma: case NetworkManager::ConnectionSettings::Gsm: if (m_signal == 0 ) { return QStringLiteral("network-mobile-0"); } else if (m_signal < 20) { return QStringLiteral("network-mobile-20"); } else if (m_signal < 40) { return QStringLiteral("network-mobile-40"); } else if (m_signal < 60) { return QStringLiteral("network-mobile-60"); } else if (m_signal < 80) { return QStringLiteral("network-mobile-80"); } else { return QStringLiteral("network-mobile-100"); } break; case NetworkManager::ConnectionSettings::Infiniband: break; case NetworkManager::ConnectionSettings::OLPCMesh: break; case NetworkManager::ConnectionSettings::Pppoe: return QStringLiteral("network-mobile-100"); break; case NetworkManager::ConnectionSettings::Vlan: break; case NetworkManager::ConnectionSettings::Vpn: case NetworkManager::ConnectionSettings::WireGuard: return QStringLiteral("network-vpn"); break; case NetworkManager::ConnectionSettings::Wired: - if (connectionState() == NetworkManager::ActiveConnection::Activated) { + if (m_connectionState == NetworkManager::ActiveConnection::Activated) { return QStringLiteral("network-wired-activated"); } else { return QStringLiteral("network-wired"); } break; case NetworkManager::ConnectionSettings::Wireless: if (m_signal == 0 ) { if (m_mode == NetworkManager::WirelessSetting::Adhoc || m_mode == NetworkManager::WirelessSetting::Ap) { return (m_securityType <= NetworkManager::NoneSecurity) ? QStringLiteral("network-wireless-100") : QStringLiteral("network-wireless-100-locked"); } return (m_securityType <= NetworkManager::NoneSecurity) ? QStringLiteral("network-wireless-0") : QStringLiteral("network-wireless-0-locked"); } else if (m_signal < 20) { return (m_securityType <= NetworkManager::NoneSecurity) ? QStringLiteral("network-wireless-20") : QStringLiteral("network-wireless-20-locked"); } else if (m_signal < 40) { return (m_securityType <= NetworkManager::NoneSecurity) ? QStringLiteral("network-wireless-40") : QStringLiteral("network-wireless-40-locked"); } else if (m_signal < 60) { return (m_securityType <= NetworkManager::NoneSecurity) ? QStringLiteral("network-wireless-60") : QStringLiteral("network-wireless-60-locked"); } else if (m_signal < 80) { return (m_securityType <= NetworkManager::NoneSecurity) ? QStringLiteral("network-wireless-80") : QStringLiteral("network-wireless-80-locked"); } else { return (m_securityType <= NetworkManager::NoneSecurity) ? QStringLiteral("network-wireless-100") : QStringLiteral("network-wireless-100-locked"); } break; default: break; } - if (connectionState() == NetworkManager::ActiveConnection::Activated) { + if (m_connectionState == NetworkManager::ActiveConnection::Activated) { return QStringLiteral("network-wired-activated"); } else { return QStringLiteral("network-wired"); } } NetworkModelItem::ItemType NetworkModelItem::itemType() const { if (!m_devicePath.isEmpty() || m_type == NetworkManager::ConnectionSettings::Bond || m_type == NetworkManager::ConnectionSettings::Bridge || m_type == NetworkManager::ConnectionSettings::Vlan || m_type == NetworkManager::ConnectionSettings::Team || ((NetworkManager::status() == NetworkManager::Connected || NetworkManager::status() == NetworkManager::ConnectedLinkLocal || NetworkManager::status() == NetworkManager::ConnectedSiteOnly) && (m_type == NetworkManager::ConnectionSettings::Vpn || m_type == NetworkManager::ConnectionSettings::WireGuard))) { if (m_connectionPath.isEmpty() && m_type == NetworkManager::ConnectionSettings::Wireless) { return NetworkModelItem::AvailableAccessPoint; } else { return NetworkModelItem::AvailableConnection; } } return NetworkModelItem::UnavailableConnection; } NetworkManager::WirelessSetting::NetworkMode NetworkModelItem::mode() const { return m_mode; } void NetworkModelItem::setMode(const NetworkManager::WirelessSetting::NetworkMode mode) { - m_mode = mode; + if (m_mode != mode) { + m_mode = mode; + refreshIcon(); + } } QString NetworkModelItem::name() const { return m_name; } void NetworkModelItem::setName(const QString &name) { - m_name = name; + if (m_name != name) { + m_name = name; + m_changedRoles << NetworkModel::NameRole; + } } QString NetworkModelItem::originalName() const { if (m_deviceName.isEmpty()) { return m_name; } return m_name % QLatin1String(" (") % m_deviceName % ')'; } QString NetworkModelItem::sectionType() const { if (m_connectionState == NetworkManager::ActiveConnection::Activated) { return i18n("Active connections"); } else { return i18n("Available connections"); } } NetworkManager::WirelessSecurityType NetworkModelItem::securityType() const { return m_securityType; } void NetworkModelItem::setSecurityType(NetworkManager::WirelessSecurityType type) { - m_securityType = type; + if (m_securityType != type) { + m_securityType = type; + m_changedRoles << NetworkModel::SecurityTypeRole; + refreshIcon(); + } } int NetworkModelItem::signal() const { return m_signal; } void NetworkModelItem::setSignal(int signal) { - m_signal = signal; + if (m_signal != signal) { + m_signal = signal; + m_changedRoles << NetworkModel::SignalRole; + refreshIcon(); + } } bool NetworkModelItem::slave() const { return m_slave; } void NetworkModelItem::setSlave(bool slave) { - m_slave = slave; + if (m_slave != slave) { + m_slave = slave; + m_changedRoles << NetworkModel::SlaveRole; + } } QString NetworkModelItem::specificPath() const { return m_specificPath; } void NetworkModelItem::setSpecificPath(const QString &path) { - m_specificPath = path; + if (m_specificPath != path) { + m_specificPath = path; + m_changedRoles << NetworkModel::SpecificPathRole; + } } QString NetworkModelItem::ssid() const { return m_ssid; } void NetworkModelItem::setSsid(const QString &ssid) { - m_ssid = ssid; + if (m_ssid != ssid) { + m_ssid = ssid; + m_changedRoles << NetworkModel::SsidRole << NetworkModel::UniRole; + } } NetworkManager::ConnectionSettings::ConnectionType NetworkModelItem::type() const { return m_type; } QDateTime NetworkModelItem::timestamp() const { return m_timestamp; } void NetworkModelItem::setTimestamp(const QDateTime &date) { - m_timestamp = date; + if (m_timestamp != date) { + m_timestamp = date; + m_changedRoles << NetworkModel::TimeStampRole; + } } void NetworkModelItem::setType(NetworkManager::ConnectionSettings::ConnectionType type) { - m_type = type; + if (m_type != type) { + m_type = type; + m_changedRoles << NetworkModel::TypeRole << NetworkModel::ItemTypeRole << NetworkModel::UniRole; + + refreshIcon(); + } } QString NetworkModelItem::uni() const { if (m_type == NetworkManager::ConnectionSettings::Wireless && m_uuid.isEmpty()) { return m_ssid + '%' + m_devicePath; } else { return m_connectionPath + '%' + m_devicePath; } } QString NetworkModelItem::uuid() const { return m_uuid; } void NetworkModelItem::setUuid(const QString &uuid) { - m_uuid = uuid; + if (m_uuid != uuid) { + m_uuid = uuid; + m_changedRoles << NetworkModel::UuidRole; + } } QString NetworkModelItem::vpnState() const { return UiUtils::vpnConnectionStateToString(m_vpnState); } void NetworkModelItem::setVpnState(NetworkManager::VpnConnection::State state) { - m_vpnState = state; + if (m_vpnState != state) { + m_vpnState = state; + m_changedRoles << NetworkModel::VpnState; + } } QString NetworkModelItem::vpnType() const { return m_vpnType; } void NetworkModelItem::setVpnType(const QString &type) { - m_vpnType = type; + if (m_vpnType != type) { + m_vpnType = type; + m_changedRoles << NetworkModel::VpnType; + } } qulonglong NetworkModelItem::rxBytes() const { return m_rxBytes; } void NetworkModelItem::setRxBytes(qulonglong bytes) { m_rxBytes = bytes; } qulonglong NetworkModelItem::txBytes() const { return m_txBytes; } void NetworkModelItem::setTxBytes(qulonglong bytes) { m_txBytes = bytes; } bool NetworkModelItem::operator==(const NetworkModelItem *item) const { if (!item->uuid().isEmpty() && !uuid().isEmpty()) { if (item->devicePath() == devicePath() && item->uuid() == uuid()) { return true; } } else if (item->type() == NetworkManager::ConnectionSettings::Wireless && type() == NetworkManager::ConnectionSettings::Wireless) { if (item->ssid() == ssid() && item->devicePath() == devicePath()) { return true; } } return false; } void NetworkModelItem::invalidateDetails() { m_detailsValid = false; } void NetworkModelItem::updateDetails() const { m_detailsValid = true; m_details.clear(); if (itemType() == NetworkModelItem::UnavailableConnection) { return; } NetworkManager::Device::Ptr device = NetworkManager::findNetworkInterface(m_devicePath); // Get IPv[46]Address if (device && device->ipV4Config().isValid() && m_connectionState == NetworkManager::ActiveConnection::Activated) { if (!device->ipV4Config().addresses().isEmpty()) { QHostAddress addr = device->ipV4Config().addresses().first().ip(); if (!addr.isNull()) { m_details << i18n("IPv4 Address") << addr.toString(); } } } if (device && device->ipV6Config().isValid() && m_connectionState == NetworkManager::ActiveConnection::Activated) { if (!device->ipV6Config().addresses().isEmpty()) { QHostAddress addr = device->ipV6Config().addresses().first().ip(); if (!addr.isNull()) { m_details << i18n("IPv6 Address") << addr.toString(); } } } if (m_type == NetworkManager::ConnectionSettings::Wired) { NetworkManager::WiredDevice::Ptr wiredDevice = device.objectCast(); if (wiredDevice) { if (m_connectionState == NetworkManager::ActiveConnection::Activated) { m_details << i18n("Connection speed") << UiUtils::connectionSpeed(wiredDevice->bitRate()); } m_details << i18n("MAC Address") << wiredDevice->permanentHardwareAddress(); } } else if (m_type == NetworkManager::ConnectionSettings::Wireless) { NetworkManager::WirelessDevice::Ptr wirelessDevice = device.objectCast(); m_details << i18n("Access point (SSID)") << m_ssid; if (m_mode == NetworkManager::WirelessSetting::Infrastructure) { - m_details << i18n("Signal strength") << QString("%1%").arg(m_signal); + m_details << i18n("Signal strength") << QStringLiteral("%1%").arg(m_signal); } if (m_connectionState == NetworkManager::ActiveConnection::Activated) { m_details << i18n("Security type") << UiUtils::labelFromWirelessSecurity(m_securityType); } if (wirelessDevice) { if (m_connectionState == NetworkManager::ActiveConnection::Activated) { m_details << i18n("Connection speed") << UiUtils::connectionSpeed(wirelessDevice->bitRate()); } m_details << i18n("MAC Address") << wirelessDevice->permanentHardwareAddress(); } } else if (m_type == NetworkManager::ConnectionSettings::Gsm || m_type == NetworkManager::ConnectionSettings::Cdma) { #if WITH_MODEMMANAGER_SUPPORT NetworkManager::ModemDevice::Ptr modemDevice = device.objectCast(); if (modemDevice) { ModemManager::ModemDevice::Ptr modem = ModemManager::findModemDevice(modemDevice->udi()); if (modem) { ModemManager::Modem::Ptr modemNetwork = modem->interface(ModemManager::ModemDevice::ModemInterface).objectCast(); if (m_type == NetworkManager::ConnectionSettings::Gsm) { ModemManager::Modem3gpp::Ptr gsmNet = modem->interface(ModemManager::ModemDevice::GsmInterface).objectCast(); if (gsmNet) { m_details << i18n("Operator") << gsmNet->operatorName(); } } else { ModemManager::ModemCdma::Ptr cdmaNet = modem->interface(ModemManager::ModemDevice::CdmaInterface).objectCast(); m_details << i18n("Network ID") << QString("%1").arg(cdmaNet->nid()); } if (modemNetwork) { m_details << i18n("Signal Quality") << QString("%1%").arg(modemNetwork->signalQuality().signal); m_details << i18n("Access Technology") << UiUtils::convertAccessTechnologyToString(modemNetwork->accessTechnologies()); } } } #endif } else if (m_type == NetworkManager::ConnectionSettings::Vpn) { m_details << i18n("VPN plugin") << m_vpnType; if (m_connectionState == NetworkManager::ActiveConnection::Activated) { NetworkManager::ActiveConnection::Ptr active = NetworkManager::findActiveConnection(m_activeConnectionPath); NetworkManager::VpnConnection::Ptr vpnConnection; if (active) { vpnConnection = NetworkManager::VpnConnection::Ptr(new NetworkManager::VpnConnection(active->path()), &QObject::deleteLater); } if (vpnConnection && !vpnConnection->banner().isEmpty()) { m_details << i18n("Banner") << vpnConnection->banner().simplified(); } } } else if (m_type == NetworkManager::ConnectionSettings::Bluetooth) { NetworkManager::BluetoothDevice::Ptr bluetoothDevice = device.objectCast(); if (bluetoothDevice) { m_details << i18n("Name") << bluetoothDevice->name(); if (bluetoothDevice->bluetoothCapabilities() == NetworkManager::BluetoothDevice::Pan) { m_details << i18n("Capabilities") << QStringLiteral("PAN"); } else if (bluetoothDevice->bluetoothCapabilities() == NetworkManager::BluetoothDevice::Dun) { m_details << i18n("Capabilities") << QStringLiteral("DUN"); } m_details << i18n("MAC Address") << bluetoothDevice->hardwareAddress(); } } else if (m_type == NetworkManager::ConnectionSettings::Infiniband) { NetworkManager::InfinibandDevice::Ptr infinibandDevice = device.objectCast(); m_details << i18n("Type") << i18n("Infiniband"); if (infinibandDevice) { m_details << i18n("MAC Address") << infinibandDevice->hwAddress(); } } else if (m_type == NetworkManager::ConnectionSettings::Bond) { NetworkManager::BondDevice::Ptr bondDevice = device.objectCast(); m_details << i18n("Type") << i18n("Bond"); if (bondDevice) { m_details << i18n("MAC Address") << bondDevice->hwAddress(); } } else if (m_type == NetworkManager::ConnectionSettings::Bridge) { NetworkManager::BridgeDevice::Ptr bridgeDevice = device.objectCast(); m_details << i18n("Type") << i18n("Bridge"); if (bridgeDevice) { m_details << i18n("MAC Address") << bridgeDevice->hwAddress(); } } else if (m_type == NetworkManager::ConnectionSettings::Vlan) { NetworkManager::VlanDevice::Ptr vlanDevice = device.objectCast(); m_details << i18n("Type") << i18n("Vlan"); if (vlanDevice) { m_details << i18n("Vlan ID") << QString("%1").arg(vlanDevice->vlanId()); m_details << i18n("MAC Address") << vlanDevice->hwAddress(); } } else if (m_type == NetworkManager::ConnectionSettings::Adsl) { m_details << i18n("Type") << i18n("Adsl"); } else if (m_type == NetworkManager::ConnectionSettings::Team) { NetworkManager::TeamDevice::Ptr teamDevice = device.objectCast(); m_details << i18n("Type") << i18n("Team"); if (teamDevice) { m_details << i18n("MAC Address") << teamDevice->hwAddress(); } } } diff --git a/libs/models/networkmodelitem.h b/libs/models/networkmodelitem.h index 0f4f4209..7256bedb 100644 --- a/libs/models/networkmodelitem.h +++ b/libs/models/networkmodelitem.h @@ -1,150 +1,158 @@ /* 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_MODEL_NETWORK_MODEL_ITEM_H #define PLASMA_NM_MODEL_NETWORK_MODEL_ITEM_H #include #include #include #include #include #include "networkmodel.h" class Q_DECL_EXPORT NetworkModelItem : public QObject { Q_OBJECT public: enum ItemType { UnavailableConnection, AvailableConnection, AvailableAccessPoint }; explicit NetworkModelItem(QObject *parent = nullptr); explicit NetworkModelItem(const NetworkModelItem *item, QObject *parent = nullptr); ~NetworkModelItem() override; QString activeConnectionPath() const; void setActiveConnectionPath(const QString &path); QString connectionPath() const; void setConnectionPath(const QString &path); NetworkManager::ActiveConnection::State connectionState() const; void setConnectionState(NetworkManager::ActiveConnection::State state); QStringList details() const; QString deviceName() const; void setDeviceName(const QString &name); QString devicePath() const; void setDevicePath(const QString &path); QString deviceState() const; void setDeviceState(const NetworkManager::Device::State state); bool duplicate() const; - QString icon() const; + void setIcon(const QString &icon); + QString icon() const { return m_icon; } ItemType itemType() const; NetworkManager::WirelessSetting::NetworkMode mode() const; void setMode(const NetworkManager::WirelessSetting::NetworkMode mode); QString name() const; void setName(const QString &name); QString originalName() const; QString sectionType() const; NetworkManager::WirelessSecurityType securityType() const; void setSecurityType(NetworkManager::WirelessSecurityType type); int signal() const; void setSignal(int signal); bool slave() const; void setSlave(bool slave); QString specificPath() const; void setSpecificPath(const QString &path); QString ssid() const; void setSsid(const QString &ssid); QDateTime timestamp() const; void setTimestamp(const QDateTime &date); NetworkManager::ConnectionSettings::ConnectionType type() const; void setType(NetworkManager::ConnectionSettings::ConnectionType type); QString uni() const; QString uuid() const; void setUuid(const QString &uuid); QString vpnState() const; void setVpnState(NetworkManager::VpnConnection::State state); QString vpnType() const; void setVpnType(const QString &type); qulonglong rxBytes() const; void setRxBytes(qulonglong bytes); qulonglong txBytes() const; void setTxBytes(qulonglong bytes); bool operator==(const NetworkModelItem *item) const; + QVector changedRoles() const { return m_changedRoles; } + void clearChangedRoles() { m_changedRoles.clear(); } + public Q_SLOTS: void invalidateDetails(); private: + QString computeIcon() const; + void refreshIcon(); void updateDetails() const; QString m_activeConnectionPath; QString m_connectionPath; NetworkManager::ActiveConnection::State m_connectionState; QString m_devicePath; QString m_deviceName; NetworkManager::Device::State m_deviceState; mutable QStringList m_details; mutable bool m_detailsValid; bool m_duplicate; NetworkManager::WirelessSetting::NetworkMode m_mode; QString m_name; NetworkManager::WirelessSecurityType m_securityType; int m_signal; bool m_slave; QString m_specificPath; QString m_ssid; QDateTime m_timestamp; NetworkManager::ConnectionSettings::ConnectionType m_type; QString m_uuid; QString m_vpnType; NetworkManager::VpnConnection::State m_vpnState; qulonglong m_rxBytes; qulonglong m_txBytes; + QString m_icon; + QVector m_changedRoles; }; #endif // PLASMA_NM_MODEL_NETWORK_MODEL_ITEM_H