Warning, /plasma/plasma-systemmonitor/src/table/BaseTableView.qml is written in an unsupported language. File is not indexed.

0001 /*
0002  * SPDX-FileCopyrightText: 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005  */
0006 
0007 import QtQuick 2.12
0008 import QtQuick.Controls 2.12
0009 import QtQuick.Layouts 1.12
0010 import QtQml.Models 2.12
0011 
0012 import org.kde.kirigami 2.2 as Kirigami
0013 import org.kde.ksysguard.table 1.0 as Table
0014 
0015 FocusScope {
0016     id: root
0017 
0018     property var model
0019     property alias delegate: tableView.delegate
0020 
0021     property alias headerModel: heading.sourceModel
0022 
0023     property alias sortColumn: heading.sortColumn
0024     property alias sortOrder: heading.sortOrder
0025     property alias sortName: heading.sortName
0026     property alias idRole: heading.idRole
0027 
0028     // Column widths in fractions of the entire view width
0029     // Since column sizes are relative to a given view width, the widths of individual
0030     // columns need to be expressed as a fraction of the entire width. columnWidths
0031     // and defaultColumnWidth both store these fractions. Note that minimumColumnWidth
0032     // is expressed as a pixel value since we do not want that to scale with view width.
0033     property var columnWidths: []
0034     property real defaultColumnWidth: 0.1
0035     property real minimumColumnWidth: Kirigami.Units.gridUnit * 4
0036     property real rowHeight: Kirigami.Units.gridUnit + Kirigami.Units.smallSpacing * 2
0037 
0038     readonly property alias headerHeight: heading.height
0039 
0040     readonly property alias selection: tableView.selectionModel
0041     readonly property alias rows: tableView.rows
0042     readonly property alias columns: tableView.columns
0043 
0044     signal contextMenuRequested(var index, point position)
0045     signal headerContextMenuRequested(int column, point position)
0046     signal sort(int column, int order)
0047 
0048     Layout.minimumHeight: heading.height + root.rowHeight * 3
0049 
0050     clip: true
0051 
0052     function setColumnWidth(index, width) {
0053         if (index < 0 || index >= tableView.columns || width < minimumColumnWidth) {
0054             return
0055         }
0056 
0057         while (index >= columnWidths.length) {
0058             columnWidths.push(defaultColumnWidth)
0059         }
0060 
0061         columnWidths[index] = width / scrollView.innerWidth
0062         columnWidthsChanged();
0063     }
0064 
0065     // This is a workaround for a small memory leak in QQmlPropertyCache.
0066     // When using Connection {} in combination with
0067     // QAbstractItemModel::layoutChanged() from within QML,
0068     // QQmlPropertyCache::createArgumentsObject() will leak. As a workaround, we
0069     // can put a proxy signal in between that is used instead and the leak won't
0070     // happen.
0071     // TODO KF6: Remove this as the bug doesn't exist in Qt 6.
0072     function onModelLayoutChanged() {
0073         tableView.modelLayoutHasChanged()
0074     }
0075 
0076     onColumnWidthsChanged: tableView.forceLayout()
0077 
0078     Kirigami.Theme.inherit: false
0079     Kirigami.Theme.colorSet: Kirigami.Theme.View
0080 
0081     TableViewHeader {
0082         id: heading
0083 
0084         view: tableView
0085 
0086         width: scrollView.width
0087         onSort: root.sort(column, order)
0088 
0089         onResize: root.setColumnWidth(column, width)
0090 
0091         onContextMenuRequested: root.headerContextMenuRequested(column, position)
0092 
0093     }
0094 
0095     ScrollView {
0096         id: scrollView
0097         anchors.fill: parent
0098         anchors.topMargin: heading.height
0099 
0100         property real innerWidth: LayoutMirroring.enabled ? width - leftPadding : width - rightPadding
0101 
0102         background: Rectangle { color: Kirigami.Theme.backgroundColor; Kirigami.Theme.colorSet: Kirigami.Theme.View }
0103 
0104         TableView {
0105             id: tableView
0106             anchors.left: parent.left
0107             property ItemSelectionModel selectionModel: ItemSelectionModel {
0108                 id: selectionModel
0109                 model: tableView.model
0110             }
0111             property int hoveredRow: -1
0112             property int sortColumn: root.sortColumn
0113 
0114             signal modelLayoutHasChanged()
0115 
0116             signal contextMenuRequested(var index, point position)
0117             onContextMenuRequested: root.contextMenuRequested(index, position)
0118 
0119             onWidthChanged: forceLayout()
0120 
0121             // FIXME Until Tableview correctly reverses its columns, see QTBUG-90547
0122             model: root.model
0123             Binding on model {
0124                 when: scrollView.LayoutMirroring.enabled
0125                 value: Table.ReverseColumnsProxyModel {
0126                     sourceModel: root.model
0127                 }
0128             }
0129 
0130             activeFocusOnTab: true
0131 
0132             clip: true
0133             boundsBehavior: Flickable.StopAtBounds
0134 
0135             Keys.onPressed: {
0136                 switch (event.key) {
0137                     case Qt.Key_Up:
0138                         selectRelative(-1)
0139                         if (!atYBeginning) {
0140                             contentY -= root.rowHeight
0141                             returnToBounds()
0142                         }
0143                         event.accepted = true
0144                         return;
0145                     case Qt.Key_Down:
0146                         selectRelative(1)
0147                         if (!atYEnd) {
0148                             contentY += root.rowHeight
0149                             returnToBounds()
0150                         }
0151                         event.accepted = true
0152                         return;
0153                     case Qt.Key_PageUp:
0154                         if (!atYBeginning) {
0155                             if ((contentY - (tableView.height - root.rowHeight)) < 0) {
0156                                 contentY = 0
0157                             } else {
0158                                 contentY -= tableView.height - root.rowHeight // subtracting root.rowHeight so the last row still visible
0159                             }
0160                             returnToBounds()
0161                         }
0162                         return;
0163                     case Qt.Key_PageDown:
0164                         if (!atYEnd) {
0165                             if ((contentY + (tableView.height - root.rowHeight)) > contentHeight - height) {
0166                                 contentY = contentHeight - height
0167                             } else {
0168                                 contentY += tableView.height - root.rowHeight // subtracting root.rowHeight so the last row still visible
0169                             }
0170                             returnToBounds()
0171                         }
0172                         return;
0173                     case Qt.Key_Home:
0174                         if (!atYBeginning) {
0175                             contentY = 0
0176                             returnToBounds()
0177                         }
0178                         return;
0179                     case Qt.Key_End:
0180                         if (!atYEnd) {
0181                             contentY = contentHeight - height
0182                             returnToBounds()
0183                         }
0184                         return;
0185                     case Qt.Key_Menu:
0186                         contextMenuRequested(selectionModel.currentIndex, mapToGlobal(0, 0))
0187                         return;
0188                     default:
0189                         break;
0190                 }
0191                 if (event.matches(StandardKey.SelectAll)) {
0192                     selectionModel.select(model.index(0, 0), ItemSelectionModel.ClearAndSelect | ItemSelectionModel.Columns);
0193                     return;
0194                 }
0195             }
0196 
0197             onActiveFocusChanged: {
0198                 if (activeFocus && !selectionModel.hasSelection) {
0199                     selectionModel.setCurrentIndex(model.index(0, 0), ItemSelectionModel.ClearAndSelect)
0200                 }
0201             }
0202 
0203             function selectRelative(delta) {
0204                 var nextRow = selectionModel.currentIndex.row + delta
0205                 if (nextRow < 0) {
0206                     nextRow = 0
0207                 }
0208                 if (nextRow >= rows) {
0209                     nextRow = rows - 1
0210                 }
0211                 var index = model.index(nextRow, selectionModel.currentIndex.column)
0212                 selectionModel.setCurrentIndex(index, ItemSelectionModel.ClearAndSelect | ItemSelectionModel.Rows)
0213             }
0214 
0215             columnWidthProvider: function(index) {
0216                 // FIXME Until Tableview correctly reverses its columns, see QTBUG-90547
0217                 if (scrollView.LayoutMirroring.enabled) {
0218                     var width = root.columnWidths[root.columnWidths.length - index - 1]
0219                 } else {
0220                     var width = root.columnWidths[index]
0221                 }
0222                 if (width === undefined || width === null) {
0223                     width = root.defaultColumnWidth
0224                 } else {
0225                     width = width
0226                 }
0227                 width = Math.max(Math.floor(width * scrollView.innerWidth), root.minimumColumnWidth)
0228                 return width
0229             }
0230 
0231             rowHeightProvider: (index) => root.rowHeight
0232 
0233             contentWidth: {
0234                 var w = 0
0235                 for (var i = 0; i < columns; i++) {
0236                     w += columnWidthProvider(i)
0237                 }
0238                 return Math.max(w, scrollView.innerWidth)
0239             }
0240             // FIXME: because of the delay populating the model, TableView seems to not calculate a proper contentHeight automatically
0241             contentHeight : root.rowHeight * rows
0242         }
0243     }
0244 }
0245