Warning, /plasma/flatpak-kcm/ui/permissions.qml is written in an unsupported language. File is not indexed.

0001 /**
0002  * SPDX-FileCopyrightText: 2022 Suhaas Joshi <joshiesuhaas0@gmail.com>
0003  * SPDX-FileCopyrightText: 2023 ivan tkachenko <me@ratijas.tk>
0004  * SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 pragma ComponentBehavior: Bound
0008 
0009 import QtQuick
0010 import QtQuick.Controls as QQC2
0011 import QtQuick.Layouts
0012 
0013 import org.kde.kcmutils as KCM
0014 import org.kde.kirigami as Kirigami
0015 import org.kde.plasma.kcm.flatpakpermissions
0016 
0017 KCM.ScrollViewKCM {
0018     id: root
0019 
0020     required property FlatpakReference ref
0021 
0022     title: i18n("Permissions")
0023     implicitWidth: Kirigami.Units.gridUnit * 15
0024     framedView: false
0025 
0026     Kirigami.PlaceholderMessage {
0027         text: i18n("Select an application from the list to view its permissions here")
0028         width: parent.width - (Kirigami.Units.largeSpacing * 4)
0029         anchors.centerIn: parent
0030         visible: ref === null
0031     }
0032 
0033     Kirigami.Separator {
0034         anchors.left: parent.left
0035         height: parent.height
0036     }
0037 
0038     Component {
0039         id: addEnvironmentVariableDialogComponent
0040 
0041         AddEnvironmentVariableDialog {
0042             parent: root.Kirigami.ColumnView.view
0043             model: permsModel
0044 
0045             onClosed: destroy()
0046         }
0047     }
0048 
0049     Component {
0050         id: textPromptDialogComponent
0051 
0052         TextPromptDialog {
0053             parent: root.Kirigami.ColumnView.view
0054             model: permsModel
0055 
0056             onClosed: destroy()
0057         }
0058     }
0059 
0060     // Having it inside a component helps to separate layouts and workarounds for nullable property accesses.
0061     Component {
0062         id: headerComponent
0063 
0064         RowLayout {
0065             id: header
0066 
0067             readonly property url icon: root.ref.iconSource
0068             readonly property string title: root.ref.displayName
0069             readonly property string subtitle: root.ref.version
0070 
0071             spacing: 0
0072 
0073             width: ListView.view.width - ListView.view.leftMargin - ListView.view.rightMargin
0074 
0075             Kirigami.Icon {
0076                 // Fallback doesn't kick in when source is an empty string/url
0077                 source: header.icon.toString() !== "" ? header.icon : "application-vnd.flatpak.ref"
0078 
0079                 Layout.alignment: Qt.AlignCenter
0080                 Layout.preferredWidth: Kirigami.Units.iconSizes.large
0081                 Layout.preferredHeight: Kirigami.Units.iconSizes.large
0082 
0083                 // RowLayout is incapable of paddings, so use margins on both child items instead.
0084                 Layout.margins: Kirigami.Units.largeSpacing
0085             }
0086             ColumnLayout {
0087                 spacing: Kirigami.Units.smallSpacing
0088                 Layout.fillWidth: true
0089 
0090                 Layout.margins: Kirigami.Units.largeSpacing
0091                 Layout.leftMargin: 0
0092 
0093                 Kirigami.Heading {
0094                     text: header.title
0095                     wrapMode: Text.Wrap
0096                     Layout.fillWidth: true
0097                 }
0098                 Kirigami.Heading {
0099                     text: header.subtitle
0100                     type: Kirigami.Heading.Secondary
0101                     level: 3
0102                     wrapMode: Text.Wrap
0103                     Layout.fillWidth: true
0104                 }
0105             }
0106         }
0107     }
0108 
0109     view: ListView {
0110         model: FlatpakPermissionModel {
0111             id: permsModel
0112             reference: root.ref
0113         }
0114 
0115         currentIndex: -1
0116         // Mitigate ListView's poor layouting stills.
0117         // Without it, section delegates may shift down and overlap.
0118         reuseItems: false
0119         cacheBuffer: 10000
0120 
0121         // Ref is assumed to remain constant for the lifetime of this page. If
0122         // it's not null, then it would remain so, and no further checks are
0123         // needed inside the component.
0124         header: root.ref === null ? null : headerComponent
0125         headerPositioning: ListView.InlineHeader
0126 
0127         section.property: "section"
0128         section.criteria: ViewSection.FullString
0129         section.delegate: Kirigami.ListSectionHeader {
0130             id: sectionDelegate
0131 
0132             required property string section
0133 
0134             /**
0135              * Sorry about this mess. ListView automatically converts data of
0136              * section role to string, so we parse it back into enum.
0137              */
0138             readonly property /*FlatpakPermissionsSectionType::Type*/ int sectionType: parseInt(section)
0139 
0140             width: ListView.view.width - ListView.view.leftMargin - ListView.view.rightMargin
0141             label: permsModel.sectionHeaderForSectionType(sectionType)
0142             QQC2.ToolButton {
0143                 text: permsModel.showAdvanced ? i18n("Hide advanced permissions") : i18n("Show advanced permissions")
0144                 display: QQC2.AbstractButton.IconOnly
0145                 icon.name: permsModel.showAdvanced ? "collapse" : "expand"
0146                 visible: sectionDelegate.sectionType === FlatpakPermissionsSectionType.Advanced
0147                 onClicked: permsModel.showAdvanced = !permsModel.showAdvanced
0148                 Layout.alignment: Qt.AlignRight
0149 
0150                 QQC2.ToolTip.text: text
0151                 QQC2.ToolTip.visible: Kirigami.Settings.tabletMode ? pressed : hovered
0152                 QQC2.ToolTip.delay: Kirigami.Settings.tabletMode ? Qt.styleHints.mousePressAndHoldInterval : Kirigami.Units.toolTipDelay
0153             }
0154             QQC2.ToolButton {
0155                 text: i18n("Add New")
0156                 icon.name: "bqm-add"
0157                 visible: [
0158                     FlatpakPermissionsSectionType.Filesystems,
0159                     FlatpakPermissionsSectionType.SessionBus,
0160                     FlatpakPermissionsSectionType.SystemBus,
0161                     FlatpakPermissionsSectionType.Environment,
0162                 ].includes(sectionDelegate.sectionType)
0163                 onClicked: {
0164                     if (sectionDelegate.sectionType === FlatpakPermissionsSectionType.Environment) {
0165                         const dialog = addEnvironmentVariableDialogComponent.createObject(root, {
0166                             model: permsModel,
0167                         });
0168                         dialog.open();
0169                     } else {
0170                         const dialog = textPromptDialogComponent.createObject(root, {
0171                             model: permsModel,
0172                             sectionType: sectionDelegate.sectionType,
0173                         });
0174                         dialog.open();
0175                     }
0176                 }
0177                 Layout.alignment: Qt.AlignRight
0178 
0179                 QQC2.ToolTip.text: permsModel.sectionAddButtonToolTipTextForSectionType(sectionDelegate.sectionType)
0180                 QQC2.ToolTip.visible: Kirigami.Settings.tabletMode ? pressed : hovered
0181                 QQC2.ToolTip.delay: Kirigami.Settings.tabletMode ? Qt.styleHints.mousePressAndHoldInterval : Kirigami.Units.toolTipDelay
0182             }
0183         }
0184 
0185         // Can't use a CheckDelegate or one of its subclasses since we need the checkbox
0186         // to highlight when it's in a non-default state and none of the pre-made delegates
0187         // can do that
0188         delegate: QQC2.ItemDelegate {
0189             id: permItem
0190 
0191             required property var model
0192             required property int index
0193 
0194             function toggleAndUncheck() {
0195                 if (checkable) {
0196                     permsModel.togglePermissionAtRow(index);
0197                 }
0198                 ListView.view.currentIndex = -1;
0199             }
0200 
0201             width: ListView.view.width - ListView.view.leftMargin - ListView.view.rightMargin
0202 
0203             // Default-provided custom entries are not meant to be unchecked:
0204             // it is a meaningless undefined operation.
0205             checkable: model.canBeDisabled
0206 
0207             visible: model.isNotDummy
0208 
0209             onClicked: toggleAndUncheck()
0210 
0211             contentItem: RowLayout {
0212                 spacing: Kirigami.Units.smallSpacing
0213 
0214                 QQC2.CheckBox {
0215                     id: checkBox
0216                     enabled: permItem.checkable
0217                     checked: permItem.model.isEffectiveEnabled
0218 
0219                     onToggled: permItem.toggleAndUncheck()
0220 
0221                     KCM.SettingHighlighter {
0222                         highlight: permItem.model.isEffectiveEnabled !== permItem.model.isDefaultEnabled
0223                     }
0224                 }
0225 
0226                 QQC2.Label {
0227                     Layout.fillWidth: true
0228                     text: model.description
0229                     elide: Text.ElideRight
0230                 }
0231 
0232                 QQC2.ComboBox {
0233                     visible: [
0234                         FlatpakPermissionsSectionType.Filesystems,
0235                         FlatpakPermissionsSectionType.SessionBus,
0236                         FlatpakPermissionsSectionType.SystemBus,
0237                     ].includes(permItem.model.section)
0238 
0239                     enabled: checkBox.checked
0240 
0241                     model: permItem.model.valuesModel
0242                     textRole: "display"
0243                     valueRole: "value"
0244 
0245                     KCM.SettingHighlighter {
0246                         highlight: permItem.model.effectiveValue !== permItem.model.defaultValue
0247                     }
0248 
0249                     onActivated: index => {
0250                         // Assuming this is only called for appropriate visible entries.
0251                         permsModel.setPermissionValueAtRow(permItem.index, currentValue);
0252                     }
0253 
0254                     Component.onCompleted: {
0255                         // Still need to check section type, as this is called for every entry.
0256                         if (permItem.model.isNotDummy && [
0257                                 FlatpakPermissionsSectionType.Filesystems,
0258                                 FlatpakPermissionsSectionType.SessionBus,
0259                                 FlatpakPermissionsSectionType.SystemBus,
0260                             ].includes(permItem.model.section)) {
0261                             currentIndex = Qt.binding(() => indexOfValue(permItem.model.effectiveValue));
0262                         }
0263                     }
0264                 }
0265 
0266                 QQC2.TextField {
0267                     visible: permItem.model.isNotDummy && permItem.model.section === FlatpakPermissionsSectionType.Environment
0268                     text: (permItem.model.isNotDummy && permItem.model.section === FlatpakPermissionsSectionType.Environment)
0269                         ? permItem.model.effectiveValue : ""
0270                     enabled: checkBox.checked
0271 
0272                     onTextEdited: {
0273                         permsModel.setPermissionValueAtRow(permItem.index, text);
0274                     }
0275 
0276                     KCM.SettingHighlighter {
0277                         highlight: permItem.model.effectiveValue !== permItem.model.defaultValue
0278                     }
0279                 }
0280             }
0281         }
0282     }
0283 }