Warning, /plasma/bluedevil/src/kcm/package/contents/ui/main.qml is written in an unsupported language. File is not indexed.

0001 /**
0002  * SPDX-FileCopyrightText: 2020 Nicolas Fella <nicolas.fella@gmx.de>
0003  * SPDX-FileCopyrightText: 2021 Tom Zander <tom@flowee.org>
0004  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005  */
0006 
0007 import QtQuick 2.2
0008 import QtQuick.Layouts 1.1
0009 import QtQuick.Controls 2.10 as QQC2
0010 
0011 import org.kde.kirigami 2.20 as Kirigami
0012 import org.kde.kcm 1.2
0013 
0014 import org.kde.bluezqt 1.0 as BluezQt
0015 
0016 import org.kde.plasma.private.bluetooth 1.0
0017 
0018 ScrollViewKCM {
0019 
0020     id: root
0021 
0022     function makeCall(call) {
0023         busyIndicator.running = true
0024         call.finished.connect(call => {
0025             busyIndicator.running = false
0026             if (call.error) {
0027                 errorMessage.text = call.errorText
0028                 errorMessage.visible = true
0029             }
0030         })
0031     }
0032 
0033     Connections {
0034         target: kcm
0035 
0036         function onErrorOccured(errorText) {
0037             errorMessage.text = errorText
0038             errorMessage.visible = true
0039         }
0040     }
0041 
0042     Component {
0043         id: forgetDialogComponent
0044 
0045         Kirigami.PromptDialog {
0046             id: dialog
0047 
0048             required property BluezQt.Adapter adapter
0049             required property BluezQt.Device device
0050             required property string name
0051 
0052             signal call(BluezQt.PendingCall pc)
0053 
0054             title: i18n("Forget this Device?")
0055             subtitle: i18n("Are you sure you want to forget \"%1\"?", dialog.name)
0056 
0057             showCloseButton: false
0058 
0059             // Need to use fully custom actions because it's not possible to override
0060             // the text and icon of a single standardbutton, and if we use just a
0061             // custom action for that one, then it's in the wrong visual position
0062             // relative to the StandardButton-provided Cancel button
0063             standardButtons: Kirigami.Dialog.NoButton
0064             customFooterActions: [
0065                 Kirigami.Action {
0066                     text: i18nc("@action:button", "Forget Device")
0067                     icon.name: "edit-delete-remove"
0068                     onTriggered: {
0069                         dialog.accept();
0070                     }
0071                 },
0072                 Kirigami.Action {
0073                     text: i18nc("@action:button", "Cancel")
0074                     icon.name: "dialog-cancel"
0075                     onTriggered: {
0076                         dialog.reject();
0077                     }
0078                     shortcut: StandardKey.Cancel
0079                 }
0080             ]
0081 
0082             onAccepted: call(adapter.removeDevice(device))
0083 
0084             contentData: [
0085                 Connections {
0086                     target: dialog.device
0087                     function onDeviceRemoved() {
0088                         dialog.reject();
0089                     }
0090                 },
0091                 Connections {
0092                     target: dialog.adapter
0093                     function onAdapterRemoved() {
0094                         dialog.reject();
0095                     }
0096                     function onPoweredChanged() {
0097                         if (!dialog.adapter.powered) {
0098                             dialog.reject();
0099                         }
0100                     }
0101                 }
0102             ]
0103         }
0104     }
0105 
0106     implicitHeight: Kirigami.Units.gridUnit * 28
0107     implicitWidth: Kirigami.Units.gridUnit * 28
0108 
0109     function setBluetoothEnabled(enabled) {
0110         BluezQt.Manager.bluetoothBlocked = !enabled
0111 
0112         for (var i = 0; i < BluezQt.Manager.adapters.length; ++i) {
0113             var adapter = BluezQt.Manager.adapters[i];
0114             adapter.powered = enabled;
0115         }
0116     }
0117 
0118     header: Kirigami.InlineMessage {
0119         id: errorMessage
0120         type: Kirigami.MessageType.Error
0121         showCloseButton: true
0122     }
0123 
0124     view: ListView {
0125         id: list
0126         clip: true
0127 
0128         Kirigami.PlaceholderMessage {
0129             id: noBluetoothMessage
0130             // We cannot use the adapter count here because that can be zero when
0131             // bluetooth is disabled even when there are physical devices
0132             visible: BluezQt.Manager.rfkill.state === BluezQt.Rfkill.Unknown
0133             icon.name: "edit-none"
0134             text: i18n("No Bluetooth adapters found")
0135             width: parent.width - (Kirigami.Units.largeSpacing * 4)
0136             anchors.centerIn: parent
0137         }
0138 
0139         Kirigami.PlaceholderMessage {
0140             id: bluetoothDisabledMessage
0141             visible: BluezQt.Manager.operational && !BluezQt.Manager.bluetoothOperational && !noBluetoothMessage.visible
0142             icon.name: "network-bluetooth"
0143             text: i18n("Bluetooth is disabled")
0144             width: parent.width - (Kirigami.Units.largeSpacing * 4)
0145             anchors.centerIn: parent
0146 
0147             helpfulAction: Kirigami.Action {
0148                 iconName: "network-bluetooth"
0149                 text: i18n("Enable")
0150                 onTriggered: {
0151                     root.setBluetoothEnabled(true)
0152                 }
0153             }
0154         }
0155 
0156         Kirigami.PlaceholderMessage {
0157             visible: !noBluetoothMessage.visible && !bluetoothDisabledMessage.visible && list.count === 0
0158             icon.name: "network-bluetooth-activated"
0159             text: i18n("No devices paired")
0160             width: parent.width - (Kirigami.Units.largeSpacing * 4)
0161             anchors.centerIn: parent
0162         }
0163 
0164         model: BluezQt.Manager.bluetoothOperational ? devicesModel : null
0165 
0166         QQC2.BusyIndicator {
0167             id: busyIndicator
0168             running: false
0169             anchors.centerIn: parent
0170         }
0171 
0172 
0173         DevicesProxyModel {
0174             id: devicesModel
0175             sourceModel: BluezQt.DevicesModel { }
0176         }
0177 
0178         section.property: "Connected"
0179         section.delegate: Kirigami.ListSectionHeader {
0180             text: section === "true" ? i18n("Connected") : i18n("Available")
0181         }
0182 
0183         delegate: Kirigami.SwipeListItem {
0184 
0185             // content item includes its own padding
0186             padding: 0
0187 
0188             contentItem: Kirigami.BasicListItem {
0189                 // The parent item already has a highlight
0190                 activeBackgroundColor: "transparent"
0191 
0192                 separatorVisible: false
0193 
0194                 text: model.Name
0195                 icon: model.Icon
0196                 iconSize: Kirigami.Units.iconSizes.medium
0197                 onClicked: kcm.push("Device.qml", {device: model.Device})
0198             }
0199 
0200             actions: [
0201                 Kirigami.Action {
0202                     text: model.Connected ? i18n("Disconnect") : i18n("Connect")
0203                     icon.name: model.Connected ? "network-disconnect" : "network-connect"
0204                     onTriggered: {
0205                         if (model.Connected) {
0206                             root.makeCall(model.Device.disconnectFromDevice())
0207                         } else {
0208                             root.makeCall(model.Device.connectToDevice())
0209                         }
0210                     }
0211                 },
0212                 Kirigami.Action {
0213                     text: i18nc("@action:button %1 is the name of a Bluetooth device", "Forget \"%1\"", model.Name)
0214                     icon.name: "edit-delete-remove"
0215                     onTriggered: {
0216                         const dialog = forgetDialogComponent.createObject(root, {
0217                             adapter: model.Adapter,
0218                             device: model.Device,
0219                             name: model.Name,
0220                         });
0221                         // Use IIFE (Immediately Invoked Function Expression) to hard-copy a reference
0222                         // to root object, to avoid it being lost if the delegate is destroyed.
0223                         dialog.call.connect((function (root) {
0224                             return (call => root.makeCall(call));
0225                         })(root));
0226                         dialog.closed.connect(() => dialog.destroy());
0227                         dialog.open();
0228                     }
0229                 }
0230             ]
0231         }
0232     }
0233 
0234     // System Settings doesn't draw its own footer buttons, so extra footer
0235     // paddings here to make them look better isn't necessary
0236     extraFooterTopPadding: false
0237     footer: RowLayout {
0238         visible: BluezQt.Manager.bluetoothOperational
0239 
0240         QQC2.Button {
0241             text: i18n("Add New Deviceā€¦")
0242             icon.name: "list-add"
0243             onClicked: kcm.runWizard()
0244         }
0245 
0246         QQC2.Button {
0247             text: i18n("Disable Bluetooth")
0248             icon.name: "network-bluetooth"
0249             onClicked: {
0250                 root.setBluetoothEnabled(false)
0251             }
0252         }
0253 
0254         Item {
0255             Layout.fillWidth: true
0256         }
0257 
0258         QQC2.Button {
0259             text: i18n("Configureā€¦")
0260             icon.name: "configure"
0261             onClicked: kcm.push("General.qml")
0262         }
0263     }
0264 }