├── src ├── migrator │ ├── global │ │ ├── globalconfigmigrator.json │ │ ├── CMakeLists.txt │ │ ├── globalconfigmigrator.h │ │ └── globalconfigmigrator.cpp │ ├── kkc │ │ ├── kkcmigrator.json │ │ ├── CMakeLists.txt │ │ ├── kkcmigrator.h │ │ └── kkcmigrator.cpp │ ├── skk │ │ ├── skkmigrator.json │ │ ├── CMakeLists.txt │ │ ├── skkmigrator.h │ │ └── skkmigrator.cpp │ ├── pinyin │ │ ├── pinyinmigrator.json │ │ ├── CMakeLists.txt │ │ ├── pinyinmigrator.h │ │ └── pinyinmigrator.cpp │ ├── rime │ │ ├── rimemigrator.json │ │ ├── CMakeLists.txt │ │ ├── rimemigrator.h │ │ └── rimemigrator.cpp │ ├── table │ │ ├── tablemigrator.json │ │ ├── CMakeLists.txt │ │ ├── tablemigrator.h │ │ └── tablemigrator.cpp │ ├── lib │ │ ├── migrator.cpp │ │ ├── migratorfactoryplugin.cpp │ │ ├── log.cpp │ │ ├── pipelinejob.cpp │ │ ├── log.h │ │ ├── pipelinejob.h │ │ ├── migrator.h │ │ ├── renamefile.h │ │ ├── copydirectory.h │ │ ├── migratorfactory_p.h │ │ ├── renamefile.cpp │ │ ├── pipeline.h │ │ ├── migratorfactory.h │ │ ├── migratorfactoryplugin.h │ │ ├── dbuswatcher.h │ │ ├── callbackrunner.h │ │ ├── dbuscaller.h │ │ ├── CMakeLists.txt │ │ ├── callbackrunner.cpp │ │ ├── pipeline.cpp │ │ ├── configmigrator.h │ │ ├── dbuscaller.cpp │ │ ├── processrunner.h │ │ ├── dbuswatcher.cpp │ │ ├── processrunner.cpp │ │ ├── migratorfactory.cpp │ │ ├── configmigrator.cpp │ │ └── copydirectory.cpp │ ├── CMakeLists.txt │ └── app │ │ ├── org.fcitx.fcitx5-migrator.desktop.in │ │ ├── progresspage.ui │ │ ├── welcomepage.h │ │ ├── welcomepage.cpp │ │ ├── mainwindow.cpp │ │ ├── progresspage.h │ │ ├── CMakeLists.txt │ │ ├── taskpage.h │ │ ├── mainwindow.h │ │ ├── main.cpp │ │ ├── progresspage.cpp │ │ ├── welcomepage.ui │ │ └── taskpage.ui ├── lib │ ├── CMakeLists.txt │ ├── configlib │ │ ├── logging.cpp │ │ ├── logging.h │ │ ├── font.h │ │ ├── CMakeLists.txt │ │ ├── dbusprovider.h │ │ ├── iso639.h │ │ ├── dbusprovider.cpp │ │ ├── iso639.cpp │ │ ├── layoutprovider.h │ │ ├── font.cpp │ │ ├── layoutmodel.h │ │ └── imconfig.h │ └── configwidgetslib │ │ ├── categoryhelper.h │ │ ├── verticalscrollarea.h │ │ ├── varianthelper.h │ │ ├── fontbutton.h │ │ ├── erroroverlay.h │ │ ├── verticalscrollarea.cpp │ │ ├── CMakeLists.txt │ │ ├── listoptionwidget.h │ │ ├── keylistwidget.h │ │ ├── optionwidget.h │ │ ├── addonselector.h │ │ ├── layoutselector.h │ │ ├── impage.h │ │ ├── fontbutton.cpp │ │ ├── fontbutton.ui │ │ ├── configwidget.h │ │ ├── addonselector.ui │ │ ├── layoutselector.ui │ │ ├── erroroverlay.cpp │ │ ├── varianthelper.cpp │ │ ├── listoptionwidget.ui │ │ └── categoryhelper.cpp ├── configtool │ ├── org.fcitx.fcitx5-config-qt.desktop.in │ ├── CMakeLists.txt │ ├── mainwindow.ui │ ├── mainwindow.h │ └── main.cpp ├── CMakeLists.txt ├── kcm │ ├── CMakeLists.txt │ ├── ui │ │ ├── StringOption.qml │ │ ├── SaveWarningDialog.qml │ │ ├── BoolOption.qml │ │ ├── utils.js │ │ ├── ExternalOption.qml │ │ ├── IntegerOption.qml │ │ ├── FontOption.qml │ │ ├── ConfigPage.qml │ │ ├── ColorOption.qml │ │ ├── AddIMPage.qml │ │ ├── OptionLoader.qml │ │ ├── EnumOption.qml │ │ ├── ConfigGroup.qml │ │ ├── KeyListOption.qml │ │ └── SelectLayoutSheet.qml │ ├── kcm_fcitx5.json │ └── main.h └── plasmathemegenerator │ └── CMakeLists.txt ├── po ├── kcm_fcitx5 │ ├── CMakeLists.txt │ └── LINGUAS ├── fcitx5-configtool │ ├── CMakeLists.txt │ └── LINGUAS └── CMakeLists.txt ├── .gitignore ├── Messages.sh ├── layout ├── kbd-layout-viewer5.desktop.in ├── CMakeLists.txt ├── deadmapdata.h └── main.cpp ├── config.h.in ├── cmake ├── FindXKeyboardConfig.cmake ├── FindXKBCommon.cmake └── FindIsoCodes.cmake ├── README ├── README.md ├── .clang-format ├── .github └── workflows │ └── check.yml └── CMakeLists.txt /src/migrator/global/globalconfigmigrator.json: -------------------------------------------------------------------------------- 1 | {} 2 | 3 | -------------------------------------------------------------------------------- /po/kcm_fcitx5/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | fcitx5_install_translation(kcm_fcitx5) 2 | -------------------------------------------------------------------------------- /src/migrator/kkc/kkcmigrator.json: -------------------------------------------------------------------------------- 1 | { 2 | "addon": "kkc" 3 | } 4 | 5 | -------------------------------------------------------------------------------- /src/migrator/skk/skkmigrator.json: -------------------------------------------------------------------------------- 1 | { 2 | "addon": "skk" 3 | } 4 | 5 | -------------------------------------------------------------------------------- /src/migrator/pinyin/pinyinmigrator.json: -------------------------------------------------------------------------------- 1 | { 2 | "addon": "pinyin" 3 | } 4 | -------------------------------------------------------------------------------- /src/migrator/rime/rimemigrator.json: -------------------------------------------------------------------------------- 1 | { 2 | "addon": "skk" 3 | } 4 | 5 | -------------------------------------------------------------------------------- /src/migrator/table/tablemigrator.json: -------------------------------------------------------------------------------- 1 | { 2 | "addon": "table" 3 | } 4 | 5 | -------------------------------------------------------------------------------- /po/fcitx5-configtool/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | fcitx5_install_translation(fcitx5-configtool) 2 | -------------------------------------------------------------------------------- /po/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(fcitx5-configtool) 2 | add_subdirectory(kcm_fcitx5) 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/* 2 | *.kdev4 3 | .kdev_include_paths 4 | .directory 5 | *.kate-swp 6 | *.orig 7 | *~ 8 | .* -------------------------------------------------------------------------------- /po/fcitx5-configtool/LINGUAS: -------------------------------------------------------------------------------- 1 | 2 | ca 3 | da 4 | de 5 | fr 6 | he 7 | ja 8 | ko 9 | ru 10 | tr 11 | vi 12 | zh_CN 13 | zh_TW 14 | -------------------------------------------------------------------------------- /po/kcm_fcitx5/LINGUAS: -------------------------------------------------------------------------------- 1 | 2 | ca 3 | da 4 | de 5 | es 6 | fr 7 | he 8 | ja 9 | ko 10 | ru 11 | tr 12 | vi 13 | zh_CN 14 | zh_TW 15 | -------------------------------------------------------------------------------- /src/lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(configlib) 2 | 3 | if (ENABLE_CONFIG_QT) 4 | add_subdirectory(configwidgetslib) 5 | endif() 6 | -------------------------------------------------------------------------------- /src/migrator/lib/migrator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #include "migrator.h" 8 | -------------------------------------------------------------------------------- /src/migrator/lib/migratorfactoryplugin.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #include "migratorfactoryplugin.h" 8 | -------------------------------------------------------------------------------- /Messages.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | gen_pot kde:appdata:desktop:ui fcitx5-configtool po/fcitx5-configtool layout/ src/configtool/ src/lib/ src/migrator/ 4 | gen_pot kde:appdata:desktop:ui kcm_fcitx5 po/kcm_fcitx5 src/kcm/ src/plasmathemegenerator/ 5 | -------------------------------------------------------------------------------- /src/migrator/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(app) 2 | add_subdirectory(lib) 3 | add_subdirectory(pinyin) 4 | add_subdirectory(skk) 5 | add_subdirectory(kkc) 6 | add_subdirectory(rime) 7 | add_subdirectory(global) 8 | add_subdirectory(table) 9 | -------------------------------------------------------------------------------- /src/migrator/app/org.fcitx.fcitx5-migrator.desktop.in: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Fcitx 5 Migration Wizard 3 | Comment=Import data from other input method such as Fcitx 4 4 | Icon=fcitx 5 | Exec=fcitx5-migrator 6 | Type=Application 7 | Categories=Settings; 8 | -------------------------------------------------------------------------------- /src/lib/configlib/logging.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017~2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #include "logging.h" 8 | 9 | Q_LOGGING_CATEGORY(KCM_FCITX5, "fcitx5-config") 10 | -------------------------------------------------------------------------------- /layout/kbd-layout-viewer5.desktop.in: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Exec=kbd-layout-viewer5 3 | Icon=input-keyboard 4 | Type=Application 5 | 6 | Name=Keyboard layout viewer 7 | Comment=View keyboard layout 8 | 9 | X-KDE-Keywords=keyboard;input;im 10 | 11 | Categories=Qt;KDE;Utility; 12 | -------------------------------------------------------------------------------- /src/migrator/kkc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(kkcmigrator STATIC kkcmigrator.cpp) 2 | target_link_libraries(kkcmigrator Fcitx5Migrator) 3 | target_compile_definitions(kkcmigrator PRIVATE "-DQT_STATICPLUGIN") 4 | set_target_properties(kkcmigrator PROPERTIES POSITION_INDEPENDENT_CODE TRUE) 5 | 6 | -------------------------------------------------------------------------------- /src/migrator/skk/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(skkmigrator STATIC skkmigrator.cpp) 2 | target_link_libraries(skkmigrator Fcitx5Migrator) 3 | target_compile_definitions(skkmigrator PRIVATE "-DQT_STATICPLUGIN") 4 | set_target_properties(skkmigrator PROPERTIES POSITION_INDEPENDENT_CODE TRUE) 5 | 6 | -------------------------------------------------------------------------------- /src/configtool/org.fcitx.fcitx5-config-qt.desktop.in: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Fcitx 5 Configuration 3 | GenericName=Input Method Configuration 4 | Comment=Change Fcitx 5 Configuration 5 | Icon=fcitx 6 | Exec=fcitx5-config-qt 7 | Type=Application 8 | Categories=Settings; 9 | NoDisplay=true 10 | -------------------------------------------------------------------------------- /src/migrator/rime/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(rimemigrator STATIC rimemigrator.cpp) 2 | target_link_libraries(rimemigrator Fcitx5Migrator) 3 | target_compile_definitions(rimemigrator PRIVATE "-DQT_STATICPLUGIN") 4 | set_target_properties(rimemigrator PROPERTIES POSITION_INDEPENDENT_CODE TRUE) 5 | 6 | -------------------------------------------------------------------------------- /src/migrator/pinyin/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(pinyinmigrator STATIC pinyinmigrator.cpp) 2 | target_link_libraries(pinyinmigrator Fcitx5Migrator) 3 | target_compile_definitions(pinyinmigrator PRIVATE "-DQT_STATICPLUGIN") 4 | set_target_properties(pinyinmigrator PROPERTIES POSITION_INDEPENDENT_CODE TRUE) 5 | -------------------------------------------------------------------------------- /src/migrator/table/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(tablemigrator STATIC tablemigrator.cpp) 2 | target_link_libraries(tablemigrator Fcitx5Migrator) 3 | target_compile_definitions(tablemigrator PRIVATE "-DQT_STATICPLUGIN") 4 | set_target_properties(tablemigrator PROPERTIES POSITION_INDEPENDENT_CODE TRUE) 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if (ENABLE_KCM) 2 | add_subdirectory(kcm) 3 | endif() 4 | add_subdirectory(lib) 5 | 6 | if (ENABLE_CONFIG_QT) 7 | add_subdirectory(configtool) 8 | endif() 9 | 10 | add_subdirectory(migrator) 11 | 12 | if (ENABLE_KCM) 13 | add_subdirectory(plasmathemegenerator) 14 | endif() 15 | -------------------------------------------------------------------------------- /src/migrator/lib/log.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018-2018 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | 8 | #include "log.h" 9 | 10 | namespace fcitx { 11 | 12 | Q_LOGGING_CATEGORY(migrator, "migrator") 13 | 14 | } // namespace fcitx 15 | -------------------------------------------------------------------------------- /src/migrator/global/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(globalconfigmigrator STATIC globalconfigmigrator.cpp) 2 | target_link_libraries(globalconfigmigrator Fcitx5Migrator) 3 | target_compile_definitions(globalconfigmigrator PRIVATE "-DQT_STATICPLUGIN") 4 | set_target_properties(globalconfigmigrator PROPERTIES POSITION_INDEPENDENT_CODE TRUE) 5 | 6 | -------------------------------------------------------------------------------- /src/migrator/lib/pipelinejob.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018-2018 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #include "pipelinejob.h" 8 | 9 | namespace fcitx { 10 | 11 | PipelineJob::PipelineJob(QObject *parent) : QObject(parent) {} 12 | 13 | } // namespace fcitx 14 | -------------------------------------------------------------------------------- /src/kcm/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | kcmutils_add_qml_kcm(kcm_fcitx5 SOURCES main.cpp) 2 | target_link_libraries(kcm_fcitx5 KF${QT_MAJOR_VERSION}::KCMUtilsQuick) 3 | 4 | target_link_libraries(kcm_fcitx5 5 | Qt${QT_MAJOR_VERSION}::Quick 6 | KF${QT_MAJOR_VERSION}::CoreAddons 7 | KF${QT_MAJOR_VERSION}::I18n 8 | XKBCommon::XKBCommon 9 | configlib 10 | ) 11 | -------------------------------------------------------------------------------- /src/lib/configlib/logging.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017~2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | #ifndef _KCM_FCITX_LOGGING_H_ 7 | #define _KCM_FCITX_LOGGING_H_ 8 | 9 | #include 10 | 11 | Q_DECLARE_LOGGING_CATEGORY(KCM_FCITX5) 12 | 13 | #endif // _KCM_FCITX_LOGGING_H_ 14 | -------------------------------------------------------------------------------- /src/migrator/lib/log.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018-2018 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _PINYINDICTMANAGER_LOG_H_ 8 | #define _PINYINDICTMANAGER_LOG_H_ 9 | 10 | #include 11 | 12 | namespace fcitx { 13 | 14 | Q_DECLARE_LOGGING_CATEGORY(migrator) 15 | 16 | } // namespace fcitx 17 | 18 | #endif // _PINYINDICTMANAGER_LOG_H_ 19 | -------------------------------------------------------------------------------- /src/plasmathemegenerator/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(fcitx5-plasma-theme-generator main.cpp) 2 | 3 | target_link_libraries(fcitx5-plasma-theme-generator 4 | KF${QT_MAJOR_VERSION}::IconThemes 5 | KF${QT_MAJOR_VERSION}::I18n 6 | Fcitx5::Utils 7 | Fcitx5::Config) 8 | 9 | target_link_libraries(fcitx5-plasma-theme-generator 10 | Plasma::Plasma 11 | KF${QT_MAJOR_VERSION}::Svg) 12 | 13 | install(TARGETS fcitx5-plasma-theme-generator DESTINATION ${CMAKE_INSTALL_BINDIR}) 14 | -------------------------------------------------------------------------------- /src/lib/configlib/font.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #ifndef _CONFIGLIB_FONT_H_ 8 | #define _CONFIGLIB_FONT_H_ 9 | 10 | #include 11 | #include 12 | 13 | namespace fcitx { 14 | namespace kcm { 15 | 16 | QFont parseFont(const QString &str); 17 | QString fontToString(const QFont &font); 18 | 19 | } // namespace kcm 20 | } // namespace fcitx 21 | 22 | #endif // _CONFIGLIB_FONT_H_ 23 | -------------------------------------------------------------------------------- /src/migrator/app/progresspage.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | ProgressPage 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/lib/configwidgetslib/categoryhelper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017~2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #ifndef _KCM_FCITX5_CATEGORYHELPER_H_ 8 | #define _KCM_FCITX5_CATEGORYHELPER_H_ 9 | 10 | #include 11 | #include 12 | 13 | namespace fcitx { 14 | namespace kcm { 15 | 16 | void paintCategoryHeader(QPainter *painter, const QStyleOptionViewItem &option, 17 | const QModelIndex &index); 18 | 19 | QSize categoryHeaderSizeHint(); 20 | 21 | } // namespace kcm 22 | } // namespace fcitx 23 | 24 | #endif // _KCM_FCITX5_CATEGORYHELPER_H_ 25 | -------------------------------------------------------------------------------- /config.h.in: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017~2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | #ifndef _KCM_FCITX5_CONFIG_H_ 7 | #define _KCM_FCITX5_CONFIG_H_ 8 | 9 | #cmakedefine PROJECT_VERSION "@PROJECT_VERSION@" 10 | #cmakedefine XKEYBOARDCONFIG_XKBBASE "@XKEYBOARDCONFIG_XKBBASE@" 11 | #cmakedefine ISOCODES_ISO639_2_JSON "@ISOCODES_ISO639_2_JSON@" 12 | #cmakedefine ISOCODES_ISO639_3_JSON "@ISOCODES_ISO639_3_JSON@" 13 | #cmakedefine ISOCODES_ISO639_5_JSON "@ISOCODES_ISO639_5_JSON@" 14 | #cmakedefine CONFIG_QT_UNIQUE_APP_SUPPORT 15 | 16 | #define FCITX5_QT_GUI_WRAPPER "@FCITX5_QT_GUI_WRAPPER@" 17 | 18 | #endif // _KCM_FCITX5_CONFIG_H_ 19 | -------------------------------------------------------------------------------- /cmake/FindXKeyboardConfig.cmake: -------------------------------------------------------------------------------- 1 | find_package(PkgConfig) 2 | 3 | pkg_check_modules(PKG_XKEYBOARDCONFIG QUIET xkeyboard-config) 4 | 5 | pkg_get_variable(XKEYBOARDCONFIG_XKBBASE xkeyboard-config xkb_base) 6 | pkg_get_variable(XKEYBOARDCONFIG_DATADIR xkeyboard-config datadir) 7 | 8 | set(XKEYBOARDCONFIG_VERSION ${PKG_XKEYBOARDCONFIG_VERSION}) 9 | mark_as_advanced(XKEYBOARDCONFIG_VERSION) 10 | 11 | include(FindPackageHandleStandardArgs) 12 | find_package_handle_standard_args(XKeyboardConfig 13 | FOUND_VAR 14 | XKEYBOARDCONFIG_FOUND 15 | REQUIRED_VARS 16 | XKEYBOARDCONFIG_XKBBASE 17 | XKEYBOARDCONFIG_DATADIR 18 | VERSION_VAR 19 | XKEYBOARDCONFIG_VERSION 20 | ) 21 | -------------------------------------------------------------------------------- /src/kcm/ui/StringOption.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | import QtQuick 8 | import QtQuick.Controls 9 | 10 | TextField { 11 | property string typeName 12 | property string description 13 | property variant defaultValue 14 | property variant properties 15 | property string rawValue 16 | property bool needsSave: text !== rawValue 17 | 18 | function load(rawValue) { 19 | text = rawValue; 20 | } 21 | function save() { 22 | rawValue = text; 23 | } 24 | 25 | Component.onCompleted: { 26 | load(rawValue); 27 | save(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/lib/configwidgetslib/verticalscrollarea.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017~2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #ifndef _KCM_FCITX_VERTICALSCROLLAREA_H_ 8 | #define _KCM_FCITX_VERTICALSCROLLAREA_H_ 9 | 10 | #include 11 | namespace fcitx { 12 | namespace kcm { 13 | class VerticalScrollArea : public QScrollArea { 14 | Q_OBJECT 15 | public: 16 | explicit VerticalScrollArea(QWidget *parent = 0); 17 | void setWidget(QWidget *widget); 18 | 19 | protected: 20 | bool eventFilter(QObject *o, QEvent *e) override; 21 | }; 22 | 23 | } // namespace kcm 24 | } // namespace fcitx 25 | 26 | #endif // _KCM_FCITX_VERTICALSCROLLAREA_H_ 27 | -------------------------------------------------------------------------------- /src/migrator/app/welcomepage.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #ifndef _FCITX5_CONFIGTOOL_MIGRATOR_APP_WELCOMEPAGE_H_ 8 | #define _FCITX5_CONFIGTOOL_MIGRATOR_APP_WELCOMEPAGE_H_ 9 | 10 | #include "ui_welcomepage.h" 11 | 12 | namespace fcitx { 13 | 14 | class MainWindow; 15 | 16 | class WelcomePage : public QWizardPage, private Ui::WelcomePage { 17 | Q_OBJECT 18 | public: 19 | explicit WelcomePage(MainWindow *parent); 20 | 21 | bool isComplete() const override; 22 | 23 | private: 24 | MainWindow *parent_; 25 | }; 26 | 27 | } // namespace fcitx 28 | 29 | #endif // _FCITX5_CONFIGTOOL_MIGRATOR_APP_WELCOMEPAGE_H_ 30 | -------------------------------------------------------------------------------- /src/kcm/ui/SaveWarningDialog.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | import QtQuick 8 | import QtQuick.Controls 9 | 10 | Dialog { 11 | id: notSavedDialog 12 | closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent 13 | focus: true 14 | modal: true 15 | standardButtons: Dialog.Ok 16 | title: i18n("Some config is not saved") 17 | x: (parent.width - width) / 2 18 | y: parent.height / 2 - height 19 | 20 | Label { 21 | text: i18n("Current page is not yet saved. Please save the config first.") 22 | } 23 | 24 | Overlay.modal: Rectangle { 25 | color: "#99000000" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/lib/configwidgetslib/varianthelper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017~2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #ifndef _KCM_FCITX5_VARIANTHELPER_H_ 8 | #define _KCM_FCITX5_VARIANTHELPER_H_ 9 | 10 | #include 11 | #include 12 | 13 | namespace fcitx { 14 | namespace kcm { 15 | 16 | QVariant readVariant(const QVariant &value, const QString &path); 17 | 18 | bool readBool(const QVariantMap &map, const QString &path); 19 | 20 | QString readString(const QVariantMap &map, const QString &path); 21 | 22 | void writeVariant(QVariantMap &map, const QString &path, const QVariant &value); 23 | 24 | } // namespace kcm 25 | } // namespace fcitx 26 | 27 | #endif // _KCM_FCITX5_VARIANTHELPER_H_ 28 | -------------------------------------------------------------------------------- /src/kcm/ui/BoolOption.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | import QtQuick 8 | import QtQuick.Controls 9 | 10 | CheckBox { 11 | property string typeName 12 | property string description 13 | property variant defaultValue 14 | property variant properties 15 | property variant rawValue 16 | property bool needsSave: value !== checked 17 | property bool value: rawValue === "True" 18 | 19 | function load(rawValue) { 20 | checked = rawValue === "True"; 21 | } 22 | function save() { 23 | rawValue = checked ? "True" : "False"; 24 | } 25 | 26 | Component.onCompleted: { 27 | load(rawValue); 28 | save(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/lib/configlib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(configlib STATIC 2 | iso639.cpp 3 | dbusprovider.cpp 4 | model.cpp 5 | addonmodel.cpp 6 | imconfig.cpp 7 | logging.cpp 8 | font.cpp 9 | layoutmodel.cpp 10 | layoutprovider.cpp 11 | ) 12 | set_target_properties(configlib PROPERTIES 13 | POSITION_INDEPENDENT_CODE TRUE 14 | AUTOMOC TRUE 15 | AUTOUIC TRUE 16 | AUTOUIC_OPTIONS "-tr=fcitx::tr2fcitx;--include=fcitxqti18nhelper.h" 17 | ) 18 | target_include_directories(configlib INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) 19 | target_link_libraries(configlib 20 | Qt${QT_MAJOR_VERSION}::Core Qt${QT_MAJOR_VERSION}::Gui Fcitx5Qt${QT_MAJOR_VERSION}::DBusAddons 21 | Fcitx5::Core Fcitx5::Utils 22 | Fcitx5Qt${QT_MAJOR_VERSION}::WidgetsAddons 23 | ) 24 | 25 | -------------------------------------------------------------------------------- /src/migrator/lib/pipelinejob.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018-2018 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _PINYINDICTMANAGER_PIPELINEJOB_H_ 8 | #define _PINYINDICTMANAGER_PIPELINEJOB_H_ 9 | 10 | #include "fcitx5migrator_export.h" 11 | #include 12 | 13 | namespace fcitx { 14 | 15 | class FCITX5MIGRATOR_EXPORT PipelineJob : public QObject { 16 | Q_OBJECT 17 | public: 18 | PipelineJob(QObject *parent = nullptr); 19 | 20 | virtual void start() = 0; 21 | virtual void abort() = 0; 22 | virtual void cleanUp() = 0; 23 | 24 | Q_SIGNALS: 25 | void finished(bool success); 26 | void message(const QString &icon, const QString &message); 27 | }; 28 | 29 | } // namespace fcitx 30 | 31 | #endif // _PINYINDICTMANAGER_PIPELINEJOB_H_ 32 | -------------------------------------------------------------------------------- /src/migrator/lib/migrator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #ifndef _FCITX5_CONFIGTOOL_MIGRATOR_LIB_MIGRATOR_H_ 8 | #define _FCITX5_CONFIGTOOL_MIGRATOR_LIB_MIGRATOR_H_ 9 | 10 | #include "fcitx5migrator_export.h" 11 | #include 12 | 13 | namespace fcitx { 14 | 15 | class Pipeline; 16 | 17 | class FCITX5MIGRATOR_EXPORT Migrator : public QObject { 18 | public: 19 | virtual QString name() const = 0; 20 | virtual QString description() const = 0; 21 | virtual bool check() const = 0; 22 | 23 | virtual bool hasOfflineJob() const = 0; 24 | virtual void addOfflineJob(Pipeline *) {} 25 | virtual void addOnlineJob(Pipeline *) {} 26 | }; 27 | 28 | } // namespace fcitx 29 | 30 | #endif // _FCITX5_CONFIGTOOL_MIGRATOR_LIB_MIGRATOR_H_ 31 | -------------------------------------------------------------------------------- /src/migrator/app/welcomepage.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #include "welcomepage.h" 8 | #include "mainwindow.h" 9 | 10 | namespace fcitx { 11 | 12 | WelcomePage::WelcomePage(MainWindow *parent) 13 | : QWizardPage(parent), parent_(parent) { 14 | setupUi(this); 15 | fcitxNotRunningMessage->setVisible(!parent_->dbus()->available()); 16 | 17 | connect(parent->dbus(), &kcm::DBusProvider::availabilityChanged, this, 18 | &QWizardPage::completeChanged); 19 | connect(parent->dbus(), &kcm::DBusProvider::availabilityChanged, this, 20 | [this](bool avail) { fcitxNotRunningMessage->setVisible(!avail); }); 21 | } 22 | 23 | bool WelcomePage::isComplete() const { return parent_->dbus()->available(); } 24 | } // namespace fcitx 25 | -------------------------------------------------------------------------------- /src/migrator/lib/renamefile.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018-2018 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _PINYINDICTMANAGER_RENAMEFILE_H_ 8 | #define _PINYINDICTMANAGER_RENAMEFILE_H_ 9 | 10 | #include "pipelinejob.h" 11 | #include 12 | 13 | namespace fcitx { 14 | 15 | class FCITX5MIGRATOR_EXPORT RenameFile : public PipelineJob { 16 | Q_OBJECT 17 | public: 18 | explicit RenameFile(const QString &from, const QString &to, 19 | QObject *parent = nullptr); 20 | void start() override; 21 | void abort() override; 22 | void cleanUp() override; 23 | 24 | private Q_SLOTS: 25 | void emitFinished(bool result); 26 | 27 | private: 28 | QString from_, to_; 29 | }; 30 | 31 | } // namespace fcitx 32 | 33 | #endif // _PINYINDICTMANAGER_RENAMEFILE_H_ 34 | -------------------------------------------------------------------------------- /src/lib/configwidgetslib/fontbutton.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2012~2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | #ifndef _KCM_FCITX_FONTBUTTON_H_ 7 | #define _KCM_FCITX_FONTBUTTON_H_ 8 | 9 | #include "ui_fontbutton.h" 10 | 11 | namespace fcitx { 12 | namespace kcm { 13 | 14 | class FontButton : public QWidget, public Ui::FontButton { 15 | Q_OBJECT 16 | public: 17 | explicit FontButton(QWidget *parent = 0); 18 | virtual ~FontButton(); 19 | const QFont &font(); 20 | QString fontName(); 21 | 22 | public Q_SLOTS: 23 | void setFont(const QFont &font); 24 | Q_SIGNALS: 25 | void fontChanged(const QFont &font); 26 | private Q_SLOTS: 27 | void selectFont(); 28 | 29 | private: 30 | QFont font_; 31 | }; 32 | 33 | } // namespace kcm 34 | } // namespace fcitx 35 | 36 | #endif // _KCM_FCITX_FONTBUTTON_H_ 37 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | fcitx5-configtool 2 | ============================================== 3 | 4 | [![Jenkins Build Status](https://img.shields.io/jenkins/s/https/jenkins.fcitx-im.org/job/fcitx5-configtool.svg)](https://jenkins.fcitx-im.org/job/fcitx5-configtool/) 5 | 6 | fcitx5-configtool is a Qt-based GUI tool that provides a user-friendly configuration interface for Fcitx 5. It has two different implementations: one based on QWidget, which can be accessed via fcitx5-config-qt, and the other based on KCM/Kirigami2, which can be found in Plasma systemsettings. 7 | 8 | ## Installation 9 | 10 | To install fcitx5-configtool, follow these steps: 11 | 12 | Install Fcitx 5. 13 | Install the fcitx5-configtool package. 14 | 15 | ## Usage 16 | 17 | To use fcitx5-configtool, follow these steps: 18 | 19 | Start fcitx5. 20 | Run fcitx5-configtool. 21 | Select and add your preferred input method from the “Available Input Methods” panel. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | fcitx5-configtool 2 | ============================================== 3 | 4 | [![Jenkins Build Status](https://img.shields.io/jenkins/s/https/jenkins.fcitx-im.org/job/fcitx5-configtool.svg)](https://jenkins.fcitx-im.org/job/fcitx5-configtool/) 5 | 6 | fcitx5-configtool is a Qt-based GUI tool that provides a user-friendly configuration interface for Fcitx 5. It has two different implementations: one based on QWidget, which can be accessed via fcitx5-config-qt, and the other based on KCM/Kirigami2, which can be found in Plasma systemsettings. 7 | 8 | ## Installation 9 | 10 | To install fcitx5-configtool, follow these steps: 11 | 12 | Install Fcitx 5. 13 | Install the fcitx5-configtool package. 14 | 15 | ## Usage 16 | 17 | To use fcitx5-configtool, follow these steps: 18 | 19 | Start fcitx5. 20 | Run fcitx5-configtool. 21 | Select and add your preferred input method from the “Available Input Methods” panel. -------------------------------------------------------------------------------- /src/migrator/app/mainwindow.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #include "mainwindow.h" 8 | #include "progresspage.h" 9 | #include "taskpage.h" 10 | #include "welcomepage.h" 11 | #include 12 | 13 | namespace fcitx { 14 | 15 | MainWindow::MainWindow(QWidget *parent) 16 | : QWizard(parent), dbus_(this), welcomePage_(new WelcomePage(this)), 17 | taskPage_(new TaskPage(this)), progressPage_(new ProgressPage(this)) { 18 | addPage(welcomePage_); 19 | addPage(taskPage_); 20 | addPage(progressPage_); 21 | setMinimumSize(QSize(700, 480)); 22 | setWindowIcon(QIcon::fromTheme("fcitx")); 23 | setWindowTitle(_("Migration Tool")); 24 | } 25 | 26 | Pipeline *MainWindow::createPipeline() { return taskPage_->createPipeline(); } 27 | 28 | } // namespace fcitx 29 | -------------------------------------------------------------------------------- /src/migrator/lib/copydirectory.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX5_CONFIGTOOL_MIGRATOR_LIB_COPYDIRECTORY_H_ 8 | #define _FCITX5_CONFIGTOOL_MIGRATOR_LIB_COPYDIRECTORY_H_ 9 | 10 | #include "callbackrunner.h" 11 | #include 12 | #include 13 | 14 | namespace fcitx { 15 | 16 | class FCITX5MIGRATOR_EXPORT CopyDirectory : public CallbackRunner { 17 | Q_OBJECT 18 | public: 19 | explicit CopyDirectory(const QString &from, const QString &to, 20 | QObject *parent = nullptr); 21 | 22 | void setExcludes(const QStringList &excludes) { excludes_ = excludes; } 23 | 24 | private: 25 | QString from_, to_; 26 | QStringList excludes_; 27 | }; 28 | 29 | } // namespace fcitx 30 | 31 | #endif // _FCITX5_CONFIGTOOL_MIGRATOR_LIB_COPYDIRECTORY_H_ 32 | -------------------------------------------------------------------------------- /src/kcm/ui/utils.js: -------------------------------------------------------------------------------- 1 | function hasProperty(obj, key) { 2 | return Object.prototype.hasOwnProperty.call(obj, key); 3 | } 4 | 5 | function getRawValue(rawValue, name) { 6 | if (name.length == 0) { 7 | return ""; 8 | } 9 | if (rawValue === null) { 10 | return ""; 11 | } 12 | for (var i = 0; i < name.length; i++) { 13 | if (hasProperty(rawValue, name[i])) { 14 | rawValue = rawValue[name[i]]; 15 | } else { 16 | return ""; 17 | } 18 | } 19 | return rawValue; 20 | } 21 | 22 | function setRawValue(rawValue, name, value) { 23 | for (var i = 0; i < name.length; i++) { 24 | if (i + 1 == name.length) { 25 | rawValue[name[i]] = value; 26 | } else { 27 | if (!hasProperty(rawValue, name[i])) { 28 | rawValue[name[i]] = {}; 29 | } 30 | rawValue = rawValue[name[i]]; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/migrator/app/progresspage.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #ifndef _FCITX5_CONFIGTOOL_MIGRATOR_APP_PROGRESSPAGE_H_ 8 | #define _FCITX5_CONFIGTOOL_MIGRATOR_APP_PROGRESSPAGE_H_ 9 | 10 | #include "pipeline.h" 11 | #include "ui_progresspage.h" 12 | #include 13 | 14 | namespace fcitx { 15 | 16 | class MainWindow; 17 | 18 | class ProgressPage : public QWizardPage, public Ui::ProgressPage { 19 | Q_OBJECT 20 | public: 21 | explicit ProgressPage(MainWindow *parent); 22 | 23 | bool isComplete() const override; 24 | void initializePage() override; 25 | 26 | void appendMessage(const QString &icon, const QString &message); 27 | 28 | private: 29 | MainWindow *parent_; 30 | Pipeline *pipeline_ = nullptr; 31 | bool done_ = false; 32 | }; 33 | 34 | } // namespace fcitx 35 | 36 | #endif // _FCITX5_CONFIGTOOL_MIGRATOR_APP_PROGRESSPAGE_H_ 37 | -------------------------------------------------------------------------------- /src/migrator/lib/migratorfactory_p.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #ifndef _FCITX5_CONFIGTOOL_MIGRATOR_LIB_MIGRATORFACTORY_P_H_ 8 | #define _FCITX5_CONFIGTOOL_MIGRATOR_LIB_MIGRATORFACTORY_P_H_ 9 | 10 | #include "migratorfactory.h" 11 | #include "migratorfactoryplugin.h" 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace fcitx { 19 | 20 | class MigratorFactoryPrivate : public QObject { 21 | Q_OBJECT 22 | public: 23 | MigratorFactoryPrivate(MigratorFactory *factory); 24 | virtual ~MigratorFactoryPrivate(); 25 | MigratorFactory *const q_ptr; 26 | Q_DECLARE_PUBLIC(MigratorFactory); 27 | 28 | private: 29 | void scan(); 30 | std::vector> plugins_; 31 | }; 32 | } // namespace fcitx 33 | 34 | #endif // _FCITX5_CONFIGTOOL_MIGRATOR_LIB_MIGRATORFACTORY_P_H_ 35 | -------------------------------------------------------------------------------- /src/configtool/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(configtool_SRCS 2 | main.cpp 3 | mainwindow.cpp 4 | ) 5 | 6 | add_executable(fcitx5-config-qt ${configtool_SRCS}) 7 | set_target_properties(fcitx5-config-qt 8 | PROPERTIES 9 | AUTOMOC TRUE 10 | AUTOUIC TRUE 11 | AUTOUIC_OPTIONS "-tr=fcitx::tr2fcitx;--include=fcitxqti18nhelper.h") 12 | 13 | target_link_libraries(fcitx5-config-qt 14 | Qt${QT_MAJOR_VERSION}::Widgets 15 | configwidgetslib 16 | ) 17 | 18 | if (CONFIG_QT_UNIQUE_APP_SUPPORT) 19 | target_link_libraries(fcitx5-config-qt 20 | KF${QT_MAJOR_VERSION}::DBusAddons 21 | KF${QT_MAJOR_VERSION}::WindowSystem 22 | ) 23 | endif() 24 | 25 | install(TARGETS fcitx5-config-qt DESTINATION ${CMAKE_INSTALL_BINDIR}) 26 | fcitx5_translate_desktop_file(org.fcitx.fcitx5-config-qt.desktop.in 27 | org.fcitx.fcitx5-config-qt.desktop PO_DIRECTORY ${PROJECT_SOURCE_DIR}/po/fcitx5-configtool) 28 | install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.fcitx.fcitx5-config-qt.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) 29 | -------------------------------------------------------------------------------- /src/migrator/lib/renamefile.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018-2018 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #include "renamefile.h" 8 | #include 9 | 10 | namespace fcitx { 11 | 12 | RenameFile::RenameFile(const QString &from, const QString &to, QObject *parent) 13 | : PipelineJob(parent), from_(from), to_(to) {} 14 | 15 | void RenameFile::start() { 16 | bool result = ::rename(from_.toLocal8Bit().constData(), 17 | to_.toLocal8Bit().constData()) >= 0; 18 | QMetaObject::invokeMethod(this, "emitFinished", Qt::QueuedConnection, 19 | Q_ARG(bool, result)); 20 | } 21 | 22 | void RenameFile::abort() {} 23 | 24 | void RenameFile::cleanUp() {} 25 | 26 | void RenameFile::emitFinished(bool result) { 27 | if (!result) { 28 | Q_EMIT message("dialog-error", _("Converter crashed.")); 29 | return; 30 | } 31 | Q_EMIT finished(result); 32 | } 33 | 34 | } // namespace fcitx 35 | -------------------------------------------------------------------------------- /src/migrator/lib/pipeline.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018-2018 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _PINYINDICTMANAGER_PIPELINE_H_ 8 | #define _PINYINDICTMANAGER_PIPELINE_H_ 9 | 10 | #include "fcitx5migrator_export.h" 11 | #include "pipelinejob.h" 12 | #include 13 | 14 | namespace fcitx { 15 | 16 | class FCITX5MIGRATOR_EXPORT Pipeline : public QObject { 17 | Q_OBJECT 18 | public: 19 | Pipeline(QObject *parent = nullptr); 20 | 21 | void addJob(PipelineJob *job); 22 | void start(); 23 | void abort(); 24 | void reset(); 25 | const std::vector &jobs() { return jobs_; } 26 | 27 | Q_SIGNALS: 28 | void finished(bool); 29 | void message(const QString &icon, const QString &message); 30 | 31 | private: 32 | void startNext(); 33 | void emitFinished(bool); 34 | 35 | std::vector jobs_; 36 | int index_ = -1; 37 | }; 38 | 39 | } // namespace fcitx 40 | 41 | #endif // _PINYINDICTMANAGER_PIPELINE_H_ 42 | -------------------------------------------------------------------------------- /src/migrator/app/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(fcitx5-migrator main.cpp mainwindow.cpp welcomepage.cpp taskpage.cpp progresspage.cpp) 2 | set_target_properties(fcitx5-migrator PROPERTIES 3 | AUTOMOC TRUE 4 | AUTOUIC TRUE 5 | AUTOUIC_OPTIONS "-tr=fcitx::tr2fcitx;--include=fcitxqti18nhelper.h") 6 | target_link_libraries(fcitx5-migrator 7 | pinyinmigrator 8 | skkmigrator 9 | rimemigrator 10 | kkcmigrator 11 | globalconfigmigrator 12 | tablemigrator 13 | Qt${QT_MAJOR_VERSION}::Widgets 14 | KF${QT_MAJOR_VERSION}::WidgetsAddons 15 | configlib 16 | Fcitx5Migrator 17 | Fcitx5Qt${QT_MAJOR_VERSION}::WidgetsAddons 18 | Fcitx5Qt${QT_MAJOR_VERSION}::DBusAddons) 19 | install(TARGETS fcitx5-migrator DESTINATION ${CMAKE_INSTALL_BINDIR}) 20 | 21 | fcitx5_translate_desktop_file(org.fcitx.fcitx5-migrator.desktop.in 22 | org.fcitx.fcitx5-migrator.desktop PO_DIRECTORY ${PROJECT_SOURCE_DIR}/po/fcitx5-configtool) 23 | install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.fcitx.fcitx5-migrator.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications) 24 | -------------------------------------------------------------------------------- /src/migrator/app/taskpage.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #ifndef _FCITX5_CONFIGTOOL_MIGRATOR_APP_TASKPAGE_H_ 8 | #define _FCITX5_CONFIGTOOL_MIGRATOR_APP_TASKPAGE_H_ 9 | 10 | #include "pipeline.h" 11 | #include "ui_taskpage.h" 12 | #include 13 | 14 | namespace fcitx { 15 | 16 | class MainWindow; 17 | class TaskModel; 18 | 19 | class TaskPage : public QWizardPage, private Ui::TaskPage { 20 | Q_OBJECT 21 | public: 22 | explicit TaskPage(MainWindow *parent); 23 | 24 | bool isComplete() const override; 25 | 26 | void initializePage() override; 27 | bool validatePage() override; 28 | 29 | Pipeline *createPipeline(); 30 | 31 | private Q_SLOTS: 32 | void availabilityChanged(bool avail); 33 | 34 | private: 35 | MainWindow *parent_; 36 | FcitxQtControllerProxy *proxy_; 37 | TaskModel *model_; 38 | }; 39 | 40 | } // namespace fcitx 41 | 42 | #endif // _FCITX5_CONFIGTOOL_MIGRATOR_APP_TASKPAGE_H_ 43 | -------------------------------------------------------------------------------- /src/migrator/rime/rimemigrator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX5_CONFIGTOOL_MIGRATOR_RIME_RIMEMIGRATOR_H_ 8 | #define _FCITX5_CONFIGTOOL_MIGRATOR_RIME_RIMEMIGRATOR_H_ 9 | 10 | #include "migrator.h" 11 | #include "migratorfactoryplugin.h" 12 | 13 | namespace fcitx { 14 | 15 | class RimeMigrator : public Migrator { 16 | Q_OBJECT 17 | public: 18 | QString name() const override; 19 | QString description() const override; 20 | bool check() const override; 21 | bool hasOfflineJob() const override { return true; } 22 | void addOfflineJob(Pipeline *pipeline) override; 23 | }; 24 | 25 | class RimeMigratorPlugin : public FcitxMigratorFactoryPlugin { 26 | Q_OBJECT 27 | public: 28 | Q_PLUGIN_METADATA(IID FcitxMigratorFactoryInterface_iid FILE 29 | "rimemigrator.json") 30 | RimeMigrator *create() override; 31 | }; 32 | 33 | } // namespace fcitx 34 | 35 | #endif // _FCITX5_CONFIGTOOL_MIGRATOR_RIME_RIMEMIGRATOR_H_ 36 | -------------------------------------------------------------------------------- /src/migrator/table/tablemigrator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX5_CONFIGTOOL_MIGRATOR_SKK_SKKMIGRATOR_H_ 8 | #define _FCITX5_CONFIGTOOL_MIGRATOR_SKK_SKKMIGRATOR_H_ 9 | 10 | #include "migrator.h" 11 | #include "migratorfactoryplugin.h" 12 | 13 | namespace fcitx { 14 | 15 | class TableMigrator : public Migrator { 16 | Q_OBJECT 17 | public: 18 | QString name() const override; 19 | QString description() const override; 20 | bool check() const override; 21 | bool hasOfflineJob() const override { return true; } 22 | void addOfflineJob(Pipeline *pipeline) override; 23 | }; 24 | 25 | class TableMigratorPlugin : public FcitxMigratorFactoryPlugin { 26 | Q_OBJECT 27 | public: 28 | Q_PLUGIN_METADATA(IID FcitxMigratorFactoryInterface_iid FILE 29 | "tablemigrator.json") 30 | TableMigrator *create() override; 31 | }; 32 | 33 | } // namespace fcitx 34 | 35 | #endif // _FCITX5_CONFIGTOOL_MIGRATOR_SKK_SKKMIGRATOR_H_ 36 | -------------------------------------------------------------------------------- /src/migrator/pinyin/pinyinmigrator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #ifndef _FCITX5_CONFIGTOOL_MIGRATOR_PINYINMIGRATOR_H_ 8 | #define _FCITX5_CONFIGTOOL_MIGRATOR_PINYINMIGRATOR_H_ 9 | 10 | #include "migrator.h" 11 | #include "migratorfactoryplugin.h" 12 | 13 | namespace fcitx { 14 | 15 | class PinyinMigrator : public Migrator { 16 | Q_OBJECT 17 | public: 18 | QString name() const override; 19 | QString description() const override; 20 | bool check() const override; 21 | bool hasOfflineJob() const override { return true; } 22 | void addOfflineJob(Pipeline *pipeline) override; 23 | }; 24 | 25 | class PinyinMigratorPlugin : public FcitxMigratorFactoryPlugin { 26 | Q_OBJECT 27 | public: 28 | Q_PLUGIN_METADATA(IID FcitxMigratorFactoryInterface_iid FILE 29 | "pinyinmigrator.json") 30 | PinyinMigrator *create() override; 31 | }; 32 | 33 | } // namespace fcitx 34 | 35 | #endif // _FCITX5_CONFIGTOOL_MIGRATOR_PINYINMIGRATOR_H_ 36 | -------------------------------------------------------------------------------- /src/migrator/app/mainwindow.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #ifndef _FCITX5_CONFIGTOOL_MIGRATOR_APP_MAINWINDOW_H_ 8 | #define _FCITX5_CONFIGTOOL_MIGRATOR_APP_MAINWINDOW_H_ 9 | 10 | #include "dbusprovider.h" 11 | #include "migratorfactory.h" 12 | #include "pipeline.h" 13 | #include 14 | #include 15 | 16 | namespace fcitx { 17 | 18 | class WelcomePage; 19 | class TaskPage; 20 | class ProgressPage; 21 | 22 | class MainWindow : public QWizard { 23 | Q_OBJECT 24 | public: 25 | explicit MainWindow(QWidget *parent = nullptr); 26 | 27 | auto *dbus() { return &dbus_; } 28 | auto *factory() const { return &factory_; } 29 | Pipeline *createPipeline(); 30 | 31 | private: 32 | kcm::DBusProvider dbus_; 33 | MigratorFactory factory_; 34 | WelcomePage *welcomePage_; 35 | TaskPage *taskPage_; 36 | ProgressPage *progressPage_; 37 | }; 38 | 39 | } // namespace fcitx 40 | 41 | #endif // _FCITX5_CONFIGTOOL_MIGRATOR_APP_MAINWINDOW_H_ 42 | -------------------------------------------------------------------------------- /src/lib/configwidgetslib/erroroverlay.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017~2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | #ifndef _FCITX_ERROROVERLAY_H_ 7 | #define _FCITX_ERROROVERLAY_H_ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace Ui { 16 | class ErrorOverlay; 17 | } 18 | 19 | namespace fcitx::kcm { 20 | 21 | class DBusProvider; 22 | 23 | class ErrorOverlay : public QWidget { 24 | Q_OBJECT 25 | public: 26 | explicit ErrorOverlay(DBusProvider *dbus, QWidget *parent); 27 | ~ErrorOverlay(); 28 | 29 | bool eventFilter(QObject *object, QEvent *event) override; 30 | private Q_SLOTS: 31 | void availabilityChanged(bool avail); 32 | void runFcitx5(); 33 | 34 | private: 35 | void reposition(); 36 | std::unique_ptr ui_; 37 | DBusProvider *dbus; 38 | QPointer baseWidget_; 39 | bool enabled_ = false; 40 | }; 41 | 42 | } // namespace fcitx::kcm 43 | 44 | #endif // _FCITX_ERROROVERLAY_H_ 45 | -------------------------------------------------------------------------------- /src/lib/configwidgetslib/verticalscrollarea.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017~2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #include 8 | #include 9 | 10 | #include "verticalscrollarea.h" 11 | 12 | namespace fcitx { 13 | namespace kcm { 14 | 15 | VerticalScrollArea::VerticalScrollArea(QWidget *parent) : QScrollArea(parent) { 16 | setFrameStyle(QFrame::NoFrame); 17 | setWidgetResizable(true); 18 | setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 19 | setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); 20 | } 21 | 22 | void VerticalScrollArea::setWidget(QWidget *widget) { 23 | QScrollArea::setWidget(widget); 24 | widget->installEventFilter(this); 25 | } 26 | 27 | bool VerticalScrollArea::eventFilter(QObject *o, QEvent *e) { 28 | if (o == widget() && e->type() == QEvent::Resize) 29 | setMinimumWidth(widget()->minimumSizeHint().width() + 30 | verticalScrollBar()->width()); 31 | 32 | return false; 33 | } 34 | 35 | } // namespace kcm 36 | } // namespace fcitx 37 | -------------------------------------------------------------------------------- /src/migrator/global/globalconfigmigrator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX5_CONFIGTOOL_MIGRATOR_SKK_SKKMIGRATOR_H_ 8 | #define _FCITX5_CONFIGTOOL_MIGRATOR_SKK_SKKMIGRATOR_H_ 9 | 10 | #include "migrator.h" 11 | #include "migratorfactoryplugin.h" 12 | 13 | namespace fcitx { 14 | 15 | class GlobalConfigMigrator : public Migrator { 16 | Q_OBJECT 17 | public: 18 | QString name() const override; 19 | QString description() const override; 20 | bool check() const override; 21 | bool hasOfflineJob() const override { return false; } 22 | void addOnlineJob(Pipeline *pipeline) override; 23 | }; 24 | 25 | class GlobalConfigMigratorPlugin : public FcitxMigratorFactoryPlugin { 26 | Q_OBJECT 27 | public: 28 | Q_PLUGIN_METADATA(IID FcitxMigratorFactoryInterface_iid FILE 29 | "globalconfigmigrator.json") 30 | GlobalConfigMigrator *create() override; 31 | }; 32 | 33 | } // namespace fcitx 34 | 35 | #endif // _FCITX5_CONFIGTOOL_MIGRATOR_SKK_SKKMIGRATOR_H_ 36 | -------------------------------------------------------------------------------- /src/lib/configwidgetslib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(configwidgetslib STATIC 2 | configwidget.cpp 3 | addonselector.cpp 4 | categoryhelper.cpp 5 | erroroverlay.cpp 6 | fontbutton.cpp 7 | keylistwidget.cpp 8 | layoutselector.cpp 9 | listoptionwidget.cpp 10 | optionwidget.cpp 11 | varianthelper.cpp 12 | verticalscrollarea.cpp 13 | impage.cpp 14 | ) 15 | set_target_properties(configwidgetslib PROPERTIES 16 | POSITION_INDEPENDENT_CODE TRUE 17 | AUTOMOC TRUE 18 | AUTOUIC TRUE 19 | AUTOUIC_OPTIONS "-tr=fcitx::tr2fcitx;--include=fcitxqti18nhelper.h" 20 | ) 21 | target_include_directories(configwidgetslib INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) 22 | target_link_libraries(configwidgetslib 23 | Qt${QT_MAJOR_VERSION}::Core 24 | Qt${QT_MAJOR_VERSION}::Widgets 25 | #Qt${QT_MAJOR_VERSION}::X11Extras 26 | KF${QT_MAJOR_VERSION}::WidgetsAddons 27 | KF${QT_MAJOR_VERSION}::ItemViews 28 | Fcitx5::Utils 29 | Fcitx5Qt${QT_MAJOR_VERSION}::DBusAddons 30 | Fcitx5Qt${QT_MAJOR_VERSION}::WidgetsAddons 31 | configlib 32 | layoutlib) 33 | -------------------------------------------------------------------------------- /src/migrator/kkc/kkcmigrator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX5_CONFIGTOOL_MIGRATOR_SKK_SKKMIGRATOR_H_ 8 | #define _FCITX5_CONFIGTOOL_MIGRATOR_SKK_SKKMIGRATOR_H_ 9 | 10 | #include "migrator.h" 11 | #include "migratorfactoryplugin.h" 12 | 13 | namespace fcitx { 14 | 15 | class KkcMigrator : public Migrator { 16 | Q_OBJECT 17 | public: 18 | QString name() const override; 19 | QString description() const override; 20 | bool check() const override; 21 | bool hasOfflineJob() const override { return true; } 22 | void addOfflineJob(Pipeline *pipeline) override; 23 | void addOnlineJob(Pipeline *pipeline) override; 24 | }; 25 | 26 | class KkcMigratorPlugin : public FcitxMigratorFactoryPlugin { 27 | Q_OBJECT 28 | public: 29 | Q_PLUGIN_METADATA(IID FcitxMigratorFactoryInterface_iid FILE 30 | "kkcmigrator.json") 31 | KkcMigrator *create() override; 32 | }; 33 | 34 | } // namespace fcitx 35 | 36 | #endif // _FCITX5_CONFIGTOOL_MIGRATOR_SKK_SKKMIGRATOR_H_ 37 | -------------------------------------------------------------------------------- /src/migrator/skk/skkmigrator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX5_CONFIGTOOL_MIGRATOR_SKK_SKKMIGRATOR_H_ 8 | #define _FCITX5_CONFIGTOOL_MIGRATOR_SKK_SKKMIGRATOR_H_ 9 | 10 | #include "migrator.h" 11 | #include "migratorfactoryplugin.h" 12 | 13 | namespace fcitx { 14 | 15 | class SkkMigrator : public Migrator { 16 | Q_OBJECT 17 | public: 18 | QString name() const override; 19 | QString description() const override; 20 | bool check() const override; 21 | bool hasOfflineJob() const override { return true; } 22 | void addOfflineJob(Pipeline *pipeline) override; 23 | void addOnlineJob(Pipeline *pipeline) override; 24 | }; 25 | 26 | class SkkMigratorPlugin : public FcitxMigratorFactoryPlugin { 27 | Q_OBJECT 28 | public: 29 | Q_PLUGIN_METADATA(IID FcitxMigratorFactoryInterface_iid FILE 30 | "skkmigrator.json") 31 | SkkMigrator *create() override; 32 | }; 33 | 34 | } // namespace fcitx 35 | 36 | #endif // _FCITX5_CONFIGTOOL_MIGRATOR_SKK_SKKMIGRATOR_H_ 37 | -------------------------------------------------------------------------------- /src/kcm/ui/ExternalOption.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | import QtQuick 8 | import QtQuick.Controls 9 | import "utils.js" as Utils 10 | 11 | Button { 12 | property string typeName 13 | property string description 14 | property variant defaultValue 15 | property variant properties 16 | property variant rawValue 17 | readonly property bool needsSave: false 18 | property bool subConfig: false 19 | 20 | icon.name: "configure" 21 | 22 | function defaults() { 23 | } 24 | function load(rawValue) { 25 | } 26 | function save() { 27 | } 28 | 29 | Component.onCompleted: { 30 | if (Utils.hasProperty(properties, "LaunchSubConfig") && properties["LaunchSubConfig"] == "True") { 31 | subConfig = true; 32 | } 33 | } 34 | onClicked: { 35 | if (subConfig) { 36 | kcm.pushConfigPage(description, properties.External); 37 | } else { 38 | kcm.launchExternal(properties.External); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/configtool/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 800 10 | 600 11 | 12 | 13 | 14 | Fcitx Configuration 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | QDialogButtonBox::Apply|QDialogButtonBox::Close|QDialogButtonBox::Ok|QDialogButtonBox::Reset|QDialogButtonBox::RestoreDefaults 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/lib/configwidgetslib/listoptionwidget.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017~2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #ifndef _KCM_FCITX5_LISTOPTIONWIDGET_H_ 8 | #define _KCM_FCITX5_LISTOPTIONWIDGET_H_ 9 | 10 | #include "optionwidget.h" 11 | #include "ui_listoptionwidget.h" 12 | 13 | namespace fcitx { 14 | namespace kcm { 15 | 16 | class ListOptionWidgetModel; 17 | 18 | class ListOptionWidget : public OptionWidget, public Ui::ListOptionWidget { 19 | Q_OBJECT 20 | public: 21 | ListOptionWidget(const FcitxQtConfigOption &option, const QString &path, 22 | QWidget *parent); 23 | 24 | void readValueFrom(const QVariantMap &map) override; 25 | void writeValueTo(QVariantMap &map) override; 26 | void restoreToDefault() override; 27 | 28 | const auto &subOption() { return subOption_; } 29 | 30 | private: 31 | void updateButton(); 32 | ListOptionWidgetModel *model_; 33 | FcitxQtConfigOption subOption_; 34 | QVariantMap defaultValue_; 35 | }; 36 | 37 | } // namespace kcm 38 | } // namespace fcitx 39 | 40 | #endif // _KCM_FCITX5_LISTOPTIONWIDGET_H_ 41 | -------------------------------------------------------------------------------- /src/migrator/lib/migratorfactory.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #ifndef _FCITX5_CONFIGTOOL_MIGRATOR_LIB_MIGRATORFACTORY_H_ 8 | #define _FCITX5_CONFIGTOOL_MIGRATOR_LIB_MIGRATORFACTORY_H_ 9 | 10 | #include "fcitx5migrator_export.h" 11 | #include "migrator.h" 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace fcitx { 18 | class MigratorFactoryPrivate; 19 | /** 20 | * ui plugin factory. 21 | **/ 22 | class FCITX5MIGRATOR_EXPORT MigratorFactory : public QObject { 23 | Q_OBJECT 24 | public: 25 | /** 26 | * create a plugin factory 27 | * 28 | * @param parent object parent 29 | **/ 30 | explicit MigratorFactory(QObject *parent = 0); 31 | virtual ~MigratorFactory(); 32 | 33 | std::vector> 34 | list(const QSet &addons) const; 35 | 36 | private: 37 | MigratorFactoryPrivate *d_ptr; 38 | Q_DECLARE_PRIVATE(MigratorFactory); 39 | }; 40 | } // namespace fcitx 41 | 42 | #endif // _FCITX5_CONFIGTOOL_MIGRATOR_LIB_MIGRATORFACTORY_H_ 43 | -------------------------------------------------------------------------------- /src/migrator/lib/migratorfactoryplugin.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #ifndef _FCITX5_CONFIGTOOL_MIGRATOR_MIGRATOR_H_ 8 | #define _FCITX5_CONFIGTOOL_MIGRATOR_MIGRATOR_H_ 9 | 10 | #include "fcitx5migrator_export.h" 11 | #include "migrator.h" 12 | 13 | namespace fcitx { 14 | 15 | struct FCITX5MIGRATOR_EXPORT FcitxMigratorFactoryInterface { 16 | virtual Migrator *create() = 0; 17 | virtual ~FcitxMigratorFactoryInterface() = default; 18 | }; 19 | 20 | #define FcitxMigratorFactoryInterface_iid \ 21 | "org.fcitx.Fcitx.FcitxMigratorFactoryInterface" 22 | } // namespace fcitx 23 | 24 | Q_DECLARE_INTERFACE(fcitx::FcitxMigratorFactoryInterface, 25 | FcitxMigratorFactoryInterface_iid) 26 | 27 | namespace fcitx { 28 | 29 | class FCITX5MIGRATOR_EXPORT FcitxMigratorFactoryPlugin 30 | : public QObject, 31 | public FcitxMigratorFactoryInterface { 32 | Q_OBJECT 33 | Q_INTERFACES(fcitx::FcitxMigratorFactoryInterface) 34 | }; 35 | 36 | } // namespace fcitx 37 | 38 | #endif // _FCITX5_CONFIGTOOL_MIGRATOR_MIGRATOR_H_ 39 | -------------------------------------------------------------------------------- /src/lib/configlib/dbusprovider.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #ifndef _DBUSPROVIDER_H_ 8 | #define _DBUSPROVIDER_H_ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace fcitx { 15 | namespace kcm { 16 | 17 | class DBusProvider : public QObject { 18 | Q_OBJECT 19 | 20 | public: 21 | DBusProvider(QObject *parent); 22 | ~DBusProvider(); 23 | 24 | bool available() const { return controller_; } 25 | bool canRestart() const { return canRestart_; } 26 | FcitxQtControllerProxy *controller() { return controller_; } 27 | 28 | Q_SIGNALS: 29 | void availabilityChanged(bool avail); 30 | void canRestartChanged(bool canRestart); 31 | 32 | private Q_SLOTS: 33 | void fcitxAvailabilityChanged(bool avail); 34 | 35 | private: 36 | void loadCanRestart(); 37 | void setCanRestart(bool canRestart); 38 | FcitxQtWatcher *watcher_; 39 | FcitxQtControllerProxy *controller_ = nullptr; 40 | bool canRestart_ = true; 41 | }; 42 | 43 | } // namespace kcm 44 | } // namespace fcitx 45 | 46 | #endif // _DBUSPROVIDER_H_ 47 | -------------------------------------------------------------------------------- /src/kcm/ui/IntegerOption.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | import QtQuick 8 | import QtQuick.Controls 9 | import "utils.js" as Utils 10 | 11 | SpinBox { 12 | property string typeName 13 | property string description 14 | property variant defaultValue 15 | property variant properties 16 | property variant rawValue 17 | property bool needsSave: value !== oldValue 18 | property int oldValue: parseInt(rawValue) 19 | 20 | from: validator.bottom 21 | to: validator.top 22 | 23 | function load(rawValue) { 24 | value = parseInt(rawValue); 25 | } 26 | function save() { 27 | rawValue = value.toString(); 28 | } 29 | 30 | Component.onCompleted: { 31 | if (Utils.hasProperty(properties, "IntMin")) { 32 | validator.bottom = parseInt(properties.IntMin); 33 | } 34 | if (Utils.hasProperty(properties, "IntMax")) { 35 | validator.top = parseInt(properties.IntMax); 36 | } 37 | load(rawValue); 38 | save(); 39 | } 40 | 41 | validator: IntValidator { 42 | id: validator 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/lib/configwidgetslib/keylistwidget.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017~2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #ifndef _KCM_FCITX_KEYLISTWIDGET_H_ 8 | #define _KCM_FCITX_KEYLISTWIDGET_H_ 9 | 10 | #include 11 | #include 12 | 13 | class QToolButton; 14 | class QBoxLayout; 15 | 16 | namespace fcitx { 17 | namespace kcm { 18 | 19 | class KeyListWidget : public QWidget { 20 | Q_OBJECT 21 | public: 22 | explicit KeyListWidget(QWidget *parent = 0); 23 | 24 | QList keys() const; 25 | void setKeys(const QList &keys); 26 | void setAllowModifierLess(bool); 27 | void setAllowModifierOnly(bool); 28 | 29 | Q_SIGNALS: 30 | void keyChanged(); 31 | 32 | protected: 33 | void resizeEvent(QResizeEvent *) override; 34 | 35 | private: 36 | void addKey(Key key = Key()); 37 | bool removeKeyAt(int idx); 38 | bool showRemoveButton() const; 39 | 40 | QToolButton *addButton_; 41 | QBoxLayout *keysLayout_; 42 | bool modifierLess_ = false; 43 | bool modifierOnly_ = false; 44 | }; 45 | 46 | } // namespace kcm 47 | } // namespace fcitx 48 | 49 | #endif // _KCM_FCITX_KEYLISTWIDGET_H_ 50 | -------------------------------------------------------------------------------- /src/migrator/lib/dbuswatcher.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX5_CONFIGTOOL_MIGRATOR_LIB_DBUSWATCHER_H_ 8 | #define _FCITX5_CONFIGTOOL_MIGRATOR_LIB_DBUSWATCHER_H_ 9 | 10 | #include "fcitx5migrator_export.h" 11 | #include "pipelinejob.h" 12 | #include 13 | #include 14 | #include 15 | 16 | namespace fcitx { 17 | 18 | class FCITX5MIGRATOR_EXPORT DBusWatcher : public PipelineJob { 19 | Q_OBJECT 20 | public: 21 | explicit DBusWatcher(const QString &service, const QString &startMessage, 22 | const QString &finishMessage, bool expectation, 23 | QObject *parent = nullptr); 24 | void start() override; 25 | void abort() override; 26 | void cleanUp() override; 27 | 28 | private Q_SLOTS: 29 | 30 | private: 31 | QString service_; 32 | QString startMessage_; 33 | QString finishMessage_; 34 | QDBusServiceWatcher *watcher_; 35 | QTimer *timer_; 36 | bool available_ = false; 37 | bool firstCheck_ = true; 38 | const bool expectation_ = false; 39 | }; 40 | 41 | } // namespace fcitx 42 | 43 | #endif // _FCITX5_CONFIGTOOL_MIGRATOR_LIB_DBUSWATCHER_H_ 44 | -------------------------------------------------------------------------------- /src/migrator/lib/callbackrunner.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX5_CONFIGTOOL_MIGRATOR_LIB_CALLBACKRUNNER_H_ 8 | #define _FCITX5_CONFIGTOOL_MIGRATOR_LIB_CALLBACKRUNNER_H_ 9 | 10 | #include "pipelinejob.h" 11 | #include 12 | #include 13 | 14 | namespace fcitx { 15 | 16 | class FCITX5MIGRATOR_EXPORT CallbackRunner : public PipelineJob { 17 | Q_OBJECT 18 | public: 19 | explicit CallbackRunner( 20 | std::function callback, 21 | QObject *parent = nullptr); 22 | void start() override; 23 | void abort() override; 24 | void cleanUp() override; 25 | 26 | /// Function to be invoked by callback. 27 | void sendMessage(const QString &icon, const QString &message); 28 | void sendMessage(const QString &message) { 29 | sendMessage("dialog-information", message); 30 | } 31 | 32 | private Q_SLOTS: 33 | void emitFinished(bool result); 34 | 35 | private: 36 | const std::function callback_; 37 | QFutureWatcher *futureWatcher_ = nullptr; 38 | }; 39 | 40 | } // namespace fcitx 41 | 42 | #endif // _FCITX5_CONFIGTOOL_MIGRATOR_LIB_CALLBACKRUNNER_H_ 43 | -------------------------------------------------------------------------------- /src/kcm/ui/FontOption.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | import QtQuick 8 | import QtQuick.Controls 9 | import QtQuick.Layouts 10 | import QtQuick.Dialogs 11 | import org.kde.kirigami as Kirigami 12 | 13 | Button { 14 | id: button 15 | property string typeName 16 | property string description 17 | property variant defaultValue 18 | property variant properties 19 | property variant rawValue 20 | property bool needsSave: text !== rawValue 21 | property font value 22 | 23 | icon.name: "document-edit" 24 | text: kcm ? kcm.fontToString(value) : "" 25 | 26 | function load(rawValue) { 27 | value = kcm.parseFont(rawValue); 28 | } 29 | function save() { 30 | rawValue = text; 31 | } 32 | 33 | Component.onCompleted: { 34 | load(rawValue); 35 | save(); 36 | } 37 | onClicked: { 38 | fontDialog.selectedFont = value; 39 | fontDialog.open(); 40 | } 41 | 42 | FontDialog { 43 | id: fontDialog 44 | title: i18nc("@title:window", "Select Font") 45 | parentWindow: button.Window.window 46 | 47 | onAccepted: { 48 | value = fontDialog.selectedFont; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /layout/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(X11Import UNKNOWN IMPORTED) 2 | set_target_properties(X11Import PROPERTIES 3 | IMPORTED_LOCATION "${X11_X11_LIB}" 4 | INTERFACE_INCLUDE_DIRECTORIES "${X11_X11_INCLUDE_PATH}") 5 | 6 | add_library(X11XkblibImport INTERFACE IMPORTED) 7 | set_target_properties(X11XkblibImport PROPERTIES 8 | INTERFACE_INCLUDE_DIRECTORIES "${X11_Xkblib_INCLUDE_PATH}") 9 | 10 | add_library(layoutlib STATIC keyboardlayoutwidget.cpp) 11 | set_target_properties(layoutlib PROPERTIES POSITION_INDEPENDENT_CODE TRUE) 12 | target_link_libraries(layoutlib PUBLIC Fcitx5::Utils Qt${QT_MAJOR_VERSION}::Widgets PRIVATE X11Import X11XkblibImport PkgConfig::XkbFile) 13 | target_include_directories(layoutlib INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) 14 | 15 | set(kbd_layout_viewer_SOURCES 16 | main.cpp 17 | ) 18 | 19 | add_executable(kbd-layout-viewer5 ${kbd_layout_viewer_SOURCES}) 20 | 21 | target_link_libraries(kbd-layout-viewer5 Fcitx5::Utils Qt${QT_MAJOR_VERSION}::Widgets layoutlib) 22 | 23 | install(TARGETS kbd-layout-viewer5 DESTINATION ${KDE_INSTALL_BINDIR}) 24 | fcitx5_translate_desktop_file( 25 | kbd-layout-viewer5.desktop.in 26 | kbd-layout-viewer5.desktop PO_DIRECTORY ${PROJECT_SOURCE_DIR}/po/fcitx5-configtool) 27 | install(FILES "${CMAKE_CURRENT_BINARY_DIR}/kbd-layout-viewer5.desktop" 28 | DESTINATION ${KDE_INSTALL_APPDIR}) 29 | -------------------------------------------------------------------------------- /src/migrator/pinyin/pinyinmigrator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #include "pinyinmigrator.h" 8 | #include "pipeline.h" 9 | #include "processrunner.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace fcitx { 16 | 17 | QString PinyinMigrator::name() const { return _("Pinyin"); } 18 | 19 | QString PinyinMigrator::description() const { 20 | return _("Import Pinyin dictionary from Fcitx 4"); 21 | } 22 | 23 | bool PinyinMigrator::check() const { 24 | auto path = 25 | StandardPaths::global().userDirectory(StandardPathsType::Config) / 26 | "fcitx/pinyin"; 27 | QFileInfo file(QString::fromStdString(path.string())); 28 | return file.isDir(); 29 | } 30 | 31 | PinyinMigrator *PinyinMigratorPlugin::create() { return new PinyinMigrator(); } 32 | 33 | void PinyinMigrator::addOfflineJob(Pipeline *pipeline) { 34 | auto *migratorJob = 35 | new ProcessRunner("libime_migrate_fcitx4_pinyin", {}, {}); 36 | migratorJob->setStartMessage(_("Migrating Pinyin data...")); 37 | migratorJob->setFinishMessage(_("Pinyin data is migrated.")); 38 | pipeline->addJob(migratorJob); 39 | } 40 | 41 | } // namespace fcitx 42 | -------------------------------------------------------------------------------- /src/migrator/lib/dbuscaller.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2013-2018 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | /* 8 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 9 | * 10 | * SPDX-License-Identifier: LGPL-2.1-or-later 11 | * 12 | */ 13 | #ifndef _FCITX5_CONFIGTOOL_MIGRATOR_LIB_DBUSCALLER_H_ 14 | #define _FCITX5_CONFIGTOOL_MIGRATOR_LIB_DBUSCALLER_H_ 15 | 16 | #include "fcitx5migrator_export.h" 17 | #include "pipelinejob.h" 18 | #include 19 | #include 20 | 21 | namespace fcitx { 22 | 23 | class FCITX5MIGRATOR_EXPORT DBusCaller : public PipelineJob { 24 | Q_OBJECT 25 | public: 26 | explicit DBusCaller(std::function callback, 27 | const QString &startMessage, 28 | const QString &finishMessage, 29 | QObject *parent = nullptr); 30 | void start() override; 31 | void abort() override; 32 | void cleanUp() override; 33 | 34 | private Q_SLOTS: 35 | 36 | private: 37 | std::function callback_; 38 | QString startMessage_; 39 | QString finishMessage_; 40 | QDBusPendingCallWatcher *watcher_; 41 | }; 42 | 43 | } // namespace fcitx 44 | 45 | #endif // _FCITX5_CONFIGTOOL_MIGRATOR_LIB_DBUSCALLER_H_ 46 | -------------------------------------------------------------------------------- /cmake/FindXKBCommon.cmake: -------------------------------------------------------------------------------- 1 | 2 | include(ECMFindModuleHelpersStub) 3 | 4 | ecm_find_package_version_check(XKBCommon) 5 | 6 | # Note that this list needs to be ordered such that any component 7 | # appears after its dependencies 8 | set(XKBCommon_known_components 9 | XKBCommon 10 | X11) 11 | 12 | set(XKBCommon_XKBCommon_component_deps) 13 | set(XKBCommon_XKBCommon_pkg_config "xkbcommon") 14 | set(XKBCommon_XKBCommon_lib "xkbcommon") 15 | set(XKBCommon_XKBCommon_header "xkbcommon/xkbcommon.h") 16 | 17 | set(XKBCommon_X11_component_deps XKBCommon) 18 | set(XKBCommon_X11_pkg_config "xkbcommon-x11") 19 | set(XKBCommon_X11_lib "xkbcommon-x11") 20 | set(XKBCommon_X11_header "xkbcommon/xkbcommon-x11.h") 21 | 22 | ecm_find_package_parse_components(XKBCommon 23 | RESULT_VAR XKBCommon_components 24 | KNOWN_COMPONENTS ${XKBCommon_known_components} 25 | ) 26 | ecm_find_package_handle_library_components(XKBCommon 27 | COMPONENTS ${XKBCommon_components} 28 | ) 29 | 30 | find_package_handle_standard_args(XKBCommon 31 | FOUND_VAR 32 | XKBCommon_FOUND 33 | REQUIRED_VARS 34 | XKBCommon_LIBRARIES 35 | VERSION_VAR 36 | XKBCommon_VERSION 37 | HANDLE_COMPONENTS 38 | ) 39 | 40 | include(FeatureSummary) 41 | set_package_properties(XKBCommon PROPERTIES 42 | URL "http://xkbcommon.org" 43 | DESCRIPTION "Keyboard handling library using XKB data" 44 | ) 45 | -------------------------------------------------------------------------------- /src/migrator/lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ecm_setup_version(PROJECT VARIABLE_PREFIX Fcitx5Migrator 2 | VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/migrator_version.h" 3 | PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/Fcitx5MigratorVersion.cmake" 4 | SOVERSION 1) 5 | 6 | add_library(Fcitx5Migrator SHARED 7 | migratorfactoryplugin.cpp 8 | migrator.cpp 9 | migratorfactory.cpp 10 | pipeline.cpp 11 | pipelinejob.cpp 12 | processrunner.cpp 13 | dbuscaller.cpp 14 | dbuswatcher.cpp 15 | renamefile.cpp 16 | copydirectory.cpp 17 | callbackrunner.cpp 18 | log.cpp 19 | configmigrator.cpp 20 | ) 21 | target_link_libraries(Fcitx5Migrator Qt${QT_MAJOR_VERSION}::Core Qt${QT_MAJOR_VERSION}::Concurrent Qt${QT_MAJOR_VERSION}::DBus Fcitx5::Config Fcitx5::Utils Fcitx5Qt${QT_MAJOR_VERSION}::DBusAddons ) 22 | set_target_properties(Fcitx5Migrator PROPERTIES 23 | VERSION ${Fcitx5Migrator_VERSION} 24 | SOVERSION ${Fcitx5Migrator_SOVERSION} 25 | EXPORT_NAME Migrator 26 | AUTOMOC TRUE 27 | AUTOUIC TRUE 28 | ) 29 | 30 | target_include_directories(Fcitx5Migrator PUBLIC "$") 31 | 32 | generate_export_header(Fcitx5Migrator BASE_NAME Fcitx5Migrator) 33 | 34 | install(TARGETS Fcitx5Migrator LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}") 35 | -------------------------------------------------------------------------------- /cmake/FindIsoCodes.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find the IsoCodes libraries 2 | # Once done this will define 3 | # 4 | # ISOCODES_FOUND - system has ISOCODES 5 | # ISOCODES_INCLUDE_DIR - the ISOCODES include directory 6 | # ISOCODES_LIBRARIES - ISOCODES library 7 | # 8 | # Copyright (c) 2012 CSSlayer 9 | # 10 | # Redistribution and use is allowed according to the terms of the BSD license. 11 | # For details see the accompanying COPYING-CMAKE-SCRIPTS file. 12 | 13 | if(ISOCODES_INCLUDE_DIR AND ISOCODES_LIBRARIES) 14 | # Already in cache, be silent 15 | set(ISOCODES_FIND_QUIETLY TRUE) 16 | endif(ISOCODES_INCLUDE_DIR AND ISOCODES_LIBRARIES) 17 | 18 | find_package(PkgConfig) 19 | pkg_check_modules(PC_ISOCODES iso-codes) 20 | 21 | find_file(ISOCODES_ISO639_2_JSON iso_639-2.json 22 | HINTS "${PC_ISOCODES_PREFIX}/share/iso-codes/json/" 23 | ) 24 | 25 | find_file(ISOCODES_ISO639_3_JSON iso_639-3.json 26 | HINTS "${PC_ISOCODES_PREFIX}/share/iso-codes/json/" 27 | ) 28 | 29 | find_file(ISOCODES_ISO639_5_JSON iso_639-5.json 30 | HINTS "${PC_ISOCODES_PREFIX}/share/iso-codes/json/" 31 | ) 32 | 33 | include(FindPackageHandleStandardArgs) 34 | find_package_handle_standard_args(IsoCodes DEFAULT_MSG ISOCODES_ISO639_2_JSON ISOCODES_ISO639_3_JSON ISOCODES_ISO639_5_JSON) 35 | 36 | mark_as_advanced(ISOCODES_ISO639_2_JSON ISOCODES_ISO639_3_JSON ISOCODES_ISO639_5_JSON) 37 | -------------------------------------------------------------------------------- /src/kcm/ui/ConfigPage.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | import QtQuick 8 | import QtQuick.Controls 9 | import org.kde.kirigami as Kirigami 10 | import org.kde.kcmutils as KCM 11 | 12 | Kirigami.ScrollablePage { 13 | id: configPage 14 | property alias needsSave: configGroup.needsSave 15 | property alias rawValue: configGroup.rawValue 16 | property alias typeMap: configGroup.typeMap 17 | property alias typeName: configGroup.typeName 18 | property string uri 19 | 20 | function defaults() { 21 | configGroup.defaults(); 22 | } 23 | function load() { 24 | configGroup.load(); 25 | } 26 | function save() { 27 | configGroup.save(); 28 | kcm.saveConfig(uri, rawValue); 29 | } 30 | function showWarning() { 31 | dialog.open(); 32 | } 33 | 34 | Component.onCompleted: positionTimer.start() 35 | 36 | ConfigGroup { 37 | id: configGroup 38 | visible: false 39 | width: parent.width 40 | 41 | SaveWarningDialog { 42 | id: dialog 43 | parent: configPage 44 | } 45 | 46 | // Hack for force relayout the scrollview 47 | Timer { 48 | id: positionTimer 49 | interval: 0 50 | repeat: false 51 | 52 | onTriggered: configGroup.visible = true 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/migrator/app/main.cpp: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include "mainwindow.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | Q_IMPORT_PLUGIN(PinyinMigratorPlugin); 12 | Q_IMPORT_PLUGIN(SkkMigratorPlugin); 13 | Q_IMPORT_PLUGIN(KkcMigratorPlugin); 14 | Q_IMPORT_PLUGIN(RimeMigratorPlugin); 15 | Q_IMPORT_PLUGIN(GlobalConfigMigratorPlugin); 16 | Q_IMPORT_PLUGIN(TableMigratorPlugin); 17 | 18 | int main(int argc, char *argv[]) { 19 | QApplication app(argc, argv); 20 | app.setApplicationName("fcitx5-migrator"); 21 | app.setApplicationVersion(PROJECT_VERSION); 22 | app.setApplicationDisplayName(_("Fcitx 5 Migration Wizard")); 23 | app.setOrganizationDomain("fcitx.org"); 24 | fcitx::registerFcitxQtDBusTypes(); 25 | 26 | QCommandLineParser parser; 27 | parser.addHelpOption(); 28 | parser.addVersionOption(); 29 | parser.process(app); 30 | 31 | auto disableSessionManagement = [](QSessionManager &sm) { 32 | sm.setRestartHint(QSessionManager::RestartNever); 33 | }; 34 | QObject::connect(&app, &QGuiApplication::commitDataRequest, 35 | disableSessionManagement); 36 | QObject::connect(&app, &QGuiApplication::saveStateRequest, 37 | disableSessionManagement); 38 | 39 | fcitx::MainWindow window; 40 | window.show(); 41 | return app.exec(); 42 | } 43 | -------------------------------------------------------------------------------- /src/configtool/mainwindow.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #ifndef _KCM_FCITX5_CONFIGTOOL_MAINWINDOW_H_ 8 | #define _KCM_FCITX5_CONFIGTOOL_MAINWINDOW_H_ 9 | 10 | #include "addonselector.h" 11 | #include "configwidget.h" 12 | #include "dbusprovider.h" 13 | #include "erroroverlay.h" 14 | #include "impage.h" 15 | #include "ui_mainwindow.h" 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | namespace fcitx::kcm { 23 | 24 | class MainWindow : public QMainWindow, public Ui::MainWindow { 25 | Q_OBJECT 26 | public: 27 | explicit MainWindow(QWidget *parent = nullptr); 28 | 29 | void load(); 30 | void save(); 31 | void defaults(); 32 | Q_SIGNALS: 33 | void changed(bool state); 34 | 35 | protected: 36 | void keyPressEvent(QKeyEvent *event) override; 37 | void focusInEvent(QFocusEvent *event) override; 38 | 39 | private Q_SLOTS: 40 | void clicked(QAbstractButton *button); 41 | void commitData(QSessionManager &manager); 42 | 43 | private: 44 | void handleChanged(bool changed); 45 | bool changed_ = false; 46 | DBusProvider *dbus_; 47 | ErrorOverlay *errorOverlay_; 48 | IMPage *impage_; 49 | AddonSelector *addonPage_; 50 | ConfigWidget *configPage_; 51 | }; 52 | } // namespace fcitx::kcm 53 | 54 | #endif // _KCM_FCITX5_CONFIGTOOL_MAINWINDOW_H (2)_ 55 | -------------------------------------------------------------------------------- /src/migrator/lib/callbackrunner.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #include "callbackrunner.h" 8 | #include 9 | #include 10 | 11 | namespace fcitx { 12 | 13 | CallbackRunner::CallbackRunner( 14 | std::function callback, QObject *parent) 15 | : PipelineJob(parent), callback_(std::move(callback)) {} 16 | 17 | void CallbackRunner::start() { 18 | cleanUp(); 19 | futureWatcher_ = new QFutureWatcher(this); 20 | futureWatcher_->setFuture(QtConcurrent::run(callback_, this)); 21 | connect(futureWatcher_, &QFutureWatcher::finished, this, 22 | [this]() { emitFinished(futureWatcher_->result()); }); 23 | } 24 | 25 | void CallbackRunner::abort() {} 26 | 27 | void CallbackRunner::cleanUp() { 28 | if (futureWatcher_) { 29 | disconnect(futureWatcher_, nullptr, this, nullptr); 30 | futureWatcher_->deleteLater(); 31 | futureWatcher_ = nullptr; 32 | } 33 | } 34 | 35 | void CallbackRunner::sendMessage(const QString &icon, const QString &message) { 36 | QMetaObject::invokeMethod( 37 | this, [this, icon, message]() { this->message(icon, message); }, 38 | Qt::QueuedConnection); 39 | } 40 | 41 | void CallbackRunner::emitFinished(bool result) { 42 | if (!result) { 43 | return; 44 | } 45 | Q_EMIT finished(result); 46 | } 47 | 48 | } // namespace fcitx 49 | -------------------------------------------------------------------------------- /src/kcm/kcm_fcitx5.json: -------------------------------------------------------------------------------- 1 | { 2 | "Categories": "Qt;KDE;X-KDE-settings-fcitx;", 3 | "KPlugin": { 4 | "Description": "Configure Input Method", 5 | "Description[ca]": "Configura el mètode d'entrada", 6 | "Description[da]": "Konfigurer inputmetode", 7 | "Description[de]": "Eingabemethode konfigurieren", 8 | "Description[es]": "Configurar método de entrada", 9 | "Description[fr]": "Configurer la méthode d'entrée", 10 | "Description[he]": "הגדרת שיטת קלט", 11 | "Description[ja]": "入力メソッドの設定", 12 | "Description[ko]": "입력기 구성하기", 13 | "Description[ru]": "Настроить метод ввода", 14 | "Description[zh_CN]": "配置输入法", 15 | "Description[zh_TW]": "設定輸入法", 16 | "Icon": "fcitx", 17 | "Name": "Input Method", 18 | "Name[ca]": "Mètode d'entrada", 19 | "Name[da]": "Inputmetode", 20 | "Name[de]": "Eingabemethode", 21 | "Name[es]": "Método de entrada", 22 | "Name[fr]": "Méthode de saisie", 23 | "Name[he]": "שיטת קלט", 24 | "Name[ja]": "入力メソッド", 25 | "Name[ko]": "입력기", 26 | "Name[ru]": "Метод ввода", 27 | "Name[tr]": "Giriş Yöntemi", 28 | "Name[vi]": "Kiểu gõ", 29 | "Name[zh_CN]": "输入法", 30 | "Name[zh_TW]": "輸入法", 31 | "ServiceTypes": [ 32 | "KCModule" 33 | ] 34 | }, 35 | "X-KDE-Keywords": "keyboard,input,im,fcitx", 36 | "X-KDE-ParentApp": "kcontrol", 37 | "X-KDE-System-Settings-Parent-Category": "regionalsettings" 38 | } 39 | -------------------------------------------------------------------------------- /src/migrator/lib/pipeline.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2018-2018 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #include "pipeline.h" 8 | 9 | namespace fcitx { 10 | 11 | Pipeline::Pipeline(QObject *parent) : QObject(parent) {} 12 | 13 | void Pipeline::addJob(PipelineJob *job) { 14 | job->setParent(this); 15 | jobs_.push_back(job); 16 | connect(job, &PipelineJob::message, this, &Pipeline::message); 17 | connect(job, &PipelineJob::finished, this, [this](bool success) { 18 | if (success) { 19 | startNext(); 20 | } else { 21 | emitFinished(false); 22 | } 23 | }); 24 | } 25 | 26 | void Pipeline::abort() { 27 | if (index_ < 0) { 28 | return; 29 | } 30 | jobs_[index_]->abort(); 31 | index_ = -1; 32 | } 33 | 34 | void Pipeline::reset() { 35 | abort(); 36 | for (auto *job : jobs_) { 37 | delete job; 38 | } 39 | jobs_.clear(); 40 | } 41 | 42 | void Pipeline::start() { 43 | Q_ASSERT(!jobs_.empty()); 44 | 45 | index_ = -1; 46 | startNext(); 47 | } 48 | 49 | void Pipeline::startNext() { 50 | if (index_ + 1 == static_cast(jobs_.size())) { 51 | emitFinished(true); 52 | return; 53 | } 54 | index_ += 1; 55 | jobs_[index_]->start(); 56 | } 57 | 58 | void Pipeline::emitFinished(bool result) { 59 | for (auto *job : jobs_) { 60 | job->cleanUp(); 61 | } 62 | Q_EMIT finished(result); 63 | } 64 | 65 | } // namespace fcitx 66 | -------------------------------------------------------------------------------- /src/lib/configwidgetslib/optionwidget.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017~2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #ifndef _KCM_FCITX_OPTIONWIDGET_H_ 8 | #define _KCM_FCITX_OPTIONWIDGET_H_ 9 | 10 | #include 11 | #include 12 | 13 | class QFormLayout; 14 | 15 | namespace fcitx { 16 | namespace kcm { 17 | 18 | class OptionWidget : public QWidget { 19 | Q_OBJECT 20 | public: 21 | OptionWidget(const QString &path, QWidget *parent) 22 | : QWidget(parent), path_(path) {} 23 | 24 | static OptionWidget *addWidget(QFormLayout *layout, 25 | const fcitx::FcitxQtConfigOption &option, 26 | const QString &path, QWidget *parent); 27 | 28 | static bool execOptionDialog(QWidget *parent, 29 | const fcitx::FcitxQtConfigOption &option, 30 | QVariant &result); 31 | 32 | virtual void readValueFrom(const QVariantMap &map) = 0; 33 | virtual void writeValueTo(QVariantMap &map) = 0; 34 | virtual void restoreToDefault() = 0; 35 | virtual bool isValid() const { return true; } 36 | 37 | QString prettify(const FcitxQtConfigOption &option, const QVariant &value); 38 | 39 | const QString &path() const { return path_; } 40 | Q_SIGNALS: 41 | void valueChanged(); 42 | 43 | private: 44 | QString path_; 45 | }; 46 | 47 | } // namespace kcm 48 | } // namespace fcitx 49 | 50 | #endif // _KCM_FCITX_OPTIONWIDGET_H_ 51 | -------------------------------------------------------------------------------- /src/migrator/lib/configmigrator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _FCITX5_CONFIGTOOL_MIGRATOR_LIB_CONFIGMIGRATOR_H_ 8 | #define _FCITX5_CONFIGTOOL_MIGRATOR_LIB_CONFIGMIGRATOR_H_ 9 | 10 | #include "fcitx5migrator_export.h" 11 | #include "pipelinejob.h" 12 | #include 13 | #include 14 | 15 | namespace fcitx { 16 | 17 | class FCITX5MIGRATOR_EXPORT ConfigMigrator : public PipelineJob { 18 | public: 19 | ConfigMigrator(const QString &config, 20 | std::function transformer, 21 | QObject *parent); 22 | 23 | void start() override; 24 | void abort() override; 25 | void cleanUp() override; 26 | 27 | public Q_SLOTS: 28 | void requestConfigFinished(QDBusPendingCallWatcher *watcher); 29 | 30 | QString valueByPath(const QString &path) const; 31 | void setValueByPath(const QString &path); 32 | void removeValueByPath(const QString &path); 33 | 34 | void setStartMessage(const QString &message) { startMessage_ = message; } 35 | void setFinishMessage(const QString &message) { finishMessage_ = message; } 36 | 37 | private: 38 | QString startMessage_; 39 | QString finishMessage_; 40 | 41 | QString configPath_; 42 | FcitxQtControllerProxy *proxy_ = nullptr; 43 | RawConfig config_; 44 | std::function transformer_; 45 | }; 46 | 47 | } // namespace fcitx 48 | 49 | #endif // _FCITX5_CONFIGTOOL_MIGRATOR_LIB_CONFIGMIGRATOR_H_ 50 | -------------------------------------------------------------------------------- /src/migrator/lib/dbuscaller.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #include "dbuscaller.h" 8 | #include 9 | 10 | namespace fcitx { 11 | 12 | DBusCaller::DBusCaller(std::function callback, 13 | const QString &startMessage, 14 | const QString &finishMessage, QObject *parent) 15 | : PipelineJob(parent), callback_(std::move(callback)), 16 | startMessage_(startMessage), finishMessage_(finishMessage) {} 17 | 18 | void DBusCaller::start() { 19 | watcher_ = callback_(); 20 | if (!watcher_) { 21 | message("dialog-error", QString(_("Failed to start DBus Call."))); 22 | finished(false); 23 | return; 24 | } 25 | message("", startMessage_); 26 | connect(watcher_, &QDBusPendingCallWatcher::finished, [this]() { 27 | watcher_->deleteLater(); 28 | if (watcher_->isError()) { 29 | message("dialog-error", QString(_("Got error: %1 %2")) 30 | .arg(watcher_->error().name(), 31 | watcher_->error().message())); 32 | } else { 33 | message("dialog-information", finishMessage_); 34 | } 35 | finished(!watcher_->isError()); 36 | watcher_ = nullptr; 37 | }); 38 | } 39 | 40 | void DBusCaller::abort() { cleanUp(); } 41 | 42 | void DBusCaller::cleanUp() { 43 | watcher_->deleteLater(); 44 | watcher_ = nullptr; 45 | } 46 | 47 | } // namespace fcitx 48 | -------------------------------------------------------------------------------- /src/migrator/lib/processrunner.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2013-2018 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #ifndef _PINYINDICTMANAGER_PROCESSRUNNER_H_ 8 | #define _PINYINDICTMANAGER_PROCESSRUNNER_H_ 9 | 10 | #include "fcitx5migrator_export.h" 11 | #include "pipelinejob.h" 12 | #include 13 | #include 14 | 15 | namespace fcitx { 16 | 17 | class FCITX5MIGRATOR_EXPORT ProcessRunner : public PipelineJob { 18 | Q_OBJECT 19 | public: 20 | explicit ProcessRunner(const QString &bin, const QStringList &args, 21 | const QString &file, QObject *parent = nullptr); 22 | void start() override; 23 | void abort() override; 24 | void cleanUp() override; 25 | void setIgnoreFailure(bool ignoreFailure) { 26 | ignoreFailure_ = ignoreFailure; 27 | } 28 | void setPrintOutputToMessage(bool printOutputToMessage) { 29 | printOutputToMessage_ = printOutputToMessage; 30 | } 31 | 32 | void setStartMessage(const QString &message) { startMessage_ = message; } 33 | void setFinishMessage(const QString &message) { finishMessage_ = message; } 34 | 35 | private Q_SLOTS: 36 | void processFinished(int exitCode, QProcess::ExitStatus status); 37 | 38 | private: 39 | QString startMessage_; 40 | QString finishMessage_; 41 | QProcess process_; 42 | QString bin_; 43 | QStringList args_; 44 | QString file_; 45 | bool ignoreFailure_ = false; 46 | bool printOutputToMessage_ = false; 47 | 48 | QByteArray messages_; 49 | }; 50 | 51 | } // namespace fcitx 52 | 53 | #endif // _PINYINDICTMANAGER_PROCESSRUNNER_H_ 54 | -------------------------------------------------------------------------------- /src/lib/configwidgetslib/addonselector.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017~2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | #ifndef _KCM_FCITX_ADDONSELECTOR_H_ 7 | #define _KCM_FCITX_ADDONSELECTOR_H_ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | class QDBusPendingCallWatcher; 15 | 16 | namespace Ui { 17 | class AddonSelector; 18 | } 19 | 20 | namespace fcitx { 21 | namespace kcm { 22 | 23 | class AddonModel; 24 | class AddonProxyModel; 25 | class AddonDelegate; 26 | class DBusProvider; 27 | 28 | class AddonSelector : public QWidget { 29 | Q_OBJECT 30 | 31 | public: 32 | AddonSelector(QWidget *parent, DBusProvider *dbus); 33 | virtual ~AddonSelector(); 34 | void load(); 35 | void save(); 36 | 37 | QString searchText() const; 38 | auto dbus() const { return dbus_; } 39 | 40 | bool showAdvanced() const; 41 | 42 | Q_SIGNALS: 43 | void changed(); 44 | void configCommitted(const QByteArray &componentName); 45 | 46 | private Q_SLOTS: 47 | void fetchAddonFinished(QDBusPendingCallWatcher *); 48 | void availabilityChanged(); 49 | void warnAddonDisable(const QString &addon); 50 | 51 | private: 52 | DBusProvider *dbus_; 53 | QMap nameToAddonMap_; 54 | QMap reverseDependencies_; 55 | QMap reverseOptionalDependencies_; 56 | 57 | AddonModel *addonModel_; 58 | AddonProxyModel *proxyModel_; 59 | AddonDelegate *delegate_; 60 | std::unique_ptr ui_; 61 | }; 62 | } // namespace kcm 63 | } // namespace fcitx 64 | 65 | #endif // _KCM_FCITX_ADDONSELECTOR_H_ 66 | -------------------------------------------------------------------------------- /src/migrator/app/progresspage.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #include "progresspage.h" 8 | #include "mainwindow.h" 9 | #include 10 | #include 11 | 12 | namespace fcitx { 13 | 14 | ProgressPage::ProgressPage(MainWindow *parent) 15 | : QWizardPage(parent), parent_(parent) { 16 | setupUi(this); 17 | setFinalPage(true); 18 | } 19 | 20 | bool ProgressPage::isComplete() const { return done_; } 21 | 22 | void ProgressPage::appendMessage(const QString &icon, const QString &message) { 23 | QListWidgetItem *item = 24 | new QListWidgetItem(QIcon::fromTheme(icon), message, listWidget); 25 | listWidget->addItem(item); 26 | listWidget->scrollToItem(item); 27 | } 28 | 29 | void ProgressPage::initializePage() { 30 | if (pipeline_) { 31 | delete pipeline_; 32 | } 33 | listWidget->clear(); 34 | pipeline_ = parent_->createPipeline(); 35 | done_ = false; 36 | 37 | connect(pipeline_, &Pipeline::message, this, &ProgressPage::appendMessage); 38 | 39 | connect(pipeline_, &Pipeline::finished, this, [this](bool success) { 40 | if (success) { 41 | done_ = true; 42 | parent_->button(QWizard::CancelButton)->setEnabled(false); 43 | appendMessage("dialog-positive", 44 | _("All migration tasks are completed successfully.")); 45 | Q_EMIT completeChanged(); 46 | } else { 47 | appendMessage( 48 | "dialog-error", 49 | _("One of the task is failed. Terminating the migration.")); 50 | } 51 | }); 52 | pipeline_->start(); 53 | } 54 | 55 | } // namespace fcitx 56 | -------------------------------------------------------------------------------- /src/lib/configlib/iso639.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017~2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | #ifndef _KCM_FCITX_ISO639_H_ 7 | #define _KCM_FCITX_ISO639_H_ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace fcitx { 14 | namespace kcm { 15 | 16 | class Iso639 { 17 | public: 18 | Iso639(); 19 | 20 | QString query(const QString &code) const { 21 | auto value = iso639_2data_.value(code); 22 | if (!value.isEmpty()) { 23 | return translateDomain("iso_639-2", value.toUtf8().constData()); 24 | } 25 | value = iso639_3data_.value(code); 26 | if (!value.isEmpty()) { 27 | return translateDomain("iso_639-3", value.toUtf8().constData()); 28 | } 29 | value = iso639_5data_.value(code); 30 | if (!value.isEmpty()) { 31 | return translateDomain("iso_639-5", value.toUtf8().constData()); 32 | } 33 | return value; 34 | } 35 | 36 | QString queryNative(const QString &code) const { 37 | auto value = iso639_2data_.value(code); 38 | if (!value.isEmpty()) { 39 | return value; 40 | } 41 | value = iso639_3data_.value(code); 42 | if (!value.isEmpty()) { 43 | return value; 44 | } 45 | value = iso639_5data_.value(code); 46 | if (!value.isEmpty()) { 47 | return value; 48 | } 49 | return value; 50 | } 51 | 52 | private: 53 | QMap iso639_2data_; 54 | QMap iso639_3data_; 55 | QMap iso639_5data_; 56 | }; 57 | 58 | } // namespace kcm 59 | } // namespace fcitx 60 | 61 | #endif // _KCM_FCITX_ISO639_H_ 62 | -------------------------------------------------------------------------------- /src/kcm/ui/ColorOption.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | import QtQuick 8 | import QtQuick.Controls 9 | import QtQuick.Layouts 10 | import QtQuick.Dialogs as QtDialogs 11 | import org.kde.kirigami as Kirigami 12 | 13 | RowLayout { 14 | property string typeName 15 | property string description 16 | property variant defaultValue 17 | property variant properties 18 | property variant rawValue 19 | property bool needsSave: button.text != rawValue 20 | property color value 21 | 22 | function load(rawValue) { 23 | value = kcm.parseColor(rawValue); 24 | } 25 | function save() { 26 | rawValue = button.text; 27 | } 28 | 29 | Component.onCompleted: { 30 | load(rawValue); 31 | save(); 32 | } 33 | 34 | Button { 35 | id: button 36 | icon.name: "document-edit" 37 | implicitWidth: Kirigami.Units.gridUnit * 10 38 | text: kcm ? kcm.colorToString(value) : "" 39 | 40 | Layout.fillWidth: true 41 | 42 | onClicked: { 43 | colorDialog.selectedColor = value; 44 | colorDialog.open(); 45 | } 46 | 47 | QtDialogs.ColorDialog { 48 | id: colorDialog 49 | modality: Qt.ApplicationModal 50 | options: QtDialogs.ColorDialog.ShowAlphaChannel 51 | parentWindow: button.Window.window 52 | 53 | title: i18nc("@title:window", "Select Color") 54 | 55 | onAccepted: { 56 | value = colorDialog.selectedColor; 57 | } 58 | } 59 | } 60 | Rectangle { 61 | color: value 62 | height: button.height 63 | width: height 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/migrator/rime/rimemigrator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #include "rimemigrator.h" 8 | #include "callbackrunner.h" 9 | #include "copydirectory.h" 10 | #include "pipeline.h" 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace fcitx { 19 | 20 | namespace { 21 | 22 | QString fcitx4Path() { 23 | auto path = 24 | StandardPaths::global().userDirectory(StandardPathsType::Config) / 25 | "fcitx/rime"; 26 | return QString::fromStdString(path.string()); 27 | } 28 | 29 | QString fcitx5Path() { 30 | auto path = 31 | StandardPaths::global().userDirectory(StandardPathsType::PkgData) / 32 | "rime"; 33 | return QString::fromStdString(path.string()); 34 | } 35 | 36 | } // namespace 37 | 38 | QString RimeMigrator::name() const { return _("Rime"); } 39 | 40 | QString RimeMigrator::description() const { 41 | return _("Migrate Rime dictionary from Fcitx 4. Notice: this will remove " 42 | "all the existing data."); 43 | } 44 | 45 | bool RimeMigrator::check() const { 46 | QFileInfo file(fcitx4Path()); 47 | return file.isDir(); 48 | } 49 | 50 | RimeMigrator *RimeMigratorPlugin::create() { return new RimeMigrator(); } 51 | 52 | void RimeMigrator::addOfflineJob(Pipeline *pipeline) { 53 | pipeline->addJob(new CallbackRunner( 54 | [](CallbackRunner *) { 55 | QDir dir(fcitx5Path()); 56 | return dir.removeRecursively(); 57 | }, 58 | this)); 59 | auto *migratorJob = new CopyDirectory(fcitx4Path(), fcitx5Path(), this); 60 | pipeline->addJob(migratorJob); 61 | } 62 | 63 | } // namespace fcitx 64 | -------------------------------------------------------------------------------- /src/lib/configwidgetslib/layoutselector.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017~2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | #ifndef _KCM_FCITX_LAYOUTWIDGET_H_ 7 | #define _KCM_FCITX_LAYOUTWIDGET_H_ 8 | 9 | #include "iso639.h" 10 | #include "layoutmodel.h" 11 | #include "layoutprovider.h" 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | class QDBusPendingCallWatcher; 19 | 20 | namespace Ui { 21 | class LayoutSelector; 22 | } 23 | 24 | namespace fcitx { 25 | namespace kcm { 26 | 27 | class DBusProvider; 28 | class KeyboardLayoutWidget; 29 | class LanguageFilterModel; 30 | class LayoutInfoModel; 31 | class VariantInfoModel; 32 | 33 | class LayoutSelector : public QWidget { 34 | Q_OBJECT 35 | public: 36 | LayoutSelector(DBusProvider *dbus, QWidget *parent = nullptr); 37 | ~LayoutSelector(); 38 | void setLayout(const QString &layout, const QString &variant); 39 | 40 | static std::pair 41 | selectLayout(QWidget *parent, DBusProvider *dbus, const QString &title, 42 | const QString &layout, const QString &variant, 43 | bool *ok = nullptr); 44 | 45 | std::pair layout() const; 46 | 47 | private Q_SLOTS: 48 | void languageComboBoxChanged(); 49 | void layoutComboBoxChanged(); 50 | void variantComboBoxChanged(); 51 | 52 | private: 53 | std::unique_ptr ui_; 54 | DBusProvider *dbus_; 55 | LayoutProvider *layoutProvider_; 56 | KeyboardLayoutWidget *keyboardLayoutWidget_ = nullptr; 57 | Iso639 iso639_; 58 | 59 | QString preSelectLayout_; 60 | QString preSelectVariant_; 61 | }; 62 | 63 | } // namespace kcm 64 | } // namespace fcitx 65 | 66 | #endif // _KCM_FCITX_LAYOUTWIDGET_H_ 67 | -------------------------------------------------------------------------------- /src/migrator/app/welcomepage.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | WelcomePage 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | WelcomePage 15 | 16 | 17 | Migrate Data from Fcitx 4 18 | 19 | 20 | 21 | 22 | 23 | Fcitx 5 is not running. 24 | 25 | 26 | KMessageWidget::Error 27 | 28 | 29 | 30 | 31 | 32 | 33 | This wizard will help you to migrate existing user data from Fcitx 4 to Fcitx 5 34 | 35 | 36 | true 37 | 38 | 39 | 40 | 41 | 42 | 43 | Qt::Vertical 44 | 45 | 46 | 47 | 20 48 | 40 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | KMessageWidget 58 | QFrame 59 |
kmessagewidget.h
60 |
61 |
62 | 63 | 64 |
65 | -------------------------------------------------------------------------------- /src/lib/configwidgetslib/impage.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017~2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | #ifndef _FCITX_IMPAGE_H_ 7 | #define _FCITX_IMPAGE_H_ 8 | 9 | #include "imconfig.h" 10 | #include 11 | #include 12 | #include 13 | 14 | namespace Ui { 15 | class IMPage; 16 | } 17 | 18 | namespace fcitx { 19 | namespace kcm { 20 | 21 | class AvailIMModel; 22 | class IMProxyModel; 23 | class CurrentIMModel; 24 | class DBusProvider; 25 | 26 | class IMPage : public QWidget { 27 | Q_OBJECT 28 | public: 29 | IMPage(DBusProvider *dbus, QWidget *parent); 30 | ~IMPage(); 31 | 32 | auto *config() const { return config_; } 33 | 34 | Q_SIGNALS: 35 | void changed(); 36 | public Q_SLOTS: 37 | void save(); 38 | void load(); 39 | void defaults(); 40 | 41 | private Q_SLOTS: 42 | void selectedGroupChanged(); 43 | 44 | void availIMSelectionChanged(); 45 | void currentIMCurrentChanged(); 46 | void selectCurrentIM(const QModelIndex &index); 47 | void doubleClickCurrentIM(const QModelIndex &index); 48 | void doubleClickAvailIM(const QModelIndex &index); 49 | void selectDefaultLayout(); 50 | void selectLayout(); 51 | 52 | void selectAvailIM(const QModelIndex &index); 53 | void clickAddIM(); 54 | void clickRemoveIM(); 55 | void moveDownIM(); 56 | void moveUpIM(); 57 | void configureIM(); 58 | void addGroup(); 59 | void deleteGroup(); 60 | 61 | private: 62 | void addIM(const QModelIndex &index); 63 | void removeIM(const QModelIndex &index); 64 | void checkDefaultLayout(); 65 | void emitChanged(); 66 | 67 | std::unique_ptr ui_; 68 | DBusProvider *dbus_; 69 | IMConfig *config_; 70 | }; 71 | } // namespace kcm 72 | } // namespace fcitx 73 | 74 | #endif // _FCITX_IMPAGE_H_ 75 | -------------------------------------------------------------------------------- /src/configtool/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #include "config.h" 8 | #include "mainwindow.h" 9 | #include 10 | #include 11 | #include 12 | 13 | #ifdef CONFIG_QT_UNIQUE_APP_SUPPORT 14 | #include 15 | #include 16 | #endif 17 | 18 | int main(int argc, char *argv[]) { 19 | QApplication app(argc, argv); 20 | app.setApplicationName("fcitx5-config-qt"); 21 | app.setApplicationVersion(PROJECT_VERSION); 22 | app.setApplicationDisplayName(_("Fcitx Configuration")); 23 | app.setOrganizationDomain("fcitx.org"); 24 | fcitx::registerFcitxQtDBusTypes(); 25 | 26 | QCommandLineParser parser; 27 | parser.addVersionOption(); 28 | parser.addHelpOption(); 29 | parser.process(app); 30 | 31 | auto disableSessionManagement = [](QSessionManager &sm) { 32 | sm.setRestartHint(QSessionManager::RestartNever); 33 | }; 34 | QObject::connect(&app, &QGuiApplication::commitDataRequest, 35 | disableSessionManagement); 36 | QObject::connect(&app, &QGuiApplication::saveStateRequest, 37 | disableSessionManagement); 38 | 39 | fcitx::kcm::MainWindow mainWindow; 40 | 41 | #ifdef CONFIG_QT_UNIQUE_APP_SUPPORT 42 | KDBusService dbusService(KDBusService::Unique); 43 | QObject::connect( 44 | &dbusService, &KDBusService::activateRequested, &mainWindow, 45 | [&mainWindow](const QStringList & /*args*/, 46 | const QString & /*workingDir*/) { 47 | mainWindow.show(); 48 | KWindowSystem::updateStartupId(mainWindow.windowHandle()); 49 | mainWindow.raise(); 50 | KWindowSystem::activateWindow(mainWindow.windowHandle()); 51 | }); 52 | #endif 53 | 54 | mainWindow.show(); 55 | 56 | return app.exec(); 57 | } 58 | -------------------------------------------------------------------------------- /src/lib/configlib/dbusprovider.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #include "dbusprovider.h" 8 | 9 | namespace fcitx { 10 | namespace kcm { 11 | 12 | DBusProvider::DBusProvider(QObject *parent) 13 | : QObject(parent), 14 | watcher_(new FcitxQtWatcher(QDBusConnection::sessionBus(), this)) { 15 | registerFcitxQtDBusTypes(); 16 | connect(watcher_, &FcitxQtWatcher::availabilityChanged, this, 17 | &DBusProvider::fcitxAvailabilityChanged); 18 | watcher_->watch(); 19 | } 20 | 21 | DBusProvider::~DBusProvider() { watcher_->unwatch(); } 22 | 23 | void DBusProvider::fcitxAvailabilityChanged(bool avail) { 24 | delete controller_; 25 | controller_ = nullptr; 26 | 27 | if (avail) { 28 | controller_ = 29 | new FcitxQtControllerProxy(watcher_->serviceName(), "/controller", 30 | watcher_->connection(), this); 31 | controller_->setTimeout(3000); 32 | 33 | loadCanRestart(); 34 | } 35 | 36 | Q_EMIT availabilityChanged(controller_); 37 | } 38 | 39 | void DBusProvider::setCanRestart(bool canRestart) { 40 | if (canRestart_ != canRestart) { 41 | canRestart_ = canRestart; 42 | Q_EMIT canRestartChanged(canRestart_); 43 | } 44 | } 45 | 46 | void DBusProvider::loadCanRestart() { 47 | auto call = controller_->CanRestart(); 48 | auto callwatcher = new QDBusPendingCallWatcher(call, this); 49 | connect(callwatcher, &QDBusPendingCallWatcher::finished, this, 50 | [this](QDBusPendingCallWatcher *watcher) { 51 | QDBusPendingReply canRestart = *watcher; 52 | watcher->deleteLater(); 53 | if (canRestart.isValid()) { 54 | setCanRestart(canRestart.value()); 55 | } 56 | }); 57 | } 58 | 59 | } // namespace kcm 60 | } // namespace fcitx 61 | -------------------------------------------------------------------------------- /src/lib/configwidgetslib/fontbutton.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2012~2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "font.h" 13 | #include "fontbutton.h" 14 | 15 | namespace fcitx { 16 | namespace kcm { 17 | 18 | FontButton::FontButton(QWidget *parent) : QWidget(parent) { 19 | setupUi(this); 20 | connect(fontSelectButton, &QPushButton::clicked, this, 21 | &FontButton::selectFont); 22 | } 23 | 24 | FontButton::~FontButton() {} 25 | 26 | const QFont &FontButton::font() { return font_; } 27 | 28 | QString FontButton::fontName() { return fontPreviewLabel->text(); } 29 | 30 | void FontButton::setFont(const QFont &font) { 31 | font_ = font; 32 | if (font.family() != font_.family()) { 33 | Q_EMIT fontChanged(font_); 34 | } 35 | fontPreviewLabel->setText(fontToString(font_)); 36 | fontPreviewLabel->setFont(font_); 37 | } 38 | 39 | void FontButton::selectFont() { 40 | QDialog dialog(NULL); 41 | KFontChooser *chooser = new KFontChooser(&dialog); 42 | chooser->setFont(font_); 43 | QVBoxLayout *dialogLayout = new QVBoxLayout; 44 | dialog.setLayout(dialogLayout); 45 | QDialogButtonBox *buttonBox = 46 | new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); 47 | buttonBox->button(QDialogButtonBox::Ok)->setText(_("&OK")); 48 | buttonBox->button(QDialogButtonBox::Cancel)->setText(_("&Cancel")); 49 | dialogLayout->addWidget(chooser); 50 | dialogLayout->addWidget(buttonBox); 51 | connect(buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); 52 | connect(buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); 53 | 54 | if (dialog.exec() == QDialog::Accepted) { 55 | setFont(chooser->font()); 56 | } 57 | } 58 | 59 | } // namespace kcm 60 | } // namespace fcitx 61 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: LLVM 4 | AccessModifierOffset: -4 5 | ConstructorInitializerIndentWidth: 4 6 | AlignEscapedNewlinesLeft: false 7 | AlignTrailingComments: true 8 | AllowAllParametersOfDeclarationOnNextLine: true 9 | AllowShortBlocksOnASingleLine: false 10 | AllowShortIfStatementsOnASingleLine: false 11 | AllowShortLoopsOnASingleLine: false 12 | AllowShortFunctionsOnASingleLine: All 13 | AlwaysBreakTemplateDeclarations: true 14 | AlwaysBreakBeforeMultilineStrings: false 15 | BreakBeforeBinaryOperators: false 16 | BreakBeforeTernaryOperators: true 17 | BreakConstructorInitializersBeforeComma: false 18 | BinPackParameters: true 19 | ColumnLimit: 80 20 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 21 | DerivePointerAlignment: false 22 | ExperimentalAutoDetectBinPacking: false 23 | IndentCaseLabels: false 24 | IndentWrappedFunctionNames: false 25 | IndentFunctionDeclarationAfterType: false 26 | MaxEmptyLinesToKeep: 1 27 | KeepEmptyLinesAtTheStartOfBlocks: true 28 | NamespaceIndentation: None 29 | ObjCSpaceAfterProperty: false 30 | ObjCSpaceBeforeProtocolList: true 31 | PenaltyBreakBeforeFirstCallParameter: 19 32 | PenaltyBreakComment: 300 33 | PenaltyBreakString: 1000 34 | PenaltyBreakFirstLessLess: 120 35 | PenaltyExcessCharacter: 1000000 36 | PenaltyReturnTypeOnItsOwnLine: 60 37 | PointerAlignment: Right 38 | SpacesBeforeTrailingComments: 1 39 | Cpp11BracedListStyle: true 40 | Standard: Cpp11 41 | IndentWidth: 4 42 | TabWidth: 4 43 | UseTab: Never 44 | BreakBeforeBraces: Attach 45 | SpacesInParentheses: false 46 | SpacesInAngles: false 47 | SpaceInEmptyParentheses: false 48 | SpacesInCStyleCastParentheses: false 49 | SpacesInContainerLiterals: true 50 | SpaceBeforeAssignmentOperators: true 51 | ContinuationIndentWidth: 4 52 | CommentPragmas: '^ IWYU pragma:' 53 | ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] 54 | SpaceBeforeParens: ControlStatements 55 | DisableFormat: false 56 | SortIncludes: true 57 | ... 58 | 59 | -------------------------------------------------------------------------------- /layout/deadmapdata.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011~2011 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #ifndef _LAYOUT_DEADMAPDATA_H_ 8 | #define _LAYOUT_DEADMAPDATA_H_ 9 | 10 | struct DeadMap { 11 | unsigned int dead; 12 | unsigned int nondead; 13 | } deadMapData[] = { 14 | 15 | {XK_dead_grave, 0x0060}, 16 | {XK_dead_acute, 0x00b4}, 17 | {XK_dead_circumflex, 0x02c6}, 18 | {XK_dead_tilde, 0x02dc}, 19 | {XK_dead_macron, 0x00af}, 20 | {XK_dead_breve, 0x02D8}, 21 | {XK_dead_abovedot, 0x02D9}, 22 | {XK_dead_diaeresis, 0x00A8}, 23 | {XK_dead_abovering, 0x02DA}, 24 | {XK_dead_doubleacute, 0x02DD}, 25 | {XK_dead_caron, 0x02C7}, 26 | {XK_dead_cedilla, 0x00B8}, 27 | {XK_dead_ogonek, 0x02DB}, 28 | {XK_dead_iota, 0x0269}, 29 | {XK_dead_voiced_sound, 0x309B}, 30 | {XK_dead_semivoiced_sound, 0x309A}, 31 | {XK_dead_belowdot, 0x0323}, 32 | {XK_dead_hook, 0x0309}, 33 | {XK_dead_horn, 0x031b}, 34 | {XK_dead_stroke, 0x0335}, 35 | {XK_dead_abovecomma, 0x0312}, 36 | {XK_dead_abovereversedcomma, 0x0314}, 37 | {XK_dead_doublegrave, 0x030f}, 38 | {XK_dead_belowring, 0x0325}, 39 | {XK_dead_belowmacron, 0x0331}, 40 | {XK_dead_belowcircumflex, 0x032D}, 41 | {XK_dead_belowtilde, 0x0330}, 42 | {XK_dead_belowbreve, 0x032e}, 43 | {XK_dead_belowdiaeresis, 0x0324}, 44 | {XK_dead_invertedbreve, 0x0311}, 45 | {XK_dead_belowcomma, 0x0326}, 46 | {XK_dead_currency, 0x00A4}, 47 | 48 | /* dead vowels for universal syllable entry */ 49 | {XK_dead_a, 0x0061}, 50 | {XK_dead_A, 0x0041}, 51 | {XK_dead_e, 0x0065}, 52 | {XK_dead_E, 0x0045}, 53 | {XK_dead_i, 0x0069}, 54 | {XK_dead_I, 0x0049}, 55 | {XK_dead_o, 0x006f}, 56 | {XK_dead_O, 0x004f}, 57 | {XK_dead_u, 0x0075}, 58 | {XK_dead_U, 0x0055}, 59 | {XK_dead_small_schwa, 0x0259}, 60 | {XK_dead_capital_schwa, 0x018F}, 61 | }; 62 | 63 | #endif // _LAYOUT_DEADMAPDATA_H_ 64 | -------------------------------------------------------------------------------- /src/lib/configwidgetslib/fontbutton.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | FontButton 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 186 11 | 12 | 13 | 14 | 15 | 0 16 | 0 17 | 18 | 19 | 20 | Form 21 | 22 | 23 | 24 | 0 25 | 26 | 27 | 0 28 | 29 | 30 | 0 31 | 32 | 33 | 0 34 | 35 | 36 | 37 | 38 | 39 | 0 40 | 0 41 | 42 | 43 | 44 | QFrame::StyledPanel 45 | 46 | 47 | QFrame::Sunken 48 | 49 | 50 | 51 | 52 | 53 | Qt::AlignCenter 54 | 55 | 56 | 57 | 58 | 59 | 60 | Select &Font... 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /src/lib/configlib/iso639.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017~2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #include "iso639.h" 8 | #include "config.h" 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace fcitx { 15 | namespace kcm { 16 | namespace { 17 | 18 | QMap readAlpha3ToNameMap(const char *name, const char *base) { 19 | QMap map; 20 | QFile file(name); 21 | file.open(QIODevice::ReadOnly); 22 | auto data = file.readAll(); 23 | QJsonParseError error; 24 | auto document = QJsonDocument::fromJson(data, &error); 25 | if (error.error != QJsonParseError::NoError || !document.isObject()) { 26 | return {}; 27 | } 28 | 29 | auto object = document.object(); 30 | auto iso = object.value(base); 31 | if (!iso.isArray()) { 32 | return {}; 33 | } 34 | const auto array = iso.toArray(); 35 | for (const auto &item : array) { 36 | if (!item.isObject()) { 37 | continue; 38 | } 39 | auto alpha3 = item.toObject().value("alpha_3").toString(); 40 | auto alpha2 = item.toObject().value("alpha_2").toString(); 41 | auto bibliographic = item.toObject().value("bibliographic").toString(); 42 | auto name = item.toObject().value("name").toString(); 43 | if (name.isEmpty()) { 44 | continue; 45 | } 46 | if (!alpha2.isEmpty()) { 47 | map.insert(alpha2, name); 48 | } 49 | if (!alpha3.isEmpty()) { 50 | map.insert(alpha3, name); 51 | if (!bibliographic.isEmpty()) { 52 | map.insert(bibliographic, name); 53 | } 54 | } 55 | } 56 | return map; 57 | } 58 | } // namespace 59 | 60 | Iso639::Iso639() { 61 | iso639_2data_ = readAlpha3ToNameMap(ISOCODES_ISO639_2_JSON, "639-2"); 62 | iso639_3data_ = readAlpha3ToNameMap(ISOCODES_ISO639_3_JSON, "639-3"); 63 | iso639_5data_ = readAlpha3ToNameMap(ISOCODES_ISO639_5_JSON, "639-5"); 64 | } 65 | 66 | } // namespace kcm 67 | } // namespace fcitx 68 | -------------------------------------------------------------------------------- /src/migrator/table/tablemigrator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #include "tablemigrator.h" 8 | #include "pipeline.h" 9 | #include "processrunner.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace fcitx { 18 | 19 | namespace { 20 | 21 | QString toolPath() { 22 | auto path = QStandardPaths::findExecutable("libime_migrate_fcitx4_table"); 23 | if (path.isEmpty()) { 24 | path = QStandardPaths::findExecutable( 25 | "libime_migrate_fcitx4_table", 26 | {QString::fromStdString( 27 | StandardPaths::fcitxPath("bindir").string())}); 28 | } 29 | return path; 30 | } 31 | 32 | QString fcitx4Path() { 33 | auto path = 34 | StandardPaths::global().userDirectory(StandardPathsType::Config) / 35 | "fcitx/table"; 36 | return QString::fromStdString(path.string()); 37 | } 38 | 39 | } // namespace 40 | 41 | QString TableMigrator::name() const { return _("Table"); } 42 | 43 | QString TableMigrator::description() const { 44 | return _("Import table data for installed table from Fcitx 4"); 45 | } 46 | 47 | bool TableMigrator::check() const { 48 | QFileInfo file(fcitx4Path()); 49 | return file.isDir() && !toolPath().isEmpty(); 50 | } 51 | 52 | TableMigrator *TableMigratorPlugin::create() { return new TableMigrator(); } 53 | 54 | void TableMigrator::addOfflineJob(Pipeline *pipeline) { 55 | auto tool = toolPath(); 56 | if (tool.isEmpty()) { 57 | return; 58 | } 59 | QDir tableDir(fcitx4Path()); 60 | for (const auto &name : 61 | tableDir.entryList({"*.mb"}, QDir::Files | QDir::Readable)) { 62 | auto *processRunner = new ProcessRunner(tool, {name}, {}, this); 63 | processRunner->setIgnoreFailure(true); 64 | processRunner->setPrintOutputToMessage(true); 65 | processRunner->setStartMessage( 66 | QString(_("Try to Migrating table file: %1 ...")).arg(name)); 67 | pipeline->addJob(processRunner); 68 | } 69 | } 70 | 71 | } // namespace fcitx 72 | -------------------------------------------------------------------------------- /layout/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2011~2011 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | 8 | #include "config.h" 9 | #include "keyboardlayoutwidget.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | int main(int argc, char *argv[]) { 17 | qputenv("QT_QPA_PLATFORM", "xcb"); 18 | 19 | QApplication app(argc, argv); 20 | app.setApplicationName(QLatin1String("kbd-layout-viewer")); 21 | app.setApplicationVersion(QLatin1String(PROJECT_VERSION)); 22 | 23 | if (app.platformName() != "xcb") { 24 | QMessageBox msgBox(QMessageBox::Critical, _("Error"), 25 | _("This program only works on X11.")); 26 | msgBox.exec(); 27 | return 1; 28 | } 29 | 30 | QCommandLineParser parser; 31 | parser.setApplicationDescription(_("A general keyboard layout viewer")); 32 | parser.addHelpOption(); 33 | parser.addOptions( 34 | {{{"g", "group"}, _("Keyboard layout (0-3)"), _("group")}, 35 | {{"l", "layout"}, _("Keyboard "), _("layout")}, 36 | {{"v", "variant"}, _("Keyboard layout "), _("variant")}}); 37 | 38 | parser.process(app); 39 | 40 | int group = -1; 41 | QString variant, layout; 42 | if (parser.isSet("group")) { 43 | group = parser.value("group").toInt(); 44 | } 45 | if (parser.isSet("layout")) { 46 | layout = parser.value("layout"); 47 | } 48 | if (parser.isSet("variant")) { 49 | variant = parser.value("variant"); 50 | } 51 | 52 | QMainWindow mainWindow; 53 | mainWindow.setWindowIcon(QIcon::fromTheme("input-keyboard")); 54 | mainWindow.setWindowTitle(_("Keyboard Layout viewer")); 55 | mainWindow.setMinimumSize(QSize(900, 400)); 56 | fcitx::kcm::KeyboardLayoutWidget widget; 57 | if (group > 0 || layout.isNull()) { 58 | if (group < 0) 59 | group = 0; 60 | widget.setGroup(group); 61 | } else if (!layout.isNull()) { 62 | widget.setKeyboardLayout(layout, variant); 63 | } 64 | 65 | mainWindow.setCentralWidget(&widget); 66 | mainWindow.show(); 67 | 68 | return app.exec(); 69 | } 70 | -------------------------------------------------------------------------------- /src/lib/configwidgetslib/configwidget.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017~2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #ifndef _KCM_FCITX_CONFIGWIDGET_H_ 8 | #define _KCM_FCITX_CONFIGWIDGET_H_ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | class QDBusPendingCallWatcher; 16 | class QFormLayout; 17 | 18 | namespace fcitx { 19 | namespace kcm { 20 | 21 | class DBusProvider; 22 | 23 | class ConfigWidget : public QWidget { 24 | Q_OBJECT 25 | 26 | public: 27 | explicit ConfigWidget(const QString &uri, DBusProvider *module, 28 | QWidget *parent = 0); 29 | 30 | explicit ConfigWidget(const QMap &desc, 31 | QString mainType, DBusProvider *module, 32 | QWidget *parent = 0); 33 | 34 | static QDialog *configDialog(QWidget *parent, DBusProvider *module, 35 | const QString &uri, 36 | const QString &title = QString()); 37 | 38 | auto dbus() { return dbus_; } 39 | auto &description() const { return desc_; } 40 | 41 | Q_SIGNALS: 42 | void changed(); 43 | 44 | public Q_SLOTS: 45 | void load(); 46 | void save(); 47 | void buttonClicked(QDialogButtonBox::StandardButton); 48 | 49 | QVariant value() const; 50 | void setValue(const QVariant &variant); 51 | 52 | QString extractOnlyExternalCommand() const; 53 | 54 | void requestConfig(bool sync = false); 55 | private Q_SLOTS: 56 | void requestConfigFinished(QDBusPendingCallWatcher *watcher); 57 | void doChanged(); 58 | 59 | private: 60 | void setupWidget(QWidget *widget, const QString &type, const QString &path); 61 | void addOptionWidget(QFormLayout *layout, const FcitxQtConfigOption &option, 62 | const QString &path); 63 | 64 | bool initialized_ = false; 65 | QString uri_; 66 | QMap desc_; 67 | QString mainType_; 68 | DBusProvider *dbus_; 69 | QWidget *mainWidget_; 70 | 71 | bool dontEmitChanged_ = false; 72 | }; 73 | 74 | ConfigWidget *getConfigWidget(QWidget *widget); 75 | 76 | } // namespace kcm 77 | } // namespace fcitx 78 | 79 | #endif // _KCM_FCITX_CONFIGWIDGET_H_ 80 | -------------------------------------------------------------------------------- /src/kcm/ui/AddIMPage.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | import QtQuick 8 | import QtQuick.Layouts 9 | import QtQuick.Controls 10 | import org.kde.kirigami as Kirigami 11 | import org.kde.kcmutils as KCM 12 | 13 | KCM.ScrollViewKCM { 14 | title: i18n("Add Input Method") 15 | 16 | Component.onCompleted: { 17 | search.forceActiveFocus(); 18 | } 19 | 20 | Binding { 21 | property: "filterText" 22 | target: kcm ? kcm.imConfig.availIMModel : null 23 | value: search.text 24 | } 25 | 26 | footer: RowLayout { 27 | CheckBox { 28 | checked: true 29 | text: i18n("Only &Show Current Language") 30 | visible: search.text.length === 0 31 | 32 | onClicked: { 33 | kcm.imConfig.availIMModel.showOnlyCurrentLanguage = checked; 34 | } 35 | } 36 | Item { 37 | Layout.fillWidth: true 38 | } 39 | Button { 40 | icon.name: "list-add-symbolic" 41 | text: i18n("Add") 42 | 43 | onClicked: { 44 | if (availIMView.currentIndex === -1) { 45 | return; 46 | } 47 | kcm.imConfig.addIM(availIMView.currentIndex); 48 | if (kcm.imConfig.currentIMModel.count === 1) { 49 | kcm.mainUi.checkInputMethod(); 50 | } 51 | kcm.pop(); 52 | } 53 | } 54 | } 55 | header: RowLayout { 56 | TextField { 57 | id: search 58 | Layout.fillWidth: true 59 | placeholderText: i18n("Search...") 60 | } 61 | } 62 | view: ListView { 63 | id: availIMView 64 | model: kcm ? kcm.imConfig.availIMModel : null 65 | 66 | section { 67 | property: "language" 68 | 69 | delegate: Kirigami.ListSectionHeader { 70 | label: section 71 | width: availIMView.width 72 | } 73 | } 74 | 75 | delegate: ItemDelegate { 76 | text: model.name 77 | width: parent.width 78 | highlighted: ListView.isCurrentItem 79 | 80 | onClicked: { 81 | availIMView.currentIndex = index; 82 | } 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/lib/configwidgetslib/addonselector.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | AddonSelector 4 | 5 | 6 | 7 | 0 8 | 0 9 | 557 10 | 523 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 0 19 | 20 | 21 | 0 22 | 23 | 24 | 0 25 | 26 | 27 | 0 28 | 29 | 30 | 31 | 32 | Search Addons 33 | 34 | 35 | true 36 | 37 | 38 | 39 | 40 | 41 | 42 | true 43 | 44 | 45 | true 46 | 47 | 48 | QAbstractItemView::ScrollPerItem 49 | 50 | 51 | QAbstractItemView::ScrollPerItem 52 | 53 | 54 | 0 55 | 56 | 57 | false 58 | 59 | 60 | false 61 | 62 | 63 | true 64 | 65 | 66 | true 67 | 68 | 69 | false 70 | 71 | 72 | 73 | 74 | 75 | 76 | Show &Advanced options 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /src/migrator/kkc/kkcmigrator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #include "kkcmigrator.h" 8 | #include "copydirectory.h" 9 | #include "pipeline.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | namespace fcitx { 20 | 21 | namespace { 22 | 23 | QString fcitx4Path() { 24 | auto path = 25 | StandardPaths::global().userDirectory(StandardPathsType::Config) / 26 | "fcitx/kkc"; 27 | return QString::fromStdString(path.string()); 28 | } 29 | 30 | QString fcitx5Path() { 31 | auto path = 32 | StandardPaths::global().userDirectory(StandardPathsType::PkgData) / 33 | "kkc"; 34 | return QString::fromStdString(path.string()); 35 | } 36 | 37 | } // namespace 38 | 39 | QString KkcMigrator::name() const { return _("Kkc"); } 40 | 41 | QString KkcMigrator::description() const { 42 | return _("Migrate Kkc dictionary from Fcitx 4"); 43 | } 44 | 45 | bool KkcMigrator::check() const { 46 | QFileInfo file(fcitx4Path()); 47 | return file.isDir(); 48 | } 49 | 50 | KkcMigrator *KkcMigratorPlugin::create() { return new KkcMigrator(); } 51 | 52 | void KkcMigrator::addOfflineJob(Pipeline *pipeline) { 53 | auto *migratorJob = new CopyDirectory(fcitx4Path(), fcitx5Path(), this); 54 | migratorJob->setExcludes({"^rule$"}); 55 | pipeline->addJob(migratorJob); 56 | } 57 | 58 | void KkcMigrator::addOnlineJob(Pipeline *pipeline) { 59 | auto *portRuleJob = new ConfigMigrator( 60 | "fcitx://config/addon/skk", 61 | [](RawConfig &config) { 62 | auto ruleFile = StandardPaths::global().open( 63 | StandardPathsType::Config, "fcitx/kkc/rule", 64 | StandardPathsMode::User); 65 | QFile file; 66 | if (ruleFile.isValid() && 67 | file.open(ruleFile.fd(), QIODevice::ReadOnly)) { 68 | auto rule = file.readAll().trimmed(); 69 | if (!rule.isEmpty()) { 70 | config.setValueByPath("Rule", rule.toStdString()); 71 | return true; 72 | } 73 | } 74 | return false; 75 | }, 76 | this); 77 | portRuleJob->setStartMessage(_("Migrating Kkc rule option...")); 78 | pipeline->addJob(portRuleJob); 79 | } 80 | 81 | } // namespace fcitx 82 | -------------------------------------------------------------------------------- /src/migrator/skk/skkmigrator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #include "skkmigrator.h" 8 | #include "configmigrator.h" 9 | #include "copydirectory.h" 10 | #include "pipeline.h" 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | namespace fcitx { 21 | 22 | namespace { 23 | 24 | QString fcitx4Path() { 25 | auto path = 26 | StandardPaths::global().userDirectory(StandardPathsType::Config) / 27 | "fcitx/skk"; 28 | return QString::fromStdString(path.string()); 29 | } 30 | 31 | QString fcitx5Path() { 32 | auto path = 33 | StandardPaths::global().userDirectory(StandardPathsType::PkgData) / 34 | "skk"; 35 | return QString::fromStdString(path.string()); 36 | } 37 | 38 | } // namespace 39 | 40 | QString SkkMigrator::name() const { return _("Skk"); } 41 | 42 | QString SkkMigrator::description() const { 43 | return _("Migrate Skk dictionary from Fcitx 4"); 44 | } 45 | 46 | bool SkkMigrator::check() const { 47 | QFileInfo file(fcitx4Path()); 48 | return file.isDir(); 49 | } 50 | 51 | SkkMigrator *SkkMigratorPlugin::create() { return new SkkMigrator(); } 52 | 53 | void SkkMigrator::addOfflineJob(Pipeline *pipeline) { 54 | auto *migratorJob = new CopyDirectory(fcitx4Path(), fcitx5Path(), this); 55 | migratorJob->setExcludes({"^rule$"}); 56 | pipeline->addJob(migratorJob); 57 | } 58 | 59 | void SkkMigrator::addOnlineJob(Pipeline *pipeline) { 60 | auto *portRuleJob = new ConfigMigrator( 61 | "fcitx://config/addon/skk", 62 | [](RawConfig &config) { 63 | auto ruleFile = StandardPaths::global().open( 64 | StandardPathsType::Config, "fcitx/skk/rule", 65 | StandardPathsMode::User); 66 | QFile file; 67 | if (ruleFile.isValid() && 68 | file.open(ruleFile.fd(), QIODevice::ReadOnly)) { 69 | auto rule = file.readAll().trimmed(); 70 | if (!rule.isEmpty()) { 71 | config.setValueByPath("Rule", rule.toStdString()); 72 | return true; 73 | } 74 | } 75 | return false; 76 | }, 77 | this); 78 | portRuleJob->setStartMessage(_("Migrating Skk rule option...")); 79 | pipeline->addJob(portRuleJob); 80 | } 81 | 82 | } // namespace fcitx 83 | -------------------------------------------------------------------------------- /src/lib/configwidgetslib/layoutselector.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | LayoutSelector 4 | 5 | 6 | 7 | 0 8 | 0 9 | 600 10 | 300 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Language: 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 0 31 | 0 32 | 33 | 34 | 35 | 36 | 400 37 | 0 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | Layout: 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 0 54 | 0 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | Variant: 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 0 71 | 0 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /src/migrator/app/taskpage.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | TaskPage 4 | 5 | 6 | 7 | 0 8 | 0 9 | 515 10 | 407 11 | 12 | 13 | 14 | 15 | 16 | 17 | Select migration tasks 18 | 19 | 20 | 21 | 22 | 23 | Fcitx 5 is not running. 24 | 25 | 26 | KMessageWidget::Error 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 0 39 | 0 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | Select &All 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 0 58 | 1 59 | 60 | 61 | 62 | 63 | 64 | 65 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop 66 | 67 | 68 | true 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | KMessageWidget 79 | QFrame 80 |
kmessagewidget.h
81 |
82 |
83 | 84 | 85 |
86 | -------------------------------------------------------------------------------- /src/kcm/ui/OptionLoader.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | import QtQuick 8 | import QtQuick.Controls 9 | import QtQuick.Layouts 10 | import org.kde.kirigami as Kirigami 11 | import "utils.js" as Utils 12 | 13 | Loader { 14 | id: loader 15 | property variant option 16 | property variant rawValue 17 | 18 | ToolTip.delay: Kirigami.Units.toolTipDelay 19 | ToolTip.text: option.properties && Utils.hasProperty(option.properties, "Tooltip") ? option.properties["Tooltip"] : "" 20 | ToolTip.visible: { 21 | if (option.properties && Utils.hasProperty(option.properties, "Tooltip") && loader.item) { 22 | if (Utils.hasProperty(loader.item, "hovered")) { 23 | return loader.item.hovered; 24 | } 25 | } 26 | return false; 27 | } 28 | 29 | function optionSource(data) { 30 | if (data.type == "Boolean") { 31 | return "BoolOption.qml"; 32 | } else if (data.type == "Integer") { 33 | return "IntegerOption.qml"; 34 | } else if (data.type == "Enum") { 35 | return "EnumOption.qml"; 36 | } else if (data.type == "String") { 37 | if (Utils.hasProperty(data.properties, "Font") && data.properties.Font == "True") { 38 | return "FontOption.qml"; 39 | } else if (Utils.hasProperty(data.properties, "IsEnum") && data.properties.IsEnum == "True") { 40 | return "EnumOption.qml"; 41 | } else { 42 | return "StringOption.qml"; 43 | } 44 | } else if (data.type == "List|Key") { 45 | return "KeyListOption.qml"; 46 | } else if (data.type == "Key") { 47 | return "KeyOption.qml"; 48 | } else if (data.type == "Color") { 49 | return "ColorOption.qml"; 50 | } else if (data.type.startsWith("List|")) { 51 | return "ListOption.qml"; 52 | } else if (data.type == "External") { 53 | return "ExternalOption.qml"; 54 | } else { 55 | console.log(data.type + " Not supported"); 56 | return ""; 57 | } 58 | } 59 | 60 | Component.onCompleted: { 61 | if (!option.isSection) { 62 | var prop = { 63 | "typeName": option.type, 64 | "description": option.description ? option.description : "", 65 | "defaultValue": option.defaultValue, 66 | "properties": option.properties, 67 | "rawValue": rawValue 68 | }; 69 | loader.setSource(optionSource(option), prop); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/migrator/lib/dbuswatcher.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #include "dbuswatcher.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace fcitx { 14 | 15 | DBusWatcher::DBusWatcher(const QString &service, const QString &startMessage, 16 | const QString &finishMessage, bool expectation, 17 | QObject *parent) 18 | : PipelineJob(parent), service_(service), startMessage_(startMessage), 19 | finishMessage_(finishMessage), watcher_(new QDBusServiceWatcher(this)), 20 | timer_(new QTimer(this)), expectation_(expectation) { 21 | connect(watcher_, &QDBusServiceWatcher::serviceRegistered, this, 22 | [this]() { available_ = true; }); 23 | connect(watcher_, &QDBusServiceWatcher::serviceUnregistered, this, 24 | [this]() { available_ = false; }); 25 | watcher_->setConnection(QDBusConnection::sessionBus()); 26 | watcher_->setWatchMode(QDBusServiceWatcher::WatchForOwnerChange); 27 | watcher_->addWatchedService({service}); 28 | timer_->setSingleShot(true); 29 | connect(timer_, &QTimer::timeout, this, [this]() { 30 | if (available_ != expectation_) { 31 | if (available_) { 32 | message("dialog-warning", 33 | QString(_("Service %1 still present on DBus.")) 34 | .arg(service_)); 35 | } else { 36 | message("dialog-warning", 37 | QString(_("Service %1 does not present on DBus.")) 38 | .arg(service_)); 39 | } 40 | if (firstCheck_) { 41 | timer_->setInterval(4000); 42 | firstCheck_ = false; 43 | timer_->start(); 44 | } else { 45 | finished(false); 46 | } 47 | } else { 48 | message("dialog-information", finishMessage_); 49 | finished(true); 50 | } 51 | }); 52 | } 53 | 54 | void DBusWatcher::start() { 55 | firstCheck_ = true; 56 | message("dialog-information", startMessage_); 57 | available_ = 58 | watcher_->connection().interface()->isServiceRegistered(service_); 59 | if (available_ != expectation_) { 60 | timer_->setInterval(1000); 61 | timer_->start(); 62 | } else { 63 | message("dialog-information", finishMessage_); 64 | finished(true); 65 | } 66 | } 67 | 68 | void DBusWatcher::abort() { cleanUp(); } 69 | 70 | void DBusWatcher::cleanUp() { timer_->stop(); } 71 | 72 | } // namespace fcitx 73 | -------------------------------------------------------------------------------- /src/migrator/lib/processrunner.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2013-2018 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #include "processrunner.h" 8 | #include 9 | #include 10 | #include 11 | 12 | namespace fcitx { 13 | 14 | ProcessRunner::ProcessRunner(const QString &bin, const QStringList &args, 15 | const QString &file, QObject *parent) 16 | : PipelineJob(parent), bin_(bin), args_(args), file_(file) { 17 | connect(&process_, 18 | qOverload(&QProcess::finished), this, 19 | &ProcessRunner::processFinished); 20 | connect(&process_, &QProcess::readyReadStandardOutput, this, [this] { 21 | QByteArray bytes = process_.readAllStandardOutput(); 22 | messages_.append(bytes); 23 | }); 24 | } 25 | 26 | void ProcessRunner::start() { 27 | messages_.clear(); 28 | if (process_.state() != QProcess::NotRunning) { 29 | process_.kill(); 30 | } 31 | 32 | if (!startMessage_.isEmpty()) { 33 | message("dialog-information", startMessage_); 34 | } 35 | 36 | if (printOutputToMessage_) { 37 | process_.setProcessChannelMode(QProcess::MergedChannels); 38 | } 39 | process_.start(bin_, args_); 40 | if (printOutputToMessage_) { 41 | process_.closeReadChannel(QProcess::StandardError); 42 | process_.setReadChannel(QProcess::StandardOutput); 43 | } else { 44 | process_.closeReadChannel(QProcess::StandardError); 45 | process_.closeReadChannel(QProcess::StandardOutput); 46 | } 47 | } 48 | 49 | void ProcessRunner::abort() { process_.kill(); } 50 | 51 | void ProcessRunner::cleanUp() { 52 | if (!file_.isEmpty()) { 53 | QFile::remove(file_); 54 | } 55 | } 56 | 57 | void ProcessRunner::processFinished(int exitCode, QProcess::ExitStatus status) { 58 | if (printOutputToMessage_) { 59 | for (const auto &line : messages_.split('\n')) { 60 | if (!line.isEmpty()) { 61 | Q_EMIT message("dialog-information", line); 62 | } 63 | } 64 | } 65 | if (status == QProcess::CrashExit) { 66 | Q_EMIT message("dialog-error", QString(_("%1 crashed.")).arg(file_)); 67 | Q_EMIT finished(ignoreFailure_); 68 | return; 69 | } 70 | 71 | if (exitCode != 0) { 72 | Q_EMIT message("dialog-warning", 73 | QString(_("%1 failed to start.")).arg(file_)); 74 | Q_EMIT finished(ignoreFailure_); 75 | return; 76 | } 77 | 78 | if (!finishMessage_.isEmpty()) { 79 | Q_EMIT message("dialog-information", finishMessage_); 80 | } 81 | Q_EMIT finished(true); 82 | } 83 | 84 | } // namespace fcitx 85 | -------------------------------------------------------------------------------- /src/kcm/ui/EnumOption.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | import QtQuick 8 | import QtQuick.Controls 9 | import org.kde.kirigami as Kirigami 10 | import "utils.js" as Utils 11 | 12 | Row { 13 | property string typeName 14 | property string description 15 | property variant defaultValue 16 | property variant properties 17 | property variant rawValue 18 | property bool needsSave: value != comboBox.currentIndex 19 | property int value: computeValue(rawValue) 20 | 21 | function computeValue(rawValue) { 22 | for (var i = 0; i < listModel.count; i++) { 23 | if (listModel.get(i).value == rawValue) { 24 | return i; 25 | } 26 | } 27 | return 0; 28 | } 29 | function load(rawValue) { 30 | comboBox.currentIndex = computeValue(rawValue); 31 | } 32 | function save() { 33 | rawValue = properties["Enum"][comboBox.currentIndex.toString()]; 34 | } 35 | 36 | Component.onCompleted: { 37 | var i = 0; 38 | while (true) { 39 | if (!Utils.hasProperty(properties, "Enum")) { 40 | break; 41 | } 42 | if (!Utils.hasProperty(properties["Enum"], i.toString())) { 43 | break; 44 | } 45 | var value = properties["Enum"][i.toString()]; 46 | var text = ""; 47 | if (Utils.hasProperty(properties, "EnumI18n")) { 48 | if (Utils.hasProperty(properties["EnumI18n"], i.toString())) { 49 | text = properties["EnumI18n"][i.toString()]; 50 | } 51 | } 52 | if (text == "") { 53 | text = value; 54 | } 55 | var subconfigpath = ""; 56 | if (Utils.hasProperty(properties, "SubConfigPath")) { 57 | if (Utils.hasProperty(properties["SubConfigPath"], i.toString())) { 58 | subconfigpath = properties["SubConfigPath"][i.toString()]; 59 | } 60 | } 61 | listModel.append({ 62 | "text": text, 63 | "value": value, 64 | "subconfigpath": subconfigpath 65 | }); 66 | i++; 67 | } 68 | load(rawValue); 69 | save(); 70 | } 71 | 72 | ComboBox { 73 | id: comboBox 74 | implicitWidth: Kirigami.Units.gridUnit * 14 75 | textRole: "text" 76 | 77 | model: ListModel { 78 | id: listModel 79 | } 80 | } 81 | ToolButton { 82 | id: configureButton 83 | icon.name: "configure" 84 | visible: listModel.get(comboBox.currentIndex).subconfigpath !== "" 85 | 86 | onClicked: { 87 | kcm.pushConfigPage(listModel.get(comboBox.currentIndex).text, listModel.get(comboBox.currentIndex).subconfigpath); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /.github/workflows/check.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | branches: 8 | - master 9 | jobs: 10 | clang-format: 11 | name: Check clang-format 12 | runs-on: ubuntu-latest 13 | container: archlinux:latest 14 | steps: 15 | - name: Install dependencies 16 | run: | 17 | pacman -Syu --noconfirm git clang diffutils 18 | git config --global --add safe.directory $GITHUB_WORKSPACE 19 | - uses: actions/checkout@v4 20 | - uses: fcitx/github-actions@clang-format 21 | check: 22 | name: Build and test 23 | needs: clang-format 24 | runs-on: ubuntu-latest 25 | container: archlinux:latest 26 | strategy: 27 | fail-fast: false 28 | matrix: 29 | compiler: [gcc, clang] 30 | include: 31 | - compiler: gcc 32 | cxx_compiler: g++ 33 | - compiler: clang 34 | cxx_compiler: clang++ 35 | env: 36 | CC: ${{ matrix.compiler }} 37 | CXX: ${{ matrix.cxx_compiler }} 38 | steps: 39 | - name: Install dependencies 40 | run: | 41 | pacman -Syu --noconfirm base-devel clang cmake ninja extra-cmake-modules fmt libuv git qt6-base libplasma kcmutils kdeclarative kirigami ksvg libxkbfile openmp 42 | - uses: actions/checkout@v4 43 | with: 44 | repository: fcitx/fcitx5 45 | path: fcitx5 46 | - name: Cache fcitx5 data files 47 | uses: actions/cache@v4 48 | with: 49 | path: 'fcitx5/**/*.tar.*' 50 | key: ${{ runner.os }}-${{ hashFiles('fcitx5/src/modules/spell/CMakeLists.txt') 51 | }} 52 | - name: Build and Install fcitx5 53 | uses: fcitx/github-actions@cmake 54 | with: 55 | path: fcitx5 56 | cmake-option: >- 57 | -DENABLE_KEYBOARD=Off -DENABLE_X11=Off -DENABLE_WAYLAND=Off -DENABLE_ENCHANT=Off 58 | -DENABLE_DBUS=Off -DENABLE_SERVER=Off -DENABLE_EMOJI=Off -DUSE_SYSTEMD=Off 59 | - uses: actions/checkout@v4 60 | with: 61 | repository: fcitx/fcitx5-qt 62 | path: fcitx5-qt 63 | - name: Build and Install fcitx5-qt 64 | uses: fcitx/github-actions@cmake 65 | with: 66 | repository: fcitx/fcitx5-qt 67 | path: fcitx5-qt 68 | cmake-option: >- 69 | -DENABLE_QT4=Off -DENABLE_QT5=Off -DENABLE_QT6=On 70 | - uses: actions/checkout@v4 71 | with: 72 | path: fcitx5-configtool 73 | - name: Init CodeQL 74 | uses: github/codeql-action/init@v3 75 | with: 76 | languages: cpp 77 | source-root: fcitx5-configtool 78 | - name: Build and Install fcitx5-configtool 79 | uses: fcitx/github-actions@cmake 80 | with: 81 | path: fcitx5-configtool 82 | - name: Test 83 | run: | 84 | ctest --test-dir fcitx5-configtool/build 85 | - name: CodeQL Analysis 86 | uses: github/codeql-action/analyze@v2 87 | -------------------------------------------------------------------------------- /src/lib/configwidgetslib/erroroverlay.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017~2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #include "erroroverlay.h" 8 | #include "dbusprovider.h" 9 | #include "ui_erroroverlay.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | namespace fcitx::kcm { 24 | 25 | ErrorOverlay::ErrorOverlay(DBusProvider *dbus, QWidget *parent) 26 | : QWidget(parent), ui_(std::make_unique()), 27 | baseWidget_(parent) { 28 | ui_->setupUi(this); 29 | setVisible(false); 30 | 31 | baseWidget_->installEventFilter(this); 32 | ui_->pixmapLabel->setPixmap( 33 | QIcon::fromTheme("dialog-error-symbolic").pixmap(64)); 34 | 35 | connect(baseWidget_, &QObject::destroyed, this, &QObject::deleteLater); 36 | connect(dbus, &DBusProvider::availabilityChanged, this, 37 | &ErrorOverlay::availabilityChanged); 38 | 39 | connect(ui_->runFcitxButton, &QAbstractButton::pressed, this, 40 | &ErrorOverlay::runFcitx5); 41 | availabilityChanged(dbus->available()); 42 | } 43 | 44 | ErrorOverlay::~ErrorOverlay() {} 45 | 46 | void ErrorOverlay::availabilityChanged(bool avail) { 47 | const bool newEnabled = !avail; 48 | if (enabled_ != newEnabled) { 49 | enabled_ = newEnabled; 50 | setVisible(newEnabled); 51 | if (newEnabled) { 52 | reposition(); 53 | } 54 | } 55 | } 56 | 57 | void ErrorOverlay::runFcitx5() { 58 | QProcess::startDetached( 59 | QString::fromStdString( 60 | StandardPaths::fcitxPath("bindir", "fcitx5").string()), 61 | QStringList()); 62 | } 63 | 64 | void ErrorOverlay::reposition() { 65 | if (!baseWidget_) { 66 | return; 67 | } 68 | 69 | // follow base widget visibility 70 | // needed eg. in tab widgets 71 | if (!baseWidget_->isVisible()) { 72 | hide(); 73 | return; 74 | } 75 | 76 | show(); 77 | 78 | // follow position changes 79 | const QPoint topLevelPos = baseWidget_->mapTo(window(), QPoint(0, 0)); 80 | const QPoint parentPos = parentWidget()->mapFrom(window(), topLevelPos); 81 | move(parentPos); 82 | 83 | // follow size changes 84 | // TODO: hide/scale icon if we don't have enough space 85 | resize(baseWidget_->size()); 86 | raise(); 87 | } 88 | 89 | bool ErrorOverlay::eventFilter(QObject *object, QEvent *event) { 90 | if (enabled_ && object == baseWidget_ && 91 | (event->type() == QEvent::Move || event->type() == QEvent::Resize || 92 | event->type() == QEvent::Show || event->type() == QEvent::Hide || 93 | event->type() == QEvent::ParentChange)) { 94 | reposition(); 95 | } 96 | return QWidget::eventFilter(object, event); 97 | } 98 | 99 | } // namespace fcitx::kcm 100 | -------------------------------------------------------------------------------- /src/kcm/ui/ConfigGroup.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | import QtQuick 8 | import QtQuick.Controls 9 | import QtQuick.Layouts 10 | import org.kde.kirigami as Kirigami 11 | import "utils.js" as Utils 12 | 13 | Kirigami.FormLayout { 14 | id: configGroup 15 | property string typeName 16 | property string description 17 | property variant defaultValue 18 | property variant properties 19 | property variant rawValue 20 | property bool needsSave 21 | property variant typeMap 22 | 23 | function defaults() { 24 | for (var i = 0; i < repeater.count; i++) { 25 | var loader = repeater.itemAt(i); 26 | if (loader.status == Loader.Ready) { 27 | loader.item.load(loader.option.defaultValue); 28 | } 29 | } 30 | } 31 | function load() { 32 | for (var i = 0; i < repeater.count; i++) { 33 | var loader = repeater.itemAt(i); 34 | if (loader.status == Loader.Ready) { 35 | loader.item.load(loader.item.rawValue); 36 | } 37 | } 38 | needsSave = false; 39 | } 40 | function save() { 41 | var rawValue = {}; 42 | for (var i = 0; i < repeater.count; i++) { 43 | var loader = repeater.itemAt(i); 44 | if (loader.status == Loader.Ready) { 45 | loader.item.save(); 46 | if (Utils.hasProperty(loader.item, "rawValue")) { 47 | Utils.setRawValue(rawValue, loader.option.name, loader.item.rawValue); 48 | } 49 | } 50 | } 51 | configGroup.rawValue = rawValue; 52 | configGroup.needsSave = false; 53 | } 54 | function setRawValue(rawValue) { 55 | for (var i = 0; i < repeater.count; i++) { 56 | var loader = repeater.itemAt(i); 57 | if (loader.status == Loader.Ready) { 58 | loader.item.load(Utils.getRawValue(rawValue, loader.option.name)); 59 | } 60 | } 61 | } 62 | 63 | Repeater { 64 | id: repeater 65 | model: typeMap[typeName] 66 | 67 | OptionLoader { 68 | id: loader 69 | Layout.fillWidth: option.type !== "Boolean" 70 | Kirigami.FormData.isSection: modelData.isSection 71 | Kirigami.FormData.label: modelData.isSection ? modelData.description : i18n("%1:", modelData.description) 72 | Kirigami.FormData.labelAlignment: !modelData.isSection && modelData.type.startsWith("List|") ? (height > Kirigami.Units.gridUnit * 2 ? Qt.AlignTop : 0) : 0 73 | option: modelData 74 | rawValue: modelData.isSection ? null : Utils.getRawValue(configGroup.rawValue, modelData.name) 75 | 76 | Connections { 77 | enabled: loader.status == Loader.Ready 78 | target: loader.status == Loader.Ready ? loader.item : null 79 | 80 | function onNeedsSaveChanged() { 81 | if (target.needsSave) { 82 | configGroup.needsSave = true; 83 | } 84 | } 85 | } 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/migrator/lib/migratorfactory.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | 8 | #include "migratorfactory.h" 9 | #include "migrator.h" 10 | #include "migratorfactory_p.h" 11 | #include "migratorfactoryplugin.h" 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | namespace fcitx { 28 | 29 | MigratorFactoryPrivate::MigratorFactoryPrivate(MigratorFactory *factory) 30 | : QObject(factory), q_ptr(factory) {} 31 | 32 | MigratorFactoryPrivate::~MigratorFactoryPrivate() {} 33 | 34 | void MigratorFactoryPrivate::scan() { 35 | for (const auto &staticPlugin : QPluginLoader::staticPlugins()) { 36 | auto metadata = staticPlugin.metaData(); 37 | if (metadata.value("IID") != 38 | QLatin1String(FcitxMigratorFactoryInterface_iid)) { 39 | continue; 40 | } 41 | auto pluginMetadata = metadata.value("MetaData").toObject(); 42 | auto addon = metadata.value("addon").toVariant().toString(); 43 | if (auto *plugin = qobject_cast( 44 | staticPlugin.instance())) { 45 | plugins_.emplace_back(plugin, addon); 46 | } 47 | } 48 | 49 | auto libraries = StandardPaths::global().locate( 50 | StandardPathsType::Addon, "qt" QT_STRINGIFY(QT_VERSION_MAJOR), 51 | [](const std::filesystem::path &path) { 52 | QString filePath(QString::fromStdString(path.string())); 53 | return QLibrary::isLibrary(filePath); 54 | }, 55 | StandardPathsMode::System); 56 | 57 | for (const auto &[_, filePath] : libraries) { 58 | auto *loader = 59 | new QPluginLoader(QString::fromStdString(filePath.string()), this); 60 | if (loader->metaData().value("IID") != 61 | QLatin1String(FcitxMigratorFactoryInterface_iid)) { 62 | delete loader; 63 | continue; 64 | } 65 | auto metadata = loader->metaData().value("MetaData").toObject(); 66 | auto addon = metadata.value("addon").toVariant().toString(); 67 | if (auto *plugin = qobject_cast( 68 | loader->instance())) { 69 | plugins_.emplace_back(plugin, addon); 70 | } else { 71 | delete loader; 72 | } 73 | } 74 | } 75 | 76 | MigratorFactory::MigratorFactory(QObject *parent) 77 | : QObject(parent), d_ptr(new MigratorFactoryPrivate(this)) { 78 | Q_D(MigratorFactory); 79 | d->scan(); 80 | } 81 | 82 | MigratorFactory::~MigratorFactory() {} 83 | 84 | std::vector> 85 | MigratorFactory::list(const QSet &addons) const { 86 | Q_D(const MigratorFactory); 87 | std::vector> result; 88 | for (const auto &[plugin, addon] : d->plugins_) { 89 | if (addon.isEmpty() || addons.contains(addon)) { 90 | if (auto *migrator = plugin->create()) { 91 | result.emplace_back(migrator); 92 | } 93 | } 94 | } 95 | return result; 96 | } 97 | 98 | } // namespace fcitx 99 | -------------------------------------------------------------------------------- /src/lib/configwidgetslib/varianthelper.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017~2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #include "varianthelper.h" 8 | #include 9 | 10 | namespace fcitx { 11 | namespace kcm { 12 | 13 | QVariantMap toMap(const QVariant &variant) { 14 | QVariantMap map; 15 | if (variant.canConvert()) { 16 | auto argument = qvariant_cast(variant); 17 | argument >> map; 18 | } 19 | if (variant.canConvert()) { 20 | map = variant.toMap(); 21 | } 22 | return map; 23 | } 24 | 25 | QString valueFromVariantMapByPath(const QVariantMap &map, 26 | const QStringList &path, int depth) { 27 | auto iter = map.find(path[depth]); 28 | if (iter == map.end()) { 29 | return QString(); 30 | } 31 | if (depth + 1 == path.size()) { 32 | if (iter->canConvert()) { 33 | return iter->toString(); 34 | } 35 | } else { 36 | QVariantMap map = toMap(*iter); 37 | 38 | if (!map.isEmpty()) { 39 | return valueFromVariantMapByPath(map, path, depth + 1); 40 | } 41 | } 42 | return QString(); 43 | } 44 | 45 | QVariant valueFromVariantHelper(const QVariant &value, 46 | const QStringList &pathList, int depth) { 47 | if (depth == pathList.size()) { 48 | return value; 49 | } 50 | auto map = toMap(value); 51 | // Make it finishes faster. 52 | if (map.isEmpty() || !map.contains(pathList[depth])) { 53 | return {}; 54 | } 55 | return valueFromVariantHelper(map[pathList[depth]], pathList, depth + 1); 56 | } 57 | 58 | QVariant readVariant(const QVariant &value, const QString &path) { 59 | auto pathList = path.split("/"); 60 | return valueFromVariantHelper(toMap(value), pathList, 0); 61 | } 62 | 63 | QString readString(const QVariantMap &map, const QString &path) { 64 | auto pathList = path.split("/"); 65 | if (pathList.empty()) { 66 | return QString(); 67 | } 68 | return valueFromVariantMapByPath(map, pathList, 0); 69 | } 70 | 71 | bool readBool(const QVariantMap &map, const QString &path) { 72 | return readString(map, path) == "True"; 73 | } 74 | 75 | void writeVariantHelper(QVariantMap &map, const QStringList &path, 76 | const QVariant &value, int depth) { 77 | if (depth + 1 == path.size()) { 78 | map[path[depth]] = value; 79 | } else { 80 | auto iter = map.find(path[depth]); 81 | if (iter == map.end()) { 82 | iter = map.insert(path[depth], QVariantMap()); 83 | } 84 | 85 | if (iter->typeId() != QMetaType::QVariantMap) { 86 | auto oldValue = *iter; 87 | *iter = QVariantMap({{"", oldValue}}); 88 | } 89 | 90 | auto &nextMap = *static_cast(iter->data()); 91 | writeVariantHelper(nextMap, path, value, depth + 1); 92 | } 93 | } 94 | 95 | void writeVariant(QVariantMap &map, const QString &path, 96 | const QVariant &value) { 97 | auto pathList = path.split("/"); 98 | if (pathList.empty()) { 99 | return; 100 | } 101 | writeVariantHelper(map, pathList, value, 0); 102 | } 103 | 104 | } // namespace kcm 105 | } // namespace fcitx 106 | -------------------------------------------------------------------------------- /src/migrator/global/globalconfigmigrator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #include "globalconfigmigrator.h" 8 | #include "configmigrator.h" 9 | #include "pipeline.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | namespace fcitx { 24 | 25 | namespace { 26 | 27 | QString fcitx4Path() { 28 | auto path = 29 | StandardPaths::global().userDirectory(StandardPathsType::Config) / 30 | "fcitx/config"; 31 | return QString::fromStdString(path.string()); 32 | } 33 | 34 | bool setKeyListToConfig(RawConfig &config, const std::string &path, 35 | const KeyList &keyList) { 36 | if (keyList.empty()) { 37 | return false; 38 | } 39 | config.remove(path); 40 | 41 | for (size_t i = 0; i < keyList.size(); i++) { 42 | config.setValueByPath(stringutils::joinPath(path, i), 43 | keyList[i].toString()); 44 | } 45 | return true; 46 | } 47 | 48 | } // namespace 49 | 50 | QString GlobalConfigMigrator::name() const { return _("Global Config"); } 51 | 52 | QString GlobalConfigMigrator::description() const { 53 | return _("Migrate global key option from Fcitx 4"); 54 | } 55 | 56 | bool GlobalConfigMigrator::check() const { 57 | QFileInfo file(fcitx4Path()); 58 | return file.isFile(); 59 | } 60 | 61 | GlobalConfigMigrator *GlobalConfigMigratorPlugin::create() { 62 | return new GlobalConfigMigrator(); 63 | } 64 | 65 | void GlobalConfigMigrator::addOnlineJob(Pipeline *pipeline) { 66 | auto *portRuleJob = new ConfigMigrator( 67 | "fcitx://config/global", 68 | [](RawConfig &config) { 69 | auto configFile = StandardPaths::global().open( 70 | StandardPathsType::Config, "fcitx/config", 71 | StandardPathsMode::User); 72 | if (configFile.isValid()) { 73 | bool changed = false; 74 | RawConfig fcitx4Config; 75 | readFromIni(fcitx4Config, configFile.fd()); 76 | 77 | std::vector> keyPairs = { 78 | {"Hotkey/TriggerKey", "Hotkey/TriggerKeys"}, 79 | {"Hotkey/ActivateKey", "Hotkey/ActivateKeys"}, 80 | {"Hotkey/InactivateKey", "Hotkey/DeactivateKeys"}}; 81 | for (const auto &[oldKey, newKey] : keyPairs) { 82 | if (const auto *value = fcitx4Config.valueByPath(oldKey)) { 83 | changed = setKeyListToConfig( 84 | config, newKey, 85 | Key::keyListFromString(*value)) || 86 | changed; 87 | } 88 | } 89 | 90 | return changed; 91 | } 92 | return false; 93 | }, 94 | this); 95 | portRuleJob->setStartMessage(_("Migrating global hotkey key option...")); 96 | pipeline->addJob(portRuleJob); 97 | } 98 | 99 | } // namespace fcitx 100 | -------------------------------------------------------------------------------- /src/lib/configlib/layoutprovider.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #ifndef _CONFIGLIB_LAYOUTPROVIDER_H_ 8 | #define _CONFIGLIB_LAYOUTPROVIDER_H_ 9 | 10 | #include "iso639.h" 11 | #include "layoutmodel.h" 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | class QDBusPendingCallWatcher; 23 | 24 | namespace fcitx { 25 | namespace kcm { 26 | 27 | class DBusProvider; 28 | class LanguageFilterModel; 29 | class LayoutInfoModel; 30 | class VariantInfoModel; 31 | 32 | class LayoutProvider : public QObject { 33 | Q_OBJECT 34 | Q_PROPERTY(QAbstractItemModel *languageModel READ languageModel CONSTANT) 35 | Q_PROPERTY(LanguageFilterModel *layoutModel READ layoutModel CONSTANT) 36 | Q_PROPERTY(LanguageFilterModel *variantModel READ variantModel CONSTANT) 37 | public: 38 | LayoutProvider(DBusProvider *dbus, QObject *parent = nullptr); 39 | ~LayoutProvider(); 40 | 41 | QAbstractItemModel *languageModel() const { return sortedLanguageModel_; } 42 | auto layoutModel() const { return layoutFilterModel_; } 43 | auto variantModel() const { return variantFilterModel_; } 44 | 45 | Q_INVOKABLE int layoutIndex(const QString &layoutString); 46 | Q_INVOKABLE int variantIndex(const QString &layoutString); 47 | Q_INVOKABLE QString layoutDescription(const QString &layoutString); 48 | 49 | Q_INVOKABLE void setVariantInfo(const FcitxQtLayoutInfo &info) const { 50 | variantModel_->setVariantInfo(info); 51 | } 52 | 53 | Q_INVOKABLE QString layout(int layoutIdx, int variantIdx) const { 54 | auto layoutModelIndex = layoutFilterModel_->index(layoutIdx, 0); 55 | auto variantModelIndex = variantFilterModel_->index(variantIdx, 0); 56 | if (layoutModelIndex.isValid() && variantModelIndex.isValid()) { 57 | auto layout = layoutModelIndex.data(Qt::UserRole).toString(); 58 | auto variant = variantModelIndex.data(Qt::UserRole).toString(); 59 | if (layout.isEmpty()) { 60 | return QString(); 61 | } 62 | if (variant.isEmpty()) { 63 | return layout; 64 | } 65 | return QStringLiteral("%1-%2").arg(layout, variant); 66 | } 67 | return QString(); 68 | } 69 | 70 | bool loaded() const { return loaded_; } 71 | 72 | Q_SIGNALS: 73 | void loadedChanged(); 74 | 75 | private Q_SLOTS: 76 | void availabilityChanged(); 77 | void fetchLayoutFinished(QDBusPendingCallWatcher *watcher); 78 | 79 | private: 80 | void setLoaded(bool loaded) { 81 | if (loaded != loaded_) { 82 | loaded_ = loaded; 83 | Q_EMIT loadedChanged(); 84 | } 85 | } 86 | 87 | DBusProvider *dbus_; 88 | bool loaded_ = false; 89 | LanguageModel *languageModel_; 90 | SortedLanguageModel *sortedLanguageModel_; 91 | LayoutInfoModel *layoutModel_; 92 | VariantInfoModel *variantModel_; 93 | LanguageFilterModel *layoutFilterModel_; 94 | LanguageFilterModel *variantFilterModel_; 95 | Iso639 iso639_; 96 | }; 97 | 98 | } // namespace kcm 99 | } // namespace fcitx 100 | 101 | #endif // _CONFIGLIB_LAYOUTPROVIDER_H_ 102 | -------------------------------------------------------------------------------- /src/kcm/ui/KeyListOption.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | import QtQuick 8 | import QtQuick.Layouts 9 | import QtQuick.Controls 10 | import org.kde.kirigami as Kirigami 11 | import "utils.js" as Utils 12 | 13 | RowLayout { 14 | id: keyList 15 | property string typeName 16 | property string description 17 | property variant defaultValue 18 | property variant properties 19 | property variant rawValue 20 | property alias hovered: addButton.hovered 21 | property bool needsSave 22 | 23 | function load(rawValue) { 24 | var diff = false; 25 | if (listModel.count !== 0) { 26 | listModel.remove(0, listModel.count); 27 | } 28 | var i = 0; 29 | while (true) { 30 | if (!Utils.hasProperty(rawValue, i.toString())) { 31 | break; 32 | } 33 | var value = rawValue[i.toString()]; 34 | listModel.append({ 35 | "key": value 36 | }); 37 | if (!Utils.hasProperty(keyList.rawValue, i.toString()) || rawValue[i.toString()] !== keyList.rawValue[i.toString()]) { 38 | diff = true; 39 | } 40 | i++; 41 | } 42 | if (Utils.hasProperty(keyList.rawValue, i.toString())) { 43 | diff = true; 44 | } 45 | needsSave = diff; 46 | } 47 | function save() { 48 | var newRawValue = {}; 49 | var j = 0; 50 | for (var i = 0; i < listModel.count; i++) { 51 | if (listModel.get(i).key !== "") { 52 | newRawValue[j.toString()] = listModel.get(i).key; 53 | j++; 54 | } 55 | } 56 | rawValue = newRawValue; 57 | needsSave = false; 58 | } 59 | 60 | Component.onCompleted: { 61 | load(rawValue); 62 | save(); 63 | } 64 | 65 | ColumnLayout { 66 | visible: listModel.count > 0 67 | Repeater { 68 | model: listModel 69 | 70 | delegate: RowLayout { 71 | KeyOption { 72 | Layout.fillWidth: true 73 | Layout.minimumWidth: Kirigami.Units.gridUnit * 9 74 | properties: Utils.hasProperty(keyList.properties, "ListConstrain") ? keyList.properties.ListConstrain : {} 75 | rawValue: model.key 76 | 77 | onKeyStringChanged: { 78 | model.key = keyString; 79 | keyList.needsSave = true; 80 | } 81 | } 82 | ToolButton { 83 | icon.name: "edit-delete-symbolic" 84 | 85 | onClicked: { 86 | // Need to happen before real remove. 87 | keyList.needsSave = true; 88 | listModel.remove(model.index); 89 | } 90 | } 91 | } 92 | } 93 | } 94 | ToolButton { 95 | id: addButton 96 | Layout.alignment: Qt.AlignTop | Qt.AlignLeft 97 | icon.name: "list-add-symbolic" 98 | 99 | onClicked: { 100 | keyList.needsSave = true; 101 | listModel.append({ 102 | "key": "" 103 | }); 104 | } 105 | } 106 | ListModel { 107 | id: listModel 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16 FATAL_ERROR) 2 | 3 | set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) 4 | set(CMAKE_DISABLE_SOURCE_CHANGES ON) 5 | 6 | 7 | if ("${CMAKE_BINARY_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}") 8 | message(FATAL_ERROR "In-source builds are disabled. 9 | Please create a subfolder and use `cmake ..` inside it. 10 | NOTE: cmake will now create CMakeCache.txt and CMakeFiles/*. 11 | You must delete them, or cmake will refuse to work.") 12 | endif() 13 | 14 | project(fcitx5-configtool VERSION 5.1.12) 15 | 16 | set(QT_MIN_VERSION "6.4.0") 17 | set(QT_MAJOR_VERSION 6) 18 | 19 | find_package(ECM 5.68.0 REQUIRED) 20 | set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) 21 | find_package(Qt${QT_MAJOR_VERSION} ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS Core Gui Widgets Concurrent) 22 | 23 | include(KDEInstallDirs) 24 | include(KDECMakeSettings) 25 | include(KDECompilerSettings) 26 | include(FeatureSummary) 27 | include(ECMSetupVersion) 28 | include(GenerateExportHeader) 29 | option(ENABLE_KCM "Enable KDE Config Module" On) 30 | option(ENABLE_CONFIG_QT "Enable fcitx5-config-qt" On) 31 | option(ENABLE_TEST "Enable test" Off) 32 | add_definitions(-DTRANSLATION_DOMAIN=\"kcm_fcitx5\") 33 | add_definitions(-DFCITX_GETTEXT_DOMAIN=\"fcitx5-configtool\") 34 | add_definitions(-DQT_NO_KEYWORDS) 35 | 36 | set(CONFIG_QT_UNIQUE_APP_SUPPORT 0) 37 | if (ENABLE_CONFIG_QT) 38 | find_package(KF${QT_MAJOR_VERSION}ItemViews REQUIRED) 39 | find_package(KF${QT_MAJOR_VERSION}DBusAddons 5.91) 40 | find_package(KF${QT_MAJOR_VERSION}WindowSystem 5.91) 41 | 42 | if (TARGET KF${QT_MAJOR_VERSION}::DBusAddons AND TARGET KF${QT_MAJOR_VERSION}::WindowSystem) 43 | set(CONFIG_QT_UNIQUE_APP_SUPPORT 1) 44 | endif() 45 | endif() 46 | 47 | if (ENABLE_KCM) 48 | find_package(Qt${QT_MAJOR_VERSION}Quick REQUIRED) 49 | find_package(Qt${QT_MAJOR_VERSION}QuickControls2 REQUIRED) 50 | find_package(KF${QT_MAJOR_VERSION}CoreAddons REQUIRED) 51 | find_package(KF${QT_MAJOR_VERSION}I18n REQUIRED) 52 | find_package(KF${QT_MAJOR_VERSION}Package REQUIRED) 53 | find_package(KF${QT_MAJOR_VERSION}Declarative REQUIRED) 54 | find_package(KF${QT_MAJOR_VERSION}IconThemes REQUIRED) 55 | find_package(XKBCommon REQUIRED COMPONENTS XKBCommon) 56 | find_package(KF${QT_MAJOR_VERSION}Kirigami REQUIRED) 57 | find_package(Plasma REQUIRED) 58 | find_package(KF${QT_MAJOR_VERSION}Svg REQUIRED) 59 | find_package(KF${QT_MAJOR_VERSION}KCMUtils REQUIRED) 60 | endif() 61 | 62 | find_package(Fcitx5Core 5.1.13 REQUIRED) 63 | find_package(Fcitx5Config REQUIRED) 64 | find_package(Fcitx5Utils REQUIRED) 65 | find_package(Fcitx5Qt${QT_MAJOR_VERSION}DBusAddons 5.1.4 REQUIRED) 66 | find_package(Fcitx5Qt${QT_MAJOR_VERSION}WidgetsAddons 5.0.2 REQUIRED) 67 | find_package(Qt${QT_MAJOR_VERSION}Svg) 68 | set_package_properties(Qt${QT_MAJOR_VERSION}Svg PROPERTIES 69 | DESCRIPTION "May be used for show icons" 70 | TYPE RUNTIME) 71 | 72 | get_target_property(FCITX5_QT_GUI_WRAPPER Fcitx5Qt${QT_MAJOR_VERSION}::gui-wrapper IMPORTED_LOCATION) 73 | 74 | find_package(KF${QT_MAJOR_VERSION}WidgetsAddons REQUIRED) 75 | find_package(IsoCodes REQUIRED) 76 | kde_enable_exceptions() 77 | 78 | include("${FCITX_INSTALL_CMAKECONFIG_DIR}/Fcitx5Utils/Fcitx5CompilerSettings.cmake") 79 | 80 | find_package(PkgConfig REQUIRED) 81 | find_package(Gettext REQUIRED) 82 | find_package(X11 REQUIRED) 83 | find_package(XKeyboardConfig REQUIRED) 84 | pkg_check_modules(XkbFile "xkbfile" REQUIRED IMPORTED_TARGET) 85 | 86 | configure_file(config.h.in config.h) 87 | include_directories(${CMAKE_CURRENT_BINARY_DIR}) 88 | 89 | add_subdirectory(po) 90 | add_subdirectory(src) 91 | add_subdirectory(layout) 92 | 93 | feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) 94 | -------------------------------------------------------------------------------- /src/migrator/lib/configmigrator.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #include "configmigrator.h" 8 | #include 9 | #include 10 | 11 | namespace fcitx { 12 | 13 | namespace { 14 | 15 | void decomposeDBusVariant(RawConfig &config, const QVariant &v) { 16 | QVariantMap map; 17 | if (v.canConvert()) { 18 | auto argument = qvariant_cast(v); 19 | argument >> map; 20 | } else if (v.canConvert()) { 21 | config.setValue(v.toString().toStdString()); 22 | } else { 23 | map = v.toMap(); 24 | } 25 | for (const auto &item : 26 | MakeIterRange(map.constKeyValueBegin(), map.constKeyValueEnd())) { 27 | decomposeDBusVariant(*config.get(item.first.toStdString(), true), 28 | item.second); 29 | } 30 | } 31 | 32 | QVariant rawConfigToVariant(const RawConfig &config) { 33 | if (!config.hasSubItems()) { 34 | return QString::fromStdString(config.value()); 35 | } 36 | 37 | QVariantMap map; 38 | if (!config.value().empty()) { 39 | map[""] = QString::fromStdString(config.value()); 40 | } 41 | if (config.hasSubItems()) { 42 | auto options = config.subItems(); 43 | for (auto &option : options) { 44 | auto subConfig = config.get(option); 45 | map[QString::fromStdString(option)] = 46 | rawConfigToVariant(*subConfig); 47 | } 48 | } 49 | return map; 50 | } 51 | 52 | } // namespace 53 | 54 | ConfigMigrator::ConfigMigrator(const QString &configPath, 55 | std::function transformer, 56 | QObject *parent) 57 | : PipelineJob(parent), configPath_(configPath), proxy_(nullptr), 58 | transformer_(std::move(transformer)) {} 59 | 60 | void ConfigMigrator::start() { 61 | if (proxy_) { 62 | delete proxy_; 63 | } 64 | if (!startMessage_.isEmpty()) { 65 | Q_EMIT message("dialog-information", startMessage_); 66 | } 67 | proxy_ = new FcitxQtControllerProxy("org.fcitx.Fcitx5", "/controller", 68 | QDBusConnection::sessionBus(), this); 69 | auto call = proxy_->GetConfig(configPath_); 70 | auto watcher = new QDBusPendingCallWatcher(call, this); 71 | connect(watcher, &QDBusPendingCallWatcher::finished, this, 72 | &ConfigMigrator::requestConfigFinished); 73 | } 74 | 75 | void ConfigMigrator::abort() {} 76 | 77 | void ConfigMigrator::cleanUp() { 78 | delete proxy_; 79 | proxy_ = nullptr; 80 | } 81 | 82 | void fcitx::ConfigMigrator::requestConfigFinished( 83 | QDBusPendingCallWatcher *watcher) { 84 | watcher->deleteLater(); 85 | QDBusPendingReply reply = *watcher; 86 | if (reply.isError()) { 87 | Q_EMIT message( 88 | "dialog-error", 89 | QString(_("Failed to fetch config for %1")).arg(configPath_)); 90 | Q_EMIT finished(false); 91 | return; 92 | } 93 | 94 | auto variant = reply.argumentAt<0>().variant(); 95 | config_ = RawConfig(); 96 | decomposeDBusVariant(config_, variant); 97 | // No need for update. 98 | if (!transformer_(config_)) { 99 | Q_EMIT finished(true); 100 | return; 101 | } 102 | 103 | auto newVariant = rawConfigToVariant(config_); 104 | proxy_->SetConfig(configPath_, QDBusVariant(newVariant)); 105 | if (!finishMessage_.isEmpty()) { 106 | message("dialog-information", finishMessage_); 107 | } 108 | Q_EMIT finished(true); 109 | } 110 | 111 | } // namespace fcitx 112 | -------------------------------------------------------------------------------- /src/lib/configlib/font.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #include "font.h" 8 | #include 9 | #include 10 | 11 | QFont fcitx::kcm::parseFont(const QString &string) { 12 | auto result = stringutils::split(string.toStdString(), " ", 13 | stringutils::SplitBehavior::SkipEmpty); 14 | QStringList list; 15 | for (const auto &token : result) { 16 | list << QString::fromStdString(token); 17 | } 18 | int size = 9; // Default size. 19 | if (!list.empty()) { 20 | bool ok = false; 21 | auto fontSize = list.back().toInt(&ok); 22 | if (ok) { 23 | if (fontSize > 0) { 24 | size = fontSize; 25 | } 26 | list.pop_back(); 27 | } 28 | } 29 | 30 | QFont::Style style = QFont::StyleNormal; 31 | auto weight = QFont::Normal; 32 | const QMap strToWeight = { 33 | {"Thin", QFont::Thin}, 34 | {"Ultra-Light", QFont::Thin}, 35 | {"Extra-Light", QFont::ExtraLight}, 36 | {"Light", QFont::Light}, 37 | {"Semi-Light", QFont::Light}, 38 | {"Demi-Light", QFont::Light}, 39 | {"Book", QFont::Light}, 40 | {"Regular", QFont::Normal}, 41 | {"Medium", QFont::Medium}, 42 | {"Semi-Bold", QFont::Medium}, 43 | {"Demi-Bold", QFont::DemiBold}, 44 | {"Bold", QFont::Bold}, 45 | {"Ultra-Bold", QFont::Bold}, 46 | {"Extra-Bold", QFont::ExtraBold}, 47 | {"Black", QFont::Black}, 48 | {"Ultra-Black", QFont::Black}, 49 | {"Extra-Black", QFont::Black}, 50 | }; 51 | const QMap strToStyle = { 52 | {"Italic", QFont::StyleItalic}, {"Oblique", QFont::StyleOblique}}; 53 | while (!list.empty()) { 54 | if (strToWeight.contains(list.back())) { 55 | weight = strToWeight.value(list.back(), QFont::Normal); 56 | list.pop_back(); 57 | } else if (strToStyle.contains(list.back())) { 58 | style = strToStyle.value(list.back(), QFont::StyleNormal); 59 | list.pop_back(); 60 | } else { 61 | break; 62 | } 63 | } 64 | QString family = list.join(" "); 65 | QFont font; 66 | font.setFamily(family); 67 | font.setWeight(weight); 68 | font.setStyle(style); 69 | font.setPointSize(size); 70 | return font; 71 | } 72 | 73 | QString fcitx::kcm::fontToString(const QFont &font) { 74 | QString style; 75 | QStringList styles; 76 | switch (font.style()) { 77 | case QFont::StyleItalic: 78 | styles << "Italic"; 79 | break; 80 | case QFont::StyleOblique: 81 | styles << "Oblique"; 82 | break; 83 | default: 84 | break; 85 | } 86 | #define CASE_WEIGHT(WEIGHT, WEIGHT_STR) \ 87 | case QFont::WEIGHT: \ 88 | styles << WEIGHT_STR; \ 89 | break; 90 | // Use the string accepted by pango. 91 | switch (font.weight()) { 92 | CASE_WEIGHT(Thin, "Thin") 93 | CASE_WEIGHT(ExtraLight, "Extra-Light") 94 | CASE_WEIGHT(Light, "Light") 95 | CASE_WEIGHT(Medium, "Medium") 96 | CASE_WEIGHT(DemiBold, "Demi-Bold") 97 | CASE_WEIGHT(Bold, "Bold") 98 | CASE_WEIGHT(ExtraBold, "Extra-Bold") 99 | CASE_WEIGHT(Black, "Black") 100 | default: 101 | break; 102 | } 103 | style = styles.join(" "); 104 | return QStringLiteral("%1%2%3 %4") 105 | .arg(font.family(), (!style.isEmpty() ? " " : ""), style, 106 | QString::number(font.pointSize())); 107 | } 108 | -------------------------------------------------------------------------------- /src/kcm/ui/SelectLayoutSheet.qml: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | import QtQuick 8 | import QtQuick.Layouts 9 | import QtQuick.Controls 10 | import org.kde.kirigami as Kirigami 11 | 12 | Kirigami.OverlaySheet { 13 | id: selectLayoutSheet 14 | property string im: "" 15 | 16 | function selectLayout(title, im, layout) { 17 | heading.text = title; 18 | languageComboBox.currentIndex = 0; 19 | selectLayoutSheet.im = im; 20 | var layoutIndex = kcm.layoutProvider.layoutIndex(layout); 21 | layoutComboBox.currentIndex = layoutIndex; 22 | var variantIndex = kcm.layoutProvider.variantIndex(layout); 23 | variantComboBox.currentIndex = variantIndex; 24 | open(); 25 | } 26 | 27 | Kirigami.FormLayout { 28 | implicitWidth: Kirigami.Units.gridUnit * 30 29 | 30 | ComboBox { 31 | id: languageComboBox 32 | Kirigami.FormData.label: i18n("Language:") 33 | implicitWidth: Kirigami.Units.gridUnit * 15 34 | model: kcm.layoutProvider.languageModel 35 | textRole: "name" 36 | 37 | onCurrentIndexChanged: { 38 | kcm.layoutProvider.layoutModel.language = model.language(currentIndex); 39 | layoutComboBox.currentIndex = 0; 40 | kcm.layoutProvider.setVariantInfo(kcm.layoutProvider.layoutModel.layoutInfo(layoutComboBox.currentIndex)); 41 | variantComboBox.currentIndex = 0; 42 | } 43 | } 44 | ComboBox { 45 | id: layoutComboBox 46 | Kirigami.FormData.label: i18n("Layout:") 47 | implicitWidth: Kirigami.Units.gridUnit * 15 48 | model: kcm.layoutProvider.layoutModel 49 | textRole: "name" 50 | 51 | onCurrentIndexChanged: { 52 | if (currentIndex < 0) { 53 | return; 54 | } 55 | kcm.layoutProvider.setVariantInfo(model.layoutInfo(currentIndex)); 56 | variantComboBox.currentIndex = 0; 57 | } 58 | } 59 | ComboBox { 60 | id: variantComboBox 61 | Kirigami.FormData.label: i18n("Variant:") 62 | implicitWidth: Kirigami.Units.gridUnit * 15 63 | model: kcm.layoutProvider.variantModel 64 | textRole: "name" 65 | } 66 | } 67 | 68 | footer: RowLayout { 69 | Item { 70 | Layout.fillWidth: true 71 | } 72 | Button { 73 | text: i18n("Clear") 74 | visible: im !== "" 75 | 76 | onClicked: { 77 | kcm.imConfig.setLayout(im, ""); 78 | selectLayoutSheet.close(); 79 | } 80 | } 81 | Button { 82 | text: i18n("Ok") 83 | 84 | onClicked: { 85 | if (layoutComboBox.currentIndex >= 0 && variantComboBox.currentIndex >= 0) { 86 | var layout = kcm.layoutProvider.layout(layoutComboBox.currentIndex, variantComboBox.currentIndex); 87 | if (im.length === 0) { 88 | kcm.imConfig.defaultLayout = layout; 89 | if (kcm.imConfig.currentIMModel.count > 0 && "keyboard-%0".arg(layout) != kcm.imConfig.currentIMModel.imAt(0)) { 90 | layoutNotMatchWarning.visible = false; 91 | inputMethodNotMatchWarning.visible = true; 92 | } 93 | } else { 94 | kcm.imConfig.setLayout(im, layout); 95 | } 96 | selectLayoutSheet.close(); 97 | } 98 | } 99 | } 100 | } 101 | header: Kirigami.Heading { 102 | id: heading 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/lib/configwidgetslib/listoptionwidget.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | ListOptionWidget 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 0 27 | 0 28 | 29 | 30 | 31 | Add 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 0 43 | 0 44 | 45 | 46 | 47 | Edit 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 0 59 | 0 60 | 61 | 62 | 63 | Up 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 0 75 | 0 76 | 77 | 78 | 79 | Down 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 0 91 | 0 92 | 93 | 94 | 95 | Remove 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | Qt::Vertical 106 | 107 | 108 | 109 | 20 110 | 40 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /src/lib/configlib/layoutmodel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #ifndef _CONFIGLIB_LAYOUTMODEL_H_ 8 | #define _CONFIGLIB_LAYOUTMODEL_H_ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | namespace fcitx::kcm { 24 | 25 | enum { LayoutLanguageRole = 0x3423545, LayoutInfoRole }; 26 | 27 | class LanguageModel : public QStandardItemModel { 28 | Q_OBJECT 29 | public: 30 | LanguageModel(QObject *parent = nullptr); 31 | void append(const QString &name, const QString &language); 32 | }; 33 | 34 | class SortedLanguageModel : public QSortFilterProxyModel { 35 | Q_OBJECT 36 | public: 37 | using QSortFilterProxyModel::QSortFilterProxyModel; 38 | // Forward role names. 39 | QHash roleNames() const override { 40 | if (sourceModel()) { 41 | return sourceModel()->roleNames(); 42 | } 43 | return QSortFilterProxyModel::roleNames(); 44 | } 45 | Q_INVOKABLE QString language(int row) const; 46 | 47 | protected: 48 | bool lessThan(const QModelIndex &left, 49 | const QModelIndex &right) const override { 50 | const bool leftIsAny = left.data(Qt::UserRole).toString().isEmpty(); 51 | const bool rightIsAny = right.data(Qt::UserRole).toString().isEmpty(); 52 | if (leftIsAny || rightIsAny) { 53 | return leftIsAny > rightIsAny; 54 | } 55 | return QString::localeAwareCompare( 56 | left.data(Qt::DisplayRole).toString(), 57 | right.data(Qt::DisplayRole).toString()) < 0; 58 | } 59 | }; 60 | 61 | class LanguageFilterModel : public QSortFilterProxyModel { 62 | Q_OBJECT 63 | Q_PROPERTY(QString language READ language WRITE setLanguage); 64 | 65 | public: 66 | using QSortFilterProxyModel::QSortFilterProxyModel; 67 | // Forward role names. 68 | QHash roleNames() const override { 69 | if (sourceModel()) { 70 | return sourceModel()->roleNames(); 71 | } 72 | return QSortFilterProxyModel::roleNames(); 73 | } 74 | 75 | const QString &language() const { return language_; } 76 | void setLanguage(const QString &language); 77 | 78 | Q_INVOKABLE QVariant layoutInfo(int row) const; 79 | 80 | protected: 81 | bool filterAcceptsRow(int source_row, const QModelIndex &) const override; 82 | bool lessThan(const QModelIndex &left, 83 | const QModelIndex &right) const override; 84 | 85 | private: 86 | QString language_; 87 | }; 88 | 89 | class LayoutInfoModel : public QAbstractListModel { 90 | Q_OBJECT 91 | public: 92 | using QAbstractListModel::QAbstractListModel; 93 | QHash roleNames() const override; 94 | 95 | auto &layoutInfo() const { return layoutInfo_; } 96 | void setLayoutInfo(FcitxQtLayoutInfoList info); 97 | 98 | QVariant data(const QModelIndex &index, 99 | int role = Qt::DisplayRole) const override; 100 | 101 | int rowCount(const QModelIndex &parent = QModelIndex()) const override; 102 | 103 | private: 104 | FcitxQtLayoutInfoList layoutInfo_; 105 | }; 106 | 107 | class VariantInfoModel : public QAbstractListModel { 108 | Q_OBJECT 109 | public: 110 | using QAbstractListModel::QAbstractListModel; 111 | QHash roleNames() const override; 112 | 113 | auto &variantInfo() const { return variantInfo_; } 114 | void setVariantInfo(const FcitxQtLayoutInfo &info); 115 | 116 | QVariant data(const QModelIndex &index, 117 | int role = Qt::DisplayRole) const override; 118 | 119 | int rowCount(const QModelIndex &parent = QModelIndex()) const override; 120 | 121 | private: 122 | FcitxQtVariantInfoList variantInfo_; 123 | }; 124 | 125 | } // namespace fcitx::kcm 126 | 127 | #endif // _CONFIGLIB_LAYOUTMODEL_H_ 128 | -------------------------------------------------------------------------------- /src/lib/configlib/imconfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #ifndef _CONFIGLIB_ABSTRACTIMPAGE_H_ 8 | #define _CONFIGLIB_ABSTRACTIMPAGE_H_ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace fcitx::kcm { 18 | 19 | class IMConfigModelInterface; 20 | class IMProxyModel; 21 | class FilteredIMModel; 22 | class DBusProvider; 23 | 24 | class IMConfig : public QObject { 25 | Q_OBJECT 26 | Q_PROPERTY(fcitx::kcm::FilteredIMModel *currentIMModel READ currentIMModel 27 | CONSTANT) 28 | Q_PROPERTY( 29 | fcitx::kcm::IMProxyModel *availIMModel READ availIMModel CONSTANT) 30 | Q_PROPERTY(QString defaultLayout READ defaultLayout WRITE setDefaultLayout 31 | NOTIFY defaultLayoutChanged) 32 | Q_PROPERTY(QStringList groups READ groups NOTIFY groupsChanged) 33 | Q_PROPERTY(QString currentGroup READ currentGroup WRITE setCurrentGroup) 34 | Q_PROPERTY(bool needSave READ needSave) 35 | Q_PROPERTY(bool needUpdate READ needUpdate NOTIFY needUpdateChanged) 36 | public: 37 | enum ModelMode { Tree, Flatten }; 38 | 39 | IMConfig(DBusProvider *dbus, ModelMode mode, QObject *parent); 40 | ~IMConfig(); 41 | 42 | FilteredIMModel *currentIMModel() const { return currentIMModel_; } 43 | IMProxyModel *availIMModel() const { return availIMModel_; } 44 | const QStringList &groups() const { return groups_; } 45 | const QString ¤tGroup() const { return lastGroup_; } 46 | void setCurrentGroup(const QString &name); 47 | bool needSave() const { return needSave_; } 48 | bool needUpdate() const { return needUpdate_; } 49 | 50 | void addIM(const QModelIndex &index); 51 | void removeIM(const QModelIndex &index); 52 | 53 | const auto &imEntries() const { return imEntries_; } 54 | void setIMEntries(const FcitxQtStringKeyValueList &imEntires) { 55 | imEntries_ = imEntires; 56 | updateIMList(); 57 | } 58 | 59 | const QString &defaultLayout() const { return defaultLayout_; } 60 | void setDefaultLayout(const QString &l) { 61 | if (defaultLayout_ != l) { 62 | defaultLayout_ = l; 63 | emitChanged(); 64 | Q_EMIT defaultLayoutChanged(); 65 | } 66 | } 67 | 68 | Q_INVOKABLE void setLayout(const QString &im, const QString &layout) { 69 | for (auto &imEntry : imEntries_) { 70 | if (imEntry.key() == im) { 71 | imEntry.setValue(layout); 72 | emitChanged(); 73 | updateIMList(); 74 | return; 75 | } 76 | } 77 | } 78 | 79 | void emitChanged(); 80 | 81 | public Q_SLOTS: 82 | void addGroup(const QString &name); 83 | void deleteGroup(const QString &name); 84 | void save(); 85 | void load(); 86 | void defaults(); 87 | void addIM(int idx); 88 | void removeIM(int idx); 89 | void move(int from, int to); 90 | void refresh(); 91 | void restart(); 92 | void checkUpdate(); 93 | 94 | Q_SIGNALS: 95 | void changed(); 96 | void currentGroupChanged(const QString &group); 97 | void groupsChanged(const QStringList &groups); 98 | void imListChanged(); 99 | void defaultLayoutChanged(); 100 | void needUpdateChanged(bool); 101 | 102 | private Q_SLOTS: 103 | void availabilityChanged(); 104 | void fetchGroupInfoFinished(QDBusPendingCallWatcher *watcher); 105 | void fetchInputMethodsFinished(QDBusPendingCallWatcher *watcher); 106 | void fetchGroupsFinished(QDBusPendingCallWatcher *watcher); 107 | void checkUpdateFinished(QDBusPendingCallWatcher *watcher); 108 | 109 | private: 110 | void reloadGroup(); 111 | void updateIMList(bool excludeCurrent = false); 112 | 113 | DBusProvider *dbus_; 114 | IMProxyModel *availIMModel_; 115 | IMConfigModelInterface *internalAvailIMModel_ = nullptr; 116 | FilteredIMModel *currentIMModel_; 117 | QString defaultLayout_; 118 | FcitxQtStringKeyValueList imEntries_; 119 | FcitxQtInputMethodEntryList allIMs_; 120 | QStringList groups_; 121 | QString lastGroup_; 122 | bool needSave_ = false; 123 | bool needUpdate_ = false; 124 | }; 125 | } // namespace fcitx::kcm 126 | 127 | #endif // _CONFIGLIB_ABSTRACTIMPAGE_H_ 128 | -------------------------------------------------------------------------------- /src/lib/configwidgetslib/categoryhelper.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2017~2017 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #include "categoryhelper.h" 8 | #include 9 | 10 | namespace fcitx { 11 | namespace kcm { 12 | 13 | static constexpr int SPACING = 4; 14 | 15 | void paintCategoryHeader(QPainter *painter, const QStyleOptionViewItem &option, 16 | const QModelIndex &index) { 17 | 18 | painter->save(); 19 | painter->setRenderHint(QPainter::Antialiasing); 20 | 21 | const QString category = 22 | index.model()->data(index, Qt::DisplayRole).toString(); 23 | QRect optRect = option.rect; 24 | optRect.translate(SPACING, SPACING); 25 | optRect.setWidth(optRect.width() - SPACING * 2); 26 | optRect.setHeight(optRect.height() - SPACING * 2); 27 | QFont font(QApplication::font()); 28 | font.setBold(true); 29 | const QFontMetrics fontMetrics = QFontMetrics(font); 30 | 31 | QColor outlineColor = option.palette.text().color(); 32 | outlineColor.setAlphaF(0.35); 33 | 34 | // BEGIN: top left corner 35 | { 36 | painter->save(); 37 | painter->setPen(outlineColor); 38 | const QPointF topLeft(optRect.topLeft()); 39 | QRectF arc(topLeft, QSizeF(4, 4)); 40 | arc.translate(0.5, 0.5); 41 | painter->drawArc(arc, 1440, 1440); 42 | painter->restore(); 43 | } 44 | // END: top left corner 45 | 46 | // BEGIN: left vertical line 47 | { 48 | QPoint start(optRect.topLeft()); 49 | start.ry() += 3; 50 | QPoint verticalGradBottom(optRect.topLeft()); 51 | verticalGradBottom.ry() += fontMetrics.height() + 5; 52 | QLinearGradient gradient(start, verticalGradBottom); 53 | gradient.setColorAt(0, outlineColor); 54 | gradient.setColorAt(1, Qt::transparent); 55 | painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), 56 | gradient); 57 | } 58 | // END: left vertical line 59 | 60 | // BEGIN: horizontal line 61 | { 62 | QPoint start(optRect.topLeft()); 63 | start.rx() += 3; 64 | QPoint horizontalGradTop(optRect.topLeft()); 65 | horizontalGradTop.rx() += optRect.width() - 6; 66 | painter->fillRect(QRect(start, QSize(optRect.width() - 6, 1)), 67 | outlineColor); 68 | } 69 | // END: horizontal line 70 | 71 | // BEGIN: top right corner 72 | { 73 | painter->save(); 74 | painter->setPen(outlineColor); 75 | QPointF topRight(optRect.topRight()); 76 | topRight.rx() -= 4; 77 | QRectF arc(topRight, QSizeF(4, 4)); 78 | arc.translate(0.5, 0.5); 79 | painter->drawArc(arc, 0, 1440); 80 | painter->restore(); 81 | } 82 | // END: top right corner 83 | 84 | // BEGIN: right vertical line 85 | { 86 | QPoint start(optRect.topRight()); 87 | start.ry() += 3; 88 | QPoint verticalGradBottom(optRect.topRight()); 89 | verticalGradBottom.ry() += fontMetrics.height() + 5; 90 | QLinearGradient gradient(start, verticalGradBottom); 91 | gradient.setColorAt(0, outlineColor); 92 | gradient.setColorAt(1, Qt::transparent); 93 | painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), 94 | gradient); 95 | } 96 | // END: right vertical line 97 | 98 | // BEGIN: text 99 | { 100 | QRect textRect(option.rect); 101 | textRect.setTop(textRect.top() + 7); 102 | textRect.setLeft(textRect.left() + 7); 103 | textRect.setHeight(fontMetrics.height()); 104 | textRect.setRight(textRect.right() - 7); 105 | 106 | painter->save(); 107 | painter->setFont(font); 108 | QColor penColor(option.palette.text().color()); 109 | penColor.setAlphaF(0.6); 110 | painter->setPen(penColor); 111 | painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, category); 112 | painter->restore(); 113 | } 114 | // END: text 115 | 116 | painter->restore(); 117 | } 118 | 119 | QSize categoryHeaderSizeHint() { 120 | QFont font(QApplication::font()); 121 | font.setBold(true); 122 | QFontMetrics fontMetrics(font); 123 | const int height = fontMetrics.height() + 1 /* 1 pixel-width gradient */ 124 | + 11 /* top and bottom separation */ + SPACING; 125 | return QSize(0, height); 126 | } 127 | 128 | } // namespace kcm 129 | } // namespace fcitx 130 | -------------------------------------------------------------------------------- /src/kcm/main.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | * 6 | */ 7 | #ifndef _KCM_FCITX5_KCM_NG_MAIN_H_ 8 | #define _KCM_FCITX5_KCM_NG_MAIN_H_ 9 | 10 | #include "addonmodel.h" 11 | #include "dbusprovider.h" 12 | #include "font.h" 13 | #include "imconfig.h" 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | namespace fcitx::kcm { 27 | 28 | class FcitxModule : public KQuickConfigModule { 29 | Q_OBJECT 30 | Q_PROPERTY(IMConfig *imConfig READ imConfig CONSTANT) 31 | Q_PROPERTY(LayoutProvider *layoutProvider READ layoutProvider CONSTANT) 32 | Q_PROPERTY(AddonProxyModel *addonModel READ addonModel CONSTANT) 33 | Q_PROPERTY(bool availability READ availability NOTIFY availabilityChanged) 34 | Q_PROPERTY(bool canRestart READ canRestart NOTIFY canRestartChanged) 35 | public: 36 | FcitxModule(QObject *parent, const KPluginMetaData &metaData); 37 | virtual ~FcitxModule() override; 38 | 39 | auto imConfig() const { return imConfig_; } 40 | auto layoutProvider() const { return layoutProvider_; } 41 | auto addonModel() const { return addonProxyModel_; } 42 | bool availability() const { return dbus_->available(); } 43 | bool canRestart() const { return dbus_->canRestart(); } 44 | 45 | public Q_SLOTS: 46 | void load() override; 47 | void save() override; 48 | void defaults() override; 49 | void loadAddon(); 50 | void saveAddon(); 51 | 52 | void pushConfigPage(const QString &title, const QString &uri); 53 | void launchExternal(const QString &uri); 54 | void saveConfig(const QString &uri, const QVariant &value); 55 | QQuickItem *pageNeedsSave(int idx); 56 | 57 | QFont parseFont(const QString &font) { 58 | return ::fcitx::kcm::parseFont(font); 59 | } 60 | QString fontToString(const QFont &font) { 61 | return ::fcitx::kcm::fontToString(font); 62 | } 63 | 64 | QColor parseColor(const QString &str) { 65 | Color color; 66 | try { 67 | color.setFromString(str.toStdString()); 68 | } catch (...) { 69 | } 70 | QColor qcolor; 71 | qcolor.setRedF(color.redF()); 72 | qcolor.setGreenF(color.greenF()); 73 | qcolor.setBlueF(color.blueF()); 74 | qcolor.setAlphaF(color.alphaF()); 75 | return qcolor; 76 | } 77 | QString colorToString(const QColor &color) { 78 | Color fcitxColor; 79 | fcitxColor.setRedF(color.redF()); 80 | fcitxColor.setGreenF(color.greenF()); 81 | fcitxColor.setBlueF(color.blueF()); 82 | fcitxColor.setAlphaF(color.alphaF()); 83 | return QString::fromStdString(fcitxColor.toString()); 84 | } 85 | 86 | void grabKeyboard(QQuickItem *item); 87 | void ungrabKeyboard(QQuickItem *item); 88 | 89 | bool eventFilter(QObject *watched, QEvent *event) override; 90 | 91 | QString eventToString(bool keyCode); 92 | QString localizedKeyString(const QString &str); 93 | 94 | void runFcitx(); 95 | void fixLayout(); 96 | void fixInputMethod(); 97 | 98 | Q_SIGNALS: 99 | void availabilityChanged(bool avail); 100 | void canRestartChanged(bool canRestart); 101 | 102 | private Q_SLOTS: 103 | void handleAvailabilityChanged(bool avail); 104 | void pageNeedsSaveChanged(); 105 | 106 | private: 107 | DBusProvider *dbus_; 108 | IMConfig *imConfig_; 109 | LayoutProvider *layoutProvider_; 110 | FlatAddonModel *addonModel_; 111 | AddonProxyModel *addonProxyModel_; 112 | QMap> pages_; 113 | struct XKBStateDeleter { 114 | void operator()(struct xkb_state *state) const { 115 | xkb_state_unref(state); 116 | } 117 | }; 118 | struct XKBKeymapDeleter { 119 | void operator()(struct xkb_keymap *keymap) const { 120 | xkb_keymap_unref(keymap); 121 | } 122 | }; 123 | struct XKBContextDeleter { 124 | void operator()(struct xkb_context *context) const { 125 | xkb_context_unref(context); 126 | } 127 | }; 128 | using ScopedXKBState = std::unique_ptr; 129 | using ScopedXKBKeymap = 130 | std::unique_ptr; 131 | using ScopedXKBContext = 132 | std::unique_ptr; 133 | ScopedXKBState xkbState_; 134 | ScopedXKBKeymap xkbKeymap_; 135 | ScopedXKBContext xkbContext_; 136 | Key key_; 137 | }; 138 | 139 | } // namespace fcitx::kcm 140 | 141 | #endif // _KCM_FCITX5_KCM_NG_MAIN_H_ 142 | -------------------------------------------------------------------------------- /src/migrator/lib/copydirectory.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * SPDX-FileCopyrightText: 2020~2020 CSSlayer 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | * 6 | */ 7 | #include "copydirectory.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #if defined(Q_OS_LINUX) 15 | #include 16 | #include 17 | #include 18 | 19 | // in case linux/fs.h is too old and doesn't define it: 20 | #ifndef FICLONE 21 | #define FICLONE _IOW(0x94, 9, int) 22 | #endif 23 | #endif 24 | 25 | namespace fcitx { 26 | 27 | namespace { 28 | 29 | bool cloneFile(int srcfd, int dstfd) { 30 | #if defined(Q_OS_LINUX) 31 | if (ioctl(dstfd, FICLONE, srcfd) == 0) { 32 | return true; 33 | } 34 | 35 | size_t sendFileLimit = 0x7ffff000; 36 | ssize_t n = sendfile(dstfd, srcfd, NULL, sendFileLimit); 37 | if (n != -1) { 38 | while (n) { 39 | n = sendfile(dstfd, srcfd, NULL, sendFileLimit); 40 | if (n == -1) { 41 | return false; 42 | } 43 | } 44 | return true; 45 | } 46 | 47 | // Check errno as suggested in manpage. 48 | if (errno != EINVAL && errno != ENOSYS) { 49 | return false; 50 | } 51 | #endif 52 | // Fallback to write. 53 | 54 | char buffer[4096]; 55 | while (true) { 56 | auto in = fs::safeRead(srcfd, buffer, sizeof(buffer)); 57 | if (in < 0) { 58 | return false; 59 | } 60 | if (in == 0) { 61 | break; 62 | } 63 | if (in != fs::safeWrite(dstfd, buffer, in)) { 64 | return false; 65 | } 66 | } 67 | return true; 68 | } 69 | 70 | bool checkFileName(const QString &name, 71 | const QList &excludes) { 72 | for (const auto ®exp : excludes) { 73 | if (regexp.match(name).hasMatch()) { 74 | return false; 75 | } 76 | } 77 | return true; 78 | } 79 | 80 | bool copyDirRecursive(CopyDirectory *that, const QString &from, 81 | const QString &to, 82 | const QList &excludes) { 83 | QDir fromDir(from); 84 | if (!fromDir.exists()) { 85 | that->sendMessage("dialog-error", 86 | QString(_("Directory %1 does not exist.")).arg(from)); 87 | return false; 88 | } 89 | 90 | QDir toDir(to); 91 | if (!toDir.exists() && !toDir.mkpath(".")) { 92 | that->sendMessage("dialog-error", 93 | QString(_("Failed to create directory %1.")).arg(to)); 94 | return false; 95 | } 96 | for (const auto &name : 97 | fromDir.entryList(QDir::NoDotAndDotDot | QDir::Files)) { 98 | auto fromFile = fromDir.filePath(name); 99 | auto toFile = toDir.filePath(name); 100 | if (!checkFileName(name, excludes)) { 101 | continue; 102 | } 103 | 104 | QSaveFile to(toFile); 105 | QFile from(fromFile); 106 | if (!from.open(QIODevice::ReadOnly)) { 107 | return false; 108 | } 109 | if (!to.open(QIODevice::WriteOnly)) { 110 | return false; 111 | } 112 | 113 | that->sendMessage( 114 | "", QString(_("Copying file %1 to %2")).arg(fromFile, toFile)); 115 | if (cloneFile(from.handle(), to.handle())) { 116 | to.commit(); 117 | } else { 118 | to.cancelWriting(); 119 | that->sendMessage("dialog-error", 120 | QString(_("Failed to copy file %1 to %2")) 121 | .arg(fromFile, toFile)); 122 | return false; 123 | } 124 | } 125 | for (const auto &name : 126 | fromDir.entryList(QDir::NoDotAndDotDot | QDir::Dirs)) { 127 | if (checkFileName(name, excludes)) { 128 | continue; 129 | } 130 | if (!copyDirRecursive(that, fromDir.filePath(name), 131 | toDir.filePath(name), excludes)) { 132 | return false; 133 | } 134 | } 135 | 136 | return true; 137 | } 138 | 139 | } // namespace 140 | 141 | CopyDirectory::CopyDirectory(const QString &from, const QString &to, 142 | QObject *parent) 143 | : CallbackRunner( 144 | [from, to](CallbackRunner *runner) { 145 | auto that = static_cast(runner); 146 | QList matchers; 147 | for (const auto &exclude : that->excludes_) { 148 | matchers.push_back(QRegularExpression(exclude)); 149 | } 150 | return copyDirRecursive(that, from, to, matchers); 151 | ; 152 | }, 153 | parent) {} 154 | 155 | } // namespace fcitx 156 | --------------------------------------------------------------------------------