File fcitx5-configtool-revert-drop-qt5.patch of Package fcitx5-configtool
diff -urN fcitx5-configtool-5.1.12/CMakeLists.txt fcitx5-configtool-5.1.12.new/CMakeLists.txt
--- fcitx5-configtool-5.1.12/CMakeLists.txt 2025-12-22 14:18:08.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/CMakeLists.txt 2026-02-08 22:16:45.455817979 +0800
@@ -13,13 +13,24 @@
project(fcitx5-configtool VERSION 5.1.12)
+option(USE_QT6 "Build with Qt6" On)
+
+if (USE_QT6)
set(QT_MIN_VERSION "6.4.0")
set(QT_MAJOR_VERSION 6)
+else()
+set(QT_MIN_VERSION "5.12.0")
+set(QT_MAJOR_VERSION 5)
+endif()
find_package(ECM 5.68.0 REQUIRED)
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR})
find_package(Qt${QT_MAJOR_VERSION} ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS Core Gui Widgets Concurrent)
+if (QT_MAJOR_VERSION STREQUAL 5)
+find_package(Qt${QT_MAJOR_VERSION}X11Extras ${QT_MIN_VERSION} CONFIG REQUIRED)
+endif()
+
include(KDEInstallDirs)
include(KDECMakeSettings)
include(KDECompilerSettings)
@@ -53,10 +64,20 @@
find_package(KF${QT_MAJOR_VERSION}Declarative REQUIRED)
find_package(KF${QT_MAJOR_VERSION}IconThemes REQUIRED)
find_package(XKBCommon REQUIRED COMPONENTS XKBCommon)
- find_package(KF${QT_MAJOR_VERSION}Kirigami REQUIRED)
- find_package(Plasma REQUIRED)
- find_package(KF${QT_MAJOR_VERSION}Svg REQUIRED)
- find_package(KF${QT_MAJOR_VERSION}KCMUtils REQUIRED)
+ if (QT_MAJOR_VERSION STREQUAL 5)
+ find_package(KF${QT_MAJOR_VERSION}Plasma REQUIRED)
+ find_package(KF${QT_MAJOR_VERSION}Kirigami2 5.68 REQUIRED)
+ if (KF${QT_MAJOR_VERSION}Kirigami2_VERSION VERSION_LESS 5.76)
+ set(DISABLE_UNDER_KIRIGAMI2_5_76 "//Needs Kirigami2 5.76 ")
+ else()
+ set(DISABLE_UNDER_KIRIGAMI2_5_76 "")
+ endif()
+ elseif (QT_MAJOR_VERSION STREQUAL 6)
+ find_package(KF${QT_MAJOR_VERSION}Kirigami REQUIRED)
+ find_package(Plasma REQUIRED)
+ find_package(KF${QT_MAJOR_VERSION}Svg REQUIRED)
+ find_package(KF${QT_MAJOR_VERSION}KCMUtils REQUIRED)
+ endif()
endif()
find_package(Fcitx5Core 5.1.13 REQUIRED)
diff -urN fcitx5-configtool-5.1.12/layout/CMakeLists.txt fcitx5-configtool-5.1.12.new/layout/CMakeLists.txt
--- fcitx5-configtool-5.1.12/layout/CMakeLists.txt 2025-12-22 14:18:08.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/layout/CMakeLists.txt 2026-02-08 22:16:45.455986583 +0800
@@ -10,6 +10,9 @@
add_library(layoutlib STATIC keyboardlayoutwidget.cpp)
set_target_properties(layoutlib PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
target_link_libraries(layoutlib PUBLIC Fcitx5::Utils Qt${QT_MAJOR_VERSION}::Widgets PRIVATE X11Import X11XkblibImport PkgConfig::XkbFile)
+if (QT_MAJOR_VERSION STREQUAL 5)
+target_link_libraries(layoutlib PUBLIC Qt${QT_MAJOR_VERSION}::X11Extras)
+endif()
target_include_directories(layoutlib INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
set(kbd_layout_viewer_SOURCES
diff -urN fcitx5-configtool-5.1.12/layout/keyboardlayoutwidget.cpp fcitx5-configtool-5.1.12.new/layout/keyboardlayoutwidget.cpp
--- fcitx5-configtool-5.1.12/layout/keyboardlayoutwidget.cpp 2025-12-22 14:18:08.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/layout/keyboardlayoutwidget.cpp 2026-02-08 22:16:45.456187447 +0800
@@ -12,6 +12,9 @@
#include <QPainter>
#include <QPainterPath>
#include <QVector2D>
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+#include <QX11Info>
+#endif
#include <qmath.h>
#include <fcitx-utils/key.h>
@@ -44,6 +47,12 @@
namespace kcm {
namespace {
+
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+bool isPlatformX11() { return QX11Info::isPlatformX11(); }
+
+auto *getXDisplay() { return QX11Info::display(); }
+#else
bool isPlatformX11() {
return qGuiApp->nativeInterface<QNativeInterface::QX11Application>();
}
@@ -52,6 +61,7 @@
return qGuiApp->nativeInterface<QNativeInterface::QX11Application>()
->display();
}
+#endif
} // namespace
diff -urN fcitx5-configtool-5.1.12/layout/main.cpp fcitx5-configtool-5.1.12.new/layout/main.cpp
--- fcitx5-configtool-5.1.12/layout/main.cpp 2025-12-22 14:18:08.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/layout/main.cpp 2026-02-08 22:16:45.456320876 +0800
@@ -49,6 +49,10 @@
variant = parser.value("variant");
}
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+ app.setAttribute(Qt::AA_UseHighDpiPixmaps);
+#endif
+
QMainWindow mainWindow;
mainWindow.setWindowIcon(QIcon::fromTheme("input-keyboard"));
mainWindow.setWindowTitle(_("Keyboard Layout viewer"));
diff -urN fcitx5-configtool-5.1.12/src/configtool/mainwindow.cpp fcitx5-configtool-5.1.12.new/src/configtool/mainwindow.cpp
--- fcitx5-configtool-5.1.12/src/configtool/mainwindow.cpp 2025-12-22 14:18:08.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/configtool/mainwindow.cpp 2026-02-08 22:21:32.614381000 +0800
@@ -21,7 +21,6 @@
#include <QPushButton>
#include <QSessionManager>
#include <QWidget>
-#include <QtVersionChecks>
#include <fcitx-utils/i18n.h>
namespace fcitx::kcm {
diff -urN fcitx5-configtool-5.1.12/src/kcm/CMakeLists.txt fcitx5-configtool-5.1.12.new/src/kcm/CMakeLists.txt
--- fcitx5-configtool-5.1.12/src/kcm/CMakeLists.txt 2025-12-22 14:18:08.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/kcm/CMakeLists.txt 2026-02-08 22:16:45.456367202 +0800
@@ -1,5 +1,42 @@
-kcmutils_add_qml_kcm(kcm_fcitx5 SOURCES main.cpp)
-target_link_libraries(kcm_fcitx5 KF${QT_MAJOR_VERSION}::KCMUtilsQuick)
+if (QT_MAJOR_VERSION STREQUAL 5)
+ add_library(kcm_fcitx5 MODULE
+ main.cpp
+ )
+ target_link_libraries(kcm_fcitx5 KF${QT_MAJOR_VERSION}::QuickAddons KF${QT_MAJOR_VERSION}::Declarative)
+
+ file(GLOB_RECURSE inFiles RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
+ "${CMAKE_CURRENT_SOURCE_DIR}/package/*")
+ foreach(infileName ${inFiles})
+ configure_file(
+ "${CMAKE_CURRENT_SOURCE_DIR}/${infileName}"
+ "${CMAKE_CURRENT_BINARY_DIR}/${infileName}" @ONLY
+ )
+ endforeach()
+
+ # This is a hack against kpackage_install_package
+ # 1. kpackage_install_package only accept relative path to ${CMAKE_CURRENT_SOURCE_DIR}
+ # 2. It need metadata.desktop to run properly, but we only have untranslated file at that time.
+ # So we just delete the file during the cmake.
+ file(RELATIVE_PATH RELATIVE_BINARY_DIR ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR})
+ if (KF5Declarative_VERSION VERSION_GREATER_EQUAL 5.104.0)
+ install(TARGETS kcm_fcitx5 DESTINATION ${KDE_INSTALL_PLUGINDIR}/plasma/kcms/systemsettings)
+ kpackage_install_package(${RELATIVE_BINARY_DIR}/package kcm_fcitx5 kcms)
+ fcitx5_translate_desktop_file(kcm_fcitx5.desktop.in
+ kcm_fcitx5.desktop PO_DIRECTORY ${PROJECT_SOURCE_DIR}/po/kcm_fcitx5)
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/kcm_fcitx5.desktop"
+ DESTINATION ${KDE_INSTALL_APPDIR})
+ else()
+ install(TARGETS kcm_fcitx5 DESTINATION ${KDE_INSTALL_PLUGINDIR}/kcms)
+ fcitx5_translate_desktop_file(kcm_fcitx5_kservice.desktop.in
+ kcm_fcitx5_kservice.desktop PO_DIRECTORY ${PROJECT_SOURCE_DIR}/po/kcm_fcitx5)
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/kcm_fcitx5_kservice.desktop"
+ DESTINATION ${KDE_INSTALL_KSERVICES5DIR} RENAME kcm_fcitx5.desktop)
+ endif()
+
+elseif(QT_MAJOR_VERSION STREQUAL 6)
+ kcmutils_add_qml_kcm(kcm_fcitx5 SOURCES main.cpp)
+ target_link_libraries(kcm_fcitx5 KF${QT_MAJOR_VERSION}::KCMUtilsQuick)
+endif()
target_link_libraries(kcm_fcitx5
Qt${QT_MAJOR_VERSION}::Quick
diff -urN fcitx5-configtool-5.1.12/src/kcm/kcm_fcitx5.desktop.in fcitx5-configtool-5.1.12.new/src/kcm/kcm_fcitx5.desktop.in
--- fcitx5-configtool-5.1.12/src/kcm/kcm_fcitx5.desktop.in 1970-01-01 08:00:00.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/kcm/kcm_fcitx5.desktop.in 2026-02-08 22:16:45.456395886 +0800
@@ -0,0 +1,8 @@
+[Desktop Entry]
+Icon=fcitx
+Type=Application
+X-KDE-AliasFor=systemsettings
+Exec=systemsettings kcm_fcitx5
+NoDisplay=True
+Name=Input Method
+Comment=Configure Input Method
\ 文件末尾没有换行符
diff -urN fcitx5-configtool-5.1.12/src/kcm/kcm_fcitx5_kservice.desktop.in fcitx5-configtool-5.1.12.new/src/kcm/kcm_fcitx5_kservice.desktop.in
--- fcitx5-configtool-5.1.12/src/kcm/kcm_fcitx5_kservice.desktop.in 1970-01-01 08:00:00.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/kcm/kcm_fcitx5_kservice.desktop.in 2026-02-08 22:16:45.456425801 +0800
@@ -0,0 +1,16 @@
+[Desktop Entry]
+Icon=fcitx
+Type=Service
+
+X-KDE-ServiceTypes=KCModule
+X-KDE-Library=kcm_fcitx5
+X-KDE-ParentApp=kcontrol
+
+X-KDE-System-Settings-Parent-Category=regionalsettings
+
+Name=Input Method
+Comment=Configure Input Method
+
+X-KDE-Keywords=keyboard,input,im,fcitx
+
+Categories=Qt;KDE;X-KDE-settings-fcitx;
diff -urN fcitx5-configtool-5.1.12/src/kcm/main.cpp fcitx5-configtool-5.1.12.new/src/kcm/main.cpp
--- fcitx5-configtool-5.1.12/src/kcm/main.cpp 2025-12-22 14:18:08.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/kcm/main.cpp 2026-02-08 22:16:45.456485903 +0800
@@ -36,7 +36,6 @@
#include <fcitx-utils/misc.h>
#include <fcitx-utils/standardpaths.h>
#include <fcitxqtdbustypes.h>
-#include <kquickconfigmodule.h>
namespace fcitx::kcm {
@@ -67,16 +66,44 @@
}
} // namespace
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
FcitxModule::FcitxModule(QObject *parent, const KPluginMetaData &metaData)
- : KQuickConfigModule(parent, metaData), dbus_(new DBusProvider(this)),
+ : FcitxKCMBase(parent, metaData),
+#elif defined(FCITX_USE_NEW_KDECLARATIVE)
+FcitxModule::FcitxModule(QObject *parent, const KPluginMetaData &metaData,
+ const QVariantList &args)
+ : FcitxKCMBase(parent, metaData, args),
+#else
+FcitxModule::FcitxModule(QObject *parent, const QVariantList &args)
+ : FcitxKCMBase(parent, args),
+#endif
+ dbus_(new DBusProvider(this)),
imConfig_(new IMConfig(dbus_, IMConfig::Flatten, this)),
layoutProvider_(new LayoutProvider(dbus_, this)),
addonModel_(new FlatAddonModel(this)),
addonProxyModel_(new AddonProxyModel(this)) {
+#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0))
+ qmlRegisterType<FilteredIMModel>();
+ qmlRegisterType<IMProxyModel>();
+ qmlRegisterType<LanguageModel>();
+#else
qmlRegisterAnonymousType<FilteredIMModel>("", 1);
qmlRegisterAnonymousType<IMProxyModel>("", 1);
qmlRegisterAnonymousType<LanguageModel>("", 1);
+#endif
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) && \
+ !defined(FCITX_USE_NEW_KDECLARATIVE)
+ KAboutData *about =
+ new KAboutData("kcm_fcitx5", i18n("Fcitx 5"), PROJECT_VERSION,
+ i18n("Configure Fcitx 5"), KAboutLicense::GPL_V2,
+ i18n("Copyright 2017 Xuetian Weng"), QString(),
+ QString(), "wengxt@gmail.com");
+
+ about->addAuthor(i18n("Xuetian Weng"), i18n("Author"), "wengxt@gmail.com");
+
+ setAboutData(about);
+#endif
addonProxyModel_->setSourceModel(addonModel_);
addonProxyModel_->sort(0);
@@ -100,14 +127,13 @@
XKB_KEYMAP_COMPILE_NO_FLAGS));
xkbState_.reset(xkb_state_new(xkbKeymap_.get()));
- connect(this, &KQuickConfigModule::pagePushed, this,
- [this](QQuickItem *page) {
- pages_[currentIndex() + 1] = page;
- if (page->property("needsSave").isValid()) {
- connect(page, SIGNAL(needsSaveChanged()), this,
- SLOT(pageNeedsSaveChanged()));
- }
- });
+ connect(this, &FcitxKCMBase::pagePushed, this, [this](QQuickItem *page) {
+ pages_[currentIndex() + 1] = page;
+ if (page->property("needsSave").isValid()) {
+ connect(page, SIGNAL(needsSaveChanged()), this,
+ SLOT(pageNeedsSaveChanged()));
+ }
+ });
}
FcitxModule::~FcitxModule() {}
diff -urN fcitx5-configtool-5.1.12/src/kcm/main.h fcitx5-configtool-5.1.12.new/src/kcm/main.h
--- fcitx5-configtool-5.1.12/src/kcm/main.h 2025-12-22 14:18:08.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/kcm/main.h 2026-02-08 22:16:45.456541106 +0800
@@ -11,8 +11,6 @@
#include "dbusprovider.h"
#include "font.h"
#include "imconfig.h"
-#include <KPluginMetaData>
-#include <KQuickConfigModule>
#include <QFont>
#include <QMap>
#include <QObject>
@@ -23,9 +21,29 @@
#include <memory>
#include <xkbcommon/xkbcommon.h>
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+#include <KPluginMetaData>
+#include <KQuickConfigModule>
+#define FCITX_USE_NEW_KDECLARATIVE
+#else
+#include <KQuickAddons/ConfigModule>
+#include <kdeclarative_version.h>
+
+#if KDECLARATIVE_VERSION >= QT_VERSION_CHECK(5, 104, 0)
+#define FCITX_USE_NEW_KDECLARATIVE
+#endif
+
+#endif
+
namespace fcitx::kcm {
-class FcitxModule : public KQuickConfigModule {
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+using FcitxKCMBase = KQuickConfigModule;
+#else
+using FcitxKCMBase = KQuickAddons::ConfigModule;
+#endif
+
+class FcitxModule : public FcitxKCMBase {
Q_OBJECT
Q_PROPERTY(IMConfig *imConfig READ imConfig CONSTANT)
Q_PROPERTY(LayoutProvider *layoutProvider READ layoutProvider CONSTANT)
@@ -33,7 +51,14 @@
Q_PROPERTY(bool availability READ availability NOTIFY availabilityChanged)
Q_PROPERTY(bool canRestart READ canRestart NOTIFY canRestartChanged)
public:
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
FcitxModule(QObject *parent, const KPluginMetaData &metaData);
+#elif defined(FCITX_USE_NEW_KDECLARATIVE)
+ FcitxModule(QObject *parent, const KPluginMetaData &metaData,
+ const QVariantList &args);
+#else
+ FcitxModule(QObject *parent, const QVariantList &args);
+#endif
virtual ~FcitxModule() override;
auto imConfig() const { return imConfig_; }
diff -urN fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/AddIMPage.qml fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/AddIMPage.qml
--- fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/AddIMPage.qml 1970-01-01 08:00:00.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/AddIMPage.qml 2026-02-08 22:16:45.456605316 +0800
@@ -0,0 +1,82 @@
+/*
+ * SPDX-FileCopyrightText: 2020~2020 CSSlayer <wengxt@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+import QtQuick 2.12
+import QtQuick.Layouts 1.12
+import QtQuick.Controls 2.12
+import org.kde.kirigami 2.10 as Kirigami
+import org.kde.kcm 1.2 as KCM
+
+KCM.ScrollViewKCM {
+ title: i18n("Add Input Method")
+
+ Component.onCompleted: {
+ search.forceActiveFocus();
+ }
+
+ Binding {
+ property: "filterText"
+ target: kcm.imConfig.availIMModel
+ value: search.text
+ }
+
+ footer: RowLayout {
+ CheckBox {
+ checked: true
+ text: i18n("Only &Show Current Language")
+ visible: search.text.length === 0
+
+ onClicked: {
+ kcm.imConfig.availIMModel.showOnlyCurrentLanguage = checked;
+ }
+ }
+ Item {
+ Layout.fillWidth: true
+ }
+ Button {
+ icon.name: "list-add-symbolic"
+ text: i18n("Add")
+
+ onClicked: {
+ if (availIMView.currentIndex === -1) {
+ return;
+ }
+ kcm.imConfig.addIM(availIMView.currentIndex);
+ if (kcm.imConfig.currentIMModel.count === 1) {
+ kcm.mainUi.checkInputMethod();
+ }
+ kcm.pop();
+ }
+ }
+ }
+ header: RowLayout {
+ TextField {
+ id: search
+ Layout.fillWidth: true
+ placeholderText: i18n("Search...")
+ }
+ }
+ view: ListView {
+ id: availIMView
+ model: kcm.imConfig.availIMModel
+
+ section {
+ property: "language"
+
+ delegate: Kirigami.ListSectionHeader {
+ label: section
+ }
+ }
+
+ delegate: Kirigami.BasicListItem {
+ label: model.name
+
+ onClicked: {
+ availIMView.currentIndex = index;
+ }
+ }
+ }
+}
diff -urN fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/AddonPage.qml fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/AddonPage.qml
--- fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/AddonPage.qml 1970-01-01 08:00:00.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/AddonPage.qml 2026-02-08 22:16:45.456648446 +0800
@@ -0,0 +1,168 @@
+/*
+ * SPDX-FileCopyrightText: 2020~2020 CSSlayer <wengxt@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+import QtQuick 2.12
+import QtQuick.Layouts 1.12
+import QtQuick.Controls 2.12
+import org.kde.kirigami 2.10 as Kirigami
+import org.kde.kcm 1.2 as KCM
+
+KCM.ScrollViewKCM {
+ id: addonPage
+ property bool needsSave: false
+ property string reenableAddon
+
+ title: i18n("Addons")
+
+ function defaults() {
+ }
+ function load() {
+ kcm.loadAddon();
+ needsSave = false;
+ }
+ function save() {
+ kcm.saveAddon();
+ needsSave = false;
+ }
+ function showWarning() {
+ dialog.open();
+ }
+
+ Binding {
+ property: "filterText"
+ target: kcm.addonModel
+ value: search.text
+ }
+ SaveWarningDialog {
+ id: dialog
+ }
+
+ header: ColumnLayout {
+ Kirigami.InlineMessage {
+ id: showOptionWarning
+ Layout.fillWidth: true
+ visible: showEnable.checked
+ type: Kirigami.MessageType.Warning
+ text: i18n("The feature of enabling/disabling addons is only intended for advanced users who understand the potential implication. Fcitx needs to be restarted to make the changes to enable/disable to take effect.")
+ }
+ Kirigami.InlineMessage {
+ id: disableAddonWarning
+ Layout.fillWidth: true
+ showCloseButton: true
+ type: Kirigami.MessageType.Warning
+
+ actions: [
+ Kirigami.Action {
+ displayHint: Kirigami.Action.DisplayHint.KeepVisible
+ iconName: "edit-undo"
+ text: i18n("Re-Enable")
+
+ onTriggered: {
+ kcm.addonModel.sourceModel.enable(reenableAddon);
+ disableAddonWarning.visible = false;
+ }
+ }
+ ]
+ }
+ RowLayout {
+ TextField {
+ id: search
+ Layout.fillWidth: true
+ placeholderText: i18n("Search...")
+ }
+ }
+ }
+ view: ListView {
+ model: kcm.addonModel
+
+ section {
+ property: "categoryName"
+
+ delegate: Kirigami.ListSectionHeader {
+ label: section
+ }
+ }
+
+ delegate: Kirigami.SwipeListItem {
+ id: listItem
+ RowLayout {
+ CheckBox {
+ id: itemChecked
+ Layout.alignment: Qt.AlignVCenter
+ Layout.leftMargin: Kirigami.Units.gridUnit
+ checked: model.enabled
+ visible: showEnable.checked
+
+ onClicked: {
+ model.enabled = !model.enabled;
+ if (!model.enabled) {
+ var dependencies = model.dependencies;
+ var optionalDependencies = model.optionalDependencies;
+ if (dependencies.length > 0 || optionalDependencies.length > 0) {
+ reenableAddon = model.uniqueName;
+ var sep = i18nc("Separator of a comma list", ", ");
+ var depWarning = "";
+ if (dependencies.length > 0) {
+ var addonNames = [];
+ for (var i = 0; i < dependencies.length; i++) {
+ var name = kcm.addonModel.sourceModel.addonName(dependencies[i]);
+ if (name) {
+ addonNames.push(name);
+ }
+ }
+ depWarning = depWarning.concat(i18n("- Disable %1\n", addonNames.join(sep)));
+ }
+ if (optionalDependencies.length > 0) {
+ var addonNames = [];
+ for (var i = 0; i < optionalDependencies.length; i++) {
+ var name = kcm.addonModel.sourceModel.addonName(optionalDependencies[i]);
+ if (name) {
+ addonNames.push(name);
+ }
+ }
+ depWarning = depWarning.concat(i18n("- Disable some features in %1\n", addonNames.join(sep)));
+ }
+ disableAddonWarning.text = i18n("Disabling %1 will also:\n%2\nAre you sure you want to disable it?", model.name, depWarning);
+ disableAddonWarning.visible = true;
+ }
+ }
+ needsSave = true;
+ }
+ }
+ ColumnLayout {
+ Kirigami.Heading {
+ Layout.fillWidth: true
+ elide: Text.ElideRight
+ level: 5
+ text: model.enabled ? model.name : i18n("%1 (Disabled)", model.name)
+ }
+ Label {
+ opacity: listItem.hovered ? 0.8 : 0.6
+ text: model.comment
+ visible: model.comment.length > 0
+ }
+ }
+ }
+
+ actions: [
+ Kirigami.Action {
+ icon.name: "configure"
+ visible: model.configurable
+
+ onTriggered: kcm.pushConfigPage(model.name, "fcitx://config/addon/" + model.uniqueName)
+ }
+ ]
+ }
+ }
+ footer: CheckBox {
+ id: showEnable
+ text: i18n("Show &Advanced options")
+
+ onClicked: {
+ showOptionWarning.visible = true;
+ }
+ }
+}
diff -urN fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/BoolOption.qml fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/BoolOption.qml
--- fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/BoolOption.qml 1970-01-01 08:00:00.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/BoolOption.qml 2026-02-08 22:16:45.456676228 +0800
@@ -0,0 +1,26 @@
+/*
+ * SPDX-FileCopyrightText: 2020~2020 CSSlayer <wengxt@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+
+CheckBox {
+ property bool needsSave: value !== checked
+ property variant rawValue
+ property bool value: rawValue === "True"
+
+ function load(rawValue) {
+ checked = rawValue === "True";
+ }
+ function save() {
+ rawValue = checked ? "True" : "False";
+ }
+
+ Component.onCompleted: {
+ load(rawValue);
+ save();
+ }
+}
diff -urN fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/ColorOption.qml fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/ColorOption.qml
--- fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/ColorOption.qml 1970-01-01 08:00:00.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/ColorOption.qml 2026-02-08 22:16:45.456702818 +0800
@@ -0,0 +1,50 @@
+/*
+ * SPDX-FileCopyrightText: 2020~2020 CSSlayer <wengxt@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+import QtQuick.Layouts 1.12
+import QtQuick.Dialogs 1.1 as QtDialogs
+import org.kde.kirigami 2.10 as Kirigami
+
+RowLayout {
+ property bool needsSave: button.text != rawValue
+ property variant rawValue
+
+ function load(rawValue) {
+ colorDialog.color = kcm.parseColor(rawValue);
+ }
+ function save() {
+ rawValue = button.text;
+ }
+
+ Component.onCompleted: {
+ load(rawValue);
+ save();
+ }
+
+ Button {
+ id: button
+ icon.name: "document-edit"
+ text: kcm.colorToString(colorDialog.color)
+
+ Layout.fillWidth: true
+
+ onClicked: colorDialog.open()
+
+ QtDialogs.ColorDialog {
+ id: colorDialog
+ modality: Qt.ApplicationModal
+ showAlphaChannel: true
+ title: i18nc("@title:window", "Select Color")
+ }
+ }
+ Rectangle {
+ color: colorDialog.color
+ height: button.height
+ width: height
+ }
+}
diff -urN fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/ConfigGroup.qml fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/ConfigGroup.qml
--- fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/ConfigGroup.qml 1970-01-01 08:00:00.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/ConfigGroup.qml 2026-02-08 22:16:45.456732312 +0800
@@ -0,0 +1,85 @@
+/*
+ * SPDX-FileCopyrightText: 2020~2020 CSSlayer <wengxt@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+import QtQuick.Layouts 1.12
+import org.kde.kirigami 2.10 as Kirigami
+import "utils.js" as Utils
+
+Kirigami.FormLayout {
+ id: configGroup
+ property bool needsSave
+ property variant rawValue
+ property variant typeMap
+ property string typeName
+
+ function defaults() {
+ for (var i = 0; i < repeater.count; i++) {
+ var loader = repeater.itemAt(i);
+ if (loader.status == Loader.Ready) {
+ loader.item.load(loader.option.defaultValue);
+ }
+ }
+ }
+ function load() {
+ for (var i = 0; i < repeater.count; i++) {
+ var loader = repeater.itemAt(i);
+ if (loader.status == Loader.Ready) {
+ loader.item.load(loader.item.rawValue);
+ }
+ }
+ needsSave = false;
+ }
+ function save() {
+ var rawValue = {};
+ for (var i = 0; i < repeater.count; i++) {
+ var loader = repeater.itemAt(i);
+ if (loader.status == Loader.Ready) {
+ loader.item.save();
+ if (loader.item.hasOwnProperty("rawValue")) {
+ Utils.setRawValue(rawValue, loader.option.name, loader.item.rawValue);
+ }
+ }
+ }
+ configGroup.rawValue = rawValue;
+ configGroup.needsSave = false;
+ }
+ function setRawValue(rawValue) {
+ for (var i = 0; i < repeater.count; i++) {
+ var loader = repeater.itemAt(i);
+ if (loader.status == Loader.Ready) {
+ loader.item.load(Utils.getRawValue(rawValue, loader.option.name));
+ }
+ }
+ }
+
+ Repeater {
+ id: repeater
+ model: typeMap[typeName]
+
+ OptionLoader {
+ id: loader
+ Layout.fillWidth: option.type !== "Boolean"
+ Kirigami.FormData.isSection: modelData.isSection
+ Kirigami.FormData.label: modelData.isSection ? modelData.description : i18n("%1:", modelData.description)
+ @DISABLE_UNDER_KIRIGAMI2_5_76@ Kirigami.FormData.labelAlignment: !modelData.isSection && modelData.type.startsWith("List|") ? (height > Kirigami.Units.gridUnit * 2 ? Qt.AlignTop : 0) : 0
+ option: modelData
+ rawValue: modelData.isSection ? null : Utils.getRawValue(configGroup.rawValue, modelData.name)
+
+ Connections {
+ enabled: loader.status == Loader.Ready
+ target: loader.status == Loader.Ready ? loader.item : null
+
+ function onNeedsSaveChanged() {
+ if (target.needsSave) {
+ configGroup.needsSave = true;
+ }
+ }
+ }
+ }
+ }
+}
diff -urN fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/ConfigPage.qml fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/ConfigPage.qml
--- fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/ConfigPage.qml 1970-01-01 08:00:00.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/ConfigPage.qml 2026-02-08 22:16:45.456758662 +0800
@@ -0,0 +1,55 @@
+/*
+ * SPDX-FileCopyrightText: 2020~2020 CSSlayer <wengxt@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+import org.kde.kirigami 2.10 as Kirigami
+import org.kde.kcm 1.1 as KCM
+
+Kirigami.ScrollablePage {
+ id: configPage
+ property alias needsSave: configGroup.needsSave
+ property alias rawValue: configGroup.rawValue
+ property alias typeMap: configGroup.typeMap
+ property alias typeName: configGroup.typeName
+ property string uri
+
+ function defaults() {
+ configGroup.defaults();
+ }
+ function load() {
+ configGroup.load();
+ }
+ function save() {
+ configGroup.save();
+ kcm.saveConfig(uri, rawValue);
+ }
+ function showWarning() {
+ dialog.open();
+ }
+
+ Component.onCompleted: positionTimer.start()
+
+ ConfigGroup {
+ id: configGroup
+ visible: false
+ width: parent.width
+
+ SaveWarningDialog {
+ id: dialog
+ parent: configPage
+ }
+
+ // Hack for force relayout the scrollview
+ Timer {
+ id: positionTimer
+ interval: 0
+ repeat: false
+
+ onTriggered: configGroup.visible = true
+ }
+ }
+}
diff -urN fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/EnumOption.qml fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/EnumOption.qml
--- fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/EnumOption.qml 1970-01-01 08:00:00.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/EnumOption.qml 2026-02-08 22:16:45.456788818 +0800
@@ -0,0 +1,86 @@
+/*
+ * SPDX-FileCopyrightText: 2020~2020 CSSlayer <wengxt@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+import org.kde.kirigami 2.10 as Kirigami
+
+Row {
+ property bool needsSave: value != comboBox.currentIndex
+ property variant properties
+ property variant rawValue
+ property int value: computeValue(rawValue)
+
+ function computeValue(rawValue) {
+ for (var i = 0; i < listModel.count; i++) {
+ if (listModel.get(i).value == rawValue) {
+ return i;
+ }
+ }
+ return 0;
+ }
+ function load(rawValue) {
+ comboBox.currentIndex = computeValue(rawValue);
+ }
+ function save() {
+ rawValue = properties["Enum"][comboBox.currentIndex.toString()];
+ }
+
+ Component.onCompleted: {
+ var i = 0;
+ while (true) {
+ if (!properties.hasOwnProperty("Enum")) {
+ break;
+ }
+ if (!properties["Enum"].hasOwnProperty(i.toString())) {
+ break;
+ }
+ var value = properties["Enum"][i.toString()];
+ var text = "";
+ if (properties.hasOwnProperty("EnumI18n")) {
+ if (properties["EnumI18n"].hasOwnProperty(i.toString())) {
+ text = properties["EnumI18n"][i.toString()];
+ }
+ }
+ if (text == "") {
+ text = value;
+ }
+ var subconfigpath = "";
+ if (properties.hasOwnProperty("SubConfigPath")) {
+ if (properties["SubConfigPath"].hasOwnProperty(i.toString())) {
+ subconfigpath = properties["SubConfigPath"][i.toString()];
+ }
+ }
+ listModel.append({
+ "text": text,
+ "value": value,
+ "subconfigpath": subconfigpath
+ });
+ i++;
+ }
+ load(rawValue);
+ save();
+ }
+
+ ComboBox {
+ id: comboBox
+ implicitWidth: Kirigami.Units.gridUnit * 14
+ textRole: "text"
+
+ model: ListModel {
+ id: listModel
+ }
+ }
+ ToolButton {
+ id: configureButton
+ icon.name: "configure"
+ visible: listModel.get(comboBox.currentIndex).subconfigpath !== ""
+
+ onClicked: {
+ kcm.pushConfigPage(listModel.get(comboBox.currentIndex).text, listModel.get(comboBox.currentIndex).subconfigpath);
+ }
+ }
+}
diff -urN fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/ExternalOption.qml fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/ExternalOption.qml
--- fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/ExternalOption.qml 1970-01-01 08:00:00.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/ExternalOption.qml 2026-02-08 22:16:45.456824795 +0800
@@ -0,0 +1,37 @@
+/*
+ * SPDX-FileCopyrightText: 2020~2020 CSSlayer <wengxt@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+
+Button {
+ property string description
+ readonly property bool needsSave: false
+ property variant properties
+ property bool subConfig: false
+
+ icon.name: "configure"
+
+ function defaults() {
+ }
+ function load(rawValue) {
+ }
+ function save() {
+ }
+
+ Component.onCompleted: {
+ if (properties.hasOwnProperty("LaunchSubConfig") && properties["LaunchSubConfig"] == "True") {
+ subConfig = true;
+ }
+ }
+ onClicked: {
+ if (subConfig) {
+ kcm.pushConfigPage(description, properties.External);
+ } else {
+ kcm.launchExternal(properties.External);
+ }
+ }
+}
diff -urN fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/FontOption.qml fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/FontOption.qml
--- fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/FontOption.qml 1970-01-01 08:00:00.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/FontOption.qml 2026-02-08 22:16:45.456860361 +0800
@@ -0,0 +1,37 @@
+/*
+ * SPDX-FileCopyrightText: 2020~2020 CSSlayer <wengxt@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+import QtQuick.Layouts 1.12
+import QtQuick.Dialogs 1.1 as QtDialogs
+import org.kde.kirigami 2.10 as Kirigami
+
+Button {
+ property bool needsSave: text !== rawValue
+ property variant rawValue
+
+ icon.name: "document-edit"
+ text: kcm.fontToString(fontDialog.font)
+
+ function load(rawValue) {
+ fontDialog.font = kcm.parseFont(rawValue);
+ }
+ function save() {
+ rawValue = text;
+ }
+
+ Component.onCompleted: {
+ load(rawValue);
+ save();
+ }
+ onClicked: fontDialog.open()
+
+ QtDialogs.FontDialog {
+ id: fontDialog
+ title: i18nc("@title:window", "Select Font")
+ }
+}
diff -urN fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/IntegerOption.qml fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/IntegerOption.qml
--- fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/IntegerOption.qml 1970-01-01 08:00:00.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/IntegerOption.qml 2026-02-08 22:16:45.456886430 +0800
@@ -0,0 +1,40 @@
+/*
+ * SPDX-FileCopyrightText: 2020~2020 CSSlayer <wengxt@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+
+SpinBox {
+ property bool needsSave: value !== oldValue
+ property int oldValue: parseInt(rawValue)
+ property variant properties
+ property variant rawValue
+
+ from: validator.bottom
+ to: validator.top
+
+ function load(rawValue) {
+ value = parseInt(rawValue);
+ }
+ function save() {
+ rawValue = value.toString();
+ }
+
+ Component.onCompleted: {
+ if (properties.hasOwnProperty("IntMin")) {
+ validator.bottom = parseInt(properties.IntMin);
+ }
+ if (properties.hasOwnProperty("IntMax")) {
+ validator.top = parseInt(properties.IntMax);
+ }
+ load(rawValue);
+ save();
+ }
+
+ validator: IntValidator {
+ id: validator
+ }
+}
diff -urN fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/KeyListOption.qml fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/KeyListOption.qml
--- fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/KeyListOption.qml 1970-01-01 08:00:00.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/KeyListOption.qml 2026-02-08 22:16:45.456918860 +0800
@@ -0,0 +1,105 @@
+/*
+ * SPDX-FileCopyrightText: 2020~2020 CSSlayer <wengxt@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+import QtQuick 2.12
+import QtQuick.Layouts 1.12
+import QtQuick.Controls 2.12
+import org.kde.kirigami 2.10 as Kirigami
+
+RowLayout {
+ id: keyList
+ property alias hovered: addButton.hovered
+ property bool needsSave
+ property variant properties
+ property variant rawValue
+
+ function load(rawValue) {
+ var diff = false;
+ if (listModel.count !== 0) {
+ listModel.remove(0, listModel.count);
+ }
+ var i = 0;
+ while (true) {
+ if (!rawValue.hasOwnProperty(i.toString())) {
+ break;
+ }
+ var value = rawValue[i.toString()];
+ listModel.append({
+ "key": value
+ });
+ if (!keyList.rawValue.hasOwnProperty(i.toString()) || rawValue[i.toString()] !== keyList.rawValue[i.toString()]) {
+ diff = true;
+ }
+ i++;
+ }
+ if (keyList.rawValue.hasOwnProperty(i.toString())) {
+ diff = true;
+ }
+ needsSave = diff;
+ }
+ function save() {
+ var newRawValue = {};
+ var j = 0;
+ for (var i = 0; i < listModel.count; i++) {
+ if (listModel.get(i).key !== "") {
+ newRawValue[j.toString()] = listModel.get(i).key;
+ j++;
+ }
+ }
+ rawValue = newRawValue;
+ needsSave = false;
+ }
+
+ Component.onCompleted: {
+ load(rawValue);
+ save();
+ }
+
+ ColumnLayout {
+ visible: listModel.count > 0
+ Repeater {
+ model: listModel
+
+ delegate: RowLayout {
+ KeyOption {
+ Layout.fillWidth: true
+ Layout.minimumWidth: Kirigami.Units.gridUnit * 9
+ properties: keyList.properties.hasOwnProperty("ListConstrain") ? keyList.properties.ListConstrain : {}
+ rawValue: model.key
+
+ onKeyStringChanged: {
+ model.key = keyString;
+ keyList.needsSave = true;
+ }
+ }
+ ToolButton {
+ icon.name: "edit-delete-symbolic"
+
+ onClicked: {
+ // Need to happen before real remove.
+ keyList.needsSave = true;
+ listModel.remove(model.index);
+ }
+ }
+ }
+ }
+ }
+ ToolButton {
+ id: addButton
+ Layout.alignment: Qt.AlignTop | Qt.AlignLeft
+ icon.name: "list-add-symbolic"
+
+ onClicked: {
+ keyList.needsSave = true;
+ listModel.append({
+ "key": ""
+ });
+ }
+ }
+ ListModel {
+ id: listModel
+ }
+}
diff -urN fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/KeyOption.qml fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/KeyOption.qml
--- fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/KeyOption.qml 1970-01-01 08:00:00.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/KeyOption.qml 2026-02-08 22:16:45.456957221 +0800
@@ -0,0 +1,151 @@
+/*
+ * SPDX-FileCopyrightText: 2020~2020 CSSlayer <wengxt@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+import "utils.js" as Utils
+
+Button {
+ id: root
+ property bool allowModifierLess: false
+ property bool allowModifierOnly: false
+ property string currentKeyString: ""
+ property bool grab: false
+ property string keyString: ""
+ property bool needsSave: keyString !== rawValue
+ property variant properties
+ property variant rawValue
+
+ down: grab
+ flat: false
+ focus: grab
+ text: prettyKeyString(grab ? currentKeyString : keyString)
+
+ function accept() {
+ kcm.ungrabKeyboard(root);
+ grab = false;
+ }
+ function isOkWhenModifierless(event) {
+ var isSpecialKey = event.key == Qt.Key_Return || event.key == Qt.Key_Space || event.key == Qt.Key_Tab || event.key == Qt.Key_Backtab || event.key == Qt.Key_Backspace || event.key == Qt.Key_Delete;
+ if (isSpecialKey) {
+ if ((event.modifiers & Qt.ShiftModifier) != 0) {
+ return true;
+ }
+ return false;
+ } else if (event.text.length === 1) {
+ return false;
+ }
+ return true;
+ }
+ function load(rawValue) {
+ keyString = rawValue;
+ }
+ function prettyKeyString(keyString) {
+ if (keyString === "") {
+ if (grab) {
+ return i18n("...");
+ } else {
+ return i18n("Empty");
+ }
+ }
+ return kcm.localizedKeyString(keyString);
+ }
+ function save() {
+ rawValue = keyString;
+ }
+
+ Component.onCompleted: {
+ if (properties.hasOwnProperty("AllowModifierLess")) {
+ allowModifierLess = properties.AllowModifierLess == "True";
+ }
+ if (properties.hasOwnProperty("AllowModifierOnly")) {
+ allowModifierOnly = properties.AllowModifierOnly == "True";
+ }
+ load(rawValue);
+ save();
+ }
+ Keys.onPressed: {
+ event.accepted = true;
+ if (!grab) {
+ return;
+ }
+ var done = true;
+ currentKeyString = kcm.eventToString(keyCodeAction.checked);
+ if (text === "") {
+ done = false;
+ }
+ var modifiers = event.modifiers & (Qt.ShiftModifier | Qt.ControlModifier | Qt.AltModifier | Qt.MetaModifier);
+ if ((modifiers & ~Qt.ShiftModifier) == 0) {
+ if (!isOkWhenModifierless(event) && !allowModifierLess) {
+ done = false;
+ }
+ }
+ if ((event.key == Qt.Key_Shift || event.key == Qt.Key_Control || event.key == Qt.Key_Meta || event.key == Qt.Key_Super_L || event.key == Qt.Key_Super_R || event.key == Qt.Key_Hyper_L || event.key == Qt.Key_Hyper_R || event.key == Qt.Key_Alt)) {
+ done = false;
+ }
+ if (done) {
+ keyString = currentKeyString;
+ accept();
+ }
+ }
+ Keys.onReleased: {
+ event.accepted = true;
+ if (!grab) {
+ return;
+ }
+ var done = false;
+ if (allowModifierOnly && (event.key == Qt.Key_Shift || event.key == Qt.Key_Control || event.key == Qt.Key_Meta || event.key == Qt.Key_Super_L || event.key == Qt.Key_Super_R || event.key == Qt.Key_Hyper_L || event.key == Qt.Key_Hyper_R || event.key == Qt.Key_Alt)) {
+ done = true;
+ }
+ var keyStr = kcm.eventToString(keyCodeAction.checked);
+ if (keyStr === "") {
+ done = false;
+ }
+ if (done) {
+ keyString = keyStr;
+ accept();
+ } else {
+ if (event.modifiers == 0) {
+ currentKeyString = "";
+ } else {
+ currentKeyString = keyStr;
+ }
+ }
+ }
+ Keys.onShortcutOverride: {
+ event.accepted = true;
+ Keys.onPressed(event);
+ }
+ onClicked: {
+ if (down) {
+ keyString = "";
+ accept();
+ } else {
+ grab = true;
+ currentKeyString = "";
+ kcm.grabKeyboard(root);
+ }
+ }
+ onPressAndHold: {
+ contextMenu.popup();
+ }
+
+ Menu {
+ id: contextMenu
+ Action {
+ id: keyCodeAction
+ checkable: true
+ text: i18n("Key code mode")
+ }
+ Action {
+ id: voidSymbolAction
+ text: i18n("Void Symbol")
+ onTriggered: {
+ keyString = "VoidSymbol";
+ }
+ }
+ }
+}
diff -urN fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/ListOption.qml fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/ListOption.qml
--- fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/ListOption.qml 1970-01-01 08:00:00.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/ListOption.qml 2026-02-08 22:16:45.457008026 +0800
@@ -0,0 +1,255 @@
+/*
+ * SPDX-FileCopyrightText: 2020~2020 CSSlayer <wengxt@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+import QtQuick 2.12
+import QtQuick.Layouts 1.12
+import QtQuick.Controls 2.12
+import org.kde.kirigami 2.10 as Kirigami
+
+ColumnLayout {
+ id: listOption
+ property alias hovered: addButton.hovered
+ property bool needsSave: false
+ property variant properties
+ property variant rawValue
+ readonly property string subTypeName: typeName.substr(5)
+ property string typeName
+
+ function getOption() {
+ var option = {};
+ option.isSection = false;
+ option.type = subTypeName;
+ option.properties = properties;
+ option.defaultValue = "";
+ option.name = [];
+ return option;
+ }
+ function load(rawValue) {
+ needsSave = (rawValue !== listOption.rawValue);
+ if (listModel.count !== 0) {
+ listModel.remove(0, listModel.count);
+ }
+ var i = 0;
+ while (true) {
+ if (!rawValue.hasOwnProperty(i.toString())) {
+ break;
+ }
+ var value = rawValue[i.toString()];
+ listModel.append({
+ "value": value
+ });
+ i++;
+ }
+ }
+ function prettify(value, subType) {
+ if (subType == "Integer") {
+ return value;
+ } else if (subType == "String") {
+ return value;
+ } else if (subType == "Boolean") {
+ return value == "True" ? i18n("Yes") : i18n("No");
+ } else if (subType == "Key") {
+ return kcm.localizedKeyString(value);
+ } else if (subType == "Enum") {
+ var i = 0;
+ var enumMap = {};
+ while (true) {
+ if (!properties.Enum.hasOwnProperty(i.toString())) {
+ break;
+ }
+ var enumString = properties.Enum[i.toString()];
+ var text = enumString;
+ if (properties.hasOwnProperty("EnumI18n") && properties.EnumI18n.hasOwnProperty(i.toString())) {
+ text = properties.EnumI18n[i.toString()];
+ }
+ enumMap[enumString] = text;
+ i++;
+ }
+ return enumMap[value];
+ } else if (subType.startsWith("List|")) {
+ var i = 0;
+ subSubType = subType.substr(5);
+ var strs = [];
+ while (true) {
+ if (!value.hasOwnProperty(i.toString())) {
+ break;
+ }
+ var subValue = prettify(value[i.toString()]);
+ strs.push(subValue);
+ i++;
+ }
+ return i18n("[%1]", strs.join(" "));
+ } else if (configPage.typeMap.hasOwnProperty(subType)) {
+ for (var i = 0; i < configPage.typeMap[subTypeName].length; ++i) {
+ var option = configPage.typeMap[subTypeName][i];
+ if (option.name.length === 1 && option.name[0] === properties.ListDisplayOption) {
+ return prettify(value[properties.ListDisplayOption], option.type);
+ }
+ }
+ }
+ return "";
+ }
+ function save() {
+ var newRawValue = {};
+ var j = 0;
+ for (var i = 0; i < listModel.count; i++) {
+ if (listModel.get(i).value !== "") {
+ newRawValue[j.toString()] = listModel.get(i).value;
+ j++;
+ }
+ }
+ rawValue = newRawValue;
+ }
+
+ Component.onCompleted: {
+ load(rawValue);
+ save();
+ }
+
+ Component {
+ id: delegateComponent
+ Kirigami.SwipeListItem {
+ id: listItem
+ RowLayout {
+ Kirigami.ListItemDragHandle {
+ listItem: listItem
+ listView: optionView
+
+ onMoveRequested: {
+ needsSave = true;
+ listModel.move(oldIndex, newIndex, 1);
+ }
+ }
+ Label {
+ Layout.fillWidth: true
+ color: listItem.checked || (listItem.pressed && !listItem.checked && !listItem.sectionDelegate) ? listItem.activeTextColor : listItem.textColor
+ height: Math.max(implicitHeight, Kirigami.Units.iconSizes.smallMedium)
+ text: model !== null ? prettify(model.value, subTypeName) : ""
+ elide: Text.ElideRight
+ }
+ }
+
+ actions: [
+ Kirigami.Action {
+ iconName: "document-edit"
+ text: i18n("edit")
+
+ onTriggered: {
+ sheet.edit(model.index);
+ }
+ },
+ Kirigami.Action {
+ iconName: "list-remove-symbolic"
+ text: i18n("Remove")
+
+ onTriggered: {
+ needsSave = true;
+ listModel.remove(model.index);
+ }
+ }
+ ]
+ }
+ }
+ ListModel {
+ id: listModel
+ }
+ ScrollView {
+ Layout.fillWidth: true
+ Kirigami.Theme.colorSet: Kirigami.Theme.View
+ Kirigami.Theme.inherit: false
+ ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
+ implicitHeight: optionView.contentHeight
+ implicitWidth: Kirigami.Units.gridUnit * 10
+
+ ListView {
+ id: optionView
+ model: listModel
+
+ delegate: Kirigami.DelegateRecycler {
+ sourceComponent: delegateComponent
+ width: optionView.width
+ }
+ }
+ }
+ RowLayout {
+ ToolButton {
+ id: addButton
+ icon.name: "list-add-symbolic"
+ text: i18n("Add")
+
+ onClicked: {
+ sheet.edit(listModel.count);
+ }
+ }
+ }
+ Kirigami.OverlaySheet {
+ id: sheet
+ property int editIndex: -1
+ readonly property bool isSubConfig: configPage.typeMap.hasOwnProperty(subTypeName)
+
+ parent: configPage
+
+ function edit(index) {
+ editIndex = index;
+ if (editIndex < listModel.count) {
+ if (isSubConfig) {
+ item().setRawValue(listModel.get(sheet.editIndex).value);
+ } else {
+ item().load(listModel.get(sheet.editIndex).value);
+ }
+ } else {
+ if (isSubConfig) {
+ item().defaults();
+ } else {
+ item().load("");
+ }
+ }
+ sheet.open();
+ }
+ function item() {
+ return isSubConfig ? optionEditor.item : optionEditor.item.item;
+ }
+
+ Loader {
+ id: optionEditor
+ sourceComponent: sheet.isSubConfig ? group : option
+ }
+
+ footer: DialogButtonBox {
+ standardButtons: DialogButtonBox.Ok | DialogButtonBox.Cancel
+
+ onAccepted: {
+ sheet.item().save();
+ // Add a new one.
+ if (sheet.editIndex == listModel.count) {
+ listModel.append({
+ "value": sheet.item().rawValue
+ });
+ } else {
+ listModel.get(sheet.editIndex).value = sheet.item().rawValue;
+ }
+ sheet.close();
+ needsSave = true;
+ }
+ onRejected: sheet.close()
+ }
+ }
+ Component {
+ id: option
+ OptionLoader {
+ option: getOption()
+ rawValue: ""
+ }
+ }
+ Component {
+ id: group
+ ConfigGroup {
+ rawValue: null
+ typeMap: configPage.typeMap
+ typeName: subTypeName
+ }
+ }
+}
diff -urN fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/main.qml fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/main.qml
--- fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/main.qml 1970-01-01 08:00:00.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/main.qml 2026-02-08 22:16:45.457070813 +0800
@@ -0,0 +1,371 @@
+/*
+ * SPDX-FileCopyrightText: 2020~2020 CSSlayer <wengxt@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+import QtQuick 2.12
+import QtQuick.Layouts 1.12
+import QtQuick.Controls 2.12
+import org.kde.kirigami 2.10 as Kirigami
+import org.kde.kcm 1.2 as KCM
+
+KCM.ScrollViewKCM {
+ id: root
+ Kirigami.ColumnView.fillWidth: true
+ implicitHeight: Kirigami.Units.gridUnit * 36
+ implicitWidth: Kirigami.Units.gridUnit * 50
+
+ function checkInputMethod() {
+ var firstIM = imList.model.imAt(0);
+ inputMethodNotMatchWarning.visible = false;
+ if (firstIM.startsWith("keyboard-")) {
+ layoutNotMatchWarning.visible = (firstIM.substr(9) != kcm.imConfig.defaultLayout);
+ } else {
+ layoutNotMatchWarning.visible = false;
+ }
+ }
+
+ SelectLayoutSheet {
+ id: selectLayoutSheet
+ parent: root
+ }
+ Component {
+ id: delegateComponent
+ Kirigami.SwipeListItem {
+ id: listItem
+ RowLayout {
+ Kirigami.ListItemDragHandle {
+ listItem: listItem
+ listView: imList
+
+ onMoveRequested: {
+ imList.model.move(oldIndex, newIndex, 1);
+ checkInputMethod();
+ }
+ }
+ Label {
+ Layout.fillWidth: true
+ color: listItem.checked || (listItem.pressed && !listItem.checked && !listItem.sectionDelegate) ? listItem.activeTextColor : listItem.textColor
+ height: Math.max(implicitHeight, Kirigami.Units.iconSizes.smallMedium)
+ text: model !== null ? model.name : ""
+ }
+ }
+
+ actions: [
+ Kirigami.Action {
+ iconName: "configure"
+ text: i18n("Configure")
+ visible: model !== null ? model.configurable : false
+
+ onTriggered: kcm.pushConfigPage(model.name, "fcitx://config/inputmethod/" + model.uniqueName)
+ },
+ Kirigami.Action {
+ iconName: "input-keyboard"
+ text: i18n("Select Layout")
+ visible: model !== null ? !model.uniqueName.startsWith("keyboard-") : false
+
+ onTriggered: selectLayoutSheet.selectLayout(i18n("Select layout for %1", model.name), model.uniqueName, (model.layout !== "" ? model.layout : kcm.imConfig.defaultLayout))
+ },
+ Kirigami.Action {
+ iconName: "list-remove-symbolic"
+ text: i18n("Remove")
+
+ onTriggered: {
+ imList.model.remove(model.index);
+ checkInputMethod();
+ }
+ }
+ ]
+ }
+ }
+ Kirigami.OverlaySheet {
+ id: addGroupSheet
+ parent: root
+
+ Kirigami.FormLayout {
+ implicitWidth: Kirigami.Units.gridUnit * 15
+
+ TextField {
+ id: groupName
+ Kirigami.FormData.label: i18n("Name:")
+ placeholderText: i18n("Group Name")
+ }
+ }
+
+ footer: RowLayout {
+ Item {
+ Layout.fillWidth: true
+ }
+ Button {
+ text: i18n("Ok")
+
+ onClicked: {
+ if (groupName.text.length) {
+ kcm.imConfig.addGroup(groupName.text);
+ addGroupSheet.close();
+ }
+ }
+ }
+ }
+ header: Kirigami.Heading {
+ text: i18n("Add Group")
+ }
+ }
+ Connections {
+ property int oldIndex: 0
+
+ target: kcm
+
+ function onCurrentIndexChanged(idx) {
+ if (idx < oldIndex) {
+ while (kcm.depth > idx + 1) {
+ var page = kcm.pageNeedsSave(kcm.depth - 1);
+ if (page === null) {
+ kcm.pop();
+ } else {
+ kcm.currentIndex = kcm.depth - 1;
+ page.showWarning();
+ break;
+ }
+ }
+ }
+ }
+ function onPagePushed() {
+ oldIndex = kcm.depth;
+ }
+ }
+ Dialog {
+ id: confirmGroupChangeDialog
+ property string nextGroup
+ property string prevGroup
+
+ closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
+ focus: true
+ modal: true
+ standardButtons: Dialog.Yes | Dialog.No
+ title: i18n("Current group changed")
+ x: (root.width - width) / 2
+ y: root.height / 2 - height
+
+ onAccepted: {
+ kcm.imConfig.currentGroup = nextGroup;
+ }
+ onRejected: {
+ var groups = kcm.imConfig.groups;
+ for (var i = 0; i < groups.length; i++) {
+ if (groups[i] == prevGroup) {
+ groupComboBox.currentIndex = i;
+ return;
+ }
+ }
+ }
+
+ Label {
+ text: i18n("Do you want to change group? Changes to current group will be lost!")
+ }
+
+ Overlay.modal: Rectangle {
+ color: "#99000000"
+ }
+ }
+
+ footer: ColumnLayout {
+ RowLayout {
+ Button {
+ icon.name: "input-keyboard"
+ text: i18n("Select system layout...")
+
+ onClicked: {
+ selectLayoutSheet.selectLayout(i18n("Select system layout for group %1", groupComboBox.currentText), "", kcm.imConfig.defaultLayout);
+ }
+
+ ToolTip {
+ text: i18n("Select system keyboard layout...")
+ visible: parent.hovered
+ }
+ }
+ Label {
+ text: kcm.layoutProvider.layoutDescription(kcm.imConfig.defaultLayout)
+ }
+ TextField {
+ Layout.fillWidth: true
+ placeholderText: i18n("Test Input")
+ }
+ }
+ RowLayout {
+ enabled: kcm.availability
+
+ Button {
+ icon.name: "configure"
+ text: i18n("Configure global options...")
+
+ onClicked: kcm.pushConfigPage(i18n("Global Options"), "fcitx://config/global")
+ }
+ Button {
+ icon.name: "configure"
+ text: i18n("Configure addons...")
+
+ onClicked: kcm.push("AddonPage.qml")
+ }
+ Item {
+ Layout.fillWidth: true
+ }
+ Button {
+ icon.name: "list-add-symbolic"
+ text: i18n("Add Input Method...")
+
+ onClicked: kcm.push("AddIMPage.qml")
+ }
+ }
+ }
+ header: ColumnLayout {
+ Kirigami.InlineMessage {
+ id: fcitxNotAvailableWarning
+ Layout.fillWidth: true
+ text: i18n("Cannot connect to Fcitx by DBus, is Fcitx running?")
+ type: Kirigami.MessageType.Warning
+ visible: !kcm.availability
+
+ actions: [
+ Kirigami.Action {
+ displayHint: Kirigami.Action.DisplayHint.KeepVisible
+ iconName: "system-run"
+ text: i18n("Run Fcitx")
+
+ onTriggered: {
+ kcm.runFcitx();
+ }
+ }
+ ]
+ }
+ Kirigami.InlineMessage {
+ id: fcitxNeedUpdateMessage
+ Layout.fillWidth: true
+ showCloseButton: true
+ text: i18n("Found updates to fcitx installation. Do you want to check for newly installed input methods and addons? To update already loaded addons, fcitx would need to be restarted.")
+ type: Kirigami.MessageType.Information
+ visible: kcm.imConfig.needUpdate
+
+ actions: [
+ Kirigami.Action {
+ displayHint: Kirigami.Action.DisplayHint.KeepVisible
+ iconName: "update-none"
+ text: i18n("Update")
+
+ onTriggered: {
+ kcm.imConfig.refresh();
+ }
+ },
+ Kirigami.Action {
+ displayHint: Kirigami.Action.DisplayHint.KeepVisible
+ iconName: "system-run"
+ text: i18n("Restart")
+ visible: kcm.canRestart
+
+ onTriggered: {
+ kcm.imConfig.restart();
+ }
+ }
+ ]
+ }
+ Kirigami.InlineMessage {
+ id: layoutNotMatchWarning
+ Layout.fillWidth: true
+ showCloseButton: true
+ text: i18n("Your currently configured input method does not match your layout, do you want to change the layout setting?")
+ type: Kirigami.MessageType.Warning
+ visible: false
+
+ actions: [
+ Kirigami.Action {
+ text: i18n("Fix")
+
+ onTriggered: {
+ kcm.fixLayout();
+ layoutNotMatchWarning.visible = false;
+ }
+ }
+ ]
+ }
+ Kirigami.InlineMessage {
+ id: inputMethodNotMatchWarning
+ Layout.fillWidth: true
+ showCloseButton: true
+ text: i18n("Your currently configured input method does not match your selected layout, do you want to add the corresponding input method for the layout?")
+ type: Kirigami.MessageType.Warning
+ visible: false
+
+ actions: [
+ Kirigami.Action {
+ text: i18n("Fix")
+
+ onTriggered: {
+ kcm.fixInputMethod();
+ }
+ }
+ ]
+ }
+ RowLayout {
+ enabled: kcm.availability
+
+ Label {
+ text: i18n("Group:")
+ }
+ ComboBox {
+ id: groupComboBox
+ Layout.fillWidth: true
+ model: kcm.imConfig.groups
+
+ onActivated: {
+ if (kcm.imConfig.needSave && kcm.imConfig.currentGroup !== currentText && kcm.imConfig.currentGroup !== "") {
+ confirmGroupChangeDialog.nextGroup = currentText;
+ confirmGroupChangeDialog.prevGroup = kcm.imConfig.currentGroup;
+ confirmGroupChangeDialog.open();
+ } else {
+ kcm.imConfig.currentGroup = currentText;
+ }
+ }
+ }
+ Button {
+ icon.name: "list-add-symbolic"
+
+ onClicked: {
+ groupName.text = "";
+ addGroupSheet.open();
+ }
+ }
+ Button {
+ icon.name: "list-remove-symbolic"
+ visible: kcm.imConfig.groups && kcm.imConfig.groups.length > 1
+
+ onClicked: {
+ kcm.imConfig.deleteGroup(groupComboBox.currentText);
+ }
+ }
+ }
+ }
+ view: ListView {
+ id: imList
+ enabled: kcm.availability
+ model: kcm.imConfig.currentIMModel
+
+ section {
+ property: "active"
+ delegate: Kirigami.ListSectionHeader {
+ text: section == "inactive" ? i18n("Input Method Off") : i18n("Input Method On")
+ }
+ }
+
+ delegate: Kirigami.DelegateRecycler {
+ sourceComponent: delegateComponent
+ width: imList.width
+ }
+ moveDisplaced: Transition {
+ YAnimator {
+ duration: Kirigami.Units.longDuration
+ easing.type: Easing.InOutQuad
+ }
+ }
+ }
+}
diff -urN fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/OptionLoader.qml fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/OptionLoader.qml
--- fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/OptionLoader.qml 1970-01-01 08:00:00.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/OptionLoader.qml 2026-02-08 22:16:45.457110387 +0800
@@ -0,0 +1,66 @@
+/*
+ * SPDX-FileCopyrightText: 2020~2020 CSSlayer <wengxt@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+import QtQuick.Layouts 1.12
+import org.kde.kirigami 2.10 as Kirigami
+import "utils.js" as Utils
+
+Loader {
+ id: loader
+ property variant option
+ property variant rawValue
+
+ ToolTip.delay: Kirigami.Units.toolTipDelay
+ ToolTip.text: option.properties && option.properties.hasOwnProperty("Tooltip") ? option.properties["Tooltip"] : ""
+ ToolTip.visible: option.properties && option.properties.hasOwnProperty("Tooltip") && loader.item ? loader.item.hovered : false
+
+ function optionSource(data) {
+ if (data.type == "Boolean") {
+ return "BoolOption.qml";
+ } else if (data.type == "Integer") {
+ return "IntegerOption.qml";
+ } else if (data.type == "Enum") {
+ return "EnumOption.qml";
+ } else if (data.type == "String") {
+ if (data.properties.hasOwnProperty("Font") && data.properties.Font == "True") {
+ return "FontOption.qml";
+ } else if (data.properties.hasOwnProperty("IsEnum") && data.properties.IsEnum == "True") {
+ return "EnumOption.qml";
+ } else {
+ return "StringOption.qml";
+ }
+ } else if (data.type == "List|Key") {
+ return "KeyListOption.qml";
+ } else if (data.type == "Key") {
+ return "KeyOption.qml";
+ } else if (data.type == "Color") {
+ return "ColorOption.qml";
+ } else if (data.type.startsWith("List|")) {
+ return "ListOption.qml";
+ } else if (data.type == "External") {
+ return "ExternalOption.qml";
+ } else {
+ console.log(data.type + " Not supported");
+ return "";
+ }
+ }
+
+ Component.onCompleted: {
+ if (!option.isSection) {
+ var prop = {
+ "name": option.name,
+ "typeName": option.type,
+ "description": option.description,
+ "defaultValue": option.defaultValue,
+ "properties": option.properties,
+ "rawValue": rawValue
+ };
+ loader.setSource(optionSource(option), prop);
+ }
+ }
+}
diff -urN fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/SaveWarningDialog.qml fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/SaveWarningDialog.qml
--- fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/SaveWarningDialog.qml 1970-01-01 08:00:00.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/SaveWarningDialog.qml 2026-02-08 22:16:45.457138629 +0800
@@ -0,0 +1,27 @@
+/*
+ * SPDX-FileCopyrightText: 2020~2020 CSSlayer <wengxt@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+
+Dialog {
+ id: notSavedDialog
+ closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
+ focus: true
+ modal: true
+ standardButtons: Dialog.Ok
+ title: i18n("Some config is not saved")
+ x: (parent.width - width) / 2
+ y: parent.height / 2 - height
+
+ Label {
+ text: i18n("Current page is not yet saved. Please save the config first.")
+ }
+
+ Overlay.modal: Rectangle {
+ color: "#99000000"
+ }
+}
diff -urN fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/SelectLayoutSheet.qml fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/SelectLayoutSheet.qml
--- fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/SelectLayoutSheet.qml 1970-01-01 08:00:00.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/SelectLayoutSheet.qml 2026-02-08 22:16:45.457173344 +0800
@@ -0,0 +1,104 @@
+/*
+ * SPDX-FileCopyrightText: 2020~2020 CSSlayer <wengxt@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+import QtQuick 2.12
+import QtQuick.Layouts 1.12
+import QtQuick.Controls 2.12
+import org.kde.kirigami 2.10 as Kirigami
+
+Kirigami.OverlaySheet {
+ id: selectLayoutSheet
+ property string im: ""
+
+ function selectLayout(title, im, layout) {
+ heading.text = title;
+ languageComboBox.currentIndex = 0;
+ selectLayoutSheet.im = im;
+ var layoutIndex = kcm.layoutProvider.layoutIndex(layout);
+ layoutComboBox.currentIndex = layoutIndex;
+ var variantIndex = kcm.layoutProvider.variantIndex(layout);
+ variantComboBox.currentIndex = variantIndex;
+ open();
+ }
+
+ Kirigami.FormLayout {
+ implicitWidth: Kirigami.Units.gridUnit * 45
+
+ ComboBox {
+ id: languageComboBox
+ Kirigami.FormData.label: i18n("Language:")
+ implicitWidth: Kirigami.Units.gridUnit * 15
+ model: kcm.layoutProvider.languageModel
+ textRole: "name"
+
+ onCurrentIndexChanged: {
+ kcm.layoutProvider.layoutModel.language = model.language(currentIndex);
+ layoutComboBox.currentIndex = 0;
+ kcm.layoutProvider.setVariantInfo(kcm.layoutProvider.layoutModel.layoutInfo(layoutComboBox.currentIndex));
+ variantComboBox.currentIndex = 0;
+ }
+ }
+ ComboBox {
+ id: layoutComboBox
+ Kirigami.FormData.label: i18n("Layout:")
+ implicitWidth: Kirigami.Units.gridUnit * 15
+ model: kcm.layoutProvider.layoutModel
+ textRole: "name"
+
+ onCurrentIndexChanged: {
+ if (currentIndex < 0) {
+ return;
+ }
+ kcm.layoutProvider.setVariantInfo(model.layoutInfo(currentIndex));
+ variantComboBox.currentIndex = 0;
+ }
+ }
+ ComboBox {
+ id: variantComboBox
+ Kirigami.FormData.label: i18n("Variant:")
+ implicitWidth: Kirigami.Units.gridUnit * 15
+ model: kcm.layoutProvider.variantModel
+ textRole: "name"
+ }
+ }
+
+ footer: RowLayout {
+ Item {
+ Layout.fillWidth: true
+ }
+ Button {
+ text: i18n("Clear")
+ visible: im !== ""
+
+ onClicked: {
+ kcm.imConfig.setLayout(im, "");
+ selectLayoutSheet.close();
+ }
+ }
+ Button {
+ text: i18n("Ok")
+
+ onClicked: {
+ if (layoutComboBox.currentIndex >= 0 && variantComboBox.currentIndex >= 0) {
+ var layout = kcm.layoutProvider.layout(layoutComboBox.currentIndex, variantComboBox.currentIndex);
+ if (im.length === 0) {
+ kcm.imConfig.defaultLayout = layout;
+ if (kcm.imConfig.currentIMModel.count > 0 && "keyboard-%0".arg(layout) != kcm.imConfig.currentIMModel.imAt(0)) {
+ layoutNotMatchWarning.visible = false;
+ inputMethodNotMatchWarning.visible = true;
+ }
+ } else {
+ kcm.imConfig.setLayout(im, layout);
+ }
+ selectLayoutSheet.close();
+ }
+ }
+ }
+ }
+ header: Kirigami.Heading {
+ id: heading
+ }
+}
diff -urN fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/StringOption.qml fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/StringOption.qml
--- fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/StringOption.qml 1970-01-01 08:00:00.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/StringOption.qml 2026-02-08 22:16:45.457197359 +0800
@@ -0,0 +1,25 @@
+/*
+ * SPDX-FileCopyrightText: 2020~2020 CSSlayer <wengxt@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ */
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+
+TextField {
+ property bool needsSave: text !== rawValue
+ property string rawValue
+
+ function load(rawValue) {
+ text = rawValue;
+ }
+ function save() {
+ rawValue = text;
+ }
+
+ Component.onCompleted: {
+ load(rawValue);
+ save();
+ }
+}
diff -urN fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/utils.js fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/utils.js
--- fcitx5-configtool-5.1.12/src/kcm/package/contents/ui/utils.js 1970-01-01 08:00:00.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/kcm/package/contents/ui/utils.js 2026-02-08 22:16:45.457221233 +0800
@@ -0,0 +1,29 @@
+function getRawValue(rawValue, name) {
+ if (name.length == 0) {
+ return "";
+ }
+ if (rawValue === null) {
+ return "";
+ }
+ for (var i = 0; i < name.length; i++) {
+ if (rawValue.hasOwnProperty(name[i])) {
+ rawValue = rawValue[name[i]];
+ } else {
+ return "";
+ }
+ }
+ return rawValue;
+}
+
+function setRawValue(rawValue, name, value) {
+ for (var i = 0; i < name.length; i++) {
+ if (i + 1 == name.length) {
+ rawValue[name[i]] = value;
+ } else {
+ if (!rawValue.hasOwnProperty(name[i])) {
+ rawValue[name[i]] = {};
+ }
+ rawValue = rawValue[name[i]];
+ }
+ }
+}
diff -urN fcitx5-configtool-5.1.12/src/kcm/package/metadata.json fcitx5-configtool-5.1.12.new/src/kcm/package/metadata.json
--- fcitx5-configtool-5.1.12/src/kcm/package/metadata.json 1970-01-01 08:00:00.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/kcm/package/metadata.json 2026-02-08 22:16:45.457252892 +0800
@@ -0,0 +1,46 @@
+{
+ "KPlugin": {
+ "Authors": [
+ {
+ "Email": "fcitx-dev@googlegroups.com.",
+ "Name": "Weng Xuetian"
+ }
+ ],
+ "Description": "Configure Input Method",
+ "Description[ca]": "Configura el mètode d'entrada",
+ "Description[da]": "Konfigurer inputmetode",
+ "Description[de]": "Eingabemethode konfigurieren",
+ "Description[es]": "Configurar método de entrada",
+ "Description[fr]": "Configurer la méthode d'entrée",
+ "Description[he]": "הגדרת שיטת קלט",
+ "Description[ja]": "入力メソッドの設定",
+ "Description[ko]": "입력기 구성하기",
+ "Description[ru]": "Настроить метод ввода",
+ "Description[zh_CN]": "配置输入法",
+ "Description[zh_TW]": "設定輸入法",
+ "Icon": "fcitx",
+ "Id": "kcm_fcitx5",
+ "License": "GPL",
+ "Name": "Input Method",
+ "Name[ca]": "Mètode d'entrada",
+ "Name[da]": "Inputmetode",
+ "Name[de]": "Eingabemethode",
+ "Name[es]": "Método de entrada",
+ "Name[fr]": "Méthode de saisie",
+ "Name[he]": "שיטת קלט",
+ "Name[ja]": "入力メソッド",
+ "Name[ko]": "입력기",
+ "Name[ru]": "Метод ввода",
+ "Name[tr]": "Giriş Yöntemi",
+ "Name[vi]": "Kiểu gõ",
+ "Name[zh_CN]": "输入法",
+ "Name[zh_TW]": "輸入法",
+ "ServiceTypes": [
+ "Plasma/Generic"
+ ],
+ "Version": "",
+ "Website": ""
+ },
+ "X-Plasma-API": "declarativeappletscript",
+ "X-Plasma-MainScript": "ui/main.qml"
+}
diff -urN fcitx5-configtool-5.1.12/src/lib/configlib/addonmodel.cpp fcitx5-configtool-5.1.12.new/src/lib/configlib/addonmodel.cpp
--- fcitx5-configtool-5.1.12/src/lib/configlib/addonmodel.cpp 2025-12-22 14:18:08.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/lib/configlib/addonmodel.cpp 2026-02-08 22:16:45.457288939 +0800
@@ -420,12 +420,16 @@
QProcess::startDetached(wrapperToUse, args);
} else {
// Assume this is a program path.
+#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
QStringList args = QProcess::splitCommand(uri);
if (args.isEmpty()) {
return;
}
QString program = args.takeFirst();
QProcess::startDetached(program, args);
+#else
+ QProcess::startDetached(uri);
+#endif
}
}
diff -urN fcitx5-configtool-5.1.12/src/lib/configlib/model.cpp fcitx5-configtool-5.1.12.new/src/lib/configlib/model.cpp
--- fcitx5-configtool-5.1.12/src/lib/configlib/model.cpp 2025-12-22 14:18:08.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/lib/configlib/model.cpp 2026-02-08 22:16:45.457341778 +0800
@@ -15,7 +15,6 @@
#include <QString>
#include <QStringLiteral>
#include <Qt>
-#include <QtTypes>
#include <algorithm>
#include <fcitx-utils/i18n.h>
#include <fcitxqtdbustypes.h>
@@ -42,9 +41,9 @@
}
if (items.size() > 1) {
QLocale locale(langCode);
- if (locale.territory() != QLocale::AnyTerritory) {
+ if (locale.country() != QLocale::AnyCountry) {
territory =
- QLocale::territoryToString(locale.territory());
+ QLocale::countryToString(locale.country());
}
if (!territory.isEmpty()) {
territory =
diff -urN fcitx5-configtool-5.1.12/src/lib/configwidgetslib/addonselector.cpp fcitx5-configtool-5.1.12.new/src/lib/configwidgetslib/addonselector.cpp
--- fcitx5-configtool-5.1.12/src/lib/configwidgetslib/addonselector.cpp 2025-12-22 14:18:08.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/lib/configwidgetslib/addonselector.cpp 2026-02-08 22:16:45.457392552 +0800
@@ -46,9 +46,15 @@
protected:
QList<QWidget *> createItemWidgets(const QModelIndex &index) const override;
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
void updateItemWidgets(const QList<QWidget *> &widgets,
const QStyleOptionViewItem &option,
const QPersistentModelIndex &index) const override;
+#else
+ void updateItemWidgets(const QList<QWidget *> widgets,
+ const QStyleOptionViewItem &option,
+ const QPersistentModelIndex &index) const override;
+#endif
private Q_SLOTS:
void checkBoxClicked(bool state);
@@ -210,9 +216,15 @@
return widgetList;
}
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
void AddonDelegate::updateItemWidgets(
const QList<QWidget *> &widgets, const QStyleOptionViewItem &option,
const QPersistentModelIndex &index) const {
+#else
+void AddonDelegate::updateItemWidgets(
+ const QList<QWidget *> widgets, const QStyleOptionViewItem &option,
+ const QPersistentModelIndex &index) const {
+#endif
if (index.data(RowTypeRole).toInt() == CategoryType) {
return;
}
diff -urN fcitx5-configtool-5.1.12/src/lib/configwidgetslib/listoptionwidget.cpp fcitx5-configtool-5.1.12.new/src/lib/configwidgetslib/listoptionwidget.cpp
--- fcitx5-configtool-5.1.12/src/lib/configwidgetslib/listoptionwidget.cpp 2025-12-22 14:18:08.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/lib/configwidgetslib/listoptionwidget.cpp 2026-02-08 22:16:45.457438348 +0800
@@ -104,7 +104,11 @@
index.parent(), index.row() - 1)) {
return;
}
+#if (QT_VERSION < QT_VERSION_CHECK(5, 13, 0))
+ values_.swap(index.row() - 1, index.row());
+#else
values_.swapItemsAt(index.row() - 1, index.row());
+#endif
endMoveRows();
}
@@ -117,7 +121,11 @@
index.parent(), index.row() + 2)) {
return;
}
+#if (QT_VERSION < QT_VERSION_CHECK(5, 13, 0))
+ values_.swap(index.row(), index.row() + 1);
+#else
values_.swapItemsAt(index.row(), index.row() + 1);
+#endif
endMoveRows();
}
diff -urN fcitx5-configtool-5.1.12/src/lib/configwidgetslib/varianthelper.cpp fcitx5-configtool-5.1.12.new/src/lib/configwidgetslib/varianthelper.cpp
--- fcitx5-configtool-5.1.12/src/lib/configwidgetslib/varianthelper.cpp 2025-12-22 14:18:08.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/lib/configwidgetslib/varianthelper.cpp 2026-02-08 22:16:45.457472421 +0800
@@ -82,7 +82,11 @@
iter = map.insert(path[depth], QVariantMap());
}
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
if (iter->typeId() != QMetaType::QVariantMap) {
+#else
+ if (iter->type() != QVariant::Map) {
+#endif
auto oldValue = *iter;
*iter = QVariantMap({{"", oldValue}});
}
diff -urN fcitx5-configtool-5.1.12/src/plasmathemegenerator/CMakeLists.txt fcitx5-configtool-5.1.12.new/src/plasmathemegenerator/CMakeLists.txt
--- fcitx5-configtool-5.1.12/src/plasmathemegenerator/CMakeLists.txt 2025-12-22 14:18:08.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/plasmathemegenerator/CMakeLists.txt 2026-02-08 22:16:45.457505843 +0800
@@ -6,8 +6,13 @@
Fcitx5::Utils
Fcitx5::Config)
+if (QT_MAJOR_VERSION STREQUAL 5)
+target_link_libraries(fcitx5-plasma-theme-generator
+ KF${QT_MAJOR_VERSION}::Plasma)
+elseif (QT_MAJOR_VERSION STREQUAL 6)
target_link_libraries(fcitx5-plasma-theme-generator
Plasma::Plasma
KF${QT_MAJOR_VERSION}::Svg)
+endif()
install(TARGETS fcitx5-plasma-theme-generator DESTINATION ${CMAKE_INSTALL_BINDIR})
diff -urN fcitx5-configtool-5.1.12/src/plasmathemegenerator/main.cpp fcitx5-configtool-5.1.12.new/src/plasmathemegenerator/main.cpp
--- fcitx5-configtool-5.1.12/src/plasmathemegenerator/main.cpp 2025-12-22 14:18:08.000000000 +0800
+++ fcitx5-configtool-5.1.12.new/src/plasmathemegenerator/main.cpp 2026-02-08 22:16:45.457551278 +0800
@@ -7,9 +7,6 @@
#include "config.h"
#include <KIconLoader>
#include <KLocalizedString>
-#include <KSvg/FrameSvg>
-#include <KSvg/ImageSet>
-#include <KSvg/Svg>
#include <Plasma/Theme>
#include <QBitmap>
#include <QColor>
@@ -35,8 +32,18 @@
#include <fcntl.h>
#include <memory>
#include <string>
+
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+#include <KSvg/FrameSvg>
+#include <KSvg/ImageSet>
+#include <KSvg/Svg>
using FrameSvg = KSvg::FrameSvg;
using Svg = KSvg::Svg;
+#else
+#include <Plasma/FrameSvg>
+using FrameSvg = Plasma::FrameSvg;
+using Svg = Plasma::Svg;
+#endif
namespace {
bool fd_is_valid(int fd) { return fcntl(fd, F_GETFD) != -1 || errno != EBADF; }
@@ -126,6 +133,7 @@
theme_ = std::make_unique<Plasma::Theme>();
}
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
if (parser.isSet("theme") && !monitorMode()) {
imageSet_ = std::make_unique<KSvg::ImageSet>(theme_->themeName());
} else {
@@ -134,6 +142,7 @@
// theme's global change like composite.
imageSet_ = std::make_unique<KSvg::ImageSet>();
}
+#endif
if (monitorMode()) {
socketNotifier_ =
@@ -146,11 +155,13 @@
}
});
connect(theme_.get(), &Plasma::Theme::themeChanged, this, [this]() {
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
auto selectors = imageSet_->selectors();
// Force invalidate the cache to workaround a bug in ksvg.
// FIXME: remove this once fix is merged.
imageSet_->setSelectors({"bad"});
imageSet_->setSelectors(selectors);
+#endif
if (!generateTheme()) {
qDebug() << "Failed to generate theme.";
}
@@ -400,14 +411,21 @@
template <typename T>
void setThemeToSvg(T &svg) {
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
svg.setImageSet(imageSet_.get());
+#else
+ svg.setTheme(theme_.get());
+#endif
}
private:
QSocketNotifier *socketNotifier_ = nullptr;
int fd_ = -1;
std::unique_ptr<Plasma::Theme> theme_;
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
std::unique_ptr<KSvg::ImageSet> imageSet_;
+#else
+#endif
QString outputPath_;
};