Warning, /plasma/plasma-firewall/kcm/ui/ViewBase.qml is written in an unsupported language. File is not indexed.
0001 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0002 // SPDX-FileCopyrightText: 2018 Alexis Lopes Zubeta <contact@azubieta.net> 0003 // SPDX-FileCopyrightText: 2020 Tomaz Canabrava <tcanabrava@kde.org> 0004 0005 import QtQml 2.12 0006 import QtQuick 0007 import QtQuick.Layouts 1.3 0008 import QtQuick.Controls as QQC2 0009 import org.kde.kirigami 2.14 as Kirigami 0010 0011 import org.kde.kcmutils as KCMUtils 0012 import org.kde.kitemmodels 1.0 0013 import org.kcm.firewall 1.0 0014 0015 KCMUtils.ScrollViewKCM { 0016 id: root 0017 0018 property QtObject model 0019 property var columns: [] 0020 property alias emptyListText: emptyListLabel.text 0021 0022 property QtObject currentJob: null 0023 0024 property var blacklistRuleFactory 0025 property var blacklistColumns: [] 0026 property string blacklistRuleSuccessMessage 0027 0028 property int sortColumn: 0 0029 property int sortOrder: Qt.AscendingOrder 0030 0031 property alias filterPlaceholderText: searchField.placeholderText 0032 property var filterColumns: [] 0033 0034 property var errorMessage: modelErrorMessage 0035 0036 KSortFilterProxyModel { 0037 id: proxyModel 0038 sourceModel: root.model 0039 sortColumn: root.sortColumn 0040 sortOrder: root.sortOrder 0041 0042 function filterCb(source_row, source_parent) { 0043 const query = searchField.text.toLocaleLowerCase(); 0044 const columns = filterColumns; 0045 0046 const modelType = getModelType(); 0047 0048 for (var i = 0, length = columns.length; i < length; ++i) { 0049 const idx = sourceModel.index(source_row, columns[i], source_parent); 0050 const data = String(sourceModel.data(idx) || "").toLocaleLowerCase(); 0051 0052 if (data.includes(query)) { 0053 return true; 0054 } 0055 } 0056 0057 return false; 0058 } 0059 0060 filterRowCallback: searchField.length > 0 && filterColumns.length > 0 ? filterCb : null 0061 0062 filterColumnCallback: (source_column, source_parent) => { 0063 return columns.map(column => column.column).includes(source_column) 0064 } 0065 } 0066 0067 function getModelType() { 0068 // can this be done generically? :( 0069 if (root.model instanceof LogListModel) { 0070 return LogListModel; 0071 } else if (root.model instanceof ConnectionsModel) { 0072 return ConnectionsModel; 0073 } 0074 return null; 0075 } 0076 0077 function blacklistRow(row) { 0078 // FIXME why does TableView does that? :( 0079 // Unfortunately it also casts to 0, so the resulting model index is deemed valid 0080 if (row === undefined) { 0081 return; 0082 } 0083 0084 console.log("Accessing blacklist row", row); 0085 const idx = proxyModel.index(row, 0); 0086 const columns = blacklistColumns; 0087 const args = columns.map((column) => { 0088 return proxyModel.data(proxyModel.index(row, column)); 0089 }); 0090 0091 if (args[0] === undefined) { 0092 console.log("Error, a model refresh happened when you tried to blacklist a connection."); 0093 return; 0094 } 0095 0096 const rule = blacklistRuleFactory(...args); 0097 const job = kcm.client.addRule(rule); 0098 0099 currentJob = job; 0100 ruleCreationErrorMessage.visible = false; 0101 console.log(...args); 0102 0103 job.result.connect(function() { 0104 currentJob = null; 0105 0106 if (job.error) { 0107 if (job.error !== 4) { // FIXME magic number 0108 let indexError = job.errorString.indexOf("ERROR:"); 0109 let errorStrings = job.errorString.substring(indexError); 0110 0111 console.log(errorStrings); 0112 ruleCreationErrorMessage.text = i18n("Error creating rule: %1", errorStrings); 0113 ruleCreationErrorMessage.visible = true; 0114 } 0115 return; 0116 } 0117 0118 if (blacklistRuleSuccessMessage) { 0119 kcm.showPassiveNotification(blacklistRuleSuccessMessage); 0120 } 0121 }); 0122 } 0123 0124 header: ColumnLayout { 0125 Kirigami.InlineMessage { 0126 id: modelErrorMessage 0127 Layout.fillWidth: true 0128 type: Kirigami.MessageType.Error 0129 showCloseButton: true 0130 0131 Connections { 0132 target: root.model 0133 function onShowErrorMessage(message) { 0134 modelErrorMessage.text = message; 0135 modelErrorMessage.visible = true; 0136 } 0137 } 0138 } 0139 0140 Kirigami.InlineMessage { 0141 id: ruleCreationErrorMessage 0142 type: Kirigami.MessageType.Error 0143 Layout.fillWidth: true 0144 showCloseButton: true 0145 } 0146 0147 Kirigami.SearchField { 0148 id: searchField 0149 Layout.fillWidth: true 0150 onTextChanged: proxyModel.invalidateFilter(); 0151 enabled: root.model.count > 0 0152 visible: root.filterColumns.length > 0 0153 } 0154 } 0155 0156 QQC2.HorizontalHeaderView { 0157 id: horizontalHeader 0158 visible: tableView.rows > 0 0159 model: KColumnHeadersModel { 0160 sourceModel: proxyModel 0161 sortColumn: root.sortColumn 0162 } 0163 selectionModel: ItemSelectionModel{} 0164 syncView: tableView 0165 Layout.fillWidth: true 0166 0167 TapHandler { 0168 acceptedButtons: Qt.LeftButton 0169 0170 onTapped: (eventPoint, button) => { 0171 let cell = horizontalHeader.cellAtPosition(eventPoint.position) 0172 if (cell.x == root.sortColumn) { 0173 root.sortOrder = header.sortOrder == Qt.AscendingOrder ? Qt.DescendingOrder : Qt.AscendingOrder 0174 } else { 0175 root.sortOrder = Qt.AscendingOrder 0176 } 0177 root.sortColumn = cell.x 0178 } 0179 } 0180 } 0181 0182 view: TableView { 0183 id: tableView 0184 anchors.fill: parent 0185 topMargin: horizontalHeader.height 0186 alternatingRows: true 0187 0188 selectionModel: ItemSelectionModel {} 0189 selectionBehavior: TreeView.SelectRows 0190 function selectRelative(delta) { 0191 var nextRow = selectionModel.currentIndex.row + delta 0192 if (nextRow < 0) { 0193 nextRow = 0 0194 } 0195 if (nextRow >= rows) { 0196 nextRow = rows - 1 0197 } 0198 var index = model.index(nextRow, selectionModel.currentIndex.column) 0199 selectionModel.setCurrentIndex(index, ItemSelectionModel.ClearAndSelect | ItemSelectionModel.Rows) 0200 } 0201 Keys.onUpPressed: selectRelative(-1) 0202 Keys.onDownPressed: selectRelative(1) 0203 0204 model: proxyModel 0205 columnWidthProvider: (column) => { 0206 let explicitWidth = explicitColumnWidth(column) 0207 if (explicitWidth > 0) { 0208 return explicitWidth 0209 } 0210 let sourceColumn = proxyModel.mapToSource(proxyModel.index(0, column)).column 0211 let width = root.columns.find(c => c.column == sourceColumn).width 0212 return width 0213 } 0214 clip: true 0215 delegate: QQC2.ItemDelegate { 0216 required property var model 0217 required property bool selected 0218 required property bool current 0219 text: model.display 0220 highlighted: selected || current 0221 onClicked: { 0222 tableView.selectionModel.setCurrentIndex(tableView.model.index(model.row, model.column), ItemSelectionModel.Rows | ItemSelectionModel.ClearAndSelect) 0223 } 0224 } 0225 } 0226 0227 Kirigami.PlaceholderMessage { 0228 id: emptyListLabel 0229 parent: tableView.parent 0230 anchors.centerIn: parent 0231 width: parent.width - (Kirigami.Units.largeSpacing * 4) 0232 visible: root.model.count === 0 && !root.model.busy && !modelErrorMessage.visible 0233 } 0234 0235 QQC2.BusyIndicator { 0236 parent: tableView.parent 0237 anchors.centerIn: parent 0238 // Show busy spinner only on initial population and not while an error is shown 0239 running: root.model.count === 0 && root.model.busy && !modelErrorMessage.visible 0240 } 0241 0242 footer: RowLayout { 0243 Item { 0244 Layout.fillWidth: true 0245 } 0246 0247 InlineBusyIndicator { 0248 horizontalAlignment: Qt.AlignRight 0249 running: root.currentJob 0250 } 0251 0252 QQC2.Button { 0253 text: i18n("Blacklist Connection") 0254 icon.name: "network-disconnect" 0255 // HACK TableView lets us select a fake zero index when view is empty... 0256 enabled: tableView.selectionModel.currentIndex && model.count > 0 && !root.currentJob 0257 onClicked: blacklistRow(tableView.selectionModel.currentIndex.row) 0258 } 0259 } 0260 }