Warning, /plasma/plasma-nm/applet/contents/ui/ConnectionItem.qml is written in an unsupported language. File is not indexed.

0001 /*
0002     SPDX-FileCopyrightText: 2013-2017 Jan Grulich <jgrulich@redhat.com>
0003     SPDX-FileCopyrightText: 2020 Nate Graham <nate@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006 */
0007 
0008 import QtQuick 2.15
0009 import QtQuick.Layouts 1.15
0010 import QtQuick.Controls 2.15
0011 
0012 import org.kde.kcoreaddons 1.0 as KCoreAddons
0013 import org.kde.kquickcontrolsaddons 2.0
0014 
0015 import org.kde.plasma.core 2.0 as PlasmaCore
0016 import org.kde.plasma.components 3.0 as PlasmaComponents3
0017 import org.kde.plasma.extras 2.0 as PlasmaExtras
0018 import org.kde.plasma.networkmanagement 0.2 as PlasmaNM
0019 
0020 PlasmaExtras.ExpandableListItem {
0021     id: connectionItem
0022 
0023     property bool activating: ConnectionState == PlasmaNM.Enums.Activating
0024     property bool deactivated: ConnectionState === PlasmaNM.Enums.Deactivated
0025     property bool passwordIsStatic: (SecurityType == PlasmaNM.Enums.StaticWep || SecurityType == PlasmaNM.Enums.WpaPsk ||
0026                                      SecurityType == PlasmaNM.Enums.Wpa2Psk || SecurityType == PlasmaNM.Enums.SAE)
0027     property bool predictableWirelessPassword: !Uuid && Type == PlasmaNM.Enums.Wireless && passwordIsStatic
0028     property bool showSpeed: plasmoid.expanded &&
0029                              ConnectionState == PlasmaNM.Enums.Activated &&
0030                              (Type == PlasmaNM.Enums.Wired ||
0031                               Type == PlasmaNM.Enums.Wireless ||
0032                               Type == PlasmaNM.Enums.Gsm ||
0033                               Type == PlasmaNM.Enums.Cdma)
0034 
0035     property real rxBytes: 0
0036     property real txBytes: 0
0037 
0038     icon: model.ConnectionIcon
0039     title: model.ItemUniqueName
0040     subtitle: itemText()
0041     iconUsesPlasmaSVG: true // We want the nice detailed network SVGs from the Plasma theme
0042     isBusy: plasmoid.expanded && model.ConnectionState == PlasmaNM.Enums.Activating
0043     isDefault: ConnectionState == PlasmaNM.Enums.Activated
0044     defaultActionButtonAction: Action {
0045         id: stateChangeButton
0046 
0047         readonly property bool isDeactivated: model.ConnectionState === PlasmaNM.Enums.Deactivated
0048 
0049         enabled: {
0050             if (!connectionItem.expanded) {
0051                 return true;
0052             }
0053             if (connectionItem.customExpandedViewContent === passwordDialogComponent) {
0054                 return connectionItem.customExpandedViewContentItem.passwordField.acceptableInput;
0055             }
0056             return true;
0057         }
0058 
0059         icon.name: isDeactivated ? "network-connect" : "network-disconnect"
0060         text: isDeactivated ? i18n("Connect") : i18n("Disconnect")
0061         onTriggered: changeState()
0062     }
0063     showDefaultActionButtonWhenBusy: true
0064 
0065     Keys.onPressed: {
0066         if (!connectionItem.expanded) {
0067             event.accepted = false;
0068             return;
0069         }
0070 
0071         if ((customExpandedViewContent == detailsComponent) && showSpeed) {
0072             if (event.key == Qt.Key_Right) {
0073                 customExpandedViewContentItem.detailsTabBar.currentIndex = 1;
0074                 event.accepted = true;
0075             } else if (event.key == Qt.Key_Left) {
0076                 customExpandedViewContentItem.detailsTabBar.currentIndex = 0;
0077                 event.accepted = true;
0078             }
0079         }
0080     }
0081 
0082     contextualActionsModel: [
0083         Action {
0084             enabled: Uuid && Type === PlasmaNM.Enums.Wireless && passwordIsStatic
0085             text: i18n("Show Network's QR Code")
0086             icon.name: "view-barcode-qr"
0087             onTriggered: handler.requestWifiCode(ConnectionPath, Ssid, SecurityType, connectionItem.title);
0088         },
0089         Action {
0090             text: i18n("Configure…")
0091             icon.name: "configure"
0092             onTriggered: KCMShell.openSystemSettings(mainWindow.kcm, ["--args", "Uuid=" + Uuid])
0093         }
0094     ]
0095 
0096     customExpandedViewContent: detailsComponent
0097 
0098     Accessible.description: `${model.AccessibleDescription} ${subtitle}`
0099 
0100     Component {
0101         id: detailsComponent
0102 
0103         Column {
0104             spacing: PlasmaCore.Units.smallSpacing
0105             property Item detailsTabBar: detailsTabBar
0106 
0107             PlasmaComponents3.TabBar {
0108                 id: detailsTabBar
0109 
0110                 anchors {
0111                     left: parent.left
0112                     right: parent.right
0113                 }
0114                 height: visible ? implicitHeight : 0
0115                 implicitHeight: contentHeight
0116                 position: PlasmaComponents3.TabBar.Header
0117                 visible: showSpeed
0118 
0119                 PlasmaComponents3.TabButton {
0120                     id: speedTabButton
0121                     text: i18n("Speed")
0122                 }
0123 
0124                 PlasmaComponents3.TabButton {
0125                     id: detailsTabButton
0126                     text: i18n("Details")
0127                 }
0128 
0129                 Component.onCompleted: {
0130                     if (!showSpeed) {
0131                         currentIndex = 1;
0132                     }
0133                 }
0134             }
0135 
0136             DetailsText {
0137                 id: detailsTextColumn
0138 
0139                 width: parent.width
0140                 visible: detailsTabBar.currentIndex == 1
0141 
0142                 activeFocusOnTab: details.length > 0
0143                 details: ConnectionDetails
0144 
0145                 Accessible.description: details.join(" ")
0146 
0147                 Loader {
0148                     anchors.fill: parent
0149                     active: parent.activeFocus
0150                     asynchronous: true
0151                     z: -1
0152 
0153                     sourceComponent: PlasmaExtras.Highlight {
0154                         hovered: true
0155                     }
0156                 }
0157             }
0158 
0159             FocusScope {
0160                 anchors {
0161                     left: parent.left
0162                     right: parent.right
0163                 }
0164                 height: trafficMonitorGraph.implicitHeight
0165                 visible: detailsTabBar.currentIndex == 0
0166 
0167                 activeFocusOnTab: true
0168 
0169                 Accessible.description: i18nc("@info:tooltip", "Current download speed is %1 kibibytes per second; current upload speed is %2 kibibytes per second", Math.round(rxBytes / 1024), Math.round(txBytes / 1024))
0170 
0171                 Loader {
0172                     anchors.fill: parent
0173                     active: parent.activeFocus
0174                     asynchronous: true
0175                     z: -1
0176 
0177                     sourceComponent: PlasmaExtras.Highlight {
0178                         hovered: true
0179                     }
0180                 }
0181 
0182                 TrafficMonitor {
0183                     id: trafficMonitorGraph
0184                     width: parent.width
0185                     downloadSpeed: rxBytes
0186                     uploadSpeed: txBytes
0187                 }
0188             }
0189 
0190         }
0191     }
0192 
0193     Component {
0194         id: passwordDialogComponent
0195 
0196         ColumnLayout {
0197             property alias password: passwordField.text
0198             property alias passwordField: passwordField
0199 
0200             PasswordField {
0201                 id: passwordField
0202 
0203                 Layout.fillWidth: true
0204                 Layout.leftMargin: PlasmaCore.Units.gridUnit
0205                 Layout.rightMargin: PlasmaCore.Units.gridUnit
0206 
0207                 securityType: SecurityType
0208 
0209                 onAccepted: {
0210                     stateChangeButton.trigger()
0211                     connectionItem.customExpandedViewContent = detailsComponent
0212                 }
0213 
0214                 Component.onCompleted: {
0215                     passwordField.forceActiveFocus()
0216                     setDelayModelUpdates(true)
0217                 }
0218             }
0219         }
0220     }
0221 
0222     Timer {
0223         id: timer
0224         repeat: true
0225         interval: 2000
0226         running: showSpeed
0227         triggeredOnStart: true
0228         property real prevRxBytes
0229         property real prevTxBytes
0230         Component.onCompleted: {
0231             prevRxBytes = 0
0232             prevTxBytes = 0
0233         }
0234         onTriggered: {
0235             rxBytes = prevRxBytes == 0 ? 0 : (RxBytes - prevRxBytes) * 1000 / interval
0236             txBytes = prevTxBytes == 0 ? 0 : (TxBytes - prevTxBytes) * 1000 / interval
0237             prevRxBytes = RxBytes
0238             prevTxBytes = TxBytes
0239         }
0240     }
0241 
0242     function changeState() {
0243         if (Uuid || !predictableWirelessPassword || connectionItem.customExpandedViewContent == passwordDialogComponent) {
0244             if (ConnectionState == PlasmaNM.Enums.Deactivated) {
0245                 if (!predictableWirelessPassword && !Uuid) {
0246                     handler.addAndActivateConnection(DevicePath, SpecificPath)
0247                 } else if (connectionItem.customExpandedViewContent == passwordDialogComponent) {
0248                     if (connectionItem.customExpandedViewContentItem.password != "") {
0249                         handler.addAndActivateConnection(DevicePath, SpecificPath, connectionItem.customExpandedViewContentItem.password)
0250                         connectionItem.customExpandedViewContent = detailsComponent
0251                         connectionItem.collapse()
0252                     } else {
0253                         connectionItem.expand()
0254                     }
0255                 } else {
0256                     handler.activateConnection(ConnectionPath, DevicePath, SpecificPath)
0257                 }
0258             } else {
0259                 handler.deactivateConnection(ConnectionPath, DevicePath)
0260             }
0261         } else if (predictableWirelessPassword) {
0262             setDelayModelUpdates(true)
0263             connectionItem.customExpandedViewContent = passwordDialogComponent
0264             connectionItem.expand()
0265         }
0266     }
0267 
0268     /* This generates the formatted text under the connection name
0269        in the popup where the connections can be "Connect"ed and
0270        "Disconnect"ed. */
0271     function itemText() {
0272         if (ConnectionState == PlasmaNM.Enums.Activating) {
0273             if (Type == PlasmaNM.Enums.Vpn)
0274                 return VpnState
0275             else
0276                 return DeviceState
0277         } else if (ConnectionState == PlasmaNM.Enums.Deactivating) {
0278             if (Type == PlasmaNM.Enums.Vpn)
0279                 return VpnState
0280             else
0281                 return DeviceState
0282         } else if (Uuid && ConnectionState == PlasmaNM.Enums.Deactivated) {
0283             return LastUsed
0284         } else if (ConnectionState == PlasmaNM.Enums.Activated) {
0285             if (showSpeed) {
0286                 return i18n("Connected, ⬇ %1/s, ⬆ %2/s",
0287                     KCoreAddons.Format.formatByteSize(rxBytes),
0288                     KCoreAddons.Format.formatByteSize(txBytes))
0289             } else {
0290                 return i18n("Connected")
0291             }
0292         }
0293         return ""
0294     }
0295 
0296     function setDelayModelUpdates(delay: bool) {
0297         appletProxyModel.setData(appletProxyModel.index(index, 0), delay, PlasmaNM.NetworkModel.DelayModelUpdatesRole);
0298     }
0299 
0300     onShowSpeedChanged: {
0301         connectionModel.setDeviceStatisticsRefreshRateMs(DevicePath, showSpeed ? 2000 : 0)
0302     }
0303 
0304     onActivatingChanged: {
0305         if (ConnectionState == PlasmaNM.Enums.Activating) {
0306             ListView.view.positionViewAtBeginning()
0307         }
0308     }
0309 
0310     onDeactivatedChanged: {
0311         /* Separator is part of section, which is visible only when available connections exist. Need to determine
0312            if there is a connection in use, to show Separator. Otherwise need to hide it from the top of the list.
0313            Connections in use are always on top, only need to check the first one. */
0314         if (appletProxyModel.data(appletProxyModel.index(0, 0), PlasmaNM.NetworkModel.SectionRole) !== "Available connections") {
0315             if (connectionView.showSeparator != true) {
0316                 connectionView.showSeparator = true
0317             }
0318             return
0319         }
0320         connectionView.showSeparator = false
0321         return
0322     }
0323 
0324     onItemCollapsed: {
0325         connectionItem.customExpandedViewContent = detailsComponent;
0326         setDelayModelUpdates(false);
0327     }
0328     Component.onDestruction: {
0329         setDelayModelUpdates(false);
0330     }
0331 }