Warning, /plasma/plasma-systemmonitor/src/page/EditablePage.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
0008 import QtQuick.Controls
0009 import QtQuick.Layouts
0010 
0011 import org.kde.kirigami as Kirigami
0012 
0013 import org.kde.ksysguard.page
0014 
0015 Kirigami.ScrollablePage {
0016     id: page
0017 
0018     property PageDataObject pageData
0019     property bool edit: false
0020 
0021     title: pageData.title
0022 
0023     leftPadding: pageData.margin * Kirigami.Units.largeSpacing
0024     rightPadding: pageData.margin * Kirigami.Units.largeSpacing
0025     topPadding: pageData.margin * Kirigami.Units.largeSpacing
0026     bottomPadding: pageData.margin * Kirigami.Units.largeSpacing
0027 
0028     Kirigami.ColumnView.fillWidth: true
0029     Kirigami.ColumnView.reservedSpace: edit ? applicationWindow().pageStack.columnView.columnWidth : 0
0030 
0031     Binding {
0032         target: globalToolBarItem
0033         property: "enabled"
0034         value: contentLoader.status != Loader.Loading
0035     }
0036 
0037     readonly property real heightForContent: (parent?.height ?? 0) - topPadding - bottomPadding - (globalToolBarItem?.height ?? 0)
0038 
0039     readonly property var actionsFace: contentLoader.item && contentLoader.item.actionsFace ? contentLoader.item.actionsFace : null
0040     onActionsFaceChanged: Qt.callLater(updateActions)
0041     Connections {
0042         target: page.actionsFace
0043         function onActionsChanged() { Qt.callLater(page.updateActions) }
0044     }
0045 
0046     function updateActions() {
0047         actions = []
0048 
0049         if (!actionsFace || page.edit) {
0050             actions = defaultActions
0051             return
0052         }
0053 
0054         actions = actions.concat(page.actionsFace.actions).concat(defaultActions)
0055     }
0056 
0057     // Scroll the contents of the page based on the position of a rect (in scene
0058     // coordinates). If any part of the rect is above the visible area, contents
0059     // will be scrolled down. If any part of the rect is below the visible area,
0060     // contents will be scrolled up instead. This mimics dragging behaviour of
0061     // file managers and similar things.
0062     function scrollContents(rect) {
0063         let visibleRect = page.flickable.mapToItem(null, Qt.rect(page.flickable.x, page.flickable.y, page.flickable.width, page.flickable.height - page.bottomPadding))
0064 
0065         let minY = rect.y
0066         let maxY = rect.y + rect.height
0067 
0068         let visibleTop = visibleRect.y
0069         let visibleBottom = visibleRect.y + visibleRect.height
0070 
0071         if (minY >= visibleTop && maxY <= visibleBottom) {
0072             return
0073         }
0074 
0075         if (maxY > visibleBottom && !page.flickable.atYEnd) {
0076             page.flickable.contentY += (maxY - visibleBottom)
0077         } else if (minY < visibleTop && !page.flickable.atYBeginning) {
0078             page.flickable.contentY += (minY - visibleTop)
0079         }
0080         page.flickable.returnToBounds()
0081     }
0082 
0083     Kirigami.Action {
0084         id: editAction
0085 
0086         text: i18nc("@action", "Edit Page")
0087         icon.name: "document-edit"
0088         visible: !page.edit
0089 
0090         displayHint: page.actionsFace ? Kirigami.DisplayHint.AlwaysHide : Kirigami.DisplayHint.NoPreference
0091 
0092         onTriggered: page.edit = !page.edit
0093     }
0094     Kirigami.Action {
0095         id: saveAction
0096         text: i18nc("@action", "Save Changes")
0097         icon.name: "document-save"
0098         visible: page.edit
0099         onTriggered: {
0100             page.edit = false
0101             page.pageData.savePage()
0102         }
0103     }
0104     Kirigami.Action {
0105         id: discardAction
0106         text: i18nc("@action", "Discard Changes")
0107         icon.name: "edit-delete-remove"
0108         visible: page.edit
0109         onTriggered: {
0110             page.edit = false
0111             page.pageData.resetPage()
0112         }
0113     }
0114     Kirigami.Action {
0115         id: configureAction
0116 
0117         text: i18nc("@action", "Configure Pageā€¦")
0118         icon.name: "configure"
0119         visible: page.edit
0120 
0121         onTriggered: pageDialog.open()
0122     }
0123     Kirigami.Action {
0124         id: addRowAction
0125 
0126         text: i18nc("@action", "Add Row")
0127         icon.name: "edit-table-insert-row-under"
0128         visible: page.edit
0129 
0130         onTriggered: contentLoader.item.addRow(-1)
0131     }
0132 
0133     Kirigami.Action {
0134         id: addTitleAction
0135         text: i18nc("@action", "Add Title")
0136         icon.name: "insert-text-frame"
0137         visible: page.edit
0138 
0139         onTriggered: contentLoader.item.addTitle(-1)
0140     }
0141 
0142     readonly property var defaultActions: [editAction, saveAction, discardAction, addRowAction, addTitleAction, configureAction]
0143 
0144     Component {
0145         id: pageEditor
0146 
0147         PageEditor {
0148             parentPage: page
0149             pageData: page.pageData
0150         }
0151     }
0152 
0153     Component {
0154         id: pageContents
0155 
0156         PageContents {
0157             pageData: page.pageData
0158         }
0159     }
0160 
0161     data: [
0162         DialogLoader {
0163             id: pageDialog
0164             sourceComponent: PageDialog {
0165                 title: i18nc("@title:window %1 is page title", "Configure Page \"%1\"", page.pageData.title)
0166 
0167                 acceptText: i18nc("@action:button", "Save")
0168                 acceptIcon: "document-save"
0169 
0170                 onAboutToShow: {
0171                     name = page.pageData.title
0172                     iconName = page.pageData.icon
0173                     margin = page.pageData.margin
0174                     pageData = page.pageData
0175                     actionsFace = page.pageData.actionsFace ? page.pageData.actionsFace : ""
0176                     loadType = page.pageData.loadType ? page.pageData.loadType : "ondemand"
0177                 }
0178 
0179                 onAccepted: {
0180                     pageData.title = name
0181                     pageData.icon = iconName
0182                     pageData.margin = margin
0183                     pageData.actionsFace = actionsFace
0184                     pageData.loadType = loadType
0185                 }
0186             }
0187         },
0188         DialogLoader {
0189             id: missingSensorsDialog
0190 
0191             sourceComponent: MissingSensorsDialog {
0192                 missingSensors: contentLoader.item ? contentLoader.item.missingSensors : []
0193 
0194                 onSensorReplacementChanged: {
0195                     contentLoader.item.replaceSensors(sensorReplacement)
0196                 }
0197             }
0198         }
0199     ]
0200 
0201     Rectangle {
0202         id: loadOverlay
0203 
0204         parent: page.overlay
0205         anchors.fill: parent
0206         anchors.margins: -pageData.margin * Kirigami.Units.largeSpacing
0207         color: Kirigami.Theme.backgroundColor
0208 
0209         opacity: 1
0210         visible: opacity > 0
0211         Behavior on opacity { OpacityAnimator { duration: Kirigami.Units.shortDuration } }
0212 
0213         BusyIndicator {
0214             anchors.centerIn: parent
0215             running: loadOverlay.visible
0216         }
0217     }
0218 
0219     Loader {
0220         id: contentLoader
0221 
0222         width: page.width
0223         height: item ? Math.max(item.Layout.minimumHeight, page.heightForContent) : page.heightForContent
0224 
0225         property real availableHeight: page.heightForContent
0226         property real rowSpacing: page.pageData.margin * Kirigami.Units.smallSpacing
0227 
0228         sourceComponent: page.edit ? pageEditor : pageContents
0229         asynchronous: true
0230 
0231         onStatusChanged: {
0232             if (status == Loader.Loading) {
0233                 loadOverlay.opacity = 1
0234                 if (!edit && applicationWindow().pageStack.columnView.containsItem(page)) {
0235                     // Pop any pages that might have been opened during editing
0236                     applicationWindow().pageStack.pop(page)
0237                 }
0238             } else {
0239                 Qt.callLater(updateActions)
0240                 page.flickable.returnToBounds()
0241                 loadOverlay.opacity = 0
0242             }
0243         }
0244 
0245         Connections {
0246             target: contentLoader.item
0247 
0248             function onShowMissingSensors() {
0249                 missingSensorsDialog.open()
0250             }
0251         }
0252     }
0253 }