Warning, /plasma/plasma-systemmonitor/src/page/PageContents.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 0011 import QtGraphicalEffects 1.0 0012 0013 import org.kde.kirigami 2.12 as Kirigami 0014 import org.kde.ksysguard.faces 1.0 as Faces 0015 import org.kde.ksysguard.page 1.0 0016 0017 ColumnLayout { 0018 id: root 0019 0020 property PageDataObject pageData 0021 property var actionsFace 0022 property var missingSensors: [] 0023 0024 property var faceMapping: new Object() 0025 0026 signal showMissingSensors() 0027 0028 function replaceSensors(replacement) { 0029 if (!replacement) { 0030 return 0031 } 0032 0033 missingSensors = [] 0034 0035 let modifiedControllers = [] 0036 0037 for (let entry of replacement) { 0038 let controller = faceMapping[entry.face].controller 0039 controller.replaceSensors(entry.sensor, entry.replacement) 0040 modifiedControllers.push(controller) 0041 } 0042 0043 for (let c of modifiedControllers) { 0044 c.reloadConfig() 0045 } 0046 } 0047 0048 spacing: rowSpacing // From parent Loader 0049 0050 readonly property real balancedRowHeight: { 0051 let reservedSpace = 0; 0052 let minimumSpace = 0; 0053 let balancedCount = 0; 0054 let maximumCount = 0; 0055 0056 for (let i in children) { 0057 let child = children[i] 0058 if (!child.hasOwnProperty("heightMode") || !child.hasOwnProperty("minimumContentHeight")) { 0059 continue 0060 } 0061 0062 switch(child.heightMode) { 0063 case "minimum": 0064 reservedSpace += child.minimumContentHeight 0065 break; 0066 case "balanced": 0067 minimumSpace = Math.max(child.minimumContentHeight, minimumSpace) 0068 balancedCount += 1 0069 break; 0070 case "maximum": 0071 maximumCount += 1 0072 break; 0073 } 0074 } 0075 0076 // If there's nothing to balance, we can ignore the rest. 0077 if (balancedCount == 0) { 0078 return 0 0079 } 0080 0081 // If there's any rows that are set to "maximum", use the largest 0082 // minimum size for balanced rows. 0083 if (maximumCount > 0) { 0084 return minimumSpace 0085 } 0086 0087 // Note that "availableHeight" here comes from the parent loader and 0088 // represents the available size of the content area of the page. 0089 let balancedHeight = (availableHeight - reservedSpace - root.spacing * (children.length - 1)) / balancedCount 0090 return Math.max(balancedHeight, minimumSpace) 0091 } 0092 0093 Kirigami.InlineMessage { 0094 id: missingMessage 0095 0096 Layout.fillWidth: true 0097 0098 visible: root.missingSensors.length > 0 0099 type: Kirigami.MessageType.Error 0100 text: i18n("This page is missing some sensors and will not display correctly."); 0101 0102 actions: Kirigami.Action { 0103 icon.name: "document-edit" 0104 text: i18nc("@action:button", "Fix…") 0105 onTriggered: root.showMissingSensors() 0106 } 0107 } 0108 0109 Repeater { 0110 model: PageDataModel { data: root.pageData } 0111 0112 Item { 0113 Layout.fillWidth: true 0114 Layout.fillHeight: heightMode != "minimum" 0115 Layout.preferredHeight: 0 0116 Layout.minimumHeight: { 0117 if (heightMode == "minimum") { 0118 return minimumContentHeight 0119 } 0120 0121 if (heightMode == "balanced") { 0122 return root.balancedRowHeight 0123 } 0124 0125 return -1 0126 } 0127 Layout.maximumHeight: { 0128 if (heightMode == "minimum") { 0129 return minimumContentHeight 0130 } 0131 0132 if (heightMode == "balanced") { 0133 return root.balancedRowHeight 0134 } 0135 0136 return -1 0137 } 0138 0139 readonly property real minimumContentHeight: { 0140 if (model.data.isTitle) { 0141 return title.height 0142 } 0143 0144 return rowContents.Layout.minimumHeight 0145 } 0146 0147 readonly property string heightMode: { 0148 if (model.data.heightMode) { 0149 return model.data.heightMode 0150 } 0151 0152 if (model.data.isTitle) { 0153 return "minimum" 0154 } 0155 0156 return "balanced" 0157 } 0158 0159 Kirigami.Heading { 0160 id: title 0161 anchors.left: parent.left 0162 level: 2 0163 text: model.data.title ? model.data.title : "" 0164 visible: model.data.isTitle 0165 } 0166 0167 GridLayout { 0168 id: rowContents 0169 0170 anchors.fill: parent 0171 visible: !model.data.isTitle 0172 0173 columnSpacing: Kirigami.Units.largeSpacing 0174 rowSpacing: Kirigami.Units.largeSpacing 0175 0176 Repeater { 0177 model: PageDataModel { data: model.data } 0178 0179 Item { 0180 Layout.fillWidth: true 0181 Layout.fillHeight: true 0182 Layout.minimumHeight: columnContents.Layout.minimumHeight + columnContents.anchors.topMargin + columnContents.anchors.bottomMargin 0183 0184 Kirigami.AbstractCard { 0185 anchors.fill: parent 0186 visible: model.data.showBackground 0187 } 0188 0189 RowLayout { 0190 id: columnContents 0191 0192 anchors.fill: parent 0193 anchors.margins: model.data.noMargins ? 0 : Kirigami.Units.largeSpacing 0194 0195 spacing: Kirigami.Units.largeSpacing 0196 0197 layer.enabled: model.data.showBackground && model.data.noMargins 0198 layer.effect: OpacityMask { 0199 maskSource: Kirigami.ShadowedRectangle { 0200 width: columnContents.width 0201 height: columnContents.height 0202 radius: Kirigami.Units.smallSpacing 0203 } 0204 } 0205 0206 Repeater { 0207 model: PageDataModel { data: model.data } 0208 0209 Loader { 0210 Layout.fillHeight: true 0211 Layout.fillWidth: model.data.isSeparator ? false : true 0212 Layout.preferredWidth: model.data.isSeparator ? 1 : 0 0213 Layout.minimumHeight: item ? item.Layout.minimumHeight : 0 0214 0215 property var modelData: model 0216 0217 sourceComponent: model.data.isSeparator ? separatorComponent : faceComponent 0218 } 0219 } 0220 } 0221 } 0222 } 0223 } 0224 } 0225 } 0226 0227 Component { 0228 id: separatorComponent 0229 0230 Kirigami.Separator { } 0231 } 0232 0233 Component { 0234 id: faceComponent 0235 0236 Control { 0237 leftPadding: 0 0238 rightPadding: 0 0239 topPadding: 0 0240 bottomPadding: 0 0241 0242 Layout.minimumHeight: contentItem ? contentItem.Layout.minimumHeight : 0 0243 0244 FaceLoader { 0245 id: loader 0246 dataObject: modelData.data 0247 0248 Component.onCompleted: { 0249 root.faceMapping[modelData.data.face] = loader 0250 } 0251 } 0252 0253 Connections { 0254 target: loader.controller 0255 0256 function onMissingSensorsChanged() { 0257 for (let i of missingSensors) { 0258 root.missingSensors.push({ 0259 "face": modelData.data.face, 0260 "title": loader.controller.title, 0261 "sensor": i 0262 }) 0263 } 0264 root.missingSensorsChanged() 0265 } 0266 0267 Component.onCompleted: { 0268 root.faceMapping[modelData.data.face] = loader 0269 } 0270 } 0271 0272 Component.onCompleted: { 0273 loader.controller.fullRepresentation.formFactor = Faces.SensorFace.Constrained; 0274 contentItem = loader.controller.fullRepresentation 0275 0276 if (root.pageData.actionsFace == modelData.data.face) { 0277 root.actionsFace = loader.controller.fullRepresentation 0278 } 0279 } 0280 TapHandler { 0281 acceptedButtons: Qt.RightButton 0282 enabled: WidgetExporter.plasmashellAvailable 0283 onTapped: { 0284 const point = parent.mapToItem(contextMenu.parent, eventPoint.position) 0285 contextMenu.x = point.x 0286 contextMenu.y = point.y 0287 contextMenu.loader = loader 0288 contextMenu.open() 0289 } 0290 } 0291 } 0292 } 0293 Menu { 0294 id: contextMenu 0295 property QtObject loader 0296 MenuItem { 0297 icon.name: "document-export" 0298 text: i18nc("@action", "Add Chart as Desktop Widget") 0299 onTriggered: { 0300 WidgetExporter.exportAsWidget(contextMenu.loader) 0301 } 0302 } 0303 } 0304 }