Commit dee476e7 authored by Devin Lin's avatar Devin Lin 🎨
Browse files

shell: Import applet/containment configuration dialogs

Import from plasma-nano so that we can better use it from plasma-mobile.
parent f9e0cb39
Pipeline #194193 passed with stage
in 1 minute and 26 seconds
/*
* SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.6
import QtQuick.Controls 2.3 as QtControls
import QtQuick.Layouts 1.0
import QtQuick.Window 2.2
import org.kde.kirigami 2.5 as Kirigami
import org.kde.plasma.core 2.1 as PlasmaCore
import org.kde.plasma.configuration 2.0
//TODO: all of this will be done with desktop components
Rectangle {
id: root
// Layout.minimumWidth: plasmoid.availableScreenRect.width
// Layout.minimumHeight: plasmoid.availableScreenRect.height
LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft
LayoutMirroring.childrenInherit: true
color: "transparent"
//BEGIN properties
property bool isContainment: false
property alias internalDialog: dialogContents
//END properties
//BEGIN model
property ConfigModel globalConfigModel: globalAppletConfigModel
ConfigModel {
id: globalAppletConfigModel
}
Connections {
target: root.Window.window
function onVisibleChanged() {
if (root.Window.window.visible) {
root.Window.window.showMaximized();
}
}
}
PlasmaCore.SortFilterModel {
id: configDialogFilterModel
sourceModel: configDialog.configModel
filterRole: "visible"
filterCallback: function(source_row, value) { return value; }
}
//END model
//BEGIN functions
function saveConfig() {
if (pageStack.currentItem.saveConfig) {
pageStack.currentItem.saveConfig()
}
for (var key in plasmoid.configuration) {
if (pageStack.currentItem["cfg_"+key] !== undefined) {
plasmoid.configuration[key] = pageStack.currentItem["cfg_"+key]
}
}
}
function configurationHasChanged() {
for (var key in plasmoid.configuration) {
if (pageStack.currentItem["cfg_"+key] !== undefined) {
//for objects == doesn't work
if (typeof plasmoid.configuration[key] == 'object') {
for (var i in plasmoid.configuration[key]) {
if (plasmoid.configuration[key][i] != pageStack.currentItem["cfg_"+key][i]) {
return true;
}
}
return false;
} else if (pageStack.currentItem["cfg_"+key] != plasmoid.configuration[key]) {
return true;
}
}
}
return false;
}
function settingValueChanged() {
if (pageStack.currentItem.saveConfig !== undefined) {
pageStack.currentItem.saveConfig();
} else {
root.saveConfig();
}
}
//END functions
//BEGIN connections
Component.onCompleted: {
if (!isContainment && configDialog.configModel && configDialog.configModel.count > 0) {
if (configDialog.configModel.get(0).source) {
pageStack.sourceFile = configDialog.configModel.get(0).source
} else if (configDialog.configModel.get(0).kcm) {
pageStack.sourceFile = Qt.resolvedUrl("ConfigurationKcmPage.qml");
pageStack.currentItem.kcm = configDialog.configModel.get(0).kcm;
} else {
pageStack.sourceFile = "";
}
pageStack.title = configDialog.configModel.get(0).name
} else {
pageStack.sourceFile = globalConfigModel.get(0).source
pageStack.title = globalConfigModel.get(0).name
}
// root.width = dialogRootItem.implicitWidth
// root.height = dialogRootItem.implicitHeight
}
onVisibleChanged: {
if (visible) {
dialogContents.visible = true;
}
}
//END connections
//BEGIN UI components
Rectangle {
id: dialogContents
visible: true
anchors.fill: parent
color: Kirigami.Theme.backgroundColor
ColumnLayout {
id: dialogRootItem
anchors.fill: parent
spacing: 0
implicitWidth: scroll.implicitWidth
QtControls.ScrollView {
id: scroll
activeFocusOnTab: false
Layout.fillWidth: true
Layout.fillHeight: true
implicitWidth: pageColumn.implicitWidth
implicitHeight: pageColumn.implicitHeight
property Item flickableItem: pageFlickable
// this horrible code below ensures the control with active focus stays visible in the window
// by scrolling the view up or down as needed when tabbing through the window
Window.onActiveFocusItemChanged: {
var flickable = scroll.flickableItem;
var item = Window.activeFocusItem;
if (!item) {
return;
}
// when an item within ScrollView has active focus the ScrollView,
// as FocusScope, also has it, so we only scroll in this case
if (!scroll.activeFocus) {
return;
}
var padding = PlasmaCore.Units.gridUnit * 2 // some padding to the top/bottom when we scroll
var yPos = item.mapToItem(scroll.contentItem, 0, 0).y;
if (yPos < flickable.contentY) {
flickable.contentY = Math.max(0, yPos - padding);
// The "Math.min(padding, item.height)" ensures that we only scroll the item into view
// when it's barely visible. The logic was mostly meant for keyboard navigating through
// a list of CheckBoxes, so this check keeps us from trying to scroll an inner ScrollView
// into view when it implicitly gains focus (like plasma-pa config dialog has).
} else if (yPos + Math.min(padding, item.height) > flickable.contentY + flickable.height) {
flickable.contentY = Math.min(flickable.contentHeight - flickable.height,
yPos - flickable.height + item.height + padding);
}
}
Flickable {
id: pageFlickable
anchors {
fill: parent
margins: PlasmaCore.Units.smallSpacing
}
contentHeight: pageColumn.height
contentWidth: width
ColumnLayout {
id: pageColumn
spacing: PlasmaCore.Units.largeSpacing / 2
width: pageFlickable.width
height: Math.max(implicitHeight, pageFlickable.height)
Kirigami.Heading {
id: pageTitle
Layout.fillWidth: true
level: 1
text: pageStack.title
}
QtControls.StackView {
id: pageStack
property string title: ""
property bool invertAnimations: false
Layout.fillWidth: true
Layout.fillHeight: true
implicitWidth: Math.max(currentItem ? Math.max(currentItem.Layout.minimumWidth, currentItem.Layout.preferredWidth, currentItem.implicitWidth) : 0, PlasmaCore.Units.gridUnit * 15)
implicitHeight: Math.max(currentItem ? Math.max(currentItem.Layout.minimumHeight, currentItem.Layout.preferredHeight, currentItem.implicitHeight) : 0, PlasmaCore.Units.gridUnit * 15)
property string sourceFile
onSourceFileChanged: {
if (!sourceFile) {
return;
}
//in a StackView pages need to be initialized with stackviews size, or have none
var props = {"width": width, "height": height}
var plasmoidConfig = plasmoid.configuration
for (var key in plasmoidConfig) {
props["cfg_" + key] = plasmoid.configuration[key]
}
var newItem = replace(Qt.resolvedUrl(sourceFile), props)
for (var key in plasmoidConfig) {
var changedSignal = newItem["cfg_" + key + "Changed"]
if (changedSignal) {
changedSignal.connect(root.settingValueChanged)
}
}
var configurationChangedSignal = newItem.configurationChanged
if (configurationChangedSignal) {
configurationChangedSignal.connect(root.settingValueChanged)
}
scroll.flickableItem.contentY = 0
/*
for (var prop in currentItem) {
if (prop.indexOf("cfg_") === 0) {
currentItem[prop+"Changed"].connect(root.pageChanged)
}
}*/
}
replaceEnter: Transition {
ParallelAnimation {
//OpacityAnimator when starting from 0 is buggy (it shows one frame with opacity 1)
NumberAnimation {
property: "opacity"
from: 0
to: 1
duration: PlasmaCore.Units.longDuration
easing.type: Easing.InOutQuad
}
XAnimator {
from: pageStack.invertAnimations ? -scroll.width/3: scroll.width/3
to: 0
duration: PlasmaCore.Units.longDuration
easing.type: Easing.InOutQuad
}
}
}
replaceExit: Transition {
ParallelAnimation {
OpacityAnimator {
from: 1
to: 0
duration: PlasmaCore.Units.longDuration
easing.type: Easing.InOutQuad
}
XAnimator {
from: 0
to: pageStack.invertAnimations ? scroll.width/3 : -scroll.width/3
duration: PlasmaCore.Units.longDuration
easing.type: Easing.InOutQuad
}
}
}
}
}
}
}
Rectangle {
id: separator
Layout.fillWidth: true
Layout.preferredHeight: 1
color: Kirigami.Theme.highlightColor
visible: categoriesScroll.visible
Behavior on color {
ColorAnimation {
duration: PlasmaCore.Units.longDuration
easing.type: Easing.InOutQuad
}
}
}
QtControls.ScrollView {
id: categoriesScroll
Layout.fillWidth: true
Layout.preferredHeight: categories.implicitHeight
visible: (configDialog.configModel ? configDialog.configModel.count : 0) + globalConfigModel.count > 1
Keys.onLeftPressed: {
var buttons = categories.children
var foundPrevious = false
for (var i = buttons.length - 1; i >= 0; --i) {
var button = buttons[i];
if (!button.hasOwnProperty("current")) {
// not a ConfigCategoryDelegate
continue;
}
if (foundPrevious) {
button.openCategory()
return
} else if (button.current) {
foundPrevious = true
}
}
}
Keys.onRightPressed: {
var buttons = categories.children
var foundNext = false
for (var i = 0, length = buttons.length; i < length; ++i) {
var button = buttons[i];
console.log(button)
if (!button.hasOwnProperty("current")) {
continue;
}
if (foundNext) {
button.openCategory()
return
} else if (button.current) {
foundNext = true
}
}
}
RowLayout {
id: categories
spacing: 0
width: categoriesScroll.width
height: implicitHeight
property Item currentItem: children[1]
Repeater {
model: root.isContainment ? globalConfigModel : undefined
delegate: ConfigCategoryDelegate {}
}
Repeater {
model: configDialogFilterModel
delegate: ConfigCategoryDelegate {}
}
Repeater {
model: !root.isContainment ? globalConfigModel : undefined
delegate: ConfigCategoryDelegate {}
}
}
}
}
}
//END UI components
}
/*
* SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.0
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.3 as QtControls
import QtQuick.Window 2.2
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.kquickcontrolsaddons 2.0
import org.kde.kirigami 2.5 as Kirigami
MouseArea {
id: delegate
//BEGIN properties
implicitWidth: delegateContents.implicitWidth + 4 * PlasmaCore.Units.smallSpacing
implicitHeight: delegateContents.height + PlasmaCore.Units.smallSpacing * 4
Layout.fillWidth: true
hoverEnabled: true
property bool current: (model.kcm && pageStack.currentItem.kcm && model.kcm == pageStack.currentItem.kcm) || (model.source == pageStack.sourceFile)
//END properties
//BEGIN functions
function openCategory() {
if (current) {
return;
}
if (typeof(categories.currentItem) !== "undefined") {
pageStack.invertAnimations = (categories.currentItem.x > delegate.x);
categories.currentItem = delegate;
}
if (model.source) {
pageStack.sourceFile = model.source;
} else if (model.kcm) {
pageStack.sourceFile = "";
pageStack.sourceFile = Qt.resolvedUrl("ConfigurationKcmPage.qml");
pageStack.currentItem.kcm = model.kcm;
} else {
pageStack.sourceFile = "";
}
pageStack.title = model.name
}
//END functions
//BEGIN connections
onPressed: {
categoriesScroll.forceActiveFocus()
if (current) {
return;
}
openCategory();
}
onCurrentChanged: {
if (current) {
categories.currentItem = delegate;
}
}
//END connections
//BEGIN UI components
Rectangle {
anchors.fill: parent
color: Kirigami.Theme.highlightColor
opacity: { // try to match Breeze style hover handling
var active = categoriesScroll.activeFocus && Window.active
if (current) {
if (active) {
return 1
} else if (delegate.containsMouse) {
return 0.6
} else {
return 0.3
}
} else if (delegate.containsMouse) {
if (active) {
return 0.3
} else {
return 0.1
}
}
return 0
}
Behavior on opacity {
NumberAnimation {
duration: PlasmaCore.Units.longDuration
easing.type: Easing.InOutQuad
}
}
}
ColumnLayout {
id: delegateContents
spacing: PlasmaCore.Units.smallSpacing
width: parent.width
anchors.verticalCenter: parent.verticalCenter
QIconItem {
id: iconItem
Layout.alignment: Qt.AlignHCenter
width: PlasmaCore.Units.iconSizes.medium
height: width
icon: model.icon
state: current && categoriesScroll.activeFocus ? QIconItem.SelectedState : QIconItem.DefaultState
}
QtControls.Label {
id: nameLabel
Layout.fillWidth: true
text: model.name
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
color: current && categoriesScroll.activeFocus ? Kirigami.Theme.highlightedTextColor : Kirigami.Theme.textColor
Behavior on color {
ColorAnimation {
duration: PlasmaCore.Units.longDuration
easing.type: Easing.InOutQuad
}
}
}
}
//END UI components
}
/*
* SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import org.kde.plasma.configuration 2.0
import QtQuick.Controls 2.3 as QQC2
import QtQuick.Layouts 1.1
import org.kde.newstuff 1.62 as NewStuff
import org.kde.kirigami 2.5 as Kirigami
import org.kde.plasma.core 2.0 as PlasmaCore
ColumnLayout {
id: root
property int formAlignment: wallpaperComboBox.Kirigami.ScenePosition.x - root.Kirigami.ScenePosition.x + (PlasmaCore.Units.largeSpacing/2)
property string currentWallpaper: ""
property string containmentPlugin: ""
signal configurationChanged
//BEGIN functions
function saveConfig() {
if (main.currentItem.saveConfig) {
main.currentItem.saveConfig()
}
for (var key in configDialog.wallpaperConfiguration) {
if (main.currentItem["cfg_"+key] !== undefined) {
configDialog.wallpaperConfiguration[key] = main.currentItem["cfg_"+key]
}
}
configDialog.currentWallpaper = root.currentWallpaper;
configDialog.applyWallpaper()
configDialog.containmentPlugin = root.containmentPlugin
}
//END functions
Component.onCompleted: {
for (var i = 0; i < configDialog.wallpaperConfigModel.count; ++i) {
var data = configDialog.wallpaperConfigModel.get(i);
if (configDialog.currentWallpaper == data.pluginName) {
wallpaperComboBox.currentIndex = i
wallpaperComboBox.activated(i);
break;
}
}
}
Kirigami.InlineMessage {
visible: plasmoid.immutable || animating
text: i18nd("plasma_shell_org.kde.plasma.desktop", "Layout changes have been restricted by the system administrator")
showCloseButton: true
Layout.fillWidth: true
Layout.leftMargin: Kirigami.Units.smallSpacing
Layout.rightMargin: Kirigami.Units.smallSpacing
Layout.bottomMargin: Kirigami.Units.smallSpacing * 2 // we need this because ColumnLayout's spacing is 0
}
Kirigami.FormLayout {
Layout.fillWidth: true
Component.onCompleted: {
for (var i = 0; i < configDialog.containmentPluginsConfigModel.count; ++i) {
var data = configDialog.containmentPluginsConfigModel.get(i);
if (configDialog.containmentPlugin === data.pluginName) {
pluginComboBox.currentIndex = i
pluginComboBox.activated(i);
break;
}
}
for (var i = 0; i < configDialog.wallpaperConfigModel.count; ++i) {
var data = configDialog.wallpaperConfigModel.get(i);