Skip to content

Commit

Permalink
#44: Title Replacements
Browse files Browse the repository at this point in the history
  • Loading branch information
antroids committed Jul 8, 2024
1 parent 952a915 commit de29647
Show file tree
Hide file tree
Showing 6 changed files with 271 additions and 6 deletions.
5 changes: 5 additions & 0 deletions package/contents/config/config.qml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,9 @@ ConfigModel {
source: "config/ConfigBehavior.qml"
}

ConfigCategory {
name: i18n("Replacements")
icon: "document-replace"
source: "config/TitleReplacements.qml"
}
}
9 changes: 9 additions & 0 deletions package/contents/config/main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -207,4 +207,13 @@
<default></default>
</entry>
</group>

<group name="TitleReplacements">
<entry name="titleReplacementsPatterns" type="StringList">
</entry>
<entry name="titleReplacementsTemplates" type="StringList">
</entry>
<entry name="titleReplacementsTypes" type="IntList">
</entry>
</group>
</kcfg>
183 changes: 183 additions & 0 deletions package/contents/ui/config/TitleReplacements.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/*
* SPDX-FileCopyrightText: 2024 Anton Kharuzhy <[email protected]>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/

import "../"
import "../config"
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import org.kde.kcmutils as KCM
import org.kde.kirigami as Kirigami
import org.kde.plasma.components as PlasmaComponents
import "../utils.js" as Utils

KCM.SimpleKCM {
id: page

property list<string> cfg_titleReplacementsPatterns
property list<string> cfg_titleReplacementsTemplates
property list<int> cfg_titleReplacementsTypes

enum Type {
String,
Regex
}

ColumnLayout {
RowLayout {
visible: replacementsRepeater.count > 5
Button {
text: i18n("Add Title Replacement")
onClicked: pushNewReplacement()
}
Label {
text: i18n("<a href=\"https://www.w3schools.com/jsref/jsref_obj_regexp.asp\">JavaScript RegExp Reference</a>")
onLinkActivated: function (link) {
Qt.openUrlExternally(link);
}
verticalAlignment: Text.AlignVCenter
}
}
Repeater {
id: replacementsRepeater

function updateModel() {
model = cfg_titleReplacementsPatterns.length;
}

Component.onCompleted: updateModel()

delegate: RowLayout {
id: replacement
required property int index

ComboBox {
id: titleReplacementsType

model: [i18n("String"), i18n("RegExp")]
onActivated: function () {
cfg_titleReplacementsTypes[replacement.index] = currentIndex;
}
Component.onCompleted: currentIndex = cfg_titleReplacementsTypes[replacement.index]
}

TextField {
id: titleReplacementsPattern

onTextEdited: function () {
cfg_titleReplacementsPatterns[replacement.index] = text;
}
Layout.alignment: Qt.AlignLeft
Component.onCompleted: text = cfg_titleReplacementsPatterns[replacement.index]
}

Label {
text: "=>"
}

TextField {
id: titleReplacementsTemplate

onTextEdited: function () {
cfg_titleReplacementsTemplates[replacement.index] = text;
}
Layout.alignment: Qt.AlignLeft
Component.onCompleted: text = cfg_titleReplacementsTemplates[replacement.index]
}

Button {
icon.name: "delete"
onClicked: function () {
deleteReplacement(replacement.index);
}
}
}
}
RowLayout {
Button {
text: i18n("Add Title Replacement")
onClicked: pushNewReplacement()
}
Label {
text: i18n("<a href=\"https://www.w3schools.com/jsref/jsref_obj_regexp.asp\">JavaScript RegExp Reference</a>")
onLinkActivated: function (link) {
Qt.openUrlExternally(link);
}
verticalAlignment: Text.AlignVCenter
}
}
}

footer: Kirigami.FormLayout {
Kirigami.Separator {
Kirigami.FormData.isSection: true
Kirigami.FormData.label: i18n("Title Replacements Testing")
}

TextField {
id: testInput

Kirigami.FormData.label: i18n("Test input:")
Layout.alignment: Qt.AlignLeft
Layout.minimumWidth: 400

text: "<Application> -- 123 Application title : Freeware / buy 3 - oneone"
}

TextField {
id: testOutput

Kirigami.FormData.label: i18n("Test output:")
Layout.alignment: Qt.AlignLeft
readOnly: true

Connections {
target: testInput

function onTextChanged() {
testOutput.updateTestOutput();
}
}

Connections {
target: page

function onCfg_titleReplacementsTypesChanged() {
testOutput.updateTestOutput();
}

function onCfg_titleReplacementsPatternsChanged() {
testOutput.updateTestOutput();
}

function onCfg_titleReplacementsTemplatesChanged() {
testOutput.updateTestOutput();
}
}

function updateTestOutput() {
const replacements = Utils.Replacement.createReplacementList(cfg_titleReplacementsTypes, cfg_titleReplacementsPatterns, cfg_titleReplacementsTemplates);
testOutput.text = Utils.Replacement.applyReplacementList(testInput.text, replacements);
}

Component.onCompleted: updateTestOutput()
}
}

function pushNewReplacement() {
cfg_titleReplacementsTypes.push(TitleReplacements.Type.String);
cfg_titleReplacementsTemplates.push("");
cfg_titleReplacementsPatterns.push("");
replacementsRepeater.updateModel();
}

function deleteReplacement(index) {
cfg_titleReplacementsPatterns.splice(index, 1);
cfg_titleReplacementsTypes.splice(index, 1);
cfg_titleReplacementsTemplates.splice(index, 1);
replacementsRepeater.updateModel();
}
}
15 changes: 11 additions & 4 deletions package/contents/ui/main.qml
Original file line number Diff line number Diff line change
Expand Up @@ -183,18 +183,25 @@ PlasmoidItem {
property bool empty: text === undefined || text === ""
property bool hideEmpty: empty && plasmoid.configuration.windowTitleHideEmpty
property int windowTitleSource: plasmoid.configuration.overrideElementsMaximized && tasksModel.activeWindow.maximized ? plasmoid.configuration.windowTitleSourceMaximized : plasmoid.configuration.windowTitleSource
property var titleTextReplacements: Utils.Replacement.createReplacementList(plasmoid.configuration.titleReplacementsTypes, plasmoid.configuration.titleReplacementsPatterns, plasmoid.configuration.titleReplacementsTemplates)

function titleText(windowTitleSource) {
let titleTextResult = "";
switch (windowTitleSource) {
case 0:
return tasksModel.activeWindow.appName;
titleTextResult = tasksModel.activeWindow.appName;
break;
case 1:
return tasksModel.activeWindow.decoration;
titleTextResult = tasksModel.activeWindow.decoration;
break;
case 2:
return tasksModel.activeWindow.genericAppName;
titleTextResult = tasksModel.activeWindow.genericAppName;
break;
case 3:
return plasmoid.configuration.windowTitleUndefined;
titleTextResult = plasmoid.configuration.windowTitleUndefined;
break;
}
return Utils.Replacement.applyReplacementList(titleTextResult, titleTextReplacements);
}

Layout.leftMargin: !hideEmpty ? plasmoid.configuration.windowTitleMarginsLeft : 0
Expand Down
63 changes: 62 additions & 1 deletion package/contents/ui/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,65 @@ function widgetElementModelFromName(name) {

function truncateString(str, n) {
return (str.length > n) ? str.slice(0, n - 1) + '\u2026' : str;
};
};

class Replacement {
replace(_title) {
throw new Error("Not implemented");
}

static createReplacement(type, pattern, template) {
switch (type) {
case 0: return new StringReplacement(pattern, template);
case 1: return new RegExpReplacement(pattern, template);
default:
throw new Error("Unknown replacement type: " + type);
}
}

static createReplacementList(types, patterns, templates) {
const length = types.length;
if (length !== patterns.length || length !== templates.length) {
return [];
}

let result = new Array(length);
for (let i = 0; i < length; i++) {
result[i] = Replacement.createReplacement(types[i], patterns[i], templates[i]);
}
return result;
}

static applyReplacementList(title, replacements) {
return replacements.reduce((acc, cur) => cur.replace(acc), title);
}
}

class StringReplacement extends Replacement {
constructor(stringToReplace, stringReplacement) {
super();
this.stringToReplace = stringToReplace;
this.stringReplacement = stringReplacement;
}

replace(title) {
let replaced = title.replace(this.stringToReplace, this.stringReplacement);
while (replaced !== title) {
title = replaced;
replaced = title.replace(this.stringToReplace, this.stringReplacement);
}
return replaced;
}
}

class RegExpReplacement extends Replacement {
constructor(regExp, replacement) {
super();
this.regExp = new RegExp(regExp, "g");
this.replacement = replacement;
}

replace(title) {
return title.replace(this.regExp, this.replacement);
}
}
2 changes: 1 addition & 1 deletion package/metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"Id": "com.github.antroids.application-title-bar",
"Name": "Application Title Bar",
"License": "GPL-3.0+",
"Version": "0.6.3",
"Version": "0.6.5",
"Website": "https://github.com/antroids/application-title-bar",
"FormFactors": [
"desktop"
Expand Down

0 comments on commit de29647

Please sign in to comment.