Warning, /plasma/kscreen/kcm/ui/main.qml is written in an unsupported language. File is not indexed.

0001 /*
0002     SPDX-FileCopyrightText: 2019 Roman Gilg <subdiff@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 import QtQuick 2.15
0007 import QtQuick.Layouts 1.15
0008 import QtQuick.Controls 2.15 as QQC2
0009 import org.kde.kirigami 2.20 as Kirigami
0010 import org.kde.kirigami.delegates as KD
0011 import org.kde.kitemmodels 1.0
0012 
0013 import org.kde.kcmutils as KCM
0014 import org.kde.private.kcm.kscreen 1.0 as KScreen
0015 
0016 KCM.SimpleKCM {
0017     id: root
0018 
0019     property int selectedOutput: 0
0020     property int revertCountdown: 15
0021     readonly property int topMargins: Kirigami.Units.smallSpacing
0022     readonly property bool anyMessagesShown: invalidConfigMsg.visible
0023                                              || errBackendMsg.visible
0024                                              || errSaveMsg.visible
0025                                              || scaleMsg.visible
0026                                              || connectMsg.visible
0027                                              || revertMsg.visible
0028 
0029     implicitWidth: Kirigami.Units.gridUnit * 32
0030     implicitHeight: Kirigami.Units.gridUnit * 30
0031 
0032     topPadding: anyMessagesShown ? topMargins : 0
0033     leftPadding: 0
0034     rightPadding: 0
0035 
0036     // This is to fix Output dragging
0037     flickable.interactive: Kirigami.Settings.hasTransientTouchInput
0038 
0039     Kirigami.OverlaySheet {
0040         id: confirmMsg
0041         title: i18n("Keep display configuration?")
0042         onVisibleChanged: {
0043             if (visible) {
0044                 revertButton.forceActiveFocus()
0045             } else {
0046                 revertTimer.stop();
0047             }
0048         }
0049         showCloseButton: false
0050         ColumnLayout {
0051             QQC2.Label {
0052                 Layout.fillWidth: true
0053                 Layout.maximumWidth: Math.round(root.width * 0.75)
0054                 topPadding: Kirigami.Units.largeSpacing
0055                 bottomPadding: Kirigami.Units.largeSpacing
0056                 text: i18np("Will revert to previous configuration in %1 second.",
0057                             "Will revert to previous configuration in %1 seconds.",
0058                             revertCountdown);
0059                 wrapMode: Text.WordWrap
0060             }
0061         }
0062         footer: QQC2.DialogButtonBox {
0063             id: confirmDialogButtonBox
0064             QQC2.Button {
0065                 QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.AcceptRole
0066                 Keys.onPressed: event => {
0067                     if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) {
0068                         event.accepted = true;
0069                         clicked();
0070                     }
0071                 }
0072                 icon.name: "dialog-ok"
0073                 text: i18n("&Keep")
0074             }
0075             QQC2.Button {
0076                 id: revertButton
0077                 QQC2.DialogButtonBox.buttonRole: QQC2.DialogButtonBox.RejectRole
0078                 Keys.onPressed: event => {
0079                     if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) {
0080                         event.accepted = true;
0081                         clicked();
0082                     }
0083                 }
0084                 action: QQC2.Action {
0085                     icon.name: "edit-undo"
0086                     text: i18n("&Revert")
0087                     shortcut: "Escape"
0088                     enabled: confirmMsg.visible
0089                 }
0090             }
0091             onAccepted: {
0092                 confirmMsg.close();
0093             }
0094             onRejected: {
0095                 revertTimer.stop();
0096                 kcm.setStopUpdatesFromBackend(false);
0097                 kcm.revertSettings();
0098             }
0099         }
0100     }
0101 
0102     Connections {
0103         target: kcm
0104         function onInvalidConfig(reason) {
0105             if (reason === KScreen.KCMKScreen.NoEnabledOutputs) {
0106                 invalidConfigMsg.text = i18nc("@info", "All displays are disabled. Enable at least one.")
0107             } else if (reason === KScreen.KCMKScreen.ConfigHasGaps) {
0108                 invalidConfigMsg.text = i18nc("@info", "Gaps between displays are not supported. Make sure all displays are touching.")
0109             }
0110             invalidConfigMsg.visible = true;
0111         }
0112         function onErrorOnSave() {
0113             errSaveMsg.visible = true;
0114         }
0115         function onGlobalScaleWritten() {
0116             scaleMsg.visible = true;
0117         }
0118         function onOutputConnect(connected) {
0119             if (connected) {
0120                 connectMsg.text = i18n("A new output has been added. Settings have been reloaded.");
0121             } else {
0122                 connectMsg.text = i18n("An output has been removed. Settings have been reloaded.");
0123             }
0124             connectMsg.visible = true;
0125         }
0126         function onBackendError() {
0127             errBackendMsg.visible = true;
0128         }
0129         function onSettingsReverted() {
0130             confirmMsg.close();
0131             revertMsg.visible = true;
0132         }
0133         function onShowRevertWarning() {
0134             revertCountdown = 15;
0135             confirmMsg.open();
0136             revertTimer.restart();
0137         }
0138         function onChanged() {
0139             invalidConfigMsg.visible = false;
0140             errSaveMsg.visible = false;
0141             scaleMsg.visible = false;
0142             revertMsg.visible = false;
0143         }
0144     }
0145 
0146 
0147     ColumnLayout {
0148         spacing: Kirigami.Units.smallSpacing
0149 
0150         Kirigami.InlineMessage {
0151             // Note1: There is an implicit height binding loop error on
0152             //        first invocation. Seems to be an issue in Kirigami.
0153             // Note2: This should maybe go in header component of the KCM,
0154             //        but there seems to be another issue in Kirigami then
0155             //        being always hidden. Compare Night Color KCM with
0156             //        the same issue.
0157             id: invalidConfigMsg
0158 
0159             Layout.fillWidth: true
0160             Layout.leftMargin: root.topMargins
0161             Layout.rightMargin: root.topMargins
0162             type: Kirigami.MessageType.Error
0163             showCloseButton: true
0164 
0165         }
0166         Kirigami.InlineMessage {
0167             id: errBackendMsg
0168             Layout.fillWidth: true
0169             Layout.leftMargin: root.topMargins
0170             Layout.rightMargin: root.topMargins
0171             type: Kirigami.MessageType.Error
0172             text: i18n("No KScreen backend found. Please check your KScreen installation.")
0173             visible: false
0174             showCloseButton: false
0175         }
0176         Kirigami.InlineMessage {
0177             id: errSaveMsg
0178             Layout.fillWidth: true
0179             Layout.leftMargin: root.topMargins
0180             Layout.rightMargin: root.topMargins
0181             type: Kirigami.MessageType.Error
0182             text: i18n("Outputs could not be saved due to error.")
0183             visible: false
0184             showCloseButton: true
0185         }
0186         Kirigami.InlineMessage {
0187             id: scaleMsg
0188             Layout.fillWidth: true
0189             Layout.leftMargin: root.topMargins
0190             Layout.rightMargin: root.topMargins
0191             type: Kirigami.MessageType.Information
0192             text: i18n("Global scale changes will come into effect after the system is restarted.")
0193             visible: false
0194             showCloseButton: true
0195             actions: [
0196                 Kirigami.Action {
0197                     icon.name: "system-reboot"
0198                     text: i18n("Restart")
0199                     onTriggered: kcm.requestReboot();
0200                 }
0201             ]
0202         }
0203         Kirigami.InlineMessage {
0204             id: connectMsg
0205             Layout.fillWidth: true
0206             Layout.leftMargin: root.topMargins
0207             Layout.rightMargin: root.topMargins
0208             type: Kirigami.MessageType.Information
0209             visible: false
0210             showCloseButton: true
0211         }
0212         Kirigami.InlineMessage {
0213             id: revertMsg
0214             Layout.fillWidth: true
0215             Layout.leftMargin: root.topMargins
0216             Layout.rightMargin: root.topMargins
0217             type: Kirigami.MessageType.Information
0218             text: i18n("Display configuration reverted.")
0219             visible: false
0220             showCloseButton: true
0221         }
0222 
0223         Kirigami.Dialog {
0224             id: reorderDialog
0225 
0226             title: i18nc("@title:window", "Change Priorities")
0227             showCloseButton: true
0228             standardButtons: Kirigami.Dialog.Ok
0229 
0230             contentItem: ListView {
0231                 id: reorderView
0232 
0233                 implicitWidth: Math.min(root.width * 0.75, Kirigami.Units.gridUnit * 32)
0234                 implicitHeight: contentHeight
0235 
0236                 reuseItems: true
0237                 model: KSortFilterProxyModel {
0238                     id: enabledOutputsModel
0239                     sourceModel: kcm.outputModel
0240                     filterRoleName: "enabled"
0241                     filterString: "true"
0242                     sortRoleName: "priority"
0243                     sortOrder: Qt.AscendingOrder
0244                 }
0245                 delegate: Kirigami.SwipeListItem {
0246                     id: delegate
0247 
0248                     property var output: model
0249 
0250                     width: ListView.view.width
0251 
0252                     background: null
0253                     contentItem: KD.TitleSubtitle {
0254                         title: delegate.output.display
0255                         subtitle: (delegate.output.priority === 1) ? i18n("Primary") : ""
0256                     }
0257                     actions: [
0258                         Kirigami.Action {
0259                             icon.name: "arrow-up"
0260                             text: i18n("Raise priority")
0261                             enabled: delegate.output.priority > 1
0262                             onTriggered: {
0263                                 if (enabled) {
0264                                     delegate.output.priority -= 1;
0265                                 }
0266                             }
0267                         },
0268                         Kirigami.Action {
0269                             icon.name: "arrow-down"
0270                             text: i18n("Lower priority")
0271                             enabled: delegate.output.priority < reorderView.count
0272                             onTriggered: {
0273                                 if (enabled) {
0274                                     delegate.output.priority += 1;
0275                                 }
0276                             }
0277                         }
0278                     ]
0279                 }
0280             }
0281         }
0282 
0283         Connections {
0284             target: kcm
0285             function onInvalidConfig(reason) {
0286                 if (reason === KScreen.KCMKScreen.NoEnabledOutputs) {
0287                     invalidConfigMsg.text = i18nc("@info", "All displays are disabled. Enable at least one.")
0288                 } else if (reason === KScreen.KCMKScreen.ConfigHasGaps) {
0289                     invalidConfigMsg.text = i18nc("@info", "Gaps between displays are not supported. Make sure all displays are touching.")
0290                 }
0291                 invalidConfigMsg.visible = true;
0292             }
0293             function onErrorOnSave() {
0294                 errSaveMsg.visible = true;
0295             }
0296             function onGlobalScaleWritten() {
0297                 scaleMsg.visible = true;
0298             }
0299             function onOutputConnect(connected) {
0300                 root.selectedOutput = 0;
0301                 if (connected) {
0302                     connectMsg.text = i18n("A new output has been added. Settings have been reloaded.");
0303                 } else {
0304                     connectMsg.text = i18n("An output has been removed. Settings have been reloaded.");
0305                 }
0306                 connectMsg.visible = true;
0307             }
0308             function onBackendError() {
0309                 errBackendMsg.visible = true;
0310             }
0311             function onSettingsReverted() {
0312                 confirmMsg.close();
0313                 revertMsg.visible = true;
0314             }
0315             function onShowRevertWarning() {
0316                 revertCountdown = 15;
0317                 confirmMsg.open();
0318                 revertTimer.restart();
0319             }
0320             function onChanged() {
0321                 invalidConfigMsg.visible = false;
0322                 errSaveMsg.visible = false;
0323                 scaleMsg.visible = false;
0324                 revertMsg.visible = false;
0325             }
0326         }
0327 
0328         Rectangle {
0329             Layout.preferredHeight: Math.max(root.height * 0.4, Kirigami.Units.gridUnit * 13)
0330             Layout.fillWidth: true
0331             Kirigami.Theme.inherit: false
0332             Kirigami.Theme.colorSet: Kirigami.Theme.View
0333             color: Kirigami.Theme.backgroundColor
0334 
0335             Kirigami.Separator {
0336                 anchors {
0337                     top: parent.top
0338                     left: parent.left
0339                     right: parent.right
0340                 }
0341                 visible: root.anyMessagesShown
0342             }
0343 
0344             ScreenView {
0345                 id: screen
0346 
0347                 anchors.fill: parent
0348                 enabled: kcm.outputModel && kcm.backendReady
0349                 outputs: kcm.outputModel
0350             }
0351 
0352             Kirigami.Separator {
0353                 anchors {
0354                     bottom: parent.bottom
0355                     left: parent.left
0356                     right: parent.right
0357                 }
0358             }
0359         }
0360 
0361         Panel {
0362             enabled: kcm.outputModel && kcm.backendReady
0363             Layout.fillWidth: true
0364             enabledOutputs: enabledOutputsModel
0365             selectedOutput: root.selectedOutput
0366             onSelectedOutputChanged: {
0367                 root.selectedOutput = selectedOutput;
0368                 selectedOutput = Qt.binding(() => root.selectedOutput);
0369             }
0370             onReorder: reorderDialog.open()
0371         }
0372 
0373         Timer {
0374             id: revertTimer
0375             interval: 1000
0376             running: false
0377             repeat: true
0378 
0379             onTriggered: {
0380                 revertCountdown -= 1;
0381                 if (revertCountdown < 1) {
0382                     confirmDialogButtonBox.rejected();
0383                 }
0384             }
0385         }
0386     }
0387 }