diff --git a/applet/contents/ui/ConnectionItem.qml b/applet/contents/ui/ConnectionItem.qml index 1e9c662a..7d82cc7e 100644 --- a/applet/contents/ui/ConnectionItem.qml +++ b/applet/contents/ui/ConnectionItem.qml @@ -1,445 +1,463 @@ /* Copyright 2013-2017 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.2 import QtQuick.Layouts 1.2 import QtQuick.Controls 2.4 as Controls import org.kde.kcoreaddons 1.0 as KCoreAddons import org.kde.kquickcontrolsaddons 2.0 import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.networkmanagement 0.2 as PlasmaNM -PlasmaComponents.ListItem { +ListItem { id: connectionItem property bool activating: ConnectionState == PlasmaNM.Enums.Activating - property int baseHeight: Math.max(units.iconSizes.medium, connectionNameLabel.height + connectionStatusLabel.height) + Math.round(units.gridUnit / 2) + property bool deactivated: ConnectionState === PlasmaNM.Enums.Deactivated + property int baseHeight: Uuid ? connectionNameLabel.implicitHeight + connectionStatusLabel.implicitHeight + units.smallSpacing * 2 + : stateChangeButton.implicitHeight + units.smallSpacing * 2 property bool expanded: visibleDetails || visiblePasswordDialog property bool passwordIsStatic: (SecurityType == PlasmaNM.Enums.StaticWep || SecurityType == PlasmaNM.Enums.WpaPsk || SecurityType == PlasmaNM.Enums.Wpa2Psk || SecurityType == PlasmaNM.Enums.SAE) property bool predictableWirelessPassword: !Uuid && Type == PlasmaNM.Enums.Wireless && passwordIsStatic property bool showSpeed: plasmoid.expanded && ConnectionState == PlasmaNM.Enums.Activated && (Type == PlasmaNM.Enums.Wired || Type == PlasmaNM.Enums.Wireless || Type == PlasmaNM.Enums.Gsm || Type == PlasmaNM.Enums.Cdma) property bool visibleDetails: false property bool visiblePasswordDialog: false property real rxBytes: 0 property real txBytes: 0 - checked: connectionItem.containsMouse - enabled: true - height: expanded ? baseHeight + separator.height + expandableComponentLoader.height + (2 * Math.round(units.gridUnit / 3)) : baseHeight + height: expanded ? baseHeight + expandableComponentLoader.height + units.smallSpacing * (ConnectionState == PlasmaNM.Enums.Active ? 1 : Uuid ? 2 : 1) + : baseHeight + highlightRect: Qt.rect(mainColumn.x, mainColumn.y, mainColumn.width, baseHeight) ColumnLayout { + id: mainColumn anchors.fill: parent - RowLayout { + MouseArea { Layout.fillWidth: true - spacing: Math.round(units.gridUnit / 2) - - PlasmaCore.SvgItem { - id: connectionSvgIcon - Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft - Layout.preferredHeight: units.iconSizes.medium - Layout.preferredWidth: units.iconSizes.medium - elementId: ConnectionIcon - svg: PlasmaCore.Svg { - multipleImages: true - imagePath: "icons/network" - colorGroup: PlasmaCore.ColorScope.colorGroup - } + Layout.preferredHeight: mainRow.height + Layout.alignment: Qt.AlignTop + acceptedButtons: Qt.LeftButton | Qt.RightButton + hoverEnabled: true + + onEntered: { + connectionView.currentVisibleButtonIndex = index + connectionItem.checked = true } - ColumnLayout { - Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft - spacing: 0 + onExited: { + connectionItem.checked = false + } - PlasmaComponents.Label { - id: connectionNameLabel - 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: ItemUniqueName - textFormat: Text.PlainText + onPressed: { + if (mouse.button & Qt.LeftButton) { + changeExpanded() } - PlasmaComponents.Label { - id: connectionStatusLabel - Layout.fillWidth: true - height: paintedHeight - elide: Text.ElideRight - font.pointSize: theme.smallestFont.pointSize - opacity: 0.6 - text: itemText() + if (mouse.button & Qt.RightButton) { + contextMenu.visualParent = parent + contextMenu.prepare(); + contextMenu.open(mouse.x, mouse.y) } } - PlasmaComponents.BusyIndicator { - id: connectingIndicator - Layout.alignment: Qt.AlignVCenter | Qt.AlignRight - Layout.preferredHeight: units.iconSizes.medium - Layout.preferredWidth: units.iconSizes.medium - running: plasmoid.expanded && !stateChangeButton.visible && ConnectionState == PlasmaNM.Enums.Activating - visible: running - opacity: visible - } + RowLayout { + id: mainRow + spacing: units.smallSpacing * 2 + height: baseHeight + width: mainColumn.width + anchors { + left: parent.left + right: parent.right + leftMargin: units.smallSpacing + // Identical margins around the button. + rightMargin: Math.round((baseHeight - stateChangeButton.height) / 2) + } - PlasmaComponents.Button { - id: stateChangeButton - Layout.alignment: Qt.AlignVCenter | Qt.AlignRight - opacity: connectionView.currentVisibleButtonIndex == index ? 1 : 0 - visible: opacity != 0 - text: (ConnectionState == PlasmaNM.Enums.Deactivated) ? i18n("Connect") : i18n("Disconnect") + PlasmaCore.SvgItem { + id: connectionSvgIcon + Layout.preferredHeight: Uuid ? units.iconSizes.medium : units.iconSizes.smallMedium + Layout.preferredWidth: Layout.preferredHeight + Layout.leftMargin: units.smallSpacing + elementId: ConnectionIcon + svg: PlasmaCore.Svg { + multipleImages: true + imagePath: "icons/network" + colorGroup: PlasmaCore.ColorScope.colorGroup + } + } - Behavior on opacity { NumberAnimation { duration: units.shortDuration } } + // ColumnLayout with fillWidth in children, creates bind loop for width. + Column { + Layout.fillWidth: true + Layout.preferredHeight: connectionNameLabel.height + (connectionStatusLabel.visible ? connectionStatusLabel.height : 0) + spacing: 0 + + PlasmaComponents.Label { + id: connectionNameLabel + width: parent.width + elide: Text.ElideRight + height: undefined + font.weight: ConnectionState == PlasmaNM.Enums.Activated ? Font.DemiBold : Font.Normal + font.italic: ConnectionState == PlasmaNM.Enums.Activating ? true : false + text: ItemUniqueName + textFormat: Text.PlainText + } - onClicked: changeState() - } + PlasmaComponents.Label { + id: connectionStatusLabel + width: parent.width + elide: Text.ElideRight + height: undefined + font.pointSize: theme.smallestFont.pointSize + opacity: 0.6 + text: itemText() + visible: !!Uuid + } + } - MouseArea { - acceptedButtons: Qt.RightButton - Layout.alignment: Qt.AlignTop | Qt.AlignLeft - width: parent.width - height: parent.height - onPressed: { - contextMenu.visualParent = parent - contextMenu.prepare(); - contextMenu.open(mouse.x, mouse.y) + PlasmaComponents.BusyIndicator { + id: connectingIndicator + Layout.preferredHeight: units.iconSizes.medium + Layout.preferredWidth: Layout.preferredHeight + running: plasmoid.expanded && !stateChangeButton.visible && ConnectionState == PlasmaNM.Enums.Activating + visible: running + opacity: visible } - } - } - ColumnLayout { - Layout.fillHeight: true - PlasmaCore.SvgItem { - id: separator - height: lineSvg.elementSize("horizontal-line").height - Layout.fillWidth: true - Layout.maximumHeight: height - elementId: "horizontal-line" - svg: PlasmaCore.Svg { id: lineSvg; imagePath: "widgets/line" } - visible: connectionItem.expanded - opacity: visible - } + PlasmaComponents.Button { + id: stateChangeButton + opacity: connectionView.currentVisibleButtonIndex == index ? 1 : 0 + visible: opacity != 0 + text: (ConnectionState == PlasmaNM.Enums.Deactivated) ? i18n("Connect") : i18n("Disconnect") - Loader { - id: expandableComponentLoader - Layout.fillHeight: true - Layout.fillWidth: true - height: childrenRect.height + Behavior on opacity { NumberAnimation { duration: units.shortDuration } } + + onClicked: changeState() + } } } - } + Loader { + id: expandableComponentLoader + Layout.fillWidth: true + Layout.alignment: Qt.AlignBottom + Layout.bottomMargin: units.smallSpacing + } + } PlasmaComponents.Menu { id: contextMenu property Component showQRComponent: null function prepare() { showQRMenuItem.visible = false; if (Uuid && Type === PlasmaNM.Enums.Wireless && passwordIsStatic) { if (!showQRComponent) { showQRComponent = Qt.createComponent("ShowQR.qml", this); if (showQRComponent.status === Component.Error) { console.warn("Cannot create QR code component:", showQRComponent.errorString()); } } showQRMenuItem.visible = (showQRComponent.status === Component.Ready); } } PlasmaComponents.MenuItem { text: ItemUniqueName enabled: false } PlasmaComponents.MenuItem { text: stateChangeButton.text icon: (ConnectionState == PlasmaNM.Enums.Deactivated) ? "network-connect" : "network-disconnect" onClicked: changeState() } PlasmaComponents.MenuItem { id: showQRMenuItem text: i18n("Show network's QR code") icon: "view-barcode-qr" // Updated in prepare() visible: false onClicked: { const data = handler.wifiCode(ConnectionPath, Ssid, SecurityType) var obj = contextMenu.showQRComponent.createObject(connectionItem, { content: data }); obj.showMaximized() } } PlasmaComponents.MenuItem { text: i18n("Configure...") icon: "settings-configure" onClicked: KCMShell.open([mainWindow.kcm, "--args", "Uuid=" + Uuid]) } } Component { id: detailsComponent - Item { - height: childrenRect.height + Column { + spacing: units.smallSpacing PlasmaComponents.TabBar { id: detailsTabBar anchors { left: parent.left right: parent.right - top: parent.top } height: visible ? implicitHeight : 0 visible: showSpeed PlasmaComponents.TabButton { id: speedTabButton text: i18n("Speed") } PlasmaComponents.TabButton { id: detailsTabButton text: i18n("Details") } Component.onCompleted: { if (!speedTabButton.visible) { currentTab = detailsTabButton } } } DetailsText { anchors { left: parent.left - leftMargin: units.iconSizes.medium + leftMargin: units.iconSizes.smallMedium right: parent.right - top: detailsTabBar.visible ? detailsTabBar.bottom : parent.top - topMargin: Math.round(units.gridUnit / 3) } details: ConnectionDetails visible: detailsTabBar.currentTab == detailsTabButton } TrafficMonitor { anchors { left: parent.left right: parent.right - top: detailsTabBar.visible ? detailsTabBar.bottom : parent.top - topMargin: Math.round(units.gridUnit / 3) } rxBytes: RxBytes txBytes: TxBytes interval: 2000 visible: detailsTabBar.currentTab == speedTabButton } } } Component { id: passwordDialogComponent - Item { + ColumnLayout { property alias password: passwordField.text property alias passwordInput: passwordField - height: childrenRect.height - PasswordField { id: passwordField - anchors { - left: parent.left - right: parent.right - top: parent.top - } + Layout.leftMargin: units.iconSizes.smallMedium + units.smallSpacing * 2 + Layout.bottomMargin: units.smallSpacing + Layout.preferredWidth: units.gridUnit * 15 securityType: SecurityType onAccepted: { stateChangeButton.clicked() } onAcceptableInputChanged: { stateChangeButton.enabled = acceptableInput } Component.onCompleted: { stateChangeButton.enabled = false } Component.onDestruction: { stateChangeButton.enabled = true } } } } Timer { id: timer repeat: true interval: 2000 running: showSpeed property real prevRxBytes property real prevTxBytes Component.onCompleted: { prevRxBytes = RxBytes prevTxBytes = TxBytes } onTriggered: { rxBytes = (RxBytes - prevRxBytes) * 1000 / interval txBytes = (TxBytes - prevTxBytes) * 1000 / interval prevRxBytes = RxBytes prevTxBytes = TxBytes } } states: [ State { name: "collapsed" when: !(visibleDetails || visiblePasswordDialog) StateChangeScript { script: if (expandableComponentLoader.status == Loader.Ready) {expandableComponentLoader.sourceComponent = undefined} } }, State { name: "expandedDetails" when: visibleDetails StateChangeScript { script: createContent() } }, State { name: "expandedPasswordDialog" when: visiblePasswordDialog StateChangeScript { script: createContent() } PropertyChanges { target: stateChangeButton; opacity: 1 } } ] function createContent() { if (visibleDetails) { expandableComponentLoader.sourceComponent = detailsComponent } else if (visiblePasswordDialog) { expandableComponentLoader.sourceComponent = passwordDialogComponent expandableComponentLoader.item.passwordInput.forceActiveFocus() } } function changeState() { visibleDetails = false if (Uuid || !predictableWirelessPassword || visiblePasswordDialog) { if (ConnectionState == PlasmaNM.Enums.Deactivated) { if (!predictableWirelessPassword && !Uuid) { handler.addAndActivateConnection(DevicePath, SpecificPath) } else if (visiblePasswordDialog) { if (expandableComponentLoader.item.password != "") { handler.addAndActivateConnection(DevicePath, SpecificPath, expandableComponentLoader.item.password) visiblePasswordDialog = false } else { connectionItem.clicked() } } else { handler.activateConnection(ConnectionPath, DevicePath, SpecificPath) } } else { handler.deactivateConnection(ConnectionPath, DevicePath) } } else if (predictableWirelessPassword) { appletProxyModel.dynamicSortFilter = false visiblePasswordDialog = true } } /* This generates the formatted text under the connection name in the popup where the connections can be "Connect"ed and "Disconnect"ed. */ function itemText() { if (ConnectionState == PlasmaNM.Enums.Activating) { if (Type == PlasmaNM.Enums.Vpn) return VpnState else return DeviceState } else if (ConnectionState == PlasmaNM.Enums.Deactivating) { if (Type == PlasmaNM.Enums.Vpn) return VpnState else return DeviceState - } else if (ConnectionState == PlasmaNM.Enums.Deactivated) { - var result = LastUsed - if (SecurityType > PlasmaNM.Enums.NoneSecurity) - result += ", " + SecurityTypeString - return result + } else if (Uuid && ConnectionState == PlasmaNM.Enums.Deactivated) { + return LastUsed } else if (ConnectionState == PlasmaNM.Enums.Activated) { if (showSpeed) { var downloadColor = theme.highlightColor // cycle upload color by 180 degrees var uploadColor = Qt.hsva((downloadColor.hsvHue + 0.5) % 1, downloadColor.hsvSaturation, downloadColor.hsvValue, downloadColor.a) return i18n("Connected, ⬇ %2/s, ⬆ %4/s", downloadColor, KCoreAddons.Format.formatByteSize(rxBytes), uploadColor, KCoreAddons.Format.formatByteSize(txBytes)) } else { return i18n("Connected") } } + return "" } - onShowSpeedChanged: { - connectionModel.setDeviceStatisticsRefreshRateMs(DevicePath, showSpeed ? 2000 : 0) - } - - onActivatingChanged: { - if (ConnectionState == PlasmaNM.Enums.Activating) { - ListView.view.positionViewAtBeginning() - } - } - - onClicked: { + function changeExpanded() { if (visiblePasswordDialog) { appletProxyModel.dynamicSortFilter = true visiblePasswordDialog = false } else { visibleDetails = !visibleDetails } if (visibleDetails || visiblePasswordDialog) { ListView.view.currentIndex = index } else { ListView.view.currentIndex = -1 } } + onShowSpeedChanged: { + connectionModel.setDeviceStatisticsRefreshRateMs(DevicePath, showSpeed ? 2000 : 0) + } + + onActivatingChanged: { + if (ConnectionState == PlasmaNM.Enums.Activating) { + ListView.view.positionViewAtBeginning() + } + } + onContainsMouseChanged: { if (connectionItem.containsMouse) { connectionView.currentVisibleButtonIndex = index } } + + onDeactivatedChanged: { + /* Separator is part of section, which is visible only when available connections exist. Need to determine + if there is a connection in use, to show Separator. Otherwise need to hide it from the top of the list. + Connections in use are always on top, only need to check the first one. */ + if (appletProxyModel.data(appletProxyModel.index(0, 0), PlasmaNM.NetworkModel.SectionRole) !== "Available connections") { + if (connectionView.showSeparator != true) { + connectionView.showSeparator = true + } + return + } + connectionView.showSeparator = false + return + } } diff --git a/applet/contents/ui/DetailsText.qml b/applet/contents/ui/DetailsText.qml index 049e1481..2309b140 100644 --- a/applet/contents/ui/DetailsText.qml +++ b/applet/contents/ui/DetailsText.qml @@ -1,106 +1,107 @@ /* Copyright 2013-2017 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.2 import org.kde.kquickcontrolsaddons 2.0 as KQuickControlsAddons import org.kde.plasma.components 2.0 as PlasmaComponents Column { property var details: [] KQuickControlsAddons.Clipboard { id: clipboard } PlasmaComponents.ContextMenu { id: contextMenu property string text function show(item, text, x, y) { contextMenu.text = text visualParent = item open(x, y) } PlasmaComponents.MenuItem { text: i18n("Copy") icon: "edit-copy" enabled: contextMenu.text !== "" onClicked: clipboard.content = contextMenu.text } } Repeater { id: repeater property int contentHeight: 0 property int longestString: 0 model: details.length / 2 Item { anchors { left: parent.left right: parent.right } height: Math.max(detailNameLabel.height, detailValueLabel.height) PlasmaComponents.Label { id: detailNameLabel anchors { left: parent.left leftMargin: repeater.longestString - paintedWidth + Math.round(units.gridUnit / 2) } height: paintedHeight font.pointSize: theme.smallestFont.pointSize horizontalAlignment: Text.AlignRight text: details[index*2] + ": " + opacity: 0.6 Component.onCompleted: { if (paintedWidth > repeater.longestString) { repeater.longestString = paintedWidth } } } PlasmaComponents.Label { id: detailValueLabel anchors { left: parent.left right: parent.right leftMargin: repeater.longestString + Math.round(units.gridUnit / 2) } height: paintedHeight elide: Text.ElideRight font.pointSize: theme.smallestFont.pointSize text: details[(index*2)+1] textFormat: Text.PlainText MouseArea { anchors.fill: parent acceptedButtons: Qt.RightButton onPressed: contextMenu.show(this, detailValueLabel.text, mouse.x, mouse.y) } } } } } diff --git a/applet/contents/ui/Header.qml b/applet/contents/ui/Header.qml deleted file mode 100644 index 63c12f7d..00000000 --- a/applet/contents/ui/Header.qml +++ /dev/null @@ -1,59 +0,0 @@ -/* - Copyright 2013-2017 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.2 -import org.kde.plasma.components 2.0 as PlasmaComponents -import org.kde.plasma.core 2.0 as PlasmaCore -import org.kde.plasma.networkmanagement 0.2 as PlasmaNM - -PlasmaComponents.ListItem { - id: header - - property alias text: headerLabel.text - - height: headerLabel.height + units.gridUnit; width: parent.width - sectionDelegate: true - - PlasmaNM.EnabledConnections { - id: enabledConnections - } - - PlasmaComponents.Label { - id: headerLabel - - anchors.centerIn: parent - height: paintedHeight - font.weight: Font.DemiBold - } - - Component.onCompleted: { - if (header.text === i18n("Available connections")) { - connectionView.availableConnectionsVisible = true - } - } - - Component.onDestruction: { - connectionView.availableConnectionsVisible = false - } - - onVisibleChanged: { - connectionView.availableConnectionsVisible = visible - } -} diff --git a/applet/contents/ui/ListItem.qml b/applet/contents/ui/ListItem.qml new file mode 100644 index 00000000..25e730f0 --- /dev/null +++ b/applet/contents/ui/ListItem.qml @@ -0,0 +1,90 @@ +/* + Copyright 2010 Marco Martin + Copyright 2016 Jan Grulich + Copyright 2020 George Vogiatzis + + 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.1 +import org.kde.plasma.core 2.0 as PlasmaCore + +/** + * Ignores the theme's listItem margins, and uses custom highlight(pressed) area. + * Could break some themes but the majority look fine. + * Also includes a separator to be used in sections. + */ +Item { + id: listItem + + signal clicked + + property alias containsMouse: itemMouse.containsMouse + property bool checked: false + property bool separator: false + property rect highlightRect: Qt.rect(0, 0, width, height) + + width: parent.width + + // Sections have spacing above but not below. Will use 2 of them below. + height: separator ? separatorLine.height + units.smallSpacing * 3 : parent.height + + PlasmaCore.Svg { + id: lineSvg + imagePath: "widgets/line" + } + PlasmaCore.SvgItem { + id: separatorLine + anchors { + horizontalCenter: parent.horizontalCenter + top: parent.top + topMargin: units.smallSpacing + } + elementId: "horizontal-line" + width: parent.width - units.gridUnit * 2 + svg: lineSvg + visible: separator + } + + PlasmaCore.FrameSvgItem { + id : background + imagePath: "widgets/listitem" + prefix: "normal" + anchors.fill: parent + visible: separator ? false : true + } + + PlasmaCore.FrameSvgItem { + id : pressed + imagePath: "widgets/listitem" + prefix: "pressed" + opacity: checked ? 1 : 0 + Behavior on opacity { NumberAnimation { duration: units.shortDuration } } + + x: highlightRect.x + y: highlightRect.y + height: highlightRect.height + width: highlightRect.width + } + + MouseArea { + id: itemMouse + anchors.fill: parent + hoverEnabled: true + onClicked: listItem.clicked() + } +} diff --git a/applet/contents/ui/PasswordField.qml b/applet/contents/ui/PasswordField.qml index f85eec24..f1f168bb 100644 --- a/applet/contents/ui/PasswordField.qml +++ b/applet/contents/ui/PasswordField.qml @@ -1,39 +1,38 @@ /* Copyright 2013-2017 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.2 import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.networkmanagement 0.2 as PlasmaNM PlasmaComponents.TextField { property int securityType - width: units.gridUnit * 15 echoMode: TextInput.Password revealPasswordButtonShown: true placeholderText: i18n("Password...") validator: RegExpValidator { regExp: if (securityType == PlasmaNM.Enums.StaticWep) { /^(?:.{5}|[0-9a-fA-F]{10}|.{13}|[0-9a-fA-F]{26}){1}$/ } else { /^(?:.{8,64}){1}$/ } } } diff --git a/applet/contents/ui/PopupDialog.qml b/applet/contents/ui/PopupDialog.qml index e3ae167e..ebeab6f9 100644 --- a/applet/contents/ui/PopupDialog.qml +++ b/applet/contents/ui/PopupDialog.qml @@ -1,134 +1,134 @@ /* Copyright 2013-2017 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.2 import QtQuick.Layouts 1.2 import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.extras 2.0 as PlasmaExtras import org.kde.plasma.networkmanagement 0.2 as PlasmaNM FocusScope { id: full property alias toolbarValues: toolbar PlasmaNM.AvailableDevices { id: availableDevices } Component { id: networkModelComponent PlasmaNM.NetworkModel {} } property PlasmaNM.NetworkModel connectionModel: null PlasmaNM.AppletProxyModel { id: appletProxyModel sourceModel: full.connectionModel } ColumnLayout { anchors.fill: parent Toolbar { id: toolbar Layout.fillWidth: true } PlasmaExtras.ScrollArea { id: scrollView Layout.fillWidth: true Layout.fillHeight: true frameVisible: false PlasmaExtras.Heading { id: disabledMessage anchors.fill: parent horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter level: 3 visible: connectionView.count === 0 && text != "" enabled: false text: { if (toolbarValues.displayplaneModeMessage) { return i18n("Airplane mode is enabled") } if (toolbarValues.displayWifiMessage) { if (toolbarValues.displayWwanMessage) { return i18n("Wireless and mobile networks are deactivated") } return i18n("Wireless is deactivated") } if (toolbarValues.displayWwanMessage) { return i18n("Mobile network is deactivated") } return "" } } PlasmaExtras.Heading { id: message anchors.fill: parent horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter level: 3 opacity: connectionView.count === 0 && !disabledMessage.visible ? 0.6 : 0 // Check connectionView.count again, to avoid a small delay. visible: opacity >= 0.6 && connectionView.count === 0 Behavior on opacity { NumberAnimation { duration: 5000 } } text: i18n("No available connections") } ListView { id: connectionView - property bool availableConnectionsVisible: false property int currentVisibleButtonIndex: -1 + property bool showSeparator: false - anchors.fill: parent + spacing: units.smallSpacing clip: true model: appletProxyModel currentIndex: -1 boundsBehavior: Flickable.StopAtBounds - section.property: showSections ? "Section" : "" - section.delegate: Header { text: section } + section.property: showSeparator ? "Section" : "" + section.delegate: ListItem { separator: true } delegate: ConnectionItem { } } } } Connections { target: plasmoid onExpandedChanged: { connectionView.currentVisibleButtonIndex = -1; if (expanded) { handler.requestScan(); full.connectionModel = networkModelComponent.createObject(full) } else { full.connectionModel.destroy() toolbar.closeSearch(); } } } } diff --git a/applet/contents/ui/SwitchButton.qml b/applet/contents/ui/SwitchButton.qml index b5fade10..c8c12bb4 100644 --- a/applet/contents/ui/SwitchButton.qml +++ b/applet/contents/ui/SwitchButton.qml @@ -1,61 +1,61 @@ /* Copyright 2013-2017 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.2 import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.core 2.0 as PlasmaCore Item { id: switchButton property alias icon: switchButtonIcon.source property alias checked: switchButtonCheckbox.checked property alias enabled: switchButtonCheckbox.enabled property alias tooltip: switchButtonCheckbox.tooltip signal clicked height: Math.max(switchButtonCheckbox.height, switchButtonIcon.height) - width: switchButtonCheckbox.width + switchButtonIcon.width + units.gridUnit + width: switchButtonCheckbox.width + switchButtonIcon.width + units.smallSpacing * 3 PlasmaComponents.CheckBox { id: switchButtonCheckbox anchors { left: parent.left leftMargin: units.smallSpacing } onClicked: { switchButton.clicked() } } PlasmaCore.IconItem { id: switchButtonIcon anchors { left: switchButtonCheckbox.right // Checkbox bug adds internally a smallSpacing on the right. Doubling the effective spacing here. leftMargin: units.smallSpacing verticalCenter: parent.verticalCenter } width: units.iconSizes.smallMedium height: units.iconSizes.smallMedium } } diff --git a/applet/contents/ui/Toolbar.qml b/applet/contents/ui/Toolbar.qml index 58d34a37..74219991 100644 --- a/applet/contents/ui/Toolbar.qml +++ b/applet/contents/ui/Toolbar.qml @@ -1,254 +1,258 @@ /* Copyright 2013-2017 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.2 import QtQuick.Layouts 1.2 import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.plasma.components 3.0 as PlasmaComponents3 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.networkmanagement 0.2 as PlasmaNM import org.kde.kquickcontrolsaddons 2.0 -GridLayout { +ColumnLayout { id: toolbar + spacing: units.smallSpacing readonly property var displayWifiMessage: !wifiSwitchButton.checked && wifiSwitchButton.visible readonly property var displayWwanMessage: !wwanSwitchButton.checked && wwanSwitchButton.visible readonly property var displayplaneModeMessage: planeModeSwitchButton.checked && planeModeSwitchButton.visible function closeSearch() { searchToggleButton.checked = false } - rows: 2 - columns: 2 - PlasmaCore.Svg { id: lineSvg imagePath: "widgets/line" } PlasmaNM.EnabledConnections { id: enabledConnections onWirelessEnabledChanged: { wifiSwitchButton.checked = wifiSwitchButton.enabled && enabled } onWirelessHwEnabledChanged: { wifiSwitchButton.enabled = enabled && availableDevices.wirelessDeviceAvailable && !planeModeSwitchButton.airplaneModeEnabled } onWwanEnabledChanged: { wwanSwitchButton.checked = wwanSwitchButton.enabled && enabled } onWwanHwEnabledChanged: { wwanSwitchButton.enabled = enabled && availableDevices.modemDeviceAvailable && !planeModeSwitchButton.airplaneModeEnabled } } PlasmaNM.Configuration { id: configuration } - Row { - Layout.fillWidth: true + RowLayout { + spacing: units.smallSpacing SwitchButton { id: wifiSwitchButton checked: enabled && enabledConnections.wirelessEnabled enabled: enabledConnections.wirelessHwEnabled && availableDevices.wirelessDeviceAvailable && !planeModeSwitchButton.airplaneModeEnabled tooltip: i18n("Enable wireless") icon: enabled ? "network-wireless-on" : "network-wireless-off" visible: availableDevices.wirelessDeviceAvailable onClicked: { handler.enableWireless(checked); } } SwitchButton { id: wwanSwitchButton checked: enabled && enabledConnections.wwanEnabled enabled: enabledConnections.wwanHwEnabled && availableDevices.modemDeviceAvailable && !planeModeSwitchButton.airplaneModeEnabled tooltip: i18n("Enable mobile network") icon: enabled ? "network-mobile-on" : "network-mobile-off" visible: availableDevices.modemDeviceAvailable onClicked: { handler.enableWwan(checked); } } SwitchButton { id: planeModeSwitchButton property bool initialized: false property bool airplaneModeEnabled: false checked: airplaneModeEnabled tooltip: i18n("Enable airplane mode") icon: airplaneModeEnabled ? "network-flightmode-on" : "network-flightmode-off" visible: availableDevices.modemDeviceAvailable || availableDevices.wirelessDeviceAvailable onClicked: { handler.enableAirplaneMode(checked); airplaneModeEnabled = !airplaneModeEnabled; } Binding { target: configuration property: "airplaneModeEnabled" value: planeModeSwitchButton.airplaneModeEnabled when: planeModeSwitchButton.initialized } Component.onCompleted: { airplaneModeEnabled = configuration.airplaneModeEnabled initialized = true } } - } - - Row { - Layout.column: 1 + Item { + Layout.fillWidth: true + } PlasmaComponents3.ToolButton { id: hotspotButton icon { height: units.iconSizes.small width: units.iconSizes.small name: "network-wireless-on" } checkable: true text: i18n("Hotspot") visible: handler.hotspotSupported onClicked: { if (configuration.hotspotConnectionPath) { checked = false handler.stopHotspot() } else { checked = true handler.createHotspot() } } PlasmaComponents3.ToolTip { id: tooltip } Connections { target: handler onHotspotCreated: { hotspotButton.checked = true tooltip.text = i18n("Disable Hotspot") } onHotspotDisabled: { hotspotButton.checked = false tooltip.text = i18n("Create Hotspot") } } Component.onCompleted: { checked = configuration.hotspotConnectionPath tooltip.text = configuration.hotspotConnectionPath ? i18n("Disable Hotspot") : i18n("Create Hotspot") } } PlasmaComponents3.ToolButton { id: searchToggleButton icon { height: units.iconSizes.small width: units.iconSizes.small name: "search" } checkable: true PlasmaComponents3.ToolTip { text: i18ndc("plasma-nm", "button tooltip", "Search the connections") } } PlasmaComponents3.ToolButton { id: openEditorButton icon { height: units.iconSizes.small width: units.iconSizes.small name: "configure" } visible: mainWindow.kcmAuthorized PlasmaComponents3.ToolTip { text: i18n("Configure network connections...") } onClicked: { KCMShell.open(mainWindow.kcm) } } } - PlasmaComponents.TextField { + PlasmaCore.SvgItem { + Layout.fillWidth: true + elementId: "horizontal-line" + Layout.leftMargin: - units.smallSpacing * 1.5 + Layout.rightMargin: - units.smallSpacing * 1.5 + svg: lineSvg + } + + PlasmaComponents.TextField { id: searchTextField - Layout.row: 1 - Layout.columnSpan: 2 Layout.fillWidth: true Layout.leftMargin: units.smallSpacing Layout.rightMargin: units.smallSpacing + Layout.topMargin: units.smallSpacing Layout.bottomMargin: units.smallSpacing focus: true clearButtonShown: true placeholderText: i18ndc("plasma-nm", "text field placeholder text", "Search...") visible: searchToggleButton.checked onVisibleChanged: { if (visible) { searchTextField.forceActiveFocus() } else { text = "" } } Keys.onEscapePressed: { //Check if the searchbar is actually visible before accepting the escape key. Otherwise, the escape key cannot dismiss the applet until one interacts with some other element. if (searchToggleButton.checked) { searchToggleButton.checked = false; } else { event.accepted = false; } } onTextChanged: { // Show search field when starting to type directly if (text.length && !searchToggleButton.checked) { searchToggleButton.checked = true } appletProxyModel.setFilterRegExp(text) } } } diff --git a/applet/contents/ui/main.qml b/applet/contents/ui/main.qml index c43b0eac..d2eafb7e 100644 --- a/applet/contents/ui/main.qml +++ b/applet/contents/ui/main.qml @@ -1,87 +1,86 @@ /* Copyright 2013-2017 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.2 import org.kde.plasma.plasmoid 2.0 import org.kde.plasma.networkmanagement 0.2 as PlasmaNM import org.kde.kquickcontrolsaddons 2.0 import QtQuick.Layouts 1.1 Item { id: mainWindow - property bool showSections: true readonly property string kcm: "kcm_networkmanagement.desktop" readonly property bool kcmAuthorized: KCMShell.authorize(kcm).length == 1 Plasmoid.toolTipMainText: i18n("Networks") Plasmoid.toolTipSubText: networkStatus.activeConnections Plasmoid.icon: connectionIconProvider.connectionTooltipIcon Plasmoid.switchWidth: units.gridUnit * 10 Plasmoid.switchHeight: units.gridUnit * 10 Plasmoid.compactRepresentation: CompactRepresentation { } Plasmoid.fullRepresentation: PopupDialog { id: dialogItem Layout.minimumWidth: units.iconSizes.medium * 10 Layout.minimumHeight: units.gridUnit * 20 anchors.fill: parent focus: true } function action_openKCM() { KCMShell.open(kcm) } function action_showPortal() { Qt.openUrlExternally("http://networkcheck.kde.org") } Component.onCompleted: { if (kcmAuthorized) { plasmoid.setAction("openKCM", i18n("&Configure Network Connections..."), "preferences-system-network"); } plasmoid.removeAction("configure"); plasmoid.setAction("showPortal", i18n("Open Network Login Page..."), "internet-services"); var action = plasmoid.action("showPortal"); action.visible = Qt.binding(function() { return connectionIconProvider.needsPortal; }) } PlasmaNM.NetworkStatus { id: networkStatus } PlasmaNM.ConnectionIcon { id: connectionIconProvider } PlasmaNM.Handler { id: handler } Timer { id: scanTimer interval: 10200 repeat: true running: plasmoid.expanded && !connectionIconProvider.airplaneMode onTriggered: handler.requestScan() } } diff --git a/libs/models/networkmodel.h b/libs/models/networkmodel.h index b8598547..ed16597f 100644 --- a/libs/models/networkmodel.h +++ b/libs/models/networkmodel.h @@ -1,131 +1,132 @@ /* 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_NETWORK_MODEL_H #define PLASMA_NM_NETWORK_MODEL_H #include #include "networkitemslist.h" #include #include #include #include #if WITH_MODEMMANAGER_SUPPORT #include #endif class Q_DECL_EXPORT NetworkModel : public QAbstractListModel { Q_OBJECT public: explicit NetworkModel(QObject *parent = nullptr); ~NetworkModel() override; enum ItemRole { ConnectionDetailsRole = Qt::UserRole + 1, ConnectionIconRole, ConnectionPathRole, ConnectionStateRole, DeviceName, DevicePathRole, DeviceStateRole, DuplicateRole, ItemUniqueNameRole, ItemTypeRole, LastUsedRole, LastUsedDateOnlyRole, NameRole, SecurityTypeRole, SecurityTypeStringRole, SectionRole, SignalRole, SlaveRole, SsidRole, SpecificPathRole, TimeStampRole, TypeRole, UniRole, UuidRole, VpnState, VpnType, RxBytesRole, TxBytesRole }; + Q_ENUMS(ItemRole) int rowCount(const QModelIndex &parent) const override; QVariant data(const QModelIndex &index, int role) const override; QHash roleNames() const override; public Q_SLOTS: void onItemUpdated(); void setDeviceStatisticsRefreshRateMs(const QString &devicePath, uint refreshRate); private Q_SLOTS: void accessPointSignalStrengthChanged(int signal); void activeConnectionAdded(const QString &activeConnection); void activeConnectionRemoved(const QString &activeConnection); void activeConnectionStateChanged(NetworkManager::ActiveConnection::State state); void activeVpnConnectionStateChanged(NetworkManager::VpnConnection::State state,NetworkManager::VpnConnection::StateChangeReason reason); void availableConnectionAppeared(const QString &connection); void availableConnectionDisappeared(const QString &connection); void connectionAdded(const QString &connection); void connectionRemoved(const QString &connection); void connectionUpdated(); void deviceAdded(const QString &device); void deviceRemoved(const QString &device); void deviceStateChanged(NetworkManager::Device::State state, NetworkManager::Device::State oldState, NetworkManager::Device::StateChangeReason reason); #if WITH_MODEMMANAGER_SUPPORT void gsmNetworkAccessTechnologiesChanged(QFlags accessTechnologies); void gsmNetworkCurrentModesChanged(); void gsmNetworkSignalQualityChanged(const ModemManager::SignalQualityPair &signalQuality); #endif void ipConfigChanged(); void ipInterfaceChanged(); void statusChanged(NetworkManager::Status status); void wirelessNetworkAppeared(const QString &ssid); void wirelessNetworkDisappeared(const QString &ssid); void wirelessNetworkSignalChanged(int signal); void wirelessNetworkReferenceApChanged(const QString &accessPoint); void initialize(); private: NetworkItemsList m_list; void addActiveConnection(const NetworkManager::ActiveConnection::Ptr &activeConnection); void addAvailableConnection(const QString &connection, const NetworkManager::Device::Ptr &device); void addConnection(const NetworkManager::Connection::Ptr &connection); void addDevice(const NetworkManager::Device::Ptr &device); void addWirelessNetwork(const NetworkManager::WirelessNetwork::Ptr &network, const NetworkManager::WirelessDevice::Ptr &device); void checkAndCreateDuplicate(const QString &connection, const QString &deviceUni); void initializeSignals(); void initializeSignals(const NetworkManager::ActiveConnection::Ptr &activeConnection); void initializeSignals(const NetworkManager::Connection::Ptr &connection); void initializeSignals(const NetworkManager::Device::Ptr &device); void initializeSignals(const NetworkManager::WirelessNetwork::Ptr &network); void updateItem(NetworkModelItem *item); void updateFromWirelessNetwork(NetworkModelItem *item, const NetworkManager::WirelessNetwork::Ptr &network, const NetworkManager::WirelessDevice::Ptr &device); NetworkManager::WirelessSecurityType alternativeWirelessSecurity(const NetworkManager::WirelessSecurityType type); }; #endif // PLASMA_NM_NETWORK_MODEL_H diff --git a/libs/models/networkmodelitem.cpp b/libs/models/networkmodelitem.cpp index 25e9b36e..45dea85b 100644 --- a/libs/models/networkmodelitem.cpp +++ b/libs/models/networkmodelitem.cpp @@ -1,684 +1,682 @@ /* 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) { 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) { 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) { if (m_deviceName != name) { m_deviceName = name; m_changedRoles << NetworkModel::DeviceName; } } void NetworkModelItem::setDevicePath(const QString &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) { if (m_deviceState != state) { m_deviceState = state; m_changedRoles << NetworkModel::DeviceStateRole; } } bool NetworkModelItem::duplicate() const { return m_duplicate; } 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 (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 (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 (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) { if (m_mode != mode) { m_mode = mode; refreshIcon(); } } QString NetworkModelItem::name() const { return m_name; } void NetworkModelItem::setName(const QString &name) { if (m_name != name) { m_name = name; m_changedRoles << NetworkModel::ItemUniqueNameRole << 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"); + if (m_connectionState == NetworkManager::ActiveConnection::Deactivated) { + return "Available connections"; } else { - return i18n("Available connections"); + return QString(); } } NetworkManager::WirelessSecurityType NetworkModelItem::securityType() const { return m_securityType; } void NetworkModelItem::setSecurityType(NetworkManager::WirelessSecurityType type) { if (m_securityType != type) { m_securityType = type; m_changedRoles << NetworkModel::SecurityTypeStringRole << NetworkModel::SecurityTypeRole; refreshIcon(); } } int NetworkModelItem::signal() const { return m_signal; } void NetworkModelItem::setSignal(int 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) { if (m_slave != slave) { m_slave = slave; m_changedRoles << NetworkModel::SlaveRole; } } QString NetworkModelItem::specificPath() const { return m_specificPath; } void NetworkModelItem::setSpecificPath(const QString &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) { 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) { if (m_timestamp != date) { m_timestamp = date; m_changedRoles << NetworkModel::TimeStampRole; } } void NetworkModelItem::setType(NetworkManager::ConnectionSettings::ConnectionType 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) { 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) { if (m_vpnState != state) { m_vpnState = state; m_changedRoles << NetworkModel::VpnState; } } QString NetworkModelItem::vpnType() const { return m_vpnType; } void NetworkModelItem::setVpnType(const QString &type) { if (m_vpnType != type) { m_vpnType = type; m_changedRoles << NetworkModel::VpnType; } } qulonglong NetworkModelItem::rxBytes() const { return m_rxBytes; } void NetworkModelItem::setRxBytes(qulonglong bytes) { if (m_rxBytes != bytes) { m_rxBytes = bytes; m_changedRoles << NetworkModel::RxBytesRole; } } qulonglong NetworkModelItem::txBytes() const { return m_txBytes; } void NetworkModelItem::setTxBytes(qulonglong bytes) { if (m_txBytes != bytes) { m_txBytes = bytes; m_changedRoles << NetworkModel::TxBytesRole; } } 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; m_changedRoles << NetworkModel::ConnectionDetailsRole; } 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 and related nameservers + IPv4 default gateway 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->ipV4Config().gateway().isEmpty()) { QString addr = device->ipV4Config().gateway(); if (!addr.isNull()) { m_details << i18n("IPv4 Default Gateway") << addr; } } if (!device->ipV4Config().nameservers().isEmpty()) { QHostAddress addr = device->ipV4Config().nameservers().first(); if (!addr.isNull()) { m_details << i18n("IPv4 Nameserver") << 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 (!device->ipV6Config().nameservers().isEmpty()) { QHostAddress addr = device->ipV6Config().nameservers().first(); if (!addr.isNull()) { m_details << i18n("IPv6 Nameserver") << 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") << QStringLiteral("%1%").arg(m_signal); } - if (m_connectionState == NetworkManager::ActiveConnection::Activated) { - m_details << i18n("Security type") << UiUtils::labelFromWirelessSecurity(m_securityType); - } + 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(); } } }