8b9472e0bf
When the user selects all of the types or none of them, the "types" property must be set to a special value (`NET::AllTypesMask = -1`), different than the sum of all the flags together. This re-implements this behaviour as the old KCM, fixing some heuristics that prevented finding the rule corresponding to the current window. The enum name that handles this property has been changed to `NetTypes` to make it more explicit. BUG: 423214 FIXED-IN: 5.19.3 TEST PLAN: 1. Open the `Application specific settings` on a window via menu 2. Select every "Window Type" (or none of them) 3. Give the rule a different name than the default and save 4. Open it again and check that the same rule is found
284 lines
9.7 KiB
QML
284 lines
9.7 KiB
QML
/*
|
|
* Copyright (c) 2020 Ismael Asensio <isma.af@gmail.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of
|
|
* the License or (at your option) version 3 or any later version
|
|
* accepted by the membership of KDE e.V. (or its successor approved
|
|
* by the membership of KDE e.V.), which shall act as a proxy
|
|
* defined in Section 14 of version 3 of the license.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
import QtQuick 2.14
|
|
import QtQuick.Layouts 1.14
|
|
import QtQuick.Controls 2.14 as QQC2
|
|
import org.kde.kirigami 2.12 as Kirigami
|
|
import org.kde.kcm 1.2
|
|
import org.kde.kitemmodels 1.0
|
|
import org.kde.kcms.kwinrules 1.0
|
|
|
|
|
|
ScrollViewKCM {
|
|
id: rulesEditor
|
|
|
|
property var rulesModel: kcm.rulesModel
|
|
|
|
title: rulesModel.description
|
|
|
|
view: ListView {
|
|
id: rulesView
|
|
clip: true
|
|
|
|
model: enabledRulesModel
|
|
delegate: RuleItemDelegate {}
|
|
section {
|
|
property: "section"
|
|
delegate: Kirigami.ListSectionHeader { label: section }
|
|
}
|
|
|
|
Kirigami.PlaceholderMessage {
|
|
id: hintArea
|
|
visible: rulesView.count <= 4
|
|
anchors {
|
|
// We need to center on the free space below contentItem, not the full ListView.
|
|
// Setting both top and bottom anchors (or using anchors.fill) stretches the component
|
|
// and distorts the spacing between its internal items.
|
|
// This is fine as long as we have a single item here.
|
|
horizontalCenter: parent.horizontalCenter
|
|
top: parent.contentItem.bottom
|
|
bottom: parent.bottom
|
|
}
|
|
width: parent.width - (units.largeSpacing * 4)
|
|
helpfulAction: QQC2.Action {
|
|
text: i18n("Add Properties...")
|
|
icon.name: "list-add-symbolic"
|
|
onTriggered: {
|
|
propertySheet.open();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// FIXME: InlineMessage.qml:241:13: QML Label: Binding loop detected for property "verticalAlignment"
|
|
header: Kirigami.InlineMessage {
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
text: rulesModel.warningMessage
|
|
visible: text != ""
|
|
}
|
|
|
|
footer: RowLayout {
|
|
QQC2.Button {
|
|
text: checked ? i18n("Close") : i18n("Add Properties...")
|
|
icon.name: checked ? "dialog-close" : "list-add-symbolic"
|
|
checkable: true
|
|
checked: propertySheet.sheetOpen
|
|
visible: !hintArea.visible || checked
|
|
onToggled: {
|
|
propertySheet.sheetOpen = checked;
|
|
}
|
|
}
|
|
Item {
|
|
Layout.fillWidth: true
|
|
}
|
|
QQC2.Button {
|
|
text: i18n("Detect Window Properties")
|
|
icon.name: "edit-find"
|
|
onClicked: {
|
|
overlayModel.onlySuggestions = true;
|
|
rulesModel.detectWindowProperties(delaySpin.value);
|
|
}
|
|
}
|
|
QQC2.SpinBox {
|
|
id: delaySpin
|
|
Layout.preferredWidth: Kirigami.Units.gridUnit * 8
|
|
from: 0
|
|
to: 30
|
|
textFromValue: (value, locale) => {
|
|
return (value == 0) ? i18n("Instantly")
|
|
: i18np("After %1 second", "After %1 seconds", value)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
Connections {
|
|
target: rulesModel
|
|
onSuggestionsChanged: {
|
|
propertySheet.sheetOpen = true;
|
|
}
|
|
}
|
|
|
|
Kirigami.OverlaySheet {
|
|
id: propertySheet
|
|
|
|
parent: view
|
|
|
|
header: Kirigami.Heading {
|
|
text: i18n("Select properties")
|
|
}
|
|
footer: Kirigami.SearchField {
|
|
id: searchField
|
|
horizontalAlignment: Text.AlignLeft
|
|
}
|
|
|
|
ListView {
|
|
id: overlayView
|
|
model: overlayModel
|
|
Layout.preferredWidth: Kirigami.Units.gridUnit * 28
|
|
|
|
section {
|
|
property: "section"
|
|
delegate: Kirigami.ListSectionHeader { label: section }
|
|
}
|
|
|
|
delegate: Kirigami.AbstractListItem {
|
|
id: propertyDelegate
|
|
highlighted: false
|
|
width: ListView.view.width
|
|
|
|
RowLayout {
|
|
Kirigami.Icon {
|
|
source: model.icon
|
|
Layout.preferredHeight: Kirigami.Units.iconSizes.smallMedium
|
|
Layout.preferredWidth: Kirigami.Units.iconSizes.smallMedium
|
|
Layout.alignment: Qt.AlignVCenter
|
|
}
|
|
QQC2.Label {
|
|
id: itemNameLabel
|
|
text: model.name
|
|
horizontalAlignment: Qt.AlignLeft
|
|
Layout.preferredWidth: implicitWidth
|
|
Layout.fillWidth: true
|
|
Layout.alignment: Qt.AlignVCenter
|
|
QQC2.ToolTip {
|
|
text: model.description
|
|
visible: hovered && (model.description != "")
|
|
}
|
|
}
|
|
QQC2.Label {
|
|
id: suggestedLabel
|
|
text: formatValue(model.suggested, model.type, model.options)
|
|
horizontalAlignment: Text.AlignRight
|
|
elide: Text.ElideRight
|
|
opacity: 0.7
|
|
Layout.maximumWidth: propertyDelegate.width - itemNameLabel.implicitWidth - Kirigami.Units.gridUnit * 6
|
|
Layout.alignment: Qt.AlignVCenter
|
|
QQC2.ToolTip {
|
|
text: suggestedLabel.text
|
|
visible: hovered && suggestedLabel.truncated
|
|
}
|
|
}
|
|
QQC2.ToolButton {
|
|
icon.name: (model.enabled) ? "dialog-ok-apply" : "list-add-symbolic"
|
|
opacity: propertyDelegate.hovered ? 1 : 0
|
|
onClicked: propertyDelegate.clicked()
|
|
Layout.preferredWidth: implicitWidth
|
|
Layout.leftMargin: -Kirigami.Units.smallSpacing
|
|
Layout.rightMargin: -Kirigami.Units.smallSpacing
|
|
Layout.alignment: Qt.AlignVCenter
|
|
}
|
|
}
|
|
|
|
onClicked: {
|
|
model.enabled = true;
|
|
if (model.suggested != null) {
|
|
model.value = model.suggested;
|
|
model.suggested = null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
onSheetOpenChanged: {
|
|
searchField.text = "";
|
|
if (sheetOpen) {
|
|
overlayModel.ready = true;
|
|
searchField.forceActiveFocus();
|
|
} else {
|
|
overlayModel.onlySuggestions = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
function formatValue(value, type, options) {
|
|
if (value == null) {
|
|
return "";
|
|
}
|
|
switch (type) {
|
|
case RuleItem.Boolean:
|
|
return value ? i18n("Yes") : i18n("No");
|
|
case RuleItem.Percentage:
|
|
return i18n("%1 %", value);
|
|
case RuleItem.Point:
|
|
return i18nc("Coordinates (x, y)", "(%1, %2)", value.x, value.y);
|
|
case RuleItem.Size:
|
|
return i18nc("Size (width, height)", "(%1, %2)", value.width, value.height);
|
|
case RuleItem.Option:
|
|
return options.textOfValue(value);
|
|
case RuleItem.NetTypes:
|
|
var selectedValue = value.toString(2).length - 1;
|
|
return options.textOfValue(selectedValue);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
KSortFilterProxyModel {
|
|
id: enabledRulesModel
|
|
sourceModel: rulesModel
|
|
filterRowCallback: (source_row, source_parent) => {
|
|
var index = sourceModel.index(source_row, 0, source_parent);
|
|
return sourceModel.data(index, RulesModel.EnabledRole);
|
|
}
|
|
}
|
|
|
|
KSortFilterProxyModel {
|
|
id: overlayModel
|
|
sourceModel: rulesModel
|
|
|
|
property bool onlySuggestions: false
|
|
onOnlySuggestionsChanged: {
|
|
invalidateFilter();
|
|
}
|
|
|
|
// Delay the model filtering until `ready` is set
|
|
// FIXME: Workaround https://bugs.kde.org/show_bug.cgi?id=422289
|
|
property bool ready: false
|
|
onReadyChanged: {
|
|
invalidateFilter();
|
|
}
|
|
|
|
filterString: searchField.text.trim().toLowerCase()
|
|
filterRowCallback: (source_row, source_parent) => {
|
|
if (!ready) {
|
|
return false;
|
|
}
|
|
|
|
var index = sourceModel.index(source_row, 0, source_parent);
|
|
|
|
var hasSuggestion = sourceModel.data(index, RulesModel.SuggestedValueRole) != null;
|
|
var isOptional = sourceModel.data(index, RulesModel.SelectableRole);
|
|
var isEnabled = sourceModel.data(index, RulesModel.EnabledRole);
|
|
|
|
var showItem = hasSuggestion || (!onlySuggestions && isOptional && !isEnabled);
|
|
|
|
if (!showItem) {
|
|
return false;
|
|
}
|
|
if (filterString != "") {
|
|
return sourceModel.data(index, RulesModel.NameRole).toLowerCase().includes(filterString)
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
}
|