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

0001 /*
0002  * SPDX-FileCopyrightText: 2019 Arjen Hiemstra <ahiemstra@heimr.nl>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005  */
0006 
0007 import QtCore
0008 import QtQml
0009 import QtQuick
0010 import QtQuick.Controls
0011 import QtQuick.Dialogs
0012 import QtQuick.Layouts
0013 import QtQuick.Window
0014 
0015 import org.kde.kirigami as Kirigami
0016 import org.kde.newstuff as NewStuff
0017 
0018 import org.kde.systemmonitor
0019 import org.kde.ksysguard.page as Page
0020 
0021 Kirigami.ApplicationWindow {
0022     id: app
0023 
0024     minimumWidth: Kirigami.Units.gridUnit * 34
0025     minimumHeight: Kirigami.Units.gridUnit* 27
0026 
0027     title: pageStack.currentItem?.title ?? ""
0028 
0029     header: contentItem.GraphicsInfo.api === GraphicsInfo.Software ? degradedWarning.createObject(app) : null
0030 
0031     Loader {
0032         active: !Kirigami.Settings.isMobile
0033         sourceComponent: GlobalMenu { }
0034     }
0035 
0036     Kirigami.PagePool {
0037         id: pagePoolObject
0038     }
0039 
0040     globalDrawer: Kirigami.GlobalDrawer {
0041         id: globalDrawer
0042 
0043         handleVisible: false
0044         modal: false
0045         width: collapsed ? globalToolBar.Layout.minimumWidth + Kirigami.Units.smallSpacing : Math.max(globalToolBar.implicitWidth + globalToolBar.Layout.minimumWidth + Kirigami.Units.smallSpacing * 3, Kirigami.Units.gridUnit * 10)
0046         Behavior on width { NumberAnimation {id: collapseAnimation; duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad } }
0047         showHeaderWhenCollapsed: true
0048 
0049         Kirigami.Theme.colorSet: Kirigami.Theme.View
0050 
0051         header: ToolBar {
0052             implicitHeight: app.pageStack.globalToolBar.height
0053 
0054             leftPadding: globalDrawer.collapsed ? 0 : Kirigami.Units.smallSpacing
0055             rightPadding: globalDrawer.collapsed ? Kirigami.Units.smallSpacing / 2 : Kirigami.Units.smallSpacing
0056             topPadding: 0
0057             bottomPadding: 0
0058 
0059             Kirigami.ActionToolBar {
0060                 id: globalToolBar
0061 
0062                 anchors.fill: parent
0063 
0064                 overflowIconName: "application-menu"
0065 
0066                 actions: [
0067                     Kirigami.Action {
0068                         id: toolsAction
0069                         text: i18nc("@action", "Tools")
0070                         icon.name: "tools-symbolic"
0071                     },
0072                     Kirigami.Action {
0073                         id: editPagesAction
0074                         icon.name: "handle-sort"
0075                         text: i18nc("@action", "Edit or Remove pages…")
0076                         displayHint: Kirigami.DisplayHint.AlwaysHide
0077                         onTriggered: pageSortDialog.open()
0078                     },
0079                     Kirigami.Action {
0080                         id: exportAction
0081                         text: i18nc("@action", "Export Current Page…")
0082                         icon.name: "document-export"
0083                         displayHint: Kirigami.DisplayHint.AlwaysHide
0084                         enabled: !app.pageStack.currentItem?.edit ?? false
0085                         onTriggered: exportDialog.open()
0086                     },
0087                     Kirigami.Action {
0088                         icon.name: "document-import"
0089                         text: i18nc("@action", "Import Page…")
0090                         displayHint: Kirigami.DisplayHint.AlwaysHide
0091                         onTriggered: importDialog.open()
0092                     },
0093                     NewStuff.Action {
0094                         id: ghnsAction
0095                         text: i18nc("@action:inmenu", "Get New Pages…")
0096                         configFile: "plasma-systemmonitor.knsrc"
0097                         pageStack: app.pageStack.layers
0098                         displayHint: Kirigami.DisplayHint.AlwaysHide
0099                         onEntryEvent: {
0100                             if (event === NewStuff.Engine.StatusChangedEvent) {
0101                                 pagesModel.ghnsEntryStatusChanged(entry)
0102                             }
0103                         }
0104                     },
0105                     Kirigami.Action {
0106                         id: collapseAction
0107                         icon.name: app.globalDrawer.collapsed ? "view-split-left-right" : "view-left-close"
0108                         text: app.globalDrawer.collapsed ? i18nc("@action", "Expand Sidebar") : i18nc("@action", "Collapse Sidebar")
0109                         onTriggered: app.globalDrawer.collapsed = !app.globalDrawer.collapsed
0110                         displayHint: Kirigami.DisplayHint.AlwaysHide
0111                     },
0112                     Kirigami.Action {
0113                         separator: true
0114                         displayHint: Kirigami.DisplayHint.AlwaysHide
0115                     },
0116                     Kirigami.Action {
0117                         icon.name: "tools-report-bug";
0118                         text: i18nc("@action", "Report Bug…");
0119                         displayHint: Kirigami.DisplayHint.AlwaysHide
0120                         onTriggered: Qt.openUrlExternally(CommandLineArguments.aboutData.bugAddress);
0121                     },
0122                     Kirigami.Action {
0123                         icon.name: "help-about-symbolic";
0124                         text: i18nc("@action", "About System Monitor");
0125                         displayHint: Kirigami.DisplayHint.AlwaysHide
0126                         onTriggered: app.pageStack.layers.push("AboutPage.qml")
0127                         enabled: app.pageStack.layers.depth <= 1
0128                     }
0129                 ]
0130                 Component.onCompleted: {
0131                     app.quitAction.displayHint = Kirigami.DisplayHint.AlwaysHide
0132                     actions.push(app.quitAction)
0133                 }
0134             }
0135 
0136             Instantiator {
0137                 model: ToolsModel { id: toolsModel }
0138 
0139                 Kirigami.Action {
0140                     text: model.name
0141                     icon.name: model.icon
0142                     shortcut: model.shortcut
0143                     onTriggered: toolsModel.trigger(model.id)
0144                 }
0145 
0146                 onObjectAdded: (index, object) => {
0147                     toolsAction.children.push(object)
0148                 }
0149             }
0150         }
0151 
0152         actions: [
0153             Kirigami.Action {
0154                 text: i18nc("@action", "Add New Page…")
0155                 icon.name: "list-add"
0156                 onTriggered: pageDialog.open()
0157             }
0158         ]
0159 
0160         Instantiator {
0161             model: Page.PagesModel { id: pagesModel }
0162 
0163             Page.EditablePageAction {
0164                 text: model.title
0165                 icon.name: model.icon
0166                 pagePool: pagePoolObject
0167                 pageData: model.data
0168                 visible: !model.hidden
0169                 onTriggered: {
0170                     config.lastVisitedPage = model.fileName
0171 
0172                     if (app.pageStack.layers.depth > 0) {
0173                         app.pageStack.layers.clear()
0174                     }
0175                 }
0176 
0177                 Component.onCompleted: {
0178                     if (CommandLineArguments.pageId && model.fileName == CommandLineArguments.pageId) {
0179                         trigger()
0180                     } else if (CommandLineArguments.pageName && model.title == CommandLineArguments.pageName) {
0181                         trigger()
0182                     } else if (config.startPage == model.fileName) {
0183                         trigger()
0184                     } else if (config.startPage == "" && config.lastVisitedPage == model.fileName) {
0185                         trigger()
0186                     }
0187                 }
0188             }
0189 
0190             onObjectAdded: (index, object) => {
0191                 var actions = Array.prototype.map.call(globalDrawer.actions, i => i)
0192                 actions.splice(index, 0, object)
0193                 globalDrawer.actions = actions
0194             }
0195 
0196             onObjectRemoved: (index, object) => {
0197                 var actions = Array.prototype.map.call(globalDrawer.actions, i => i)
0198                 var actionIndex = actions.indexOf(object)
0199                 actions.splice(actionIndex, 1)
0200                 globalDrawer.actions = actions
0201             }
0202         }
0203 
0204         contentData: [
0205             TapHandler {
0206                 acceptedButtons: Qt.RightButton
0207                 onTapped: globalContextMenu.popup(eventPoint.scenePosition.x, eventPoint.scenePosition.y, globalDrawer)
0208             },
0209             Menu {
0210                 id: globalContextMenu
0211 
0212                 MenuItem { action: editPagesAction }
0213                 MenuItem { action: ghnsAction }
0214                 MenuItem { action: collapseAction }
0215             }
0216         ]
0217     }
0218 
0219     Page.DialogLoader {
0220         id: pageDialog
0221 
0222         sourceComponent: Page.PageDialog {
0223             title: i18nc("@window:title", "Add New Page")
0224 
0225             onAccepted: {
0226                 var fileName = name.toLowerCase().replace(" ", "_");
0227                 var newPage = pagesModel.addPage(fileName, {title: name, icon: iconName, margin: margin})
0228                 var row = newPage.insertChild(0, {name: "row-0", isTitle: false, title: "", heightMode: "balanced"})
0229                 var column = row.insertChild(0, {name: "column-0", showBackground: true})
0230                 column.insertChild(0, {name: "section-0", isSeparator: false})
0231                 newPage.savePage()
0232 
0233                 const pageAction = Array.from(globalDrawer.actions).find(action => action.pageData.fileName == newPage.fileName)
0234                 pageAction.trigger()
0235                 app.pageStack.currentItem.edit = true
0236             }
0237         }
0238     }
0239 
0240     Page.DialogLoader {
0241         id: pageSortDialog
0242 
0243         sourceComponent: Page.PageSortDialog {
0244             title: i18nc("@window:title", "Edit Pages")
0245             model: pagesModel
0246             startPage: config.startPage
0247             onAccepted: {
0248                 config.startPage = startPage
0249                 const currentPage = pageStack.currentItem.pageData.fileName
0250                 const indices = pagesModel.match(pagesModel.index(0, 0), Page.PagesModel.FileNameRole, currentPage, 1,  Qt.MatchExactly)
0251                 if (indices.length == 0 || pagesModel.data(indices[0], Page.PagesModel.HiddenRole)) {
0252                     if (config.lastVisitedPage == currentPage) {
0253                         config.lastVisitedPage = "overview.page"
0254                     }
0255                     const startPage = config.startPage || config.lastVisitedPage
0256                     Array.prototype.find.call(globalDrawer.actions, action => action.pageData.fileName == startPage).trigger()
0257                 }
0258             }
0259         }
0260     }
0261 
0262     Page.DialogLoader {
0263         id: exportDialog
0264         sourceComponent: FileDialog {
0265             fileMode: FileDialog.SaveFile
0266             currentFolder: StandardPaths.standardLocations(StandardPaths.HomeLocation)[0]
0267             title: i18nc("@title:window %1 is the name of the page that is being exported", "Export %1", app.pageStack.currentItem.title)
0268             defaultSuffix: "page"
0269             nameFilters: [i18nc("Name filter in file dialog", "System Monitor page (*.page)")]
0270             onAccepted: app.pageStack.currentItem.pageData.saveAs(selectedFile)
0271         }
0272     }
0273     Page.DialogLoader {
0274         id: importDialog
0275         sourceComponent: FileDialog {
0276             currentFolder: StandardPaths.standardLocations(StandardPaths.HomeLocation)[0]
0277             title: i18nc("@title:window", "Import Page")
0278             defaultSuffix: "page"
0279             nameFilters: [i18nc("Name filter in file dialog", "System Monitor page (*.page)")]
0280             onAccepted: {
0281                 const newPage = pagesModel.importPage(selectedFile)
0282                 if (!newPage) {
0283                     return;
0284                 }
0285                 const pageAction = Array.from(globalDrawer.actions).find(action => action.pageData.fileName == newPage.fileName)
0286                 pageAction.trigger()
0287             }
0288         }
0289     }
0290 
0291     Configuration {
0292         id: config
0293         property alias sidebarCollapsed: globalDrawer.collapsed
0294         property alias pageOrder: pagesModel.pageOrder
0295         property alias hiddenPages: pagesModel.hiddenPages
0296         property string startPage
0297         property string lastVisitedPage
0298 
0299         property real width
0300         Binding on width {
0301             when: app.visibility == Window.Windowed
0302             delayed: true
0303             value: app.width
0304             restoreMode: Binding.RestoreNone
0305         }
0306 
0307         property real height
0308         Binding on height {
0309             when: app.visibility == Window.Windowed
0310             delayed: true
0311             value: app.height
0312             restoreMode: Binding.RestoreNone
0313         }
0314 
0315         property bool maximized
0316 
0317         Binding on maximized {
0318             when: app.visibility != Window.Hidden
0319             // This is delayed otherwise it still writes to the config property even though when is false
0320             delayed: true
0321             value: app.visibility == Window.Maximized
0322             restoreMode: Binding.RestoreNone
0323         }
0324     }
0325 
0326     onVisibilityChanged: (visibility) => {
0327         if (visibility == Window.Windowed) {
0328             width = config.width
0329             height = config.height
0330         }
0331     }
0332 
0333     Component {
0334         id: degradedWarning
0335 
0336         ToolBar {
0337             Kirigami.InlineMessage {
0338                 anchors.fill: parent
0339                 visible: true
0340                 type: Kirigami.MessageType.Warning
0341                 text: i18n("System Monitor has fallen back to software rendering because hardware acceleration is not available, and visual glitches may appear. Please check your graphics drivers.")
0342             }
0343         }
0344     }
0345 
0346     pageStack.columnView.columnWidth: Kirigami.Units.gridUnit * 22
0347 }