mirror of
https://gitgud.io/wackyideas/aerothemeplasma.git
synced 2024-08-15 00:43:43 +00:00
Very early KDE 6 release.
This commit is contained in:
parent
7cc4ccabbc
commit
686046d4f7
6272 changed files with 140920 additions and 529657 deletions
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2023 Kai Uwe Broulik <kde@broulik.de>
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
-->
|
||||
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
|
||||
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
|
||||
<kcfgfile name=""/>
|
||||
|
||||
<group name="General">
|
||||
|
||||
<entry name="currentDetailsTab" type="String">
|
||||
<label>Last selected details tab (speed, details)</label>
|
||||
<default>speed</default>
|
||||
</entry>
|
||||
|
||||
</group>
|
||||
|
||||
</kcfg>
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2013-2017 Jan Grulich <jgrulich@redhat.com>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
|
||||
import QtQuick 2.2
|
||||
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
import org.kde.plasma.plasmoid 2.0
|
||||
|
||||
MouseArea {
|
||||
id: root
|
||||
|
||||
required property bool airplaneModeAvailable
|
||||
required property string iconName
|
||||
|
||||
hoverEnabled: true
|
||||
|
||||
acceptedButtons: airplaneModeAvailable ? Qt.LeftButton | Qt.MiddleButton : Qt.LeftButton
|
||||
|
||||
property bool wasExpanded
|
||||
|
||||
onPressed: wasExpanded = mainWindow.expanded
|
||||
onClicked: mouse => {
|
||||
if (airplaneModeAvailable && mouse.button === Qt.MiddleButton) {
|
||||
mainWindow.planeModeSwitchAction.trigger();
|
||||
} else {
|
||||
mainWindow.expanded = !wasExpanded;
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.Icon {
|
||||
id: connectionIcon
|
||||
|
||||
anchors.fill: parent
|
||||
source: root.iconName
|
||||
active: parent.containsMouse
|
||||
}
|
||||
}
|
|
@ -0,0 +1,450 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2013-2017 Jan Grulich <jgrulich@redhat.com>
|
||||
SPDX-FileCopyrightText: 2020 Nate Graham <nate@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQuick.Controls 2.15
|
||||
|
||||
import org.kde.coreaddons 1.0 as KCoreAddons
|
||||
import org.kde.kcmutils as KCMUtils
|
||||
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents3
|
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras
|
||||
import org.kde.plasma.networkmanagement as PlasmaNM
|
||||
import org.kde.plasma.plasmoid 2.0
|
||||
|
||||
ExpandableListItem {
|
||||
id: connectionItem
|
||||
|
||||
property bool activating: ConnectionState === PlasmaNM.Enums.Activating
|
||||
property bool deactivated: ConnectionState === PlasmaNM.Enums.Deactivated
|
||||
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: mainWindow.expanded &&
|
||||
ConnectionState === PlasmaNM.Enums.Activated &&
|
||||
(Type === PlasmaNM.Enums.Wired ||
|
||||
Type === PlasmaNM.Enums.Wireless ||
|
||||
Type === PlasmaNM.Enums.Gsm ||
|
||||
Type === PlasmaNM.Enums.Cdma)
|
||||
|
||||
property real rxSpeed: 0
|
||||
property real txSpeed: 0
|
||||
|
||||
icon: model.ConnectionIcon
|
||||
title: model.ItemUniqueName
|
||||
subtitle: itemText()
|
||||
isBusy: false
|
||||
//isBusy: mainWindow.expanded && model.ConnectionState === PlasmaNM.Enums.Activating
|
||||
isDefault: ConnectionState === PlasmaNM.Enums.Activated
|
||||
//defaultActionButtonAction:
|
||||
showDefaultActionButtonWhenBusy: false
|
||||
|
||||
Keys.onPressed: event => {
|
||||
if (!connectionItem.expanded) {
|
||||
event.accepted = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/*if ((customExpandedViewContent === detailsComponent) && showSpeed) {
|
||||
if (event.key === Qt.Key_Right) {
|
||||
customExpandedViewContentItem.detailsTabBar.currentIndex = 1;
|
||||
event.accepted = true;
|
||||
} else if (event.key === Qt.Key_Left) {
|
||||
customExpandedViewContentItem.detailsTabBar.currentIndex = 0;
|
||||
event.accepted = true;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: connectionItem.mouseArea
|
||||
function onPressed(mouse) {
|
||||
contextMenu.show(this, mouse.x, mouse.y);
|
||||
}
|
||||
}
|
||||
PlasmaExtras.Menu {
|
||||
id: contextMenu
|
||||
property string text
|
||||
|
||||
function show(item, x, y) {
|
||||
|
||||
visualParent = connectionItem
|
||||
open(x, y)
|
||||
}
|
||||
|
||||
|
||||
PlasmaExtras.MenuItem {
|
||||
readonly property bool isDeactivated: model.ConnectionState === PlasmaNM.Enums.Deactivated
|
||||
enabled: {
|
||||
if (!connectionItem.expanded) {
|
||||
return true;
|
||||
}
|
||||
if (connectionItem.customExpandedViewContent === passwordDialogComponent) {
|
||||
return connectionItem.customExpandedViewContentItem?.passwordField.acceptableInput ?? false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//icon.name: isDeactivated ? "network-connect" : "network-disconnect"
|
||||
text: isDeactivated ? i18n("Connect") : i18n("Disconnect")
|
||||
onClicked: changeState()
|
||||
}
|
||||
PlasmaExtras.MenuItem {
|
||||
text: i18n("Speed")
|
||||
icon: "preferences-system-performance"
|
||||
onClicked: {
|
||||
const speedGraphComponent = Qt.createComponent("SpeedGraphPage.qml");
|
||||
if (speedGraphComponent.status === Component.Error) {
|
||||
console.warn("Cannot create speed graph component:", speedGraphComponent.errorString());
|
||||
return;
|
||||
}
|
||||
|
||||
mainWindow.expanded = true; // just in case.
|
||||
stack.push(speedGraphComponent, {
|
||||
downloadSpeed: Qt.binding(() => rxSpeed),
|
||||
uploadSpeed: Qt.binding(() => txSpeed),
|
||||
connectionTitle: Qt.binding(() => model.ItemUniqueName)
|
||||
});
|
||||
}
|
||||
}
|
||||
PlasmaExtras.MenuItem {
|
||||
//text: i18n("Copy")
|
||||
text: i18n("Show Network's QR Code")
|
||||
icon: "view-barcode-qr"
|
||||
visible: Uuid && Type === PlasmaNM.Enums.Wireless && passwordIsStatic
|
||||
onClicked: handler.requestWifiCode(ConnectionPath, Ssid, SecurityType);
|
||||
}
|
||||
PlasmaExtras.MenuItem {
|
||||
text: i18n("Configure…")
|
||||
icon: "configure"
|
||||
onClicked: KCMUtils.KCMLauncher.openSystemSettings(mainWindow.kcm, ["--args", "Uuid=" + Uuid])
|
||||
}
|
||||
}
|
||||
contextualActions: [
|
||||
Action {
|
||||
id: stateChangeButton
|
||||
|
||||
readonly property bool isDeactivated: model.ConnectionState === PlasmaNM.Enums.Deactivated
|
||||
|
||||
enabled: {
|
||||
if (!connectionItem.expanded) {
|
||||
return true;
|
||||
}
|
||||
if (connectionItem.customExpandedViewContent === passwordDialogComponent) {
|
||||
return connectionItem.customExpandedViewContentItem?.passwordField.acceptableInput ?? false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//icon.name: isDeactivated ? "network-connect" : "network-disconnect"
|
||||
text: isDeactivated ? i18n("Connect") : i18n("Disconnect")
|
||||
onTriggered: changeState()
|
||||
},
|
||||
Action {
|
||||
text: i18n("Details")
|
||||
//icon.name: "configure"
|
||||
onTriggered: {
|
||||
const showDetailscomponent = Qt.createComponent("NetworkDetailsPage.qml");
|
||||
if (showDetailscomponent.status === Component.Error) {
|
||||
console.warn("Cannot create details page component:", showDetailscomponent.errorString());
|
||||
return;
|
||||
}
|
||||
|
||||
mainWindow.expanded = true; // just in case.
|
||||
stack.push(showDetailscomponent, {
|
||||
details: Qt.binding(() => ConnectionDetails),
|
||||
connectionTitle: Qt.binding(() => model.ItemUniqueName)
|
||||
});
|
||||
}
|
||||
}/*,
|
||||
Action {
|
||||
enabled: Uuid && Type === PlasmaNM.Enums.Wireless && passwordIsStatic
|
||||
text: i18n("Show Network's QR Code")
|
||||
icon.name: "view-barcode-qr"
|
||||
onTriggered: handler.requestWifiCode(ConnectionPath, Ssid, SecurityType);
|
||||
},
|
||||
Action {
|
||||
text: i18n("Configure…")
|
||||
icon.name: "configure"
|
||||
onTriggered: KCMUtils.KCMLauncher.openSystemSettings(mainWindow.kcm, ["--args", "Uuid=" + Uuid])
|
||||
}*/
|
||||
]
|
||||
|
||||
/*Component {
|
||||
id: buttonsComponent
|
||||
Column {
|
||||
Button {
|
||||
text: i18n("Details")
|
||||
onClicked: {
|
||||
const showDetailscomponent = Qt.createComponent("NetworkDetailsPage.qml");
|
||||
if (showDetailscomponent.status === Component.Error) {
|
||||
console.warn("Cannot create QR code component:", showDetailscomponent.errorString());
|
||||
return;
|
||||
}
|
||||
|
||||
mainWindow.expanded = true; // just in case.
|
||||
stack.push(showDetailscomponent, {
|
||||
details: ConnectionDetails
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
//customExpandedViewContent: detailsComponent
|
||||
|
||||
Accessible.description: `${model.AccessibleDescription} ${subtitle}`
|
||||
|
||||
/*Component {
|
||||
id: detailsComponent
|
||||
|
||||
Column {
|
||||
visible: false
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
property Item detailsTabBar: detailsTabBar
|
||||
|
||||
|
||||
PlasmaComponents3.TabBar {
|
||||
id: detailsTabBar
|
||||
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
height: visible ? implicitHeight : 0
|
||||
implicitHeight: contentHeight
|
||||
position: PlasmaComponents3.TabBar.Header
|
||||
visible: false //showSpeed
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
// Only if there are the two tabs.
|
||||
if (showSpeed) {
|
||||
Plasmoid.configuration.currentDetailsTab = ["speed", "details"][currentIndex];
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!visible) {
|
||||
currentIndex = 1;
|
||||
}
|
||||
}
|
||||
|
||||
PlasmaComponents3.TabButton {
|
||||
id: speedTabButton
|
||||
text: i18n("Speed")
|
||||
}
|
||||
|
||||
PlasmaComponents3.TabButton {
|
||||
id: detailsTabButton
|
||||
text: i18n("Details")
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (!showSpeed || Plasmoid.configuration.currentDetailsTab === "details") {
|
||||
currentIndex = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DetailsText {
|
||||
id: detailsTextColumn
|
||||
|
||||
width: parent.width
|
||||
visible: detailsTabBar.currentIndex === 1
|
||||
|
||||
activeFocusOnTab: details.length > 0
|
||||
details: ConnectionDetails
|
||||
|
||||
Accessible.description: details.join(" ")
|
||||
|
||||
Loader {
|
||||
anchors.fill: parent
|
||||
active: parent.activeFocus
|
||||
asynchronous: true
|
||||
z: -1
|
||||
|
||||
sourceComponent: PlasmaExtras.Highlight {
|
||||
hovered: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FocusScope {
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
height: trafficMonitorGraph.implicitHeight
|
||||
visible: false// detailsTabBar.currentIndex === 0
|
||||
|
||||
activeFocusOnTab: true
|
||||
|
||||
Accessible.description: i18nc("@info:tooltip", "Current download speed is %1 kibibytes per second; current upload speed is %2 kibibytes per second", Math.round(rxSpeed / 1024), Math.round(txSpeed / 1024))
|
||||
|
||||
Loader {
|
||||
anchors.fill: parent
|
||||
active: parent.activeFocus
|
||||
asynchronous: true
|
||||
z: -1
|
||||
|
||||
sourceComponent: PlasmaExtras.Highlight {
|
||||
hovered: true
|
||||
}
|
||||
}
|
||||
|
||||
TrafficMonitor {
|
||||
id: trafficMonitorGraph
|
||||
width: parent.width
|
||||
downloadSpeed: rxSpeed
|
||||
uploadSpeed: txSpeed
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}*/
|
||||
|
||||
Component {
|
||||
id: passwordDialogComponent
|
||||
|
||||
ColumnLayout {
|
||||
property alias password: passwordField.text
|
||||
property alias passwordField: passwordField
|
||||
|
||||
PasswordField {
|
||||
id: passwordField
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: Kirigami.Units.iconSizes.small
|
||||
Layout.rightMargin: Kirigami.Units.iconSizes.small
|
||||
|
||||
securityType: SecurityType
|
||||
|
||||
onAccepted: {
|
||||
stateChangeButton.trigger()
|
||||
//connectionItem.customExpandedViewContent = detailsComponent
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
passwordField.forceActiveFocus()
|
||||
setDelayModelUpdates(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: timer
|
||||
repeat: true
|
||||
interval: 2000
|
||||
running: showSpeed
|
||||
triggeredOnStart: true
|
||||
// property int can overflow with the amount of bytes.
|
||||
property double prevRxBytes: 0
|
||||
property double prevTxBytes: 0
|
||||
onTriggered: {
|
||||
rxSpeed = prevRxBytes === 0 ? 0 : (RxBytes - prevRxBytes) * 1000 / interval
|
||||
txSpeed = prevTxBytes === 0 ? 0 : (TxBytes - prevTxBytes) * 1000 / interval
|
||||
prevRxBytes = RxBytes
|
||||
prevTxBytes = TxBytes
|
||||
}
|
||||
}
|
||||
|
||||
function changeState() {
|
||||
if (Uuid || !predictableWirelessPassword || connectionItem.customExpandedViewContent == passwordDialogComponent) {
|
||||
if (ConnectionState == PlasmaNM.Enums.Deactivated) {
|
||||
if (!predictableWirelessPassword && !Uuid) {
|
||||
handler.addAndActivateConnection(DevicePath, SpecificPath)
|
||||
} else if (connectionItem.customExpandedViewContent == passwordDialogComponent) {
|
||||
const item = connectionItem.customExpandedViewContentItem;
|
||||
if (item && item.password !== "") {
|
||||
handler.addAndActivateConnection(DevicePath, SpecificPath, item.password)
|
||||
//connectionItem.customExpandedViewContent = detailsComponent
|
||||
connectionItem.collapse()
|
||||
} else {
|
||||
connectionItem.expand()
|
||||
}
|
||||
} else {
|
||||
handler.activateConnection(ConnectionPath, DevicePath, SpecificPath)
|
||||
}
|
||||
} else {
|
||||
handler.deactivateConnection(ConnectionPath, DevicePath)
|
||||
}
|
||||
} else if (predictableWirelessPassword) {
|
||||
setDelayModelUpdates(true)
|
||||
connectionItem.customExpandedViewContent = passwordDialogComponent
|
||||
connectionItem.expand()
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 (Uuid && ConnectionState === PlasmaNM.Enums.Deactivated) {
|
||||
return LastUsed
|
||||
} else if (ConnectionState === PlasmaNM.Enums.Activated) {
|
||||
if (showSpeed) {
|
||||
return i18n("Connected, ⬇ %1/s, ⬆ %2/s",
|
||||
KCoreAddons.Format.formatByteSize(rxSpeed),
|
||||
KCoreAddons.Format.formatByteSize(txSpeed))
|
||||
} else {
|
||||
return i18n("Connected")
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
function setDelayModelUpdates(delay: bool) {
|
||||
appletProxyModel.setData(appletProxyModel.index(index, 0), delay, PlasmaNM.NetworkModel.DelayModelUpdatesRole);
|
||||
}
|
||||
|
||||
onShowSpeedChanged: {
|
||||
connectionModel.setDeviceStatisticsRefreshRateMs(DevicePath, showSpeed ? 2000 : 0)
|
||||
}
|
||||
|
||||
onActivatingChanged: {
|
||||
if (ConnectionState === PlasmaNM.Enums.Activating) {
|
||||
ListView.view.positionViewAtBeginning()
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
onItemCollapsed: {
|
||||
//connectionItem.customExpandedViewContent = detailsComponent;
|
||||
setDelayModelUpdates(false);
|
||||
}
|
||||
Component.onDestruction: {
|
||||
setDelayModelUpdates(false);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2013-2017 Jan Grulich <jgrulich@redhat.com>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.2
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents3
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras
|
||||
import org.kde.plasma.networkmanagement as PlasmaNM
|
||||
import org.kde.networkmanager as NMQt
|
||||
|
||||
ColumnLayout {
|
||||
id: connectionListPage
|
||||
|
||||
required property PlasmaNM.NetworkStatus nmStatus
|
||||
property alias model: connectionView.model
|
||||
property alias count: connectionView.count
|
||||
|
||||
spacing: Kirigami.Units.smallSpacing * 2
|
||||
|
||||
Keys.forwardTo: [connectionView]
|
||||
|
||||
Kirigami.InlineMessage {
|
||||
id: connectivityMessage
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: connectionView.leftMargin
|
||||
Layout.rightMargin: connectionView.rightMargin
|
||||
Layout.topMargin: Kirigami.Units.smallSpacing * 2
|
||||
Layout.preferredHeight: contentItem.implicitHeight + topPadding + bottomPadding
|
||||
type: Kirigami.MessageType.Information
|
||||
icon.name: "dialog-password"
|
||||
text: i18n("You need to log in to this network")
|
||||
visible: connectionListPage.nmStatus.connectivity === NMQt.NetworkManager.Portal
|
||||
|
||||
actions: Kirigami.Action {
|
||||
text: i18nc("@action:button", "Log in")
|
||||
onTriggered: {
|
||||
Qt.openUrlExternally(connectionListPage.nmStatus.networkCheckUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PlasmaComponents3.ScrollView {
|
||||
id: scrollView
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
contentWidth: availableWidth - contentItem.leftMargin - contentItem.rightMargin
|
||||
PlasmaComponents3.ScrollBar.horizontal.policy: PlasmaComponents3.ScrollBar.AlwaysOff
|
||||
|
||||
contentItem: ListView {
|
||||
id: connectionView
|
||||
|
||||
property int currentVisibleButtonIndex: -1
|
||||
property bool showSeparator: false
|
||||
|
||||
Keys.onDownPressed: event => {
|
||||
connectionView.incrementCurrentIndex();
|
||||
connectionView.currentItem.forceActiveFocus();
|
||||
}
|
||||
Keys.onUpPressed: event => {
|
||||
if (connectionView.currentIndex === 0) {
|
||||
connectionView.currentIndex = -1;
|
||||
toolbar.searchTextField.forceActiveFocus();
|
||||
toolbar.searchTextField.selectAll();
|
||||
} else {
|
||||
event.accepted = false;
|
||||
}
|
||||
}
|
||||
|
||||
// We use the spacing around the connectivity message, if shown.
|
||||
//topMargin: connectivityMessage.visible ? 0 : Kirigami.Units.smallSpacing
|
||||
bottomMargin: Kirigami.Units.smallSpacing * 2
|
||||
//leftMargin: Kirigami.Units.smallSpacing * 2
|
||||
//rightMargin: Kirigami.Units.smallSpacing * 2
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
model: appletProxyModel
|
||||
currentIndex: -1
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
section.property: showSeparator ? "Section" : ""
|
||||
section.delegate: ListItem {
|
||||
separator: true
|
||||
}
|
||||
highlight: PlasmaExtras.Highlight { }
|
||||
highlightMoveDuration: 0//Kirigami.Units.shortDuration
|
||||
highlightResizeDuration: 0//Kirigami.Units.shortDuration
|
||||
delegate: ConnectionItem {
|
||||
width: connectionView.width// - Kirigami.Units.smallSpacing * 4
|
||||
}
|
||||
|
||||
// Placeholder message
|
||||
Loader {
|
||||
anchors.centerIn: parent
|
||||
width: parent.width - (Kirigami.Units.largeSpacing * 4)
|
||||
active: connectionView.count === 0
|
||||
asynchronous: true
|
||||
visible: status === Loader.Ready
|
||||
sourceComponent: PlasmaExtras.PlaceholderMessage {
|
||||
iconName: {
|
||||
if (toolbar.displayplaneModeMessage) {
|
||||
return "network-flightmode-on"
|
||||
}
|
||||
if (toolbar.displayWifiMessage) {
|
||||
return "network-wireless-off"
|
||||
}
|
||||
if (toolbar.displayWwanMessage) {
|
||||
return "network-mobile-off"
|
||||
}
|
||||
return "edit-none"
|
||||
}
|
||||
text: {
|
||||
if (toolbar.displayplaneModeMessage) {
|
||||
return i18n("Airplane mode is enabled")
|
||||
}
|
||||
if (toolbar.displayWifiMessage) {
|
||||
if (toolbar.displayWwanMessage) {
|
||||
return i18n("Wireless and mobile networks are deactivated")
|
||||
}
|
||||
return i18n("Wireless is deactivated")
|
||||
}
|
||||
if (toolbar.displayWwanMessage) {
|
||||
return i18n("Mobile network is deactivated")
|
||||
}
|
||||
if (toolbar.searchTextField.text.length > 0) {
|
||||
return i18n("No matches")
|
||||
}
|
||||
return i18n("No available connections")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2013-2017 Jan Grulich <jgrulich@redhat.com>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Layouts 1.15
|
||||
|
||||
import org.kde.kquickcontrolsaddons 2.0 as KQuickControlsAddons
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents3
|
||||
|
||||
MouseArea {
|
||||
height: detailsGrid.implicitHeight
|
||||
|
||||
property string connectionTitle: ""
|
||||
property var details: []
|
||||
|
||||
acceptedButtons: Qt.RightButton
|
||||
|
||||
onPressed: mouse => {
|
||||
const item = detailsGrid.childAt(mouse.x, mouse.y);
|
||||
if (!item || !item.isContent) {
|
||||
return;
|
||||
}
|
||||
contextMenu.show(this, item.text, mouse.x, mouse.y);
|
||||
}
|
||||
|
||||
KQuickControlsAddons.Clipboard {
|
||||
id: clipboard
|
||||
}
|
||||
|
||||
PlasmaExtras.Menu {
|
||||
id: contextMenu
|
||||
property string text
|
||||
|
||||
function show(item, text, x, y) {
|
||||
contextMenu.text = text
|
||||
visualParent = item
|
||||
open(x, y)
|
||||
}
|
||||
|
||||
PlasmaExtras.MenuItem {
|
||||
text: i18n("Copy")
|
||||
icon: "edit-copy"
|
||||
enabled: contextMenu.text !== ""
|
||||
onClicked: clipboard.content = contextMenu.text
|
||||
}
|
||||
}
|
||||
|
||||
PlasmaComponents3.Label {
|
||||
id: titleLabel
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Kirigami.Units.smallSpacing
|
||||
anchors.leftMargin: Kirigami.Units.smallSpacing
|
||||
anchors.topMargin: -Kirigami.Units.smallSpacing*2
|
||||
//horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignTop
|
||||
text: connectionTitle + " " + i18n("Details")
|
||||
}
|
||||
GridLayout {
|
||||
id: detailsGrid
|
||||
width: parent.width
|
||||
columns: 2
|
||||
rowSpacing: Kirigami.Units.smallSpacing / 4
|
||||
anchors.top: titleLabel.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Kirigami.Units.smallSpacing
|
||||
anchors.leftMargin: Kirigami.Units.smallSpacing
|
||||
anchors.topMargin: Kirigami.Units.smallSpacing
|
||||
|
||||
Repeater {
|
||||
id: repeater
|
||||
|
||||
model: details.length
|
||||
|
||||
PlasmaComponents3.Label {
|
||||
Layout.fillWidth: true
|
||||
|
||||
readonly property bool isContent: index % 2
|
||||
|
||||
elide: isContent ? Text.ElideRight : Text.ElideNone
|
||||
font: Kirigami.Theme.smallFont
|
||||
horizontalAlignment: isContent ? Text.AlignRight : Text.AlignLeft
|
||||
text: isContent ? details[index] : `${details[index]}:`
|
||||
textFormat: Text.PlainText
|
||||
opacity: isContent ? 1 : 0.6
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,647 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2020 Nate Graham <nate@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Templates as T
|
||||
import org.kde.plasma.core as PlasmaCore
|
||||
import org.kde.ksvg as KSvg
|
||||
import org.kde.plasma.components as PlasmaComponents3
|
||||
import org.kde.plasma.extras as PlasmaExtras
|
||||
import org.kde.kirigami as Kirigami
|
||||
import QtQuick.Controls 2.15 as QQC2
|
||||
|
||||
/**
|
||||
* A list item that expands when clicked to show additional actions and/or a
|
||||
* custom view.
|
||||
* The list item has a standardized appearance, with an icon on the left badged
|
||||
* with an optional emblem, a title and optional subtitle to the right, an
|
||||
* optional default action button, and a button to expand and collapse the list
|
||||
* item.
|
||||
*
|
||||
* When expanded, the list item shows a list of contextually-appropriate actions
|
||||
* if contextualActions has been defined.
|
||||
* If customExpandedViewContent has been defined, it will show a custom view.
|
||||
* If both have been defined, it shows both, with the actions above the custom
|
||||
* view.
|
||||
*
|
||||
* It is not valid to define neither; define one or both.
|
||||
*
|
||||
* Note: this component should only be used for lists where the maximum number
|
||||
* of items is very low, ideally less than 10. For longer lists, consider using
|
||||
* a different paradigm.
|
||||
*
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* @code
|
||||
* import QtQuick
|
||||
* import QtQuick.Controls as QQC2
|
||||
* import org.kde.kirigami as Kirigami
|
||||
* import org.kde.plasma.extras as PlasmaExtras
|
||||
* import org.kde.plasma.components as PlasmaComponents
|
||||
*
|
||||
* PlasmaComponents.ScrollView {
|
||||
* ListView {
|
||||
* anchors.fill: parent
|
||||
* focus: true
|
||||
* currentIndex: -1
|
||||
* clip: true
|
||||
* model: myModel
|
||||
* highlight: PlasmaExtras.Highlight {}
|
||||
* highlightMoveDuration: Kirigami.Units.shortDuration
|
||||
* highlightResizeDuration: Kirigami.Units.shortDuration
|
||||
* delegate: PlasmaExtras.ExpandableListItem {
|
||||
* icon: model.iconName
|
||||
* iconEmblem: model.isPaused ? "emblem-pause" : ""
|
||||
* title: model.name
|
||||
* subtitle: model.subtitle
|
||||
* isDefault: model.isDefault
|
||||
* defaultActionButtonAction: QQC2.Action {
|
||||
* icon.name: model.isPaused ? "media-playback-start" : "media-playback-pause"
|
||||
* text: model.isPaused ? "Resume" : "Pause"
|
||||
* onTriggered: {
|
||||
* if (model.isPaused) {
|
||||
* model.resume(model.name);
|
||||
* } else {
|
||||
* model.pause(model.name);
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* contextualActions: [
|
||||
* QQC2.Action {
|
||||
* icon.name: "configure"
|
||||
* text: "Configure…"
|
||||
* onTriggered: model.configure(model.name);
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
Item {
|
||||
id: listItem
|
||||
|
||||
property alias mouseArea: listMouseArea
|
||||
/**
|
||||
* icon: var
|
||||
* The name of the icon used in the list item.
|
||||
* @sa Kirigami.Icon::source
|
||||
*
|
||||
* Required.
|
||||
*/
|
||||
property alias icon: listItemIcon.source
|
||||
|
||||
/**
|
||||
* iconEmblem: var
|
||||
* The name of the emblem to badge the icon with.
|
||||
* @sa Kirigami.Icon::source
|
||||
*
|
||||
* Optional, defaults to nothing, in which case there is no emblem.
|
||||
*/
|
||||
property alias iconEmblem: iconEmblem.source
|
||||
|
||||
/*
|
||||
* title: string
|
||||
* The name or title for this list item.
|
||||
*
|
||||
* Optional; if not defined, there will be no title and the subtitle will be
|
||||
* vertically centered in the list item.
|
||||
*/
|
||||
property alias title: listItemTitle.text
|
||||
|
||||
/*
|
||||
* subtitle: string
|
||||
* The subtitle for this list item, displayed under the title.
|
||||
*
|
||||
* Optional; if not defined, there will be no subtitle and the title will be
|
||||
* vertically centered in the list item.
|
||||
*/
|
||||
property alias subtitle: listItemSubtitle.text
|
||||
|
||||
/*
|
||||
* subtitleCanWrap: bool
|
||||
* Whether to allow the subtitle to become a multi-line string instead of
|
||||
* eliding when the text is very long.
|
||||
*
|
||||
* Optional, defaults to false.
|
||||
*/
|
||||
property bool subtitleCanWrap: false
|
||||
|
||||
/*
|
||||
* subtitleColor: color
|
||||
* The color of the subtitle text
|
||||
*
|
||||
* Optional; if not defined, the subtitle will use the default text color
|
||||
*/
|
||||
property alias subtitleColor: listItemSubtitle.color
|
||||
|
||||
/*
|
||||
* allowStyledText: bool
|
||||
* Whether to allow the title, subtitle, and tooltip to contain styled text.
|
||||
* For performance and security reasons, keep this off unless needed.
|
||||
*
|
||||
* Optional, defaults to false.
|
||||
*/
|
||||
property bool allowStyledText: false
|
||||
|
||||
/*
|
||||
* defaultActionButtonAction: T.Action
|
||||
* The Action to execute when the default button is clicked.
|
||||
*
|
||||
* Optional; if not defined, no default action button will be displayed.
|
||||
*/
|
||||
property alias defaultActionButtonAction: defaultActionButton.action
|
||||
|
||||
/*
|
||||
* defaultActionButtonVisible: bool
|
||||
* When/whether to show to default action button. Useful for making it
|
||||
* conditionally appear or disappear.
|
||||
*
|
||||
* Optional; defaults to true
|
||||
*/
|
||||
property bool defaultActionButtonVisible: true
|
||||
|
||||
/*
|
||||
* showDefaultActionButtonWhenBusy : bool
|
||||
* Whether to continue showing the default action button while the busy
|
||||
* indicator is visible. Useful for cancelable actions that could take a few
|
||||
* seconds and show a busy indicator while processing.
|
||||
*
|
||||
* Optional; defaults to false
|
||||
*/
|
||||
property bool showDefaultActionButtonWhenBusy: false
|
||||
|
||||
/*
|
||||
* contextualActions: list<T.Action>
|
||||
* A list of standard QQC2.Action objects that describes additional actions
|
||||
* that can be performed on this list item. For example:
|
||||
*
|
||||
* @code
|
||||
* contextualActions: [
|
||||
* Action {
|
||||
* text: "Do something"
|
||||
* icon.name: "document-edit"
|
||||
* onTriggered: doSomething()
|
||||
* },
|
||||
* Action {
|
||||
* text: "Do something else"
|
||||
* icon.name: "draw-polygon"
|
||||
* onTriggered: doSomethingElse()
|
||||
* },
|
||||
* Action {
|
||||
* text: "Do something completely different"
|
||||
* icon.name: "games-highscores"
|
||||
* onTriggered: doSomethingCompletelyDifferent()
|
||||
* }
|
||||
* ]
|
||||
* @endcode
|
||||
*
|
||||
* Optional; if not defined, no contextual actions will be displayed and
|
||||
* you should instead assign a custom view to customExpandedViewContent,
|
||||
* which will be shown when the user expands the list item.
|
||||
*/
|
||||
property list<T.Action> contextualActions
|
||||
|
||||
readonly property list<T.Action> __enabledContextualActions: contextualActions.filter(action => action?.enabled ?? false)
|
||||
|
||||
/*
|
||||
* A custom view to display when the user expands the list item.
|
||||
*
|
||||
* This component must define width and height properties. Width should be
|
||||
* equal to the width of the list item itself, while height: will depend
|
||||
* on the component itself.
|
||||
*
|
||||
* Optional; if not defined, no custom view actions will be displayed and
|
||||
* you should instead define contextualActions, and then actions will
|
||||
* be shown when the user expands the list item.
|
||||
*/
|
||||
property Component customExpandedViewContent
|
||||
|
||||
/*
|
||||
* The actual instance of the custom view content, if loaded.
|
||||
* @since 5.72
|
||||
*/
|
||||
property alias customExpandedViewContentItem: customContentLoader.item
|
||||
|
||||
/*
|
||||
* isBusy: bool
|
||||
* Whether or not to display a busy indicator on the list item. Set to true
|
||||
* while the item should be non-interactive because things are processing.
|
||||
*
|
||||
* Optional; defaults to false.
|
||||
*/
|
||||
property bool isBusy: false
|
||||
|
||||
/*
|
||||
* isDefault: bool
|
||||
* Whether or not this list item should be considered the "default" or
|
||||
* "Current" item in the list. When set to true, and the list itself has
|
||||
* more than one item in it, the list item's title and subtitle will be
|
||||
* drawn in a bold style.
|
||||
*
|
||||
* Optional; defaults to false.
|
||||
*/
|
||||
property bool isDefault: false
|
||||
|
||||
/**
|
||||
* expanded: bool
|
||||
* Whether the expanded view is visible.
|
||||
*
|
||||
* @since 5.98
|
||||
*/
|
||||
readonly property alias expanded: expandedView.expanded
|
||||
|
||||
/*
|
||||
* hasExpandableContent: bool (read-only)
|
||||
* Whether or not this expandable list item is actually expandable. True if
|
||||
* this item has either a custom view or else at least one enabled action.
|
||||
* Otherwise false.
|
||||
*/
|
||||
readonly property bool hasExpandableContent: customExpandedViewContent !== null || __enabledContextualActions.length > 0
|
||||
|
||||
/*
|
||||
* expand()
|
||||
* Show the expanded view, growing the list item to its taller size.
|
||||
*/
|
||||
function expand() {
|
||||
if (!listItem.hasExpandableContent) {
|
||||
return;
|
||||
}
|
||||
expandedView.expanded = true
|
||||
listItem.itemExpanded()
|
||||
}
|
||||
|
||||
/*
|
||||
* collapse()
|
||||
* Hide the expanded view and collapse the list item to its shorter size.
|
||||
*/
|
||||
function collapse() {
|
||||
if (!listItem.hasExpandableContent) {
|
||||
return;
|
||||
}
|
||||
expandedView.expanded = false
|
||||
listItem.itemCollapsed()
|
||||
}
|
||||
|
||||
/*
|
||||
* toggleExpanded()
|
||||
* Expand or collapse the list item depending on its current state.
|
||||
*/
|
||||
function toggleExpanded() {
|
||||
if (!listItem.hasExpandableContent) {
|
||||
return;
|
||||
}
|
||||
expandedView.expanded ? listItem.collapse() : listItem.expand()
|
||||
}
|
||||
|
||||
signal itemExpanded()
|
||||
signal itemCollapsed()
|
||||
|
||||
width: parent ? parent.width : undefined // Assume that we will be used as a delegate, not placed in a layout
|
||||
height: mainLayout.height
|
||||
|
||||
/* Behavior on height {
|
||||
enabled: false //listItem.ListView.view.highlightResizeDuration > 0
|
||||
SmoothedAnimation { // to match the highlight
|
||||
id: heightAnimation
|
||||
duration: listItem.ListView.view.highlightResizeDuration || -1
|
||||
velocity: listItem.ListView.view.highlightResizeVelocity
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
}
|
||||
clip: heightAnimation.running || expandedItemOpacityFade.running*/
|
||||
|
||||
onEnabledChanged: if (!listItem.enabled) { collapse() }
|
||||
|
||||
Keys.onPressed: event => {
|
||||
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
||||
if (defaultActionButtonAction) {
|
||||
defaultActionButtonAction.trigger()
|
||||
} else {
|
||||
toggleExpanded();
|
||||
}
|
||||
event.accepted = true;
|
||||
} else if (event.key === Qt.Key_Escape) {
|
||||
if (expandedView.expanded) {
|
||||
collapse();
|
||||
event.accepted = true;
|
||||
}
|
||||
// if not active, we'll let the Escape event pass through, so it can close the applet, etc.
|
||||
} else if (event.key === Qt.Key_Space) {
|
||||
toggleExpanded();
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*KeyNavigation.tab: defaultActionButtonVisible ? defaultActionButton : expandToggleButton
|
||||
KeyNavigation.right: defaultActionButtonVisible ? defaultActionButton : expandToggleButton
|
||||
KeyNavigation.down: expandToggleButton.KeyNavigation.down*/
|
||||
Keys.onDownPressed: event => {
|
||||
if (!actionsListLoader.item || ListView.view.currentIndex < 0) {
|
||||
ListView.view.incrementCurrentIndex();
|
||||
ListView.view.currentItem.forceActiveFocus(Qt.TabFocusReason);
|
||||
event.accepted = true;
|
||||
return;
|
||||
}
|
||||
event.accepted = false; // Forward to KeyNavigation.down
|
||||
}
|
||||
Keys.onUpPressed: event => {
|
||||
if (ListView.view.currentIndex === 0) {
|
||||
event.accepted = false;
|
||||
} else {
|
||||
ListView.view.decrementCurrentIndex();
|
||||
ListView.view.currentItem.forceActiveFocus(Qt.BacktabFocusReason);
|
||||
}
|
||||
}
|
||||
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.name: title
|
||||
Accessible.description: subtitle
|
||||
|
||||
// Handle left clicks and taps; don't accept stylus input or else it steals
|
||||
// events from the buttons on the list item
|
||||
TapHandler {
|
||||
enabled: listItem.hasExpandableContent
|
||||
|
||||
acceptedPointerTypes: PointerDevice.Generic | PointerDevice.Finger
|
||||
|
||||
onSingleTapped: {
|
||||
listItem.ListView.view.currentIndex = index
|
||||
listItem.toggleExpanded()
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: listMouseArea
|
||||
anchors.fill: parent
|
||||
|
||||
// This MouseArea used to intercept RightButton to open a context
|
||||
// menu, but that has been removed, and now it's only used for hover
|
||||
acceptedButtons: Qt.RightButton
|
||||
hoverEnabled: true
|
||||
|
||||
// using onPositionChanged instead of onContainsMouseChanged so this doesn't trigger when the list reflows
|
||||
onPositionChanged: {
|
||||
// don't change currentIndex if it would make listview scroll
|
||||
// see https://bugs.kde.org/show_bug.cgi?id=387797
|
||||
// this is a workaround till https://bugreports.qt.io/browse/QTBUG-114574 gets fixed
|
||||
// which would allow a proper solution
|
||||
if (parent.y - listItem.ListView.view.contentY >= 0 && parent.y - listItem.ListView.view.contentY + parent.height + 1 /* border */ < listItem.ListView.view.height) {
|
||||
listItem.ListView.view.currentIndex = (containsMouse ? index : -1)
|
||||
}
|
||||
}
|
||||
onExited: if (listItem.ListView.view.currentIndex === index) {
|
||||
listItem.ListView.view.currentIndex = -1;
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: mainLayout
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
spacing: 0
|
||||
|
||||
RowLayout {
|
||||
id: mainRowLayout
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: Kirigami.Units.smallSpacing
|
||||
// Otherwise it becomes taller when the button appears
|
||||
Layout.minimumHeight: defaultActionButton.height
|
||||
|
||||
// Icon and optional emblem
|
||||
Kirigami.Icon {
|
||||
id: listItemIcon
|
||||
|
||||
implicitWidth: Kirigami.Units.iconSizes.medium
|
||||
implicitHeight: Kirigami.Units.iconSizes.medium
|
||||
|
||||
Kirigami.Icon {
|
||||
id: iconEmblem
|
||||
|
||||
visible: valid
|
||||
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
implicitWidth: Kirigami.Units.iconSizes.small
|
||||
implicitHeight: Kirigami.Units.iconSizes.small
|
||||
}
|
||||
}
|
||||
|
||||
// Title and subtitle
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
spacing: 0
|
||||
|
||||
Kirigami.Heading {
|
||||
id: listItemTitle
|
||||
|
||||
visible: text.length > 0
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
level: 5
|
||||
|
||||
textFormat: listItem.allowStyledText ? Text.StyledText : Text.PlainText
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 1
|
||||
|
||||
// Even if it's the default item, only make it bold when
|
||||
// there's more than one item in the list, or else there's
|
||||
// only one item and it's bold, which is a little bit weird
|
||||
font.weight: listItem.isDefault && listItem.ListView.view.count > 1
|
||||
? Font.Bold
|
||||
: Font.Normal
|
||||
}
|
||||
|
||||
PlasmaComponents3.Label {
|
||||
id: listItemSubtitle
|
||||
|
||||
visible: text.length > 0
|
||||
font: Kirigami.Theme.smallFont
|
||||
|
||||
// Otherwise colored text can be hard to see
|
||||
opacity: color === Kirigami.Theme.textColor ? 0.7 : 1.0
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
textFormat: listItem.allowStyledText ? Text.StyledText : Text.PlainText
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: subtitleCanWrap ? 9999 : 1
|
||||
wrapMode: subtitleCanWrap ? Text.WordWrap : Text.NoWrap
|
||||
}
|
||||
}
|
||||
|
||||
// Busy indicator
|
||||
PlasmaComponents3.BusyIndicator {
|
||||
id: busyIndicator
|
||||
|
||||
visible: listItem.isBusy
|
||||
|
||||
// Otherwise it makes the list item taller when it appears
|
||||
Layout.maximumHeight: defaultActionButton.implicitHeight
|
||||
Layout.maximumWidth: Layout.maximumHeight
|
||||
}
|
||||
|
||||
// Default action button
|
||||
PlasmaComponents3.ToolButton {
|
||||
id: defaultActionButton
|
||||
|
||||
visible: defaultActionButtonAction
|
||||
&& listItem.defaultActionButtonVisible
|
||||
&& (!busyIndicator.visible || listItem.showDefaultActionButtonWhenBusy)
|
||||
|
||||
/*KeyNavigation.tab: expandToggleButton
|
||||
KeyNavigation.right: expandToggleButton
|
||||
KeyNavigation.down: expandToggleButton.KeyNavigation.down*/
|
||||
Keys.onUpPressed: event => listItem.Keys.upPressed(event)
|
||||
|
||||
Accessible.name: action !== null ? action.text : ""
|
||||
}
|
||||
|
||||
// Expand/collapse button
|
||||
/*PlasmaComponents3.ToolButton {
|
||||
id: expandToggleButton
|
||||
visible: listItem.hasExpandableContent
|
||||
|
||||
display: PlasmaComponents3.AbstractButton.IconOnly
|
||||
text: expandedView.expanded ? i18ndc("libplasma6", "@action:button", "Collapse") : i18ndc("libplasma6", "@action:button", "Expand")
|
||||
icon.name: expandedView.expanded ? "collapse" : "expand"
|
||||
|
||||
Keys.onUpPressed: event => listItem.Keys.upPressed(event)
|
||||
|
||||
onClicked: listItem.toggleExpanded()
|
||||
|
||||
PlasmaComponents3.ToolTip {
|
||||
text: parent.text
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
// Expanded view with actions and/or custom content in it
|
||||
Item {
|
||||
id: expandedView
|
||||
property bool expanded: false
|
||||
|
||||
Layout.preferredHeight: expanded ?
|
||||
expandedViewLayout.implicitHeight + expandedViewLayout.anchors.topMargin + expandedViewLayout.anchors.bottomMargin : 0
|
||||
Layout.fillWidth: true
|
||||
|
||||
opacity: expanded ? 1 : 0
|
||||
/* Behavior on opacity {
|
||||
enabled: false //listItem.ListView.view.highlightResizeDuration > 0
|
||||
SmoothedAnimation { // to match the highlight
|
||||
id: expandedItemOpacityFade
|
||||
duration: listItem.ListView.view.highlightResizeDuration || -1
|
||||
// velocity is divided by the default speed, as we're in the range 0-1
|
||||
velocity: listItem.ListView.view.highlightResizeVelocity / 200
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
}*/
|
||||
visible: opacity > 0
|
||||
|
||||
ColumnLayout {
|
||||
id: expandedViewLayout
|
||||
anchors.fill: parent
|
||||
anchors.margins: Kirigami.Units.smallSpacing
|
||||
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
// Actions list
|
||||
Loader {
|
||||
id: actionsListLoader
|
||||
|
||||
visible: status === Loader.Ready
|
||||
active: expandedView.visible && listItem.__enabledContextualActions.length > 0
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
sourceComponent: Item {
|
||||
height: buttonFlow.implicitHeight /2
|
||||
width: actionsListLoader.width // basically, parent.width but null-proof
|
||||
|
||||
Flow {
|
||||
id: buttonFlow
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
//anchors.leftMargin: Kirigami.Units.iconSizes.small
|
||||
//anchors.rightMargin: Kirigami.Units.iconSizes.small
|
||||
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
layoutDirection: Qt.RightToLeft
|
||||
|
||||
Repeater {
|
||||
id: actionRepeater
|
||||
|
||||
model: listItem.__enabledContextualActions
|
||||
|
||||
delegate: QQC2.Button {
|
||||
id: buttonDelegate
|
||||
required property int index
|
||||
required property T.Action modelData
|
||||
|
||||
//Layout.fillWidth: true
|
||||
//Layout.alignment: Qt.AlignRight
|
||||
|
||||
text: modelData.text
|
||||
icon.name: modelData.icon.name
|
||||
|
||||
//KeyNavigation.up: index > 0 ? actionRepeater.itemAt(index - 1) : expandToggleButton
|
||||
Keys.onDownPressed: event => {
|
||||
if (index === actionRepeater.count - 1) {
|
||||
event.accepted = true;
|
||||
listItem.ListView.view.incrementCurrentIndex();
|
||||
listItem.ListView.view.currentItem.forceActiveFocus(Qt.TabFocusReason);
|
||||
} else {
|
||||
event.accepted = false; // Forward to KeyNavigation.down
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
modelData.trigger()
|
||||
collapse()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Separator between the two items when both are shown
|
||||
KSvg.SvgItem {
|
||||
Layout.fillWidth: true
|
||||
imagePath: "widgets/line"
|
||||
elementId: "horizontal-line"
|
||||
visible: actionsListLoader.visible && customContentLoader.visible
|
||||
}
|
||||
|
||||
// Custom content item, if any
|
||||
Loader {
|
||||
id: customContentLoader
|
||||
visible: status === Loader.Ready
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
active: expandedView.visible
|
||||
asynchronous: true
|
||||
sourceComponent: listItem.customExpandedViewContent
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2010 Marco Martin <notmart@gmail.com>
|
||||
SPDX-FileCopyrightText: 2016 Jan Grulich <jgrulich@redhat.com>
|
||||
SPDX-FileCopyrightText: 2020 George Vogiatzis <gvgeo@protonmail.com>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
|
||||
import QtQuick 2.1
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
import org.kde.ksvg 1.0 as KSvg
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
MouseArea {
|
||||
id: listItem
|
||||
|
||||
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 + Kirigami.Units.smallSpacing * 3 : parent.height
|
||||
hoverEnabled: true
|
||||
|
||||
KSvg.SvgItem {
|
||||
id: separatorLine
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
top: parent.top
|
||||
topMargin: Kirigami.Units.smallSpacing
|
||||
}
|
||||
imagePath: "widgets/line"
|
||||
elementId: "horizontal-line"
|
||||
width: parent.width - Kirigami.Units.iconSizes.small * 2
|
||||
visible: separator
|
||||
}
|
||||
|
||||
KSvg.FrameSvgItem {
|
||||
id: background
|
||||
imagePath: "widgets/listitem"
|
||||
prefix: "normal"
|
||||
anchors.fill: parent
|
||||
visible: separator ? false : true
|
||||
}
|
||||
|
||||
KSvg.FrameSvgItem {
|
||||
id: pressed
|
||||
imagePath: "widgets/listitem"
|
||||
prefix: "pressed"
|
||||
opacity: checked ? 1 : 0
|
||||
Behavior on opacity { NumberAnimation { duration: Kirigami.Units.shortDuration } }
|
||||
|
||||
x: highlightRect.x
|
||||
y: highlightRect.y
|
||||
height: highlightRect.height
|
||||
width: highlightRect.width
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2023 Kai Uwe Broulik <kde@broulik.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.2
|
||||
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents3
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras
|
||||
|
||||
DetailsText {
|
||||
id: detailsTextColumn
|
||||
|
||||
/*width: parent.width
|
||||
* visible: detailsTabBar.currentIndex === 1
|
||||
*
|
||||
* activeFocusOnTab: details.length > 0*/
|
||||
//details: page.details //ConnectionDetails
|
||||
|
||||
Accessible.description: details.join(" ")
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2013-2017 Jan Grulich <jgrulich@redhat.com>
|
||||
SPDX-FileCopyrightText: 2023 ivan tkachenko <me@ratijas.tk>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
|
||||
import QtQuick
|
||||
import org.kde.plasma.networkmanagement as PlasmaNM
|
||||
import org.kde.plasma.extras as PlasmaExtras
|
||||
|
||||
PlasmaExtras.PasswordField {
|
||||
property int/*PlasmaNM.Enums.SecurityType*/ securityType
|
||||
|
||||
validator: RegularExpressionValidator {
|
||||
regularExpression: (securityType === PlasmaNM.Enums.StaticWep)
|
||||
? /^(?:.{5}|[0-9a-fA-F]{10}|.{13}|[0-9a-fA-F]{26})$/
|
||||
: /^(?:.{8,64})$/
|
||||
}
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2013-2017 Jan Grulich <jgrulich@redhat.com>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15 as QQC2
|
||||
import QtQuick.Layouts 1.2
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents3
|
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras
|
||||
import org.kde.plasma.networkmanagement as PlasmaNM
|
||||
import org.kde.plasma.plasmoid 2.0
|
||||
|
||||
PlasmaExtras.Representation {
|
||||
id: full
|
||||
|
||||
required property PlasmaNM.Handler nmHandler
|
||||
required property PlasmaNM.NetworkStatus nmStatus
|
||||
|
||||
collapseMarginsHint: true
|
||||
|
||||
Component {
|
||||
id: networkModelComponent
|
||||
PlasmaNM.NetworkModel {}
|
||||
}
|
||||
|
||||
property PlasmaNM.NetworkModel connectionModel: null
|
||||
|
||||
PlasmaNM.AppletProxyModel {
|
||||
id: appletProxyModel
|
||||
|
||||
sourceModel: full.connectionModel
|
||||
}
|
||||
|
||||
header: PlasmaExtras.PlasmoidHeading {
|
||||
focus: true
|
||||
contentItem: RowLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
Toolbar {
|
||||
id: toolbar
|
||||
Layout.fillWidth: true
|
||||
hasConnections: connectionListPage.count > 0
|
||||
visible: stack.depth === 1
|
||||
}
|
||||
|
||||
Loader {
|
||||
sourceComponent: stack.currentItem?.headerItems
|
||||
visible: !!item
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: full.nmHandler
|
||||
function onWifiCodeReceived(data, ssid) {
|
||||
if (data.length === 0) {
|
||||
console.error("Cannot create QR code component: Unsupported connection");
|
||||
return;
|
||||
}
|
||||
|
||||
const showQRComponent = Qt.createComponent("ShareNetworkQrCodePage.qml");
|
||||
if (showQRComponent.status === Component.Error) {
|
||||
console.warn("Cannot create QR code component:", showQRComponent.errorString());
|
||||
return;
|
||||
}
|
||||
|
||||
mainWindow.expanded = true; // just in case.
|
||||
stack.push(showQRComponent, {
|
||||
content: data,
|
||||
ssid
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Keys.forwardTo: [stack.currentItem]
|
||||
Keys.onPressed: event => {
|
||||
if (event.modifiers & Qt.ControlModifier && event.key == Qt.Key_F) {
|
||||
toolbar.searchTextField.forceActiveFocus();
|
||||
toolbar.searchTextField.selectAll();
|
||||
event.accepted = true;
|
||||
} else if (event.key === Qt.Key_Back || (event.modifiers & Qt.AltModifier && event.key == Qt.Key_Left)) {
|
||||
if (stack.depth > 1) {
|
||||
stack.pop();
|
||||
event.accepted = true;
|
||||
}
|
||||
} else {
|
||||
event.accepted = false;
|
||||
}
|
||||
}
|
||||
|
||||
QQC2.StackView {
|
||||
id: stack
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: backButton.top
|
||||
initialItem: ConnectionListPage {
|
||||
id: connectionListPage
|
||||
model: appletProxyModel
|
||||
nmStatus: full.nmStatus
|
||||
}
|
||||
|
||||
popEnter: Transition {}
|
||||
popExit: Transition {}
|
||||
pushEnter: Transition {}
|
||||
pushExit: Transition {}
|
||||
replaceEnter: Transition {}
|
||||
replaceExit: Transition {}
|
||||
}
|
||||
|
||||
QQC2.Button {
|
||||
id: backButton
|
||||
//anchors.top: stack.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
//Layout.alignment: Qt.AlignRight | Qt.AlignBottom
|
||||
text: "Back"
|
||||
visible: stack.depth > 1
|
||||
onClicked: {
|
||||
stack.pop()
|
||||
}
|
||||
}
|
||||
/*PlasmaExtras.Heading {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
horizontalAlignment: Qt.AlignHCenter
|
||||
text: i18nc("@action:button", "Return to Network Connections")
|
||||
visible: stack.depth > 1
|
||||
color: "#0066cc" //heading_ma.containsPress ? "#90e7ff" : (heading_ma.containsMouse ? "#b6ffff" : Kirigami.Theme.textColor)
|
||||
font.underline: heading_ma.containsMouse
|
||||
level: 5
|
||||
MouseArea {
|
||||
id: heading_ma
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
stack.pop()
|
||||
}
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
z: 5
|
||||
}
|
||||
}*/
|
||||
|
||||
Connections {
|
||||
target: mainWindow
|
||||
function onExpandedChanged(expanded) {
|
||||
if (expanded) {
|
||||
handler.requestScan();
|
||||
if (!full.connectionModel) {
|
||||
full.connectionModel = networkModelComponent.createObject(full);
|
||||
}
|
||||
} else {
|
||||
if (full.connectionModel) {
|
||||
full.connectionModel.destroy();
|
||||
full.connectionModel = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2023 Kai Uwe Broulik <kde@broulik.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.2
|
||||
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents3
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
|
||||
import org.kde.prison 1.0 as Prison
|
||||
|
||||
ColumnLayout {
|
||||
id: page
|
||||
|
||||
property string ssid
|
||||
property alias content: barcode.content
|
||||
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
PlasmaComponents3.Label {
|
||||
Layout.topMargin: page.spacing
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.minimumWidth: barcode.height
|
||||
Layout.maximumWidth: barcode.width - page.spacing * 2
|
||||
wrapMode: Text.WordWrap
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
textFormat: Text.PlainText
|
||||
text: i18n("Scan this QR code with another device to connect to the \"%1\" network.", page.ssid)
|
||||
}
|
||||
|
||||
Prison.Barcode {
|
||||
id: barcode
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
barcodeType: Prison.Barcode.QRCode
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2023 Kai Uwe Broulik <kde@broulik.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.2
|
||||
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents3
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras
|
||||
|
||||
TrafficMonitor {
|
||||
id: trafficMonitorGraph
|
||||
Accessible.description: i18nc("@info:tooltip", "Current download speed is %1 kibibytes per second; current upload speed is %2 kibibytes per second", Math.round(rxSpeed / 1024), Math.round(txSpeed / 1024))
|
||||
//width: parent.width
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2016 Marco Martin <mart@kde.org>
|
||||
SPDX-FileCopyrightText: 2016 The Qt Company Ltd.
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Templates as T
|
||||
import org.kde.ksvg as KSvg
|
||||
//NOTE: importing PlasmaCore is necessary in order to make KSvg load the current Plasma Theme
|
||||
import org.kde.plasma.core as PlasmaCore
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents3
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
T.ToolTip {
|
||||
id: control
|
||||
|
||||
x: parent ? Math.round((parent.width - implicitWidth) / 2) : 0
|
||||
y: -implicitHeight - 3
|
||||
|
||||
visible: parent instanceof T.AbstractButton && (Kirigami.Settings.tabletMode ? parent.pressed : parent.hovered) && text.length > 0
|
||||
delay: Kirigami.Settings.tabletMode ? Qt.styleHints.mousePressAndHoldInterval : Kirigami.Units.toolTipDelay
|
||||
// Never time out while being hovered; it's annoying
|
||||
timeout: -1
|
||||
|
||||
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, contentHeight + topPadding + bottomPadding)
|
||||
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, contentWidth + leftPadding + rightPadding)
|
||||
|
||||
margins: Kirigami.Units.smallSpacing
|
||||
|
||||
topPadding: backgroundItem.margins.top
|
||||
leftPadding: backgroundItem.margins.left
|
||||
rightPadding: backgroundItem.margins.right
|
||||
bottomPadding: backgroundItem.margins.bottom
|
||||
|
||||
enter: Transition {
|
||||
NumberAnimation {
|
||||
property: "opacity"
|
||||
from: 0.0
|
||||
to: 1.0
|
||||
duration: Kirigami.Units.longDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
exit: Transition {
|
||||
NumberAnimation {
|
||||
property: "opacity"
|
||||
from: 1.0
|
||||
to: 0.0
|
||||
duration: Kirigami.Units.longDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
closePolicy: T.Popup.CloseOnEscape | T.Popup.CloseOnPressOutsideParent | T.Popup.CloseOnReleaseOutsideParent
|
||||
|
||||
contentItem: Item {
|
||||
implicitWidth: Math.min(label.maxTextLength, label.contentWidth)
|
||||
implicitHeight: label.implicitHeight
|
||||
|
||||
PlasmaComponents3.Label {
|
||||
id: label
|
||||
|
||||
// This value is basically arbitrary. It just looks nice.
|
||||
readonly property double maxTextLength: Kirigami.Units.iconSizes.small * 14
|
||||
|
||||
// Strip out ampersands right before non-whitespace characters, i.e.
|
||||
// those used to determine the alt key shortcut
|
||||
text: control.text.replace(/&(?=\S)/g, "")
|
||||
wrapMode: Text.WordWrap
|
||||
font: control.font
|
||||
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Tooltip
|
||||
Kirigami.Theme.inherit: false
|
||||
|
||||
// ensure that long text actually gets wrapped
|
||||
onLineLaidOut: (line) => {
|
||||
if (line.implicitWidth > maxTextLength) {
|
||||
line.width = maxTextLength
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
background: Item {
|
||||
implicitHeight: Kirigami.Units.iconSizes.small + backgroundItem.margins.top + backgroundItem.margins.bottom
|
||||
implicitWidth: Kirigami.Units.iconSizes.small + backgroundItem.margins.left + backgroundItem.margins.right
|
||||
|
||||
KSvg.FrameSvgItem {
|
||||
anchors {
|
||||
fill: parent
|
||||
topMargin: -margins.top
|
||||
leftMargin: -margins.left
|
||||
rightMargin: -margins.right
|
||||
bottomMargin: -margins.bottom
|
||||
}
|
||||
imagePath: "solid/widgets/tooltip"
|
||||
prefix: "shadow"
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Tooltip
|
||||
Kirigami.Theme.inherit: false
|
||||
}
|
||||
|
||||
KSvg.FrameSvgItem {
|
||||
id: backgroundItem
|
||||
anchors.fill: parent
|
||||
// Because the transparent one doesn't match the appearance of all
|
||||
// other ones
|
||||
imagePath: "solid/widgets/tooltip"
|
||||
Kirigami.Theme.colorSet: Kirigami.Theme.Tooltip
|
||||
Kirigami.Theme.inherit: false
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2013-2017 Jan Grulich <jgrulich@redhat.com>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Layouts 1.2
|
||||
import org.kde.plasma.components 3.0 as PlasmaComponents3
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
import org.kde.plasma.extras 2.0 as PlasmaExtras
|
||||
import org.kde.plasma.networkmanagement as PlasmaNM
|
||||
import org.kde.kcmutils as KCMUtils
|
||||
import QtQuick.Controls 2.15 as QQC2
|
||||
|
||||
ColumnLayout {
|
||||
id: toolbar
|
||||
|
||||
readonly property var displayWifiMessage: !wifiSwitchButton.checked && wifiSwitchButton.visible
|
||||
readonly property var displayWwanMessage: !wwanSwitchButton.checked && wwanSwitchButton.visible
|
||||
readonly property var displayplaneModeMessage: planeModeSwitchButton.checked && planeModeSwitchButton.visible
|
||||
|
||||
property bool hasConnections
|
||||
property alias searchTextField: searchTextField
|
||||
|
||||
PlasmaNM.EnabledConnections {
|
||||
id: enabledConnections
|
||||
|
||||
// When user interactively toggles a checkbox, a binding may be
|
||||
// preserved, but the state gets out of sync until next relevant
|
||||
// notify signal is dispatched. So, we refresh the bindings here.
|
||||
|
||||
onWirelessEnabledChanged: wifiSwitchButton.checked = Qt.binding(() =>
|
||||
wifiSwitchButton.administrativelyEnabled && enabledConnections.wirelessEnabled
|
||||
);
|
||||
|
||||
onWwanEnabledChanged: wwanSwitchButton.checked = Qt.binding(() =>
|
||||
wwanSwitchButton.administrativelyEnabled && enabledConnections.wwanEnabled
|
||||
);
|
||||
}
|
||||
|
||||
spacing: Kirigami.Units.smallSpacing * 3
|
||||
|
||||
RowLayout {
|
||||
// Add margin before switches for consistency with other applets
|
||||
Layout.leftMargin: Kirigami.Units.smallSpacing / 2
|
||||
|
||||
spacing: parent.spacing
|
||||
|
||||
// Only show when switches are visible (and avoid parent spacing otherwise)
|
||||
visible: availableDevices.wirelessDeviceAvailable || availableDevices.modemDeviceAvailable
|
||||
|
||||
QQC2.CheckBox {
|
||||
id: wifiSwitchButton
|
||||
|
||||
// can't overload Item::enabled, because it's being used for other things, like Edit Mode on a desktop
|
||||
readonly property bool administrativelyEnabled:
|
||||
!PlasmaNM.Configuration.airplaneModeEnabled
|
||||
&& availableDevices.wirelessDeviceAvailable
|
||||
&& enabledConnections.wirelessHwEnabled
|
||||
|
||||
checked: administrativelyEnabled && enabledConnections.wirelessEnabled
|
||||
enabled: administrativelyEnabled
|
||||
|
||||
icon.name: administrativelyEnabled ? ( timer.running ? "network-wireless-acquiring" : "network-wireless-on" ) : "network-wireless-off"
|
||||
visible: availableDevices.wirelessDeviceAvailable
|
||||
|
||||
KeyNavigation.right: wwanSwitchButton.visible ? wwanSwitchButton : wwanSwitchButton.KeyNavigation.right
|
||||
|
||||
onToggled: handler.enableWireless(checked);
|
||||
text: i18n("Wi-Fi")
|
||||
|
||||
PlasmaComponents3.BusyIndicator {
|
||||
parent: wifiSwitchButton
|
||||
anchors {
|
||||
fill: wifiSwitchButton.contentItem
|
||||
leftMargin: wifiSwitchButton.indicator.width + wifiSwitchButton.spacing
|
||||
}
|
||||
z: 1
|
||||
|
||||
visible: false
|
||||
// Scanning may be too fast to notice. Prolong the animation up to at least `humanMoment`.
|
||||
running: handler.scanning || timer.running
|
||||
Timer {
|
||||
id: timer
|
||||
interval: Kirigami.Units.humanMoment
|
||||
}
|
||||
Connections {
|
||||
target: handler
|
||||
function onScanningChanged() {
|
||||
if (handler.scanning) {
|
||||
timer.restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QQC2.CheckBox {
|
||||
id: wwanSwitchButton
|
||||
|
||||
// can't overload Item::enabled, because it's being used for other things, like Edit Mode on a desktop
|
||||
readonly property bool administrativelyEnabled:
|
||||
!PlasmaNM.Configuration.airplaneModeEnabled
|
||||
&& availableDevices.modemDeviceAvailable
|
||||
&& enabledConnections.wwanHwEnabled
|
||||
|
||||
checked: administrativelyEnabled && enabledConnections.wwanEnabled
|
||||
enabled: administrativelyEnabled
|
||||
|
||||
icon.name: administrativelyEnabled ? "network-mobile-on" : "network-mobile-off"
|
||||
visible: availableDevices.modemDeviceAvailable
|
||||
|
||||
KeyNavigation.left: wifiSwitchButton
|
||||
KeyNavigation.right: planeModeSwitchButton.visible ? planeModeSwitchButton : planeModeSwitchButton.KeyNavigation.right
|
||||
|
||||
onToggled: handler.enableWwan(checked);
|
||||
|
||||
text: i18n("Mobile network")
|
||||
|
||||
}
|
||||
|
||||
QQC2.CheckBox {
|
||||
id: planeModeSwitchButton
|
||||
|
||||
property bool initialized: false
|
||||
|
||||
checked: PlasmaNM.Configuration.airplaneModeEnabled
|
||||
|
||||
icon.name: PlasmaNM.Configuration.airplaneModeEnabled ? "network-flightmode-on" : "network-flightmode-off"
|
||||
|
||||
visible: availableDevices.modemDeviceAvailable || availableDevices.wirelessDeviceAvailable
|
||||
|
||||
KeyNavigation.left: wwanSwitchButton.visible ? wwanSwitchButton : wwanSwitchButton.KeyNavigation.left
|
||||
KeyNavigation.right: hotspotButton.visible ? hotspotButton : hotspotButton.KeyNavigation.right
|
||||
|
||||
text: i18n("Airplane mode")
|
||||
onToggled: {
|
||||
handler.enableAirplaneMode(checked);
|
||||
PlasmaNM.Configuration.airplaneModeEnabled = checked;
|
||||
}
|
||||
}
|
||||
}
|
||||
PlasmaComponents3.ToolButton {
|
||||
id: hotspotButton
|
||||
|
||||
visible: false//handler.hotspotSupported
|
||||
checkable: true
|
||||
|
||||
text: i18n("Hotspot")
|
||||
icon.name: "network-wireless-on"
|
||||
|
||||
KeyNavigation.left: planeModeSwitchButton.visible ? planeModeSwitchButton : planeModeSwitchButton.KeyNavigation.left
|
||||
KeyNavigation.right: searchTextField
|
||||
|
||||
onClicked: {
|
||||
if (PlasmaNM.Configuration.hotspotConnectionPath) {
|
||||
checked = false
|
||||
handler.stopHotspot()
|
||||
} else {
|
||||
checked = true
|
||||
handler.createHotspot()
|
||||
}
|
||||
}
|
||||
|
||||
PlasmaComponents3.ToolTip {
|
||||
id: tooltip
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: handler
|
||||
function onHotspotCreated() {
|
||||
hotspotButton.checked = true
|
||||
tooltip.text = i18n("Disable Hotspot")
|
||||
}
|
||||
|
||||
function onHotspotDisabled() {
|
||||
hotspotButton.checked = false
|
||||
tooltip.text = i18n("Create Hotspot")
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
checked = PlasmaNM.Configuration.hotspotConnectionPath
|
||||
tooltip.text = PlasmaNM.Configuration.hotspotConnectionPath ? i18n("Disable Hotspot") : i18n("Create Hotspot")
|
||||
}
|
||||
}
|
||||
|
||||
PlasmaExtras.SearchField {
|
||||
id: searchTextField
|
||||
|
||||
Layout.fillWidth: true
|
||||
|
||||
visible: false
|
||||
enabled: toolbar.hasConnections || text.length > 0
|
||||
|
||||
// This uses expanded to ensure the binding gets reevaluated
|
||||
// when the plasmoid is shown again and that way ensure we are
|
||||
// always in the correct state on show.
|
||||
focus: mainWindow.expanded && !Kirigami.InputMethod.willShowOnActive
|
||||
|
||||
KeyNavigation.left: hotspotButton.visible ? hotspotButton : hotspotButton.KeyNavigation.left
|
||||
KeyNavigation.right: openEditorButton
|
||||
|
||||
onTextChanged: {
|
||||
appletProxyModel.setFilterFixedString(text)
|
||||
}
|
||||
}
|
||||
|
||||
PlasmaComponents3.ToolButton {
|
||||
id: openEditorButton
|
||||
|
||||
visible: mainWindow.kcmAuthorized && !(plasmoid.containmentDisplayHints & PlasmaCore.Types.ContainmentDrawsPlasmoidHeading)
|
||||
|
||||
icon.name: "configure"
|
||||
|
||||
PlasmaComponents3.ToolTip {
|
||||
text: i18n("Configure network connections…")
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
KCMUtils.KCMLauncher.openSystemSettings(mainWindow.kcm)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2013-2017 Jan Grulich <jgrulich@redhat.com>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import org.kde.coreaddons as KCoreAddons
|
||||
import org.kde.quickcharts as QuickCharts
|
||||
import org.kde.quickcharts.controls as QuickChartsControls
|
||||
import org.kde.plasma.components as PlasmaComponents3
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
ColumnLayout {
|
||||
|
||||
property string connectionTitle: ""
|
||||
property alias downloadSpeed: download.value
|
||||
property alias uploadSpeed: upload.value
|
||||
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
|
||||
PlasmaComponents3.Label {
|
||||
id: titleLabel
|
||||
//Layout.fillWidth: true
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Kirigami.Units.smallSpacing
|
||||
anchors.leftMargin: Kirigami.Units.smallSpacing
|
||||
anchors.topMargin: -Kirigami.Units.smallSpacing*2
|
||||
//horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignTop
|
||||
text: connectionTitle + " " + i18n("Speed")
|
||||
}
|
||||
Item {
|
||||
Layout.leftMargin: Kirigami.Units.smallSpacing
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
implicitHeight: plotter.height + metricsLabel.implicitHeight
|
||||
|
||||
QuickChartsControls.AxisLabels {
|
||||
id: verticalAxisLabels
|
||||
anchors {
|
||||
left: parent.left
|
||||
top: plotter.top
|
||||
bottom: plotter.bottom
|
||||
}
|
||||
width: metricsLabel.implicitWidth
|
||||
constrainToBounds: false
|
||||
direction: QuickChartsControls.AxisLabels.VerticalBottomTop
|
||||
delegate: PlasmaComponents3.Label {
|
||||
text: KCoreAddons.Format.formatByteSize(QuickChartsControls.AxisLabels.label) + i18n("/s")
|
||||
font: metricsLabel.font
|
||||
}
|
||||
source: QuickCharts.ChartAxisSource {
|
||||
chart: plotter
|
||||
axis: QuickCharts.ChartAxisSource.YAxis
|
||||
itemCount: 5
|
||||
}
|
||||
}
|
||||
QuickChartsControls.GridLines {
|
||||
anchors.fill: plotter
|
||||
direction: QuickChartsControls.GridLines.Vertical
|
||||
minor.visible: false
|
||||
major.count: 3
|
||||
major.lineWidth: 1
|
||||
// Same calculation as Kirigami Separator
|
||||
major.color: Kirigami.ColorUtils.linearInterpolation(Kirigami.Theme.backgroundColor, Kirigami.Theme.textColor, 0.4)
|
||||
}
|
||||
QuickCharts.LineChart {
|
||||
id: plotter
|
||||
anchors {
|
||||
left: verticalAxisLabels.right
|
||||
leftMargin: Kirigami.Units.smallSpacing
|
||||
right: parent.right
|
||||
top: parent.top
|
||||
// Align plotter lines with labels.
|
||||
topMargin: Math.round(metricsLabel.implicitHeight / 2) + Kirigami.Units.smallSpacing
|
||||
}
|
||||
height: Kirigami.Units.iconSizes.small * 8
|
||||
interpolate: true
|
||||
direction: QuickCharts.XYChart.ZeroAtEnd
|
||||
yRange {
|
||||
minimum: 100 * 1024
|
||||
increment: 100 * 1024
|
||||
}
|
||||
valueSources: [
|
||||
QuickCharts.HistoryProxySource {
|
||||
source: QuickCharts.SingleValueSource {
|
||||
id: upload
|
||||
}
|
||||
maximumHistory: 40
|
||||
fillMode: QuickCharts.HistoryProxySource.FillFromStart
|
||||
},
|
||||
QuickCharts.HistoryProxySource {
|
||||
source: QuickCharts.SingleValueSource {
|
||||
id: download
|
||||
}
|
||||
maximumHistory: 40
|
||||
fillMode: QuickCharts.HistoryProxySource.FillFromStart
|
||||
}
|
||||
]
|
||||
nameSource: QuickCharts.ArraySource {
|
||||
array: [i18n("Upload"), i18n("Download")]
|
||||
}
|
||||
colorSource: QuickCharts.ArraySource {
|
||||
// Array.reverse() mutates the array but colors.colors is read-only.
|
||||
array: [colors.colors[1], colors.colors[0]]
|
||||
}
|
||||
fillColorSource: QuickCharts.ArraySource {
|
||||
array: plotter.colorSource.array.map(color => Qt.lighter(color, 1.5))
|
||||
}
|
||||
QuickCharts.ColorGradientSource {
|
||||
id: colors
|
||||
baseColor: Kirigami.Theme.highlightColor
|
||||
itemCount: 2
|
||||
}
|
||||
}
|
||||
// Note: TextMetrics might be using a different renderType by default,
|
||||
// so we need a Label instance anyway.
|
||||
PlasmaComponents3.Label {
|
||||
id: metricsLabel
|
||||
visible: false
|
||||
font: Kirigami.Theme.smallFont
|
||||
// Measure 888.8 KiB/s
|
||||
text: KCoreAddons.Format.formatByteSize(910131) + i18n("/s")
|
||||
}
|
||||
}
|
||||
QuickChartsControls.Legend {
|
||||
chart: plotter
|
||||
Layout.leftMargin: Kirigami.Units.smallSpacing
|
||||
Layout.bottomMargin: Kirigami.Units.mediumSpacing*2
|
||||
Layout.fillWidth: true
|
||||
spacing: Kirigami.Units.largeSpacing
|
||||
delegate: RowLayout {
|
||||
spacing: Kirigami.Units.smallSpacing
|
||||
|
||||
QuickChartsControls.LegendLayout.maximumWidth: implicitWidth
|
||||
|
||||
Rectangle {
|
||||
color: model.color
|
||||
width: Kirigami.Units.smallSpacing
|
||||
height: legendLabel.height
|
||||
}
|
||||
PlasmaComponents3.Label {
|
||||
id: legendLabel
|
||||
font: Kirigami.Theme.smallFont
|
||||
text: model.name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2013-2017 Jan Grulich <jgrulich@redhat.com>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
|
||||
import QtQuick 2.2
|
||||
import org.kde.plasma.plasmoid 2.0
|
||||
import org.kde.kirigami 2.20 as Kirigami
|
||||
import org.kde.plasma.core 2.0 as PlasmaCore
|
||||
import org.kde.plasma.networkmanagement as PlasmaNM
|
||||
import org.kde.networkmanager as NMQt
|
||||
import QtQuick.Layouts 1.1
|
||||
import org.kde.kcmutils as KCMUtils
|
||||
import org.kde.config as KConfig
|
||||
|
||||
PlasmoidItem {
|
||||
id: mainWindow
|
||||
|
||||
readonly property string kcm: "kcm_networkmanagement"
|
||||
readonly property bool kcmAuthorized: KConfig.KAuthorized.authorizeControlModule("kcm_networkmanagement")
|
||||
readonly property bool delayModelUpdates: fullRepresentationItem !== null
|
||||
&& fullRepresentationItem.connectionModel !== null
|
||||
&& fullRepresentationItem.connectionModel.delayModelUpdates
|
||||
readonly property bool airplaneModeAvailable: availableDevices.modemDeviceAvailable || availableDevices.wirelessDeviceAvailable
|
||||
readonly property bool inPanel: (Plasmoid.location === PlasmaCore.Types.TopEdge
|
||||
|| Plasmoid.location === PlasmaCore.Types.RightEdge
|
||||
|| Plasmoid.location === PlasmaCore.Types.BottomEdge
|
||||
|| Plasmoid.location === PlasmaCore.Types.LeftEdge)
|
||||
property alias planeModeSwitchAction: planeAction
|
||||
|
||||
Plasmoid.title: "Open Network and Sharing Center"
|
||||
toolTipMainText: i18n("Networks")
|
||||
toolTipSubText: {
|
||||
const activeConnections = networkStatus.activeConnections;
|
||||
|
||||
if (!airplaneModeAvailable) {
|
||||
return activeConnections;
|
||||
}
|
||||
|
||||
if (PlasmaNM.Configuration.airplaneModeEnabled) {
|
||||
return i18nc("@info:tooltip", "Middle-click to turn off Airplane Mode");
|
||||
} else {
|
||||
const hint = i18nc("@info:tooltip", "Middle-click to turn on Airplane Mode");
|
||||
return activeConnections ? `${activeConnections}\n${hint}` : hint;
|
||||
}
|
||||
}
|
||||
|
||||
Plasmoid.busy: connectionIconProvider.connecting
|
||||
Plasmoid.icon: inPanel ? connectionIconProvider.connectionIcon + "-symbolic" : connectionIconProvider.connectionTooltipIcon
|
||||
switchWidth: Kirigami.Units.iconSizes.small * 10
|
||||
switchHeight: Kirigami.Units.iconSizes.small * 10
|
||||
|
||||
// Only exists because the default CompactRepresentation doesn't expose
|
||||
// a middle-click action.
|
||||
// TODO remove once it gains that feature.
|
||||
compactRepresentation: CompactRepresentation {
|
||||
airplaneModeAvailable: mainWindow.airplaneModeAvailable
|
||||
iconName: Plasmoid.icon
|
||||
}
|
||||
fullRepresentation: PopupDialog {
|
||||
id: dialogItem
|
||||
nmHandler: handler
|
||||
nmStatus: networkStatus
|
||||
readonly property int flyoutIntendedWidth: Kirigami.Units.iconSizes.small * 18
|
||||
Layout.minimumWidth: Kirigami.Units.iconSizes.medium * 10
|
||||
Layout.minimumHeight: Kirigami.Units.iconSizes.small * 20
|
||||
anchors.fill: parent
|
||||
focus: true
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: handler
|
||||
function onHotspotCreated() {
|
||||
hotspotAction.checked = true
|
||||
}
|
||||
|
||||
function onHotspotDisabled() {
|
||||
hotspotAction.checked = false
|
||||
}
|
||||
}
|
||||
Plasmoid.contextualActions: [
|
||||
PlasmaCore.Action {
|
||||
text: i18n("Enable Wi-Fi")
|
||||
icon.name: "network-wireless-on"
|
||||
priority: PlasmaCore.Action.LowPriority
|
||||
checkable: true
|
||||
checked: enabledConnections.wirelessEnabled
|
||||
visible: enabledConnections.wirelessHwEnabled
|
||||
&& availableDevices.wirelessDeviceAvailable
|
||||
&& !PlasmaNM.Configuration.airplaneModeEnabled
|
||||
onTriggered: checked => {handler.enableWireless(checked)}
|
||||
},
|
||||
PlasmaCore.Action {
|
||||
text: i18n("Enable Mobile Network")
|
||||
icon.name: "network-mobile-on"
|
||||
priority: PlasmaCore.Action.LowPriority
|
||||
checkable: true
|
||||
checked: enabledConnections.wwanEnabled
|
||||
visible: enabledConnections.wwanHwEnabled
|
||||
&& availableDevices.modemDeviceAvailable
|
||||
&& !PlasmaNM.Configuration.airplaneModeEnabled
|
||||
onTriggered: checked => {handler.enableWwan(checked)}
|
||||
},
|
||||
PlasmaCore.Action {
|
||||
id: planeAction
|
||||
text: i18n("Enable Airplane Mode")
|
||||
icon.name: "network-flightmode-on"
|
||||
priority: PlasmaCore.Action.LowPriority
|
||||
checkable: true
|
||||
checked: PlasmaNM.Configuration.airplaneModeEnabled
|
||||
visible: mainWindow.airplaneModeAvailable
|
||||
onTriggered: checked => {
|
||||
handler.enableAirplaneMode(checked)
|
||||
PlasmaNM.Configuration.airplaneModeEnabled = checked
|
||||
}
|
||||
},
|
||||
PlasmaCore.Action {
|
||||
id: hotspotAction
|
||||
text: PlasmaNM.Configuration.hotspotConnectionPath ? i18n("Disable Hotspot") : i18n("Create Hotspot")
|
||||
priority: PlasmaCore.Action.LowPriority
|
||||
checkable: true
|
||||
//checked: PlasmaNM.Configuration.airplaneModeEnabled
|
||||
visible: handler.hotspotSupported
|
||||
|
||||
onTriggered: checked => {
|
||||
if (PlasmaNM.Configuration.hotspotConnectionPath) {
|
||||
checked = false;
|
||||
handler.stopHotspot();
|
||||
} else {
|
||||
checked = true;
|
||||
handler.createHotspot();
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
checked = PlasmaNM.Configuration.hotspotConnectionPath
|
||||
}
|
||||
|
||||
},
|
||||
PlasmaCore.Action {
|
||||
text: i18n("Open Network Login Page…")
|
||||
icon.name: "network-flightmode-on"
|
||||
priority: PlasmaCore.Action.LowPriority
|
||||
visible: networkStatus.connectivity === NMQt.NetworkManager.Portal
|
||||
onTriggered: Qt.openUrlExternally("http://networkcheck.kde.org")
|
||||
}
|
||||
]
|
||||
|
||||
PlasmaCore.Action {
|
||||
id: configureAction
|
||||
text: i18n("&Configure Network Connections…")
|
||||
icon.name: "configure"
|
||||
visible: kcmAuthorized
|
||||
shortcut: "alt+d, s"
|
||||
onTriggered: KCMUtils.KCMLauncher.openSystemSettings(kcm)
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
plasmoid.setInternalAction("configure", configureAction);
|
||||
}
|
||||
|
||||
PlasmaNM.EnabledConnections {
|
||||
id: enabledConnections
|
||||
}
|
||||
|
||||
PlasmaNM.AvailableDevices {
|
||||
id: availableDevices
|
||||
}
|
||||
|
||||
PlasmaNM.NetworkStatus {
|
||||
id: networkStatus
|
||||
}
|
||||
|
||||
PlasmaNM.ConnectionIcon {
|
||||
id: connectionIconProvider
|
||||
connectivity: networkStatus.connectivity
|
||||
}
|
||||
|
||||
PlasmaNM.Handler {
|
||||
id: handler
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: scanTimer
|
||||
interval: 10200
|
||||
repeat: true
|
||||
running: mainWindow.expanded && !PlasmaNM.Configuration.airplaneModeEnabled && !mainWindow.delayModelUpdates
|
||||
|
||||
onTriggered: handler.requestScan()
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue