[plasma/plasma-sdk] themeexplorer/src: More cleanup

Tobias Fella <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit ac57a5564d0573b6fa44fdf61ca6fb97c169a800 by Tobias Fella.
Committed on 06/08/2026 at 09:25.
Pushed by tfella into branch 'master'.

More cleanup

- Register ThemeModel as a singleton instead of using it through a context property
- use ki18n qml module
- Avoid conflicts between actual components and fake components

M  +2    -2    themeexplorer/src/main.cpp
M  +67   -69   themeexplorer/src/qml/ColorEditor.qml
M  +56   -61   themeexplorer/src/qml/Main.qml
M  +6    -4    themeexplorer/src/qml/MetadataEditor.qml
M  +2    -6    themeexplorer/src/thememodel.cpp
M  +11   -2    themeexplorer/src/thememodel.h

https://invent.kde.org/plasma/plasma-sdk/-/commit/ac57a5564d0573b6fa44fdf61ca6fb97c169a800

diff --git a/themeexplorer/src/main.cpp b/themeexplorer/src/main.cpp
index 746d84e7..487eecd0 100644
--- a/themeexplorer/src/main.cpp
+++ b/themeexplorer/src/main.cpp
@@ -46,7 +46,8 @@ int main(int argc, char **argv)
     KLocalizedString::setApplicationDomain(QByteArrayLiteral("org.kde.plasma.themeexplorer"));
 
     QQmlApplicationEngine engine;
-    auto themeModel = new ThemeModel(&engine);
+
+    auto themeModel = ThemeModel::create(nullptr, nullptr);
     if (parser.isSet(themeOption)) {
         themeModel->setTheme(parser.value(themeOption));
         engine.rootContext()->setContextProperty("commandlineTheme", parser.value(themeOption));
@@ -54,7 +55,6 @@ int main(int argc, char **argv)
         themeModel->setTheme("default");
         engine.rootContext()->setContextProperty("commandlineTheme", "default");
     }
-    engine.rootContext()->setContextProperty("themeModel", QVariant::fromValue(themeModel));
 
     KLocalization::setupLocalizedContext(&engine);
     engine.loadFromModule("org.kde.plasma.themeexplorer", "Main");
diff --git a/themeexplorer/src/qml/ColorEditor.qml b/themeexplorer/src/qml/ColorEditor.qml
index f8284779..dbee55a4 100644
--- a/themeexplorer/src/qml/ColorEditor.qml
+++ b/themeexplorer/src/qml/ColorEditor.qml
@@ -4,13 +4,16 @@
  *   SPDX-License-Identifier: LGPL-2.0-or-later
  */
 
-import QtQuick 2.3
-import QtQuick.Layouts 1.1
-import QtQuick.Controls 2.15
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls
 import QtQuick.Dialogs
 import org.kde.kirigami as Kirigami
 import "fakecontrols" as FakeControls
 
+import org.kde.ki18n
+
+import org.kde.plasma.themeexplorer
 
 Dialog {
     id: dialog
@@ -35,36 +38,36 @@ Dialog {
     property alias complementaryHoverColor: complementaryHoverButton.color
     property alias complementaryFocusColor: complementaryFocusButton.color
 
-    title: i18n("Edit Colors");
+    title: KI18n.i18n("Edit Colors");
 
     onVisibleChanged: {
         if (visible) {
-            textColor = themeModel.colorEditor.textColor;
-            backgroundColor = themeModel.colorEditor.backgroundColor;
-            highlightColor = themeModel.colorEditor.highlightColor;
-            linkColor = themeModel.colorEditor.linkColor;
-            visitedLinkColor = themeModel.colorEditor.visitedLinkColor;
+            textColor = ThemeModel.colorEditor.textColor;
+            backgroundColor = ThemeModel.colorEditor.backgroundColor;
+            highlightColor = ThemeModel.colorEditor.highlightColor;
+            linkColor = ThemeModel.colorEditor.linkColor;
+            visitedLinkColor = ThemeModel.colorEditor.visitedLinkColor;
 
-            buttonTextColor = themeModel.colorEditor.buttonTextColor;
-            buttonBackgroundColor = themeModel.colorEditor.buttonBackgroundColor;
-            buttonHoverColor = themeModel.colorEditor.buttonHoverColor;
-            buttonFocusColor = themeModel.colorEditor.buttonFocusColor;
+            buttonTextColor = ThemeModel.colorEditor.buttonTextColor;
+            buttonBackgroundColor = ThemeModel.colorEditor.buttonBackgroundColor;
+            buttonHoverColor = ThemeModel.colorEditor.buttonHoverColor;
+            buttonFocusColor = ThemeModel.colorEditor.buttonFocusColor;
 
-            viewTextColor = themeModel.colorEditor.viewTextColor;
-            viewBackgroundColor = themeModel.colorEditor.viewBackgroundColor;
-            viewHoverColor = themeModel.colorEditor.viewHoverColor;
-            viewFocusColor = themeModel.colorEditor.viewFocusColor;
+            viewTextColor = ThemeModel.colorEditor.viewTextColor;
+            viewBackgroundColor = ThemeModel.colorEditor.viewBackgroundColor;
+            viewHoverColor = ThemeModel.colorEditor.viewHoverColor;
+            viewFocusColor = ThemeModel.colorEditor.viewFocusColor;
 
-            complementaryTextColor = themeModel.colorEditor.complementaryTextColor;
-            complementaryBackgroundColor = themeModel.colorEditor.complementaryBackgroundColor;
-            complementaryHoverColor = themeModel.colorEditor.complementaryHoverColor;
-            complementaryFocusColor = themeModel.colorEditor.complementaryFocusColor;
+            complementaryTextColor = ThemeModel.colorEditor.complementaryTextColor;
+            complementaryBackgroundColor = ThemeModel.colorEditor.complementaryBackgroundColor;
+            complementaryHoverColor = ThemeModel.colorEditor.complementaryHoverColor;
+            complementaryFocusColor = ThemeModel.colorEditor.complementaryFocusColor;
         }
     }
     ColorDialog {
         id: colorDialog
         modality: Qt.WindowModal
-        title: i18n("Select Color")
+        title: KI18n.i18n("Select Color")
         property Item activeButton
         onAccepted: {
             activeButton.color = color;
@@ -74,7 +77,7 @@ Dialog {
         implicitWidth:  Kirigami.Units.gridUnit * 50
         implicitHeight: Kirigami.Units.gridUnit * 42
 
-        Keys.onPressed: {
+        Keys.onPressed: event => {
             if (event.key == Qt.Key_Enter || event.key == Qt.Key_Return) {
                 dialog.accept();
             } else if (event.key == Qt.Key_Escape) {
@@ -82,11 +85,6 @@ Dialog {
             }
         }
 
-        SystemPalette {
-            id: palette
-        }
-        color: palette.window
-
         ColumnLayout {
             anchors.fill: parent
             spacing: 0
@@ -112,17 +110,17 @@ Dialog {
                         anchors.centerIn: parent
                         Label {
                             Layout.alignment: Qt.AlignHCenter
-                            text: i18n("Normal text")
+                            text: KI18n.i18n("Normal text")
                             color: textColor
                         }
                         RowLayout {
                             Layout.alignment: Qt.AlignHCenter
                             Label {
-                                text: i18n("Link")
+                                text: KI18n.i18n("Link")
                                 color: linkColor
                             }
                             Label {
-                                text: i18n("Visited Link")
+                                text: KI18n.i18n("Visited Link")
                                 color: visitedLinkColor
                             }
                         }
@@ -160,7 +158,7 @@ Dialog {
                         horizontalCenter: complementaryBar.horizontalCenter
                     }
                     Label {
-                        text: i18n("Label")
+                        text: KI18n.i18n("Label")
                         color: complementaryTextColor
                     }
                     FakeControls.CheckBox {
@@ -183,35 +181,35 @@ Dialog {
                         columnSpacing: Kirigami.Units.smallSpacing
 
                         FormLabel {
-                            text: i18n("Text color:")
+                            text: KI18n.i18n("Text color:")
                             buddy: textButton
                         }
                         ColorButton {
                             id: textButton
                         }
                         FormLabel {
-                            text: i18n("Background color:")
+                            text: KI18n.i18n("Background color:")
                             buddy: backgroundButton
                         }
                         ColorButton {
                             id: backgroundButton
                         }
                         FormLabel {
-                            text: i18n("Highlight color:")
+                            text: KI18n.i18n("Highlight color:")
                             buddy: highlightButton
                         }
                         ColorButton {
                             id: highlightButton
                         }
                         FormLabel {
-                            text: i18n("Link color:")
+                            text: KI18n.i18n("Link color:")
                             buddy: linkButton
                         }
                         ColorButton {
                             id: linkButton
                         }
                         FormLabel {
-                            text: i18n("Visited link color:")
+                            text: KI18n.i18n("Visited link color:")
                             buddy: visitedLinkButton
                         }
                         ColorButton {
@@ -219,28 +217,28 @@ Dialog {
                         }
 
                         FormLabel {
-                            text: i18n("Button text color:")
+                            text: KI18n.i18n("Button text color:")
                             buddy: buttonTextButton
                         }
                         ColorButton {
                             id: buttonTextButton
                         }
                         FormLabel {
-                            text: i18n("Button background color:")
+                            text: KI18n.i18n("Button background color:")
                             buddy: buttonBackgroundButton
                         }
                         ColorButton {
                             id: buttonBackgroundButton
                         }
                         FormLabel {
-                            text: i18n("Button mouse over color:")
+                            text: KI18n.i18n("Button mouse over color:")
                             buddy: buttonHoverButton
                         }
                         ColorButton {
                             id: buttonHoverButton
                         }
                         FormLabel {
-                            text: i18n("Button focus color:")
+                            text: KI18n.i18n("Button focus color:")
                             buddy: buttonFocusButton
                         }
                         ColorButton {
@@ -248,28 +246,28 @@ Dialog {
                         }
 
                         FormLabel {
-                            text: i18n("Text view text color:")
+                            text: KI18n.i18n("Text view text color:")
                             buddy: viewTextButton
                         }
                         ColorButton {
                             id: viewTextButton
                         }
                         FormLabel {
-                            text: i18n("Text view background color:")
+                            text: KI18n.i18n("Text view background color:")
                             buddy: viewBackgroundButton
                         }
                         ColorButton {
                             id: viewBackgroundButton
                         }
                         FormLabel {
-                            text: i18n("Text view mouse over color:")
+                            text: KI18n.i18n("Text view mouse over color:")
                             buddy: viewHoverButton
                         }
                         ColorButton {
                             id: viewHoverButton
                         }
                         FormLabel {
-                            text: i18n("Text view focus color:")
+                            text: KI18n.i18n("Text view focus color:")
                             buddy: viewFocusButton
                         }
                         ColorButton {
@@ -277,28 +275,28 @@ Dialog {
                         }
 
                         FormLabel {
-                            text: i18n("Complementary text color:")
+                            text: KI18n.i18n("Complementary text color:")
                             buddy: complementaryTextButton
                         }
                         ColorButton {
                             id: complementaryTextButton
                         }
                         FormLabel {
-                            text: i18n("Complementary background color:")
+                            text: KI18n.i18n("Complementary background color:")
                             buddy: complementaryBackgroundButton
                         }
                         ColorButton {
                             id: complementaryBackgroundButton
                         }
                         FormLabel {
-                            text: i18n("Complementary mouse over color:")
+                            text: KI18n.i18n("Complementary mouse over color:")
                             buddy: complementaryHoverButton
                         }
                         ColorButton {
                             id: complementaryHoverButton
                         }
                         FormLabel {
-                            text: i18n("Complementary focus color:")
+                            text: KI18n.i18n("Complementary focus color:")
                             buddy: complementaryFocusButton
                         }
                         ColorButton {
@@ -310,12 +308,12 @@ Dialog {
             DialogButtonBox {
                 Layout.fillWidth: true
                 Button {
-                    text: i18n("OK")
+                    text: KI18n.i18n("OK")
                     onClicked: dialog.accept()
                     DialogButtonBox.buttonRole: DialogButtonBox.AcceptRole
                 }
                 Button {
-                    text: i18n("Cancel")
+                    text: KI18n.i18n("Cancel")
                     onClicked: dialog.reject()
                     DialogButtonBox.buttonRole: DialogButtonBox.DestructiveRole
                 }
@@ -324,27 +322,27 @@ Dialog {
     }
 
     onAccepted: {
-        themeModel.colorEditor.textColor = textColor;
-        themeModel.colorEditor.backgroundColor = backgroundColor;
-        themeModel.colorEditor.highlightColor = highlightColor;
-        themeModel.colorEditor.linkColor = linkColor;
-        themeModel.colorEditor.visitedLinkColor = visitedLinkColor;
+        ThemeModel.colorEditor.textColor = textColor;
+        ThemeModel.colorEditor.backgroundColor = backgroundColor;
+        ThemeModel.colorEditor.highlightColor = highlightColor;
+        ThemeModel.colorEditor.linkColor = linkColor;
+        ThemeModel.colorEditor.visitedLinkColor = visitedLinkColor;
 
-        themeModel.colorEditor.buttonTextColor = buttonTextColor;
-        themeModel.colorEditor.buttonBackgroundColor = buttonBackgroundColor;
-        themeModel.colorEditor.buttonHoverColor = buttonHoverColor;
-        themeModel.colorEditor.buttonFocusColor = buttonFocusColor;
+        ThemeModel.colorEditor.buttonTextColor = buttonTextColor;
+        ThemeModel.colorEditor.buttonBackgroundColor = buttonBackgroundColor;
+        ThemeModel.colorEditor.buttonHoverColor = buttonHoverColor;
+        ThemeModel.colorEditor.buttonFocusColor = buttonFocusColor;
 
-        themeModel.colorEditor.viewTextColor = viewTextColor;
-        themeModel.colorEditor.viewBackgroundColor = viewBackgroundColor;
-        themeModel.colorEditor.viewHoverColor = viewHoverColor;
-        themeModel.colorEditor.viewFocusColor = viewFocusColor;
+        ThemeModel.colorEditor.viewTextColor = viewTextColor;
+        ThemeModel.colorEditor.viewBackgroundColor = viewBackgroundColor;
+        ThemeModel.colorEditor.viewHoverColor = viewHoverColor;
+        ThemeModel.colorEditor.viewFocusColor = viewFocusColor;
 
-        themeModel.colorEditor.complementaryTextColor = complementaryTextColor;
-        themeModel.colorEditor.complementaryBackgroundColor = complementaryBackgroundColor;
-        themeModel.colorEditor.complementaryHoverColor = complementaryHoverColor;
-        themeModel.colorEditor.complementaryFocusColor = complementaryFocusColor;
+        ThemeModel.colorEditor.complementaryTextColor = complementaryTextColor;
+        ThemeModel.colorEditor.complementaryBackgroundColor = complementaryBackgroundColor;
+        ThemeModel.colorEditor.complementaryHoverColor = complementaryHoverColor;
+        ThemeModel.colorEditor.complementaryFocusColor = complementaryFocusColor;
 
-        themeModel.colorEditor.save();
+        ThemeModel.colorEditor.save();
     }
 }
diff --git a/themeexplorer/src/qml/Main.qml b/themeexplorer/src/qml/Main.qml
index 8daef8f7..9de4cc30 100644
--- a/themeexplorer/src/qml/Main.qml
+++ b/themeexplorer/src/qml/Main.qml
@@ -4,14 +4,17 @@
  *   SPDX-License-Identifier: LGPL-2.0-or-later
  */
 
-import QtQuick 2.5
-import QtQuick.Controls 2.15
-import QtQuick.Layouts 1.1
+import QtQuick
+import QtQuick.Controls as QQC2
+import QtQuick.Layouts
 
-import org.kde.plasma.core as PlasmaCore
-import org.kde.kirigami 2.20 as Kirigami
+import org.kde.kirigami as Kirigami
 import org.kde.kitemmodels as KItemModels
 
+import org.kde.ki18n
+
+import org.kde.plasma.themeexplorer
+
 Kirigami.AbstractApplicationWindow {
     id: root
     width: Kirigami.Units.gridUnit * 50
@@ -20,18 +23,18 @@ Kirigami.AbstractApplicationWindow {
     property int iconSize: iconSizeSlider.value
     property alias showMargins: showMarginsCheckBox.checked
 
-    title: i18nc("@title:window", "Plasma Theme Explorer")
+    title: KI18n.i18nc("@title:window", "Plasma Theme Explorer")
 
     Shortcut {
         sequence: StandardKey.Quit
         onActivated: Qt.quit()
     }
 
-    header: ToolBar {
+    header: QQC2.ToolBar {
         RowLayout {
             anchors.fill: parent
-            ToolButton {
-                ToolTip.text: i18n("New Theme…")
+            QQC2.ToolButton {
+                QQC2.ToolTip.text: KI18n.i18n("New Theme…")
                 icon.name: "document-new"
                 onClicked: {
                     if (!root.metadataEditor) {
@@ -46,25 +49,25 @@ Kirigami.AbstractApplicationWindow {
                     root.metadataEditor.open();
                 }
             }
-            Label {
-                text: i18n("Theme:")
+            QQC2.Label {
+                text: KI18n.i18n("Theme:")
             }
-            ComboBox {
+            QQC2.ComboBox {
                 id: themeSelector
                 //FIXME: why crashes?
-                //model: 3//themeModel.themeList
+                //model: 3//ThemeModel.themeList
                 textRole: "display"
                 onCurrentIndexChanged: {
-                    themeModel.theme = themeModel.themeList.get(currentIndex).packageNameRole;
+                    ThemeModel.theme = ThemeModel.themeList.get(currentIndex).packageNameRole;
                 }
             }
-            ToolButton {
-                ToolTip.text: i18n("Open Folder")
+            QQC2.ToolButton {
+                QQC2.ToolTip.text: KI18n.i18n("Open Folder")
                 icon.name: "document-open-folder"
-                onClicked: Qt.openUrlExternally(themeModel.themeFolder);
+                onClicked: Qt.openUrlExternally(ThemeModel.themeFolder);
             }
-            ToolButton {
-                ToolTip.text: i18n("Edit Metadata…")
+            QQC2.ToolButton {
+                QQC2.ToolTip.text: KI18n.i18n("Edit Metadata…")
                 icon.name: "configure"
                 enabled: view.currentItem?.modelData.isWritable ?? false
                 onClicked: {
@@ -72,37 +75,34 @@ Kirigami.AbstractApplicationWindow {
                         root.metadataEditor = metadataEditorComponent.createObject(root);
                     }
                     root.metadataEditor.newTheme = false;
-                    root.metadataEditor.name = themeModel.theme;
-                    root.metadataEditor.author = themeModel.author;
-                    root.metadataEditor.email = themeModel.email;
-                    root.metadataEditor.license = themeModel.license;
-                    root.metadataEditor.website = themeModel.website;
+                    root.metadataEditor.name = ThemeModel.theme;
+                    root.metadataEditor.author = ThemeModel.author;
+                    root.metadataEditor.email = ThemeModel.email;
+                    root.metadataEditor.license = ThemeModel.license;
+                    root.metadataEditor.website = ThemeModel.website;
                     root.metadataEditor.open();
                 }
             }
-            ToolButton {
-                ToolTip.text: i18n("Edit Colors…")
+            QQC2.ToolButton {
+                QQC2.ToolTip.text: KI18n.i18n("Edit Colors…")
                 icon.name: "color"
                 enabled: view.currentItem?.modelData.isWritable ?? false
                 onClicked: {
-                    if (!root.colorEditor) {
-                        root.colorEditor = colorEditorComponent.createObject(root);
-                    }
-
-                    root.colorEditor.open();
+                    let colorEditor = Qt.createComponent("org.kde.plasma.themeexplorer", "ColorEditor").createObject(root) as ColorEditor;
+                    colorEditor.open();
                 }
             }
             Item {
                 Layout.fillWidth: true
                 Layout.fillHeight: true
             }
-            ToolButton {
-                ToolTip.text: i18n("Help")
+            QQC2.ToolButton {
+                QQC2.ToolTip.text: KI18n.i18n("Help")
                 icon.name: "help-contents"
                 onClicked: Qt.openUrlExternally("https://techbase.kde.org/Development/Tutorials/Plasma5/ThemeDetails");
             }
-            TextField {
-                placeholderText: i18n("Search…")
+            QQC2.TextField {
+                placeholderText: KI18n.i18n("Search…")
                 onTextChanged: searchModel.filterRegularExpression = RegExp(".*" + text + ".*")
             }
         }
@@ -113,25 +113,20 @@ Kirigami.AbstractApplicationWindow {
         id: metadataEditorComponent
         MetadataEditor {}
     }
-    property QtObject colorEditor
-    Component {
-        id: colorEditorComponent
-        ColorEditor {}
-    }
 
     Timer {
         running: true
         interval: 200
         onTriggered: {
-            themeSelector.model = themeModel.themeList
-            for (var i = 0; i < themeModel.themeList.count; ++i) {
-                if (commandlineTheme == themeModel.themeList.get(i).packageNameRole) {
+            themeSelector.model = ThemeModel.themeList
+            for (let i = 0; i < ThemeModel.themeList.count; ++i) {
+                if (commandlineTheme == ThemeModel.themeList.get(i).packageNameRole) {
                     themeSelector.currentIndex = i;
                     break;
                 }
             }
             //NOTE:assigning this in a second moment solves a crash in some versions of Qt 5.8
-            searchModel.sourceModel= themeModel
+            searchModel.sourceModel= ThemeModel
         }
     }
     SystemPalette {
@@ -143,7 +138,7 @@ Kirigami.AbstractApplicationWindow {
         Kirigami.Theme.colorSet: Kirigami.Theme.View
         color: Kirigami.Theme.backgroundColor
     }
-    ScrollView {
+    QQC2.ScrollView {
         id: scrollView
         anchors {
             top: parent.top
@@ -211,22 +206,22 @@ Kirigami.AbstractApplicationWindow {
                 top: parent.top
                 bottom: parent.bottom
             }
-            color: palette.highlight
+            // TODO color: palette.highlight
         }
         ColumnLayout {
             anchors {
                 fill: parent
                 margins: Kirigami.Units.gridUnit
             }
-            Label {
+            QQC2.Label {
                 Layout.fillWidth: true
                 visible: !view.currentItem?.modelData.isWritable ?? false
-                text: i18n("This is a readonly, system wide installed theme")
+                text: KI18n.i18n("This is a readonly, system wide installed theme")
                 wrapMode: Text.WordWrap
             }
-            Label {
+            QQC2.Label {
                 Layout.fillWidth: true
-                text: i18n("Preview:")
+                text: KI18n.i18n("Preview:")
             }
             Loader {
                 id: extendedLoader
@@ -239,36 +234,36 @@ Kirigami.AbstractApplicationWindow {
                 Layout.fillWidth: true
                 Layout.fillHeight: true
             }
-            Label {
+            QQC2.Label {
                 Layout.fillWidth: true
-                text: i18n("Image path: %1", view.currentItem?.modelData.imagePath ?? i18n("None"))
+                text: KI18n.i18n("Image path: %1", view.currentItem?.modelData.imagePath ?? KI18n.i18n("None"))
                 wrapMode: Text.WordWrap
             }
-            Label {
+            QQC2.Label {
                 Layout.fillWidth: true
-                text: i18n("Description: %1", view.currentItem?.modelData.description ?? "")
+                text: KI18n.i18n("Description: %1", view.currentItem?.modelData.description ?? "")
                 wrapMode: Text.WordWrap
             }
-            Label {
+            QQC2.Label {
                 Layout.fillWidth: true
-                text: view.currentItem && view.currentItem.modelData.usesFallback ? i18n("Missing from this theme") : i18n("Present in this theme")
+                text: view.currentItem && view.currentItem.modelData.usesFallback ? KI18n.i18n("Missing from this theme") : KI18n.i18n("Present in this theme")
                 wrapMode: Text.WordWrap
             }
-            CheckBox {
+            QQC2.CheckBox {
                 id: showMarginsCheckBox
                 text: i18n("Show Margins")
             }
-            Button {
-                text: view.currentItem && view.currentItem.modelData.usesFallback ? i18n("Create with Editor…") : i18n("Open In Editor…")
+            QQC2.Button {
+                text: view.currentItem && view.currentItem.modelData.usesFallback ? KI18n.i18n("Create with Editor…") : KI18n.i18n("Open In Editor…")
                 enabled: view.currentItem?.modelData.isWritable ?? false
                 Layout.alignment: Qt.AlignHCenter
                 onClicked: {
                     print(view.currentItem.modelData.svgAbsolutePath)
-                    themeModel.editElement(view.currentItem.modelData.imagePath)
+                    ThemeModel.editElement(view.currentItem.modelData.imagePath)
                     //Qt.openUrlExternally(view.currentItem.modelData.svgAbsolutePath)
                 }
             }
-            Slider {
+            QQC2.Slider {
                 id: iconSizeSlider
                 Layout.fillWidth: true
                 value: Kirigami.Units.gridUnit * 12
diff --git a/themeexplorer/src/qml/MetadataEditor.qml b/themeexplorer/src/qml/MetadataEditor.qml
index 54101bf2..c0f0e7ec 100644
--- a/themeexplorer/src/qml/MetadataEditor.qml
+++ b/themeexplorer/src/qml/MetadataEditor.qml
@@ -11,6 +11,8 @@ import org.kde.kirigami as Kirigami
 
 import org.kde.ki18n
 
+import org.kde.plasma.themeexplorer
+
 QQC2.Dialog {
     id: dialog
 
@@ -125,15 +127,15 @@ QQC2.Dialog {
 
     onAccepted: {
         if (dialog.newTheme) {
-            themeModel.createNewTheme(nameField.text, authorField.text, emailField.text, licenseField.editText, websiteField.text);
-            for (let i = 0; i < themeModel.themeList.count; ++i) {
-                if (nameField.text == themeModel.themeList.get(i).packageNameRole) {
+            ThemeModel.createNewTheme(nameField.text, authorField.text, emailField.text, licenseField.editText, websiteField.text);
+            for (let i = 0; i < ThemeModel.themeList.count; ++i) {
+                if (nameField.text == ThemeModel.themeList.get(i).packageNameRole) {
                     themeSelector.currentIndex = i;
                     break;
                 }
             }
         } else {
-            themeModel.editThemeMetaData(nameField.text, authorField.text, emailField.text, licenseField.editText, websiteField.text);
+            ThemeModel.editThemeMetaData(nameField.text, authorField.text, emailField.text, licenseField.editText, websiteField.text);
         }
     }
 }
diff --git a/themeexplorer/src/thememodel.cpp b/themeexplorer/src/thememodel.cpp
index 92ea0a72..3d28e216 100644
--- a/themeexplorer/src/thememodel.cpp
+++ b/themeexplorer/src/thememodel.cpp
@@ -27,8 +27,8 @@
 
 using namespace Qt::Literals::StringLiterals;
 
-ThemeModel::ThemeModel(QObject *parent)
-    : QAbstractListModel(parent)
+ThemeModel::ThemeModel()
+    : QAbstractListModel(nullptr)
     , m_theme(new Plasma::Theme)
     , m_themeName(QStringLiteral("default"))
     , m_imageSet(m_themeName, "plasma/desktoptheme")
@@ -50,10 +50,6 @@ ThemeModel::ThemeModel(QObject *parent)
     load();
 }
 
-ThemeModel::~ThemeModel()
-{
-}
-
 ThemeListModel *ThemeModel::themeList()
 {
     return m_themeListModel;
diff --git a/themeexplorer/src/thememodel.h b/themeexplorer/src/thememodel.h
index e92a5367..6a8135f2 100644
--- a/themeexplorer/src/thememodel.h
+++ b/themeexplorer/src/thememodel.h
@@ -12,7 +12,9 @@
 #include <QJsonArray>
 #include <QJsonDocument>
 #include <QJsonObject>
+#include <QQmlEngine>
 #include <kpackage/package.h>
+#include <qqmlintegration.h>
 
 namespace Plasma
 {
@@ -25,6 +27,8 @@ class ColorEditor;
 class ThemeModel : public QAbstractListModel
 {
     Q_OBJECT
+    QML_ELEMENT
+    QML_SINGLETON
 
     Q_PROPERTY(QString theme READ theme WRITE setTheme NOTIFY themeChanged)
     Q_PROPERTY(ThemeListModel *themeList READ themeList CONSTANT)
@@ -48,8 +52,12 @@ public:
         FrameSvgPrefixes,
     };
 
-    explicit ThemeModel(QObject *parent = nullptr);
-    ~ThemeModel() override;
+    static ThemeModel *create(QQmlEngine *, QJSEngine *)
+    {
+        static ThemeModel instance;
+        QQmlEngine::setObjectOwnership(&instance, QQmlEngine::CppOwnership);
+        return &instance;
+    };
 
     ThemeListModel *themeList();
     ColorEditor *colorEditor();
@@ -82,6 +90,7 @@ private Q_SLOTS:
 
 private:
     QHash<int, QByteArray> m_roleNames;
+    explicit ThemeModel();
 
     Plasma::Theme *m_theme;
     QString m_themeName;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.