Warning, /plasma/flatpak-kcm/ui/main.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.Layouts
0011 import QtQuick.Controls as QQC2
0012 import org.kde.kirigami as Kirigami
0013 import org.kde.kcmutils as KCM
0014 import org.kde.kitemmodels as KItemModels
0015 import org.kde.plasma.kcm.flatpakpermissions
0016
0017 KCM.ScrollViewKCM {
0018 id: root
0019 title: i18n("Flatpak Applications")
0020 Kirigami.ColumnView.fillWidth: false
0021 implicitWidth: Kirigami.Units.gridUnit * 40
0022 implicitHeight: Kirigami.Units.gridUnit * 20
0023 framedView: false
0024
0025 function shouldChange(toAppAtFilteredRowIndex: int) {
0026 const fromAppAtSourceRowIndex = KCM.ConfigModule.currentIndex();
0027
0028 const toAppAtSourceRowIndex = (toAppAtFilteredRowIndex === -1)
0029 ? toAppAtFilteredRowIndex
0030 : filteredRefsModel.mapToSource(filteredRefsModel.index(toAppAtFilteredRowIndex, 0)).row;
0031
0032 if (toAppAtSourceRowIndex === KCM.ConfigModule.currentIndex()) {
0033 // Don't reload if it's current anyway.
0034 return;
0035 }
0036
0037 if (fromAppAtSourceRowIndex !== -1 && KCM.ConfigModule.isSaveNeeded()) {
0038 const m = KCM.ConfigModule.refsModel;
0039 const fromAppAtSourceIndex = m.index(fromAppAtSourceRowIndex, 0);
0040 const applicationName = m.data(fromAppAtSourceIndex, FlatpakReferencesModel.Name);
0041 const applicationIcon = m.data(fromAppAtSourceIndex, FlatpakReferencesModel.Icon);
0042 const dialog = applyOrDiscardDialogComponent.createObject(this, {
0043 applicationName,
0044 applicationIcon,
0045 fromAppAtSourceRowIndex,
0046 toAppAtSourceRowIndex,
0047 });
0048 dialog.open();
0049 } else {
0050 changeApp(toAppAtSourceRowIndex)
0051 }
0052 }
0053
0054 function changeApp(toAppAtSourceRowIndex) {
0055 let ref = null;
0056 if (toAppAtSourceRowIndex !== -1) {
0057 const sourceIndex = KCM.ConfigModule.refsModel.index(toAppAtSourceRowIndex, 0);
0058 ref = KCM.ConfigModule.refsModel.data(sourceIndex, FlatpakReferencesModel.Ref) as FlatpakReference;
0059 appsListView.setCurrentIndexLater(toAppAtSourceRowIndex);
0060 }
0061 KCM.ConfigModule.pop();
0062 KCM.ConfigModule.setIndex(toAppAtSourceRowIndex);
0063 KCM.ConfigModule.push("permissions.qml", { ref });
0064 }
0065
0066 Component.onCompleted: {
0067 KCM.ConfigModule.columnWidth = Kirigami.Units.gridUnit * 15
0068 changeApp(KCM.ConfigModule.currentIndex());
0069 }
0070
0071 KCM.ConfigModule.buttons: KCM.ConfigModule.Apply | KCM.ConfigModule.Default
0072
0073 Component {
0074 id: applyOrDiscardDialogComponent
0075
0076 Kirigami.PromptDialog {
0077 id: dialog
0078
0079 required property string applicationName
0080 required property url applicationIcon
0081
0082 // source model indices
0083 required property int fromAppAtSourceRowIndex
0084 required property int toAppAtSourceRowIndex
0085
0086 readonly property bool narrow: (parent.width - leftMargin - rightMargin) < Kirigami.Units.gridUnit * 20
0087
0088 parent: root.Kirigami.ColumnView.view
0089 title: i18n("Apply Permissions")
0090 subtitle: i18n("The permissions of application %1 have been changed. Do you want to apply these changes or discard them?", applicationName)
0091 standardButtons: QQC2.Dialog.Apply | QQC2.Dialog.Discard
0092
0093 GridLayout {
0094 columns: dialog.narrow ? 1 : 2
0095 columnSpacing: Kirigami.Units.largeSpacing
0096 rowSpacing: Kirigami.Units.largeSpacing
0097
0098 Kirigami.Icon {
0099 source: dialog.applicationIcon.toString() !== "" ? dialog.applicationIcon : "application-vnd.flatpak.ref"
0100
0101 Layout.alignment: Qt.AlignCenter
0102 Layout.preferredWidth: Kirigami.Units.iconSizes.large
0103 Layout.preferredHeight: Kirigami.Units.iconSizes.large
0104 }
0105 Kirigami.SelectableLabel {
0106 text: dialog.subtitle
0107 wrapMode: Text.Wrap
0108
0109 Layout.fillWidth: true
0110 Layout.fillHeight: true
0111 }
0112 }
0113
0114 QQC2.Overlay.modal: KcmPopupModal {}
0115
0116 onOpened: {
0117 const button = standardButton(QQC2.Dialog.Apply);
0118 button.forceActiveFocus(Qt.TabFocusReason);
0119 }
0120
0121 onApplied: {
0122 root.KCM.ConfigModule.save()
0123 root.changeApp(toAppAtSourceRowIndex)
0124 dialog.close()
0125 }
0126
0127 onDiscarded: {
0128 root.KCM.ConfigModule.load()
0129 root.changeApp(fromAppAtSourceRowIndex)
0130 dialog.close()
0131 }
0132
0133 onRejected: {
0134 appsListView.currentIndex = root.KCM.ConfigModule.currentIndex()
0135 }
0136
0137 onClosed: destroy()
0138 }
0139 }
0140
0141 header: Kirigami.SearchField {
0142 id: filterField
0143 KeyNavigation.tab: appsListView
0144 KeyNavigation.down: appsListView
0145 autoAccept: false
0146 onAccepted: {
0147 if (text === "") {
0148 // The signal also fires when user clicks the "Clear" action/icon/button.
0149 // In this case don't treat it as a command to open first app.
0150 return;
0151 }
0152 if (filteredRefsModel.count >= 0) {
0153 appsListView.setCurrentIndexLater(0);
0154 root.shouldChange(0);
0155 }
0156 }
0157 }
0158
0159 view: ListView {
0160 id: appsListView
0161
0162 function setCurrentIndexLater(sourceRowIndex) {
0163 // View has not updated yet, and alas -- we don't have suitable
0164 // hooks here. Note that ListView::onCountChanged WON'T WORK, as
0165 // unlike KSortFilterProxyModel it won't trigger when changing
0166 // from e.g. 2 rows [a, b] to another 2 rows [d, c].
0167
0168 const sourceIndex = filteredRefsModel.sourceModel.index(sourceRowIndex, 0);
0169 const filteredIndex = filteredRefsModel.mapFromSource(sourceIndex);
0170 const filteredRowIndex = filteredIndex.valid ? filteredIndex.row : -1;
0171
0172 delayedCurrentIndexSetter.index = filteredRowIndex;
0173 delayedCurrentIndexSetter.start();
0174 }
0175
0176 // Using Timer object instead of Qt.callLater to get deduplication for free.
0177 Timer {
0178 id: delayedCurrentIndexSetter
0179
0180 property int index: -1
0181
0182 interval: 0
0183 running: false
0184
0185 onTriggered: {
0186 appsListView.currentIndex = index;
0187 }
0188 }
0189
0190 model: KItemModels.KSortFilterProxyModel {
0191 id: filteredRefsModel
0192 sourceModel: root.KCM.ConfigModule.refsModel
0193 sortOrder: Qt.AscendingOrder
0194 sortCaseSensitivity: Qt.CaseInsensitive
0195 sortRole: FlatpakReferencesModel.Name
0196 filterRole: FlatpakReferencesModel.Name
0197 filterString: filterField.text
0198 filterCaseSensitivity: Qt.CaseInsensitive
0199 onCountChanged: {
0200 if (count >= 0) {
0201 const sourceRowIndex = root.KCM.ConfigModule.currentIndex();
0202 appsListView.setCurrentIndexLater(sourceRowIndex);
0203 }
0204 }
0205 }
0206 currentIndex: -1
0207 delegate: QQC2.ItemDelegate {
0208 required property int index
0209 required property var model
0210
0211 width: ListView.view.width - ListView.view.leftMargin - ListView.view.rightMargin
0212
0213 highlighted: ListView.isCurrentItem
0214
0215 text: model.name
0216 // Prefer source, fallback to name. This is unusual for QtQuick.Controls.
0217 icon.name: model.icon.toString() !== "" ? "" : "application-vnd.flatpak.ref"
0218 icon.source: model.icon.toString() === "" ? "" : model.icon
0219
0220 onClicked: root.shouldChange(index)
0221 }
0222 }
0223 }