init
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled

This commit is contained in:
allhaileris
2026-02-16 15:50:16 +03:00
commit afb81b8278
13816 changed files with 3689732 additions and 0 deletions

View File

@@ -0,0 +1,17 @@
find_package(Qt6 ${REQUIRED_QT6_VERSION} CONFIG REQUIRED Core DBus Widgets)
find_package(Qt6Gui ${REQUIRED_QT6_VERSION} REQUIRED Private)
if (ENABLE_QT6_WAYLAND_WORKAROUND)
find_package(Qt6WaylandClient ${REQUIRED_QT6_VERSION} REQUIRED Private)
find_package(Qt6WaylandGlobalPrivate ${REQUIRED_QT6_VERSION} REQUIRED)
endif()
add_subdirectory(dbusaddons)
add_subdirectory(platforminputcontext)
if(NOT BUILD_ONLY_PLUGIN)
add_subdirectory(guiwrapper)
add_subdirectory(widgetsaddons)
add_subdirectory(quickphrase-editor)
add_subdirectory(immodule-probing)
endif()

View File

@@ -0,0 +1,80 @@
ecm_setup_version(PROJECT VARIABLE_PREFIX FCITX5QT6DBUSADDONS
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/fcitx5qt6dbusaddons_version.h"
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/Fcitx5Qt6DBusAddonsConfigVersion.cmake"
SOVERSION 1)
# create a Config.cmake and a ConfigVersion.cmake file and install them
set(CMAKECONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/Fcitx5Qt6DBusAddons")
configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/Fcitx5Qt6DBusAddonsConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/Fcitx5Qt6DBusAddonsConfig.cmake"
INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}
)
set(dbusaddons_SOURCES
fcitxqtwatcher.cpp
fcitxqtdbustypes.cpp
fcitxqtinputcontextproxy.cpp
fcitxqtinputcontextproxyimpl.cpp
fcitxqtinputmethodproxy.cpp
fcitxqtcontrollerproxy.cpp
)
set(dbusaddons_HEADERS
fcitxqtwatcher.h
fcitxqtdbustypes.h
fcitxqtinputcontextproxy.h
fcitxqtinputmethodproxy.h
fcitxqtcontrollerproxy.h
)
set(fcitxqtdbusaddons_INCLUDE_DIRS
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
)
add_library(Fcitx5Qt6DBusAddons ${LIBRARY_TYPE} ${dbusaddons_SOURCES})
generate_export_header(Fcitx5Qt6DBusAddons BASE_NAME Fcitx5Qt6DBusAddons)
add_library(Fcitx5Qt6::DBusAddons ALIAS Fcitx5Qt6DBusAddons)
target_include_directories(Fcitx5Qt6DBusAddons PUBLIC "$<BUILD_INTERFACE:${fcitxqtdbusaddons_INCLUDE_DIRS}>")
target_include_directories(Fcitx5Qt6DBusAddons INTERFACE "$<INSTALL_INTERFACE:${Fcitx5Qt6_INCLUDE_INSTALL_DIR}/Fcitx5Qt6DBusAddons>")
set_target_properties(Fcitx5Qt6DBusAddons
PROPERTIES VERSION ${FCITX5QT6DBUSADDONS_VERSION}
AUTOMOC TRUE
SOVERSION ${FCITX5QT6DBUSADDONS_SOVERSION}
POSITION_INDEPENDENT_CODE ON
EXPORT_NAME DBusAddons
)
target_link_libraries(
Fcitx5Qt6DBusAddons
PUBLIC
Qt6::Core
Qt6::DBus
)
if(BUILD_ONLY_PLUGIN)
set_target_properties(Fcitx5Qt6DBusAddons PROPERTIES
COMPILE_DEFINITIONS "FCITX5QT6DBUSADDONS_STATIC_DEFINE")
else()
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/Fcitx5Qt6DBusAddonsConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/Fcitx5Qt6DBusAddonsConfigVersion.cmake"
DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
COMPONENT Devel )
install(EXPORT Fcitx5Qt6DBusAddonsTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE Fcitx5Qt6DBusAddonsTargets.cmake NAMESPACE Fcitx5Qt6:: )
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/fcitx5qt6dbusaddons_version.h
DESTINATION ${Fcitx5Qt6_INCLUDE_INSTALL_DIR} COMPONENT Devel )
install(TARGETS Fcitx5Qt6DBusAddons EXPORT Fcitx5Qt6DBusAddonsTargets LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}")
install(FILES ${dbusaddons_HEADERS}
${CMAKE_CURRENT_BINARY_DIR}/fcitx5qt6dbusaddons_export.h
DESTINATION "${Fcitx5Qt6_INCLUDE_INSTALL_DIR}/Fcitx5Qt6DBusAddons")
endif()

View File

@@ -0,0 +1,8 @@
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
find_dependency(Qt6Core @REQUIRED_QT6_VERSION@)
find_dependency(Qt6DBus @REQUIRED_QT6_VERSION@)
include("${CMAKE_CURRENT_LIST_DIR}/Fcitx5Qt6DBusAddonsTargets.cmake")

View File

@@ -0,0 +1,31 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
* Command line was: qdbusxml2cpp -N -p fcitxqtcontrollerproxy -c
* FcitxQtControllerProxy interfaces/org.fcitx.Fcitx.Controller1.xml -i
* fcitxqtdbustypes.h -i fcitx5qt6dbusaddons_export.h
*
* qdbusxml2cpp is Copyright (C) 2023 The Qt Company Ltd and other contributors.
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
* before re-generating it.
*/
#include "fcitxqtcontrollerproxy.h"
namespace fcitx {
/*
* Implementation of interface class FcitxQtControllerProxy
*/
FcitxQtControllerProxy::FcitxQtControllerProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
: QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
{
}
FcitxQtControllerProxy::~FcitxQtControllerProxy()
{
}
}

View File

@@ -0,0 +1,293 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
* Command line was: qdbusxml2cpp -N -p fcitxqtcontrollerproxy -c
* FcitxQtControllerProxy interfaces/org.fcitx.Fcitx.Controller1.xml -i
* fcitxqtdbustypes.h -i fcitx5qt6dbusaddons_export.h
*
* qdbusxml2cpp is Copyright (C) 2023 The Qt Company Ltd and other contributors.
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
*/
#ifndef FCITXQTCONTROLLERPROXY_H
#define FCITXQTCONTROLLERPROXY_H
#include <QtCore/QObject>
#include <QtCore/QByteArray>
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <QtDBus/QtDBus>
#include "fcitxqtdbustypes.h"
#include "fcitx5qt6dbusaddons_export.h"
namespace fcitx {
/*
* Proxy class for interface org.fcitx.Fcitx.Controller1
*/
class FCITX5QT6DBUSADDONS_EXPORT FcitxQtControllerProxy: public QDBusAbstractInterface
{
Q_OBJECT
public:
static inline const char *staticInterfaceName()
{ return "org.fcitx.Fcitx.Controller1"; }
public:
FcitxQtControllerProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr);
~FcitxQtControllerProxy();
public Q_SLOTS: // METHODS
inline QDBusPendingReply<> Activate()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("Activate"), argumentList);
}
inline QDBusPendingReply<> AddInputMethodGroup(const QString &in0)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
return asyncCallWithArgumentList(QStringLiteral("AddInputMethodGroup"), argumentList);
}
inline QDBusPendingReply<QString> AddonForIM(const QString &in0)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
return asyncCallWithArgumentList(QStringLiteral("AddonForIM"), argumentList);
}
inline QDBusPendingReply<FcitxQtInputMethodEntryList> AvailableInputMethods()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("AvailableInputMethods"), argumentList);
}
inline QDBusPendingReply<FcitxQtLayoutInfoList> AvailableKeyboardLayouts()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("AvailableKeyboardLayouts"), argumentList);
}
inline QDBusPendingReply<bool> CanRestart() {
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("CanRestart"),
argumentList);
}
inline QDBusPendingReply<bool> CheckUpdate()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("CheckUpdate"), argumentList);
}
inline QDBusPendingReply<> Configure()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("Configure"), argumentList);
}
inline QDBusPendingReply<> ConfigureAddon(const QString &in0)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
return asyncCallWithArgumentList(QStringLiteral("ConfigureAddon"), argumentList);
}
inline QDBusPendingReply<> ConfigureIM(const QString &in0)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
return asyncCallWithArgumentList(QStringLiteral("ConfigureIM"), argumentList);
}
inline QDBusPendingReply<QString> CurrentInputMethod()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("CurrentInputMethod"), argumentList);
}
inline QDBusPendingReply<QString> CurrentUI()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("CurrentUI"), argumentList);
}
inline QDBusPendingReply<> Exit()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("Exit"), argumentList);
}
inline QDBusPendingReply<QString, QString, QString, QVariantMap,
FcitxQtFullInputMethodEntryList>
FullInputMethodGroupInfo(const QString &in0) {
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
return asyncCallWithArgumentList(
QStringLiteral("FullInputMethodGroupInfo"), argumentList);
}
inline QDBusReply<QString> FullInputMethodGroupInfo(
const QString &in0, QString &defaultInputMethod, QString &defaultLayout,
QVariantMap &properties,
FcitxQtFullInputMethodEntryList &inputMethodEntryList) {
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
QDBusMessage reply = callWithArgumentList(
QDBus::Block, QStringLiteral("FullInputMethodGroupInfo"),
argumentList);
if (reply.type() == QDBusMessage::ReplyMessage &&
reply.arguments().size() == 5) {
defaultInputMethod = qdbus_cast<QString>(reply.arguments().at(1));
defaultLayout = qdbus_cast<QString>(reply.arguments().at(2));
properties = qdbus_cast<QVariantMap>(reply.arguments().at(3));
inputMethodEntryList = qdbus_cast<FcitxQtFullInputMethodEntryList>(
reply.arguments().at(4));
}
return reply;
}
inline QDBusPendingReply<FcitxQtAddonInfoList> GetAddons()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("GetAddons"), argumentList);
}
inline QDBusPendingReply<FcitxQtAddonInfoV2List> GetAddonsV2()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("GetAddonsV2"), argumentList);
}
inline QDBusPendingReply<QDBusVariant, FcitxQtConfigTypeList> GetConfig(const QString &in0)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
return asyncCallWithArgumentList(QStringLiteral("GetConfig"), argumentList);
}
inline QDBusReply<QDBusVariant> GetConfig(const QString &in0, FcitxQtConfigTypeList &out1)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
QDBusMessage reply = callWithArgumentList(QDBus::Block, QStringLiteral("GetConfig"), argumentList);
if (reply.type() == QDBusMessage::ReplyMessage &&
reply.arguments().size() == 2) {
out1 = qdbus_cast<FcitxQtConfigTypeList>(reply.arguments().at(1));
}
return reply;
}
inline QDBusPendingReply<QString, FcitxQtStringKeyValueList> InputMethodGroupInfo(const QString &in0)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
return asyncCallWithArgumentList(QStringLiteral("InputMethodGroupInfo"), argumentList);
}
inline QDBusReply<QString> InputMethodGroupInfo(const QString &in0, FcitxQtStringKeyValueList &items)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
QDBusMessage reply = callWithArgumentList(QDBus::Block, QStringLiteral("InputMethodGroupInfo"), argumentList);
if (reply.type() == QDBusMessage::ReplyMessage &&
reply.arguments().size() == 2) {
items = qdbus_cast<FcitxQtStringKeyValueList>(reply.arguments().at(1));
}
return reply;
}
inline QDBusPendingReply<QStringList> InputMethodGroups()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("InputMethodGroups"), argumentList);
}
inline QDBusPendingReply<> Refresh()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("Refresh"), argumentList);
}
inline QDBusPendingReply<> ReloadAddonConfig(const QString &in0)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
return asyncCallWithArgumentList(QStringLiteral("ReloadAddonConfig"), argumentList);
}
inline QDBusPendingReply<> ReloadConfig()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("ReloadConfig"), argumentList);
}
inline QDBusPendingReply<> RemoveInputMethodGroup(const QString &in0)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
return asyncCallWithArgumentList(QStringLiteral("RemoveInputMethodGroup"), argumentList);
}
inline QDBusPendingReply<> ResetIMList()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("ResetIMList"), argumentList);
}
inline QDBusPendingReply<> Restart()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("Restart"), argumentList);
}
inline QDBusPendingReply<> SetAddonsState(FcitxQtAddonStateList in0)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
return asyncCallWithArgumentList(QStringLiteral("SetAddonsState"), argumentList);
}
inline QDBusPendingReply<> SetConfig(const QString &in0, const QDBusVariant &in1)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1);
return asyncCallWithArgumentList(QStringLiteral("SetConfig"), argumentList);
}
inline QDBusPendingReply<> SetCurrentIM(const QString &in0)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
return asyncCallWithArgumentList(QStringLiteral("SetCurrentIM"), argumentList);
}
inline QDBusPendingReply<> SetInputMethodGroupInfo(const QString &name, const QString &layout, FcitxQtStringKeyValueList entries)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(name) << QVariant::fromValue(layout) << QVariant::fromValue(entries);
return asyncCallWithArgumentList(QStringLiteral("SetInputMethodGroupInfo"), argumentList);
}
inline QDBusPendingReply<int> State()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("State"), argumentList);
}
inline QDBusPendingReply<> Toggle()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("Toggle"), argumentList);
}
Q_SIGNALS: // SIGNALS
void InputMethodGroupsChanged();
};
}
#endif

View File

@@ -0,0 +1,339 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <QDBusMetaType>
#include "fcitxqtdbustypes.h"
namespace fcitx {
#define FCITX5_QT_DEFINE_DBUS_TYPE(TYPE) \
qRegisterMetaType<TYPE>(#TYPE); \
qDBusRegisterMetaType<TYPE>(); \
qRegisterMetaType<TYPE##List>(#TYPE "List"); \
qDBusRegisterMetaType<TYPE##List>();
void registerFcitxQtDBusTypes() {
FCITX5_QT_DEFINE_DBUS_TYPE(FcitxQtFormattedPreedit);
FCITX5_QT_DEFINE_DBUS_TYPE(FcitxQtStringKeyValue);
FCITX5_QT_DEFINE_DBUS_TYPE(FcitxQtInputMethodEntry);
FCITX5_QT_DEFINE_DBUS_TYPE(FcitxQtFullInputMethodEntry);
FCITX5_QT_DEFINE_DBUS_TYPE(FcitxQtLayoutInfo);
FCITX5_QT_DEFINE_DBUS_TYPE(FcitxQtVariantInfo);
FCITX5_QT_DEFINE_DBUS_TYPE(FcitxQtConfigOption);
FCITX5_QT_DEFINE_DBUS_TYPE(FcitxQtConfigType);
FCITX5_QT_DEFINE_DBUS_TYPE(FcitxQtAddonInfo);
FCITX5_QT_DEFINE_DBUS_TYPE(FcitxQtAddonState);
FCITX5_QT_DEFINE_DBUS_TYPE(FcitxQtAddonInfoV2);
}
bool FcitxQtFormattedPreedit::operator==(
const FcitxQtFormattedPreedit &preedit) const {
return (preedit.format_ == format_) && (preedit.string_ == string_);
}
QDBusArgument &operator<<(QDBusArgument &argument,
const FcitxQtFormattedPreedit &preedit) {
argument.beginStructure();
argument << preedit.string();
argument << preedit.format();
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument,
FcitxQtFormattedPreedit &preedit) {
QString str;
qint32 format;
argument.beginStructure();
argument >> str >> format;
argument.endStructure();
preedit.setString(str);
preedit.setFormat(format);
return argument;
}
QDBusArgument &operator<<(QDBusArgument &argument,
const FcitxQtStringKeyValue &arg) {
argument.beginStructure();
argument << arg.key();
argument << arg.value();
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument,
FcitxQtStringKeyValue &arg) {
QString key, value;
argument.beginStructure();
argument >> key >> value;
argument.endStructure();
arg.setKey(key);
arg.setValue(value);
return argument;
}
QDBusArgument &operator<<(QDBusArgument &argument,
const FcitxQtInputMethodEntry &arg) {
argument.beginStructure();
argument << arg.uniqueName();
argument << arg.name();
argument << arg.nativeName();
argument << arg.icon();
argument << arg.label();
argument << arg.languageCode();
argument << arg.configurable();
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument,
FcitxQtInputMethodEntry &arg) {
QString uniqueName, name, nativeName, icon, label, languageCode;
bool configurable;
argument.beginStructure();
argument >> uniqueName >> name >> nativeName >> icon >> label >>
languageCode >> configurable;
argument.endStructure();
arg.setUniqueName(uniqueName);
arg.setName(name);
arg.setNativeName(nativeName);
arg.setIcon(icon);
arg.setLabel(label);
arg.setLanguageCode(languageCode);
arg.setConfigurable(configurable);
return argument;
}
QDBusArgument &operator<<(QDBusArgument &argument,
const FcitxQtFullInputMethodEntry &arg) {
argument.beginStructure();
argument << arg.uniqueName();
argument << arg.name();
argument << arg.nativeName();
argument << arg.icon();
argument << arg.label();
argument << arg.languageCode();
argument << arg.addon();
argument << arg.configurable();
argument << arg.layout();
argument << arg.properties();
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument,
FcitxQtFullInputMethodEntry &arg) {
QString uniqueName, name, nativeName, icon, label, languageCode, addon,
layout;
bool configurable;
QVariantMap properties;
argument.beginStructure();
argument >> uniqueName >> name >> nativeName >> icon >> label >>
languageCode >> addon >> configurable >> layout >> properties;
argument.endStructure();
arg.setUniqueName(uniqueName);
arg.setName(name);
arg.setNativeName(nativeName);
arg.setIcon(icon);
arg.setLabel(label);
arg.setLanguageCode(languageCode);
arg.setAddon(addon);
arg.setConfigurable(configurable);
arg.setLayout(layout);
arg.setProperties(properties);
return argument;
}
QDBusArgument &operator<<(QDBusArgument &argument,
const FcitxQtVariantInfo &arg) {
argument.beginStructure();
argument << arg.variant();
argument << arg.description();
argument << arg.languages();
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument,
FcitxQtVariantInfo &arg) {
QString variant, description;
QStringList languages;
argument.beginStructure();
argument >> variant >> description >> languages;
argument.endStructure();
arg.setVariant(variant);
arg.setDescription(description);
arg.setLanguages(languages);
return argument;
}
QDBusArgument &operator<<(QDBusArgument &argument,
const FcitxQtLayoutInfo &arg) {
argument.beginStructure();
argument << arg.layout();
argument << arg.description();
argument << arg.languages();
argument << arg.variants();
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument,
FcitxQtLayoutInfo &arg) {
QString layout, description;
QStringList languages;
FcitxQtVariantInfoList variants;
argument.beginStructure();
argument >> layout >> description >> languages >> variants;
argument.endStructure();
arg.setLayout(layout);
arg.setDescription(description);
arg.setLanguages(languages);
arg.setVariants(variants);
return argument;
}
QDBusArgument &operator<<(QDBusArgument &argument,
const FcitxQtConfigOption &arg) {
argument.beginStructure();
argument << arg.name();
argument << arg.type();
argument << arg.description();
argument << arg.defaultValue();
argument << arg.properties();
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument,
FcitxQtConfigOption &arg) {
QString name, description, type;
QDBusVariant defaultValue;
QVariantMap properties;
argument.beginStructure();
argument >> name >> type >> description >> defaultValue >> properties;
argument.endStructure();
arg.setName(name);
arg.setType(type);
arg.setDescription(description);
arg.setDefaultValue(defaultValue);
arg.setProperties(properties);
return argument;
}
QDBusArgument &operator<<(QDBusArgument &argument,
const FcitxQtConfigType &arg) {
argument.beginStructure();
argument << arg.name();
argument << arg.options();
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument,
FcitxQtConfigType &arg) {
QString name;
FcitxQtConfigOptionList options;
argument.beginStructure();
argument >> name >> options;
argument.endStructure();
arg.setName(name);
arg.setOptions(options);
return argument;
}
QDBusArgument &operator<<(QDBusArgument &argument,
const FcitxQtAddonInfo &arg) {
argument.beginStructure();
argument << arg.uniqueName();
argument << arg.name();
argument << arg.comment();
argument << arg.category();
argument << arg.configurable();
argument << arg.enabled();
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument,
FcitxQtAddonInfo &arg) {
QString uniqueName, name, comment;
int category;
bool configurable, enabled;
argument.beginStructure();
argument >> uniqueName >> name >> comment >> category >> configurable >>
enabled;
argument.endStructure();
arg.setUniqueName(uniqueName);
arg.setName(name);
arg.setComment(comment);
arg.setCategory(category);
arg.setConfigurable(configurable);
arg.setEnabled(enabled);
return argument;
}
QDBusArgument &operator<<(QDBusArgument &argument,
const FcitxQtAddonInfoV2 &arg) {
argument.beginStructure();
argument << arg.uniqueName();
argument << arg.name();
argument << arg.comment();
argument << arg.category();
argument << arg.configurable();
argument << arg.enabled();
argument << arg.onDemand();
argument << arg.dependencies();
argument << arg.optionalDependencies();
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument,
FcitxQtAddonInfoV2 &arg) {
QString uniqueName, name, comment;
int category;
bool configurable, enabled, onDemand;
QStringList dependencies, optionalDependencies;
argument.beginStructure();
argument >> uniqueName >> name >> comment >> category >> configurable >>
enabled >> onDemand >> dependencies >> optionalDependencies;
argument.endStructure();
arg.setUniqueName(uniqueName);
arg.setName(name);
arg.setComment(comment);
arg.setCategory(category);
arg.setConfigurable(configurable);
arg.setEnabled(enabled);
arg.setOnDemand(onDemand);
arg.setDependencies(dependencies);
arg.setOptionalDependencies(optionalDependencies);
return argument;
}
QDBusArgument &operator<<(QDBusArgument &argument,
const FcitxQtAddonState &arg) {
argument.beginStructure();
argument << arg.uniqueName();
argument << arg.enabled();
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument,
FcitxQtAddonState &arg) {
QString uniqueName;
bool enabled;
argument.beginStructure();
argument >> uniqueName >> enabled;
argument.endStructure();
arg.setUniqueName(uniqueName);
arg.setEnabled(enabled);
return argument;
}
} // namespace fcitx

View File

@@ -0,0 +1,173 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef _DBUSADDONS_FCITXQTDBUSTYPES_H_
#define _DBUSADDONS_FCITXQTDBUSTYPES_H_
#include "fcitx5qt6dbusaddons_export.h"
#include <QDBusArgument>
#include <QList>
#include <QMetaType>
#include <type_traits>
namespace fcitx {
FCITX5QT6DBUSADDONS_EXPORT void registerFcitxQtDBusTypes();
#define FCITX5_QT_BEGIN_DECLARE_DBUS_TYPE(TYPE) \
class FCITX5QT6DBUSADDONS_EXPORT TYPE { \
public:
#define FCITX5_QT_DECLARE_FIELD(TYPE, GETTER, SETTER) \
public: \
std::conditional_t<std::is_class<TYPE>::value, const TYPE &, TYPE> \
GETTER() const { \
return GETTER##_; \
} \
void SETTER( \
std::conditional_t<std::is_class<TYPE>::value, const TYPE &, TYPE> \
value) { \
GETTER##_ = value; \
} \
\
private: \
TYPE GETTER##_ = TYPE();
#define FCITX5_QT_END_DECLARE_DBUS_TYPE(TYPE) \
} \
; \
typedef QList<TYPE> TYPE##List; \
FCITX5QT6DBUSADDONS_EXPORT QDBusArgument &operator<<( \
QDBusArgument &argument, const TYPE &value); \
FCITX5QT6DBUSADDONS_EXPORT const QDBusArgument &operator>>( \
const QDBusArgument &argument, TYPE &value);
FCITX5_QT_BEGIN_DECLARE_DBUS_TYPE(FcitxQtFormattedPreedit);
FCITX5_QT_DECLARE_FIELD(QString, string, setString);
FCITX5_QT_DECLARE_FIELD(qint32, format, setFormat);
public:
bool operator==(const FcitxQtFormattedPreedit &preedit) const;
FCITX5_QT_END_DECLARE_DBUS_TYPE(FcitxQtFormattedPreedit);
FCITX5_QT_BEGIN_DECLARE_DBUS_TYPE(FcitxQtStringKeyValue);
FCITX5_QT_DECLARE_FIELD(QString, key, setKey);
FCITX5_QT_DECLARE_FIELD(QString, value, setValue);
FCITX5_QT_END_DECLARE_DBUS_TYPE(FcitxQtStringKeyValue);
FCITX5_QT_BEGIN_DECLARE_DBUS_TYPE(FcitxQtInputMethodEntry);
FCITX5_QT_DECLARE_FIELD(QString, uniqueName, setUniqueName);
FCITX5_QT_DECLARE_FIELD(QString, name, setName);
FCITX5_QT_DECLARE_FIELD(QString, nativeName, setNativeName);
FCITX5_QT_DECLARE_FIELD(QString, icon, setIcon);
FCITX5_QT_DECLARE_FIELD(QString, label, setLabel);
FCITX5_QT_DECLARE_FIELD(QString, languageCode, setLanguageCode);
FCITX5_QT_DECLARE_FIELD(bool, configurable, setConfigurable);
FCITX5_QT_END_DECLARE_DBUS_TYPE(FcitxQtInputMethodEntry);
FCITX5_QT_BEGIN_DECLARE_DBUS_TYPE(FcitxQtFullInputMethodEntry);
FCITX5_QT_DECLARE_FIELD(QString, uniqueName, setUniqueName);
FCITX5_QT_DECLARE_FIELD(QString, name, setName);
FCITX5_QT_DECLARE_FIELD(QString, nativeName, setNativeName);
FCITX5_QT_DECLARE_FIELD(QString, icon, setIcon);
FCITX5_QT_DECLARE_FIELD(QString, label, setLabel);
FCITX5_QT_DECLARE_FIELD(QString, languageCode, setLanguageCode);
FCITX5_QT_DECLARE_FIELD(QString, addon, setAddon);
FCITX5_QT_DECLARE_FIELD(bool, configurable, setConfigurable);
FCITX5_QT_DECLARE_FIELD(QString, layout, setLayout);
FCITX5_QT_DECLARE_FIELD(QVariantMap, properties, setProperties);
FCITX5_QT_END_DECLARE_DBUS_TYPE(FcitxQtFullInputMethodEntry);
FCITX5_QT_BEGIN_DECLARE_DBUS_TYPE(FcitxQtVariantInfo);
FCITX5_QT_DECLARE_FIELD(QString, variant, setVariant);
FCITX5_QT_DECLARE_FIELD(QString, description, setDescription);
FCITX5_QT_DECLARE_FIELD(QStringList, languages, setLanguages);
FCITX5_QT_END_DECLARE_DBUS_TYPE(FcitxQtVariantInfo);
FCITX5_QT_BEGIN_DECLARE_DBUS_TYPE(FcitxQtLayoutInfo);
FCITX5_QT_DECLARE_FIELD(QString, layout, setLayout);
FCITX5_QT_DECLARE_FIELD(QString, description, setDescription);
FCITX5_QT_DECLARE_FIELD(QStringList, languages, setLanguages);
FCITX5_QT_DECLARE_FIELD(FcitxQtVariantInfoList, variants, setVariants);
FCITX5_QT_END_DECLARE_DBUS_TYPE(FcitxQtLayoutInfo);
FCITX5_QT_BEGIN_DECLARE_DBUS_TYPE(FcitxQtConfigOption);
FCITX5_QT_DECLARE_FIELD(QString, name, setName);
FCITX5_QT_DECLARE_FIELD(QString, type, setType);
FCITX5_QT_DECLARE_FIELD(QString, description, setDescription);
FCITX5_QT_DECLARE_FIELD(QDBusVariant, defaultValue, setDefaultValue);
FCITX5_QT_DECLARE_FIELD(QVariantMap, properties, setProperties);
FCITX5_QT_END_DECLARE_DBUS_TYPE(FcitxQtConfigOption);
FCITX5_QT_BEGIN_DECLARE_DBUS_TYPE(FcitxQtConfigType);
FCITX5_QT_DECLARE_FIELD(QString, name, setName);
FCITX5_QT_DECLARE_FIELD(FcitxQtConfigOptionList, options, setOptions);
FCITX5_QT_END_DECLARE_DBUS_TYPE(FcitxQtConfigType);
FCITX5_QT_BEGIN_DECLARE_DBUS_TYPE(FcitxQtAddonInfo);
FCITX5_QT_DECLARE_FIELD(QString, uniqueName, setUniqueName);
FCITX5_QT_DECLARE_FIELD(QString, name, setName);
FCITX5_QT_DECLARE_FIELD(QString, comment, setComment);
FCITX5_QT_DECLARE_FIELD(int, category, setCategory);
FCITX5_QT_DECLARE_FIELD(bool, configurable, setConfigurable);
FCITX5_QT_DECLARE_FIELD(bool, enabled, setEnabled);
FCITX5_QT_END_DECLARE_DBUS_TYPE(FcitxQtAddonInfo);
FCITX5_QT_BEGIN_DECLARE_DBUS_TYPE(FcitxQtAddonInfoV2);
FCITX5_QT_DECLARE_FIELD(QString, uniqueName, setUniqueName);
FCITX5_QT_DECLARE_FIELD(QString, name, setName);
FCITX5_QT_DECLARE_FIELD(QString, comment, setComment);
FCITX5_QT_DECLARE_FIELD(int, category, setCategory);
FCITX5_QT_DECLARE_FIELD(bool, configurable, setConfigurable);
FCITX5_QT_DECLARE_FIELD(bool, enabled, setEnabled);
FCITX5_QT_DECLARE_FIELD(bool, onDemand, setOnDemand);
FCITX5_QT_DECLARE_FIELD(QStringList, dependencies, setDependencies);
FCITX5_QT_DECLARE_FIELD(QStringList, optionalDependencies,
setOptionalDependencies);
FCITX5_QT_END_DECLARE_DBUS_TYPE(FcitxQtAddonInfoV2);
FCITX5_QT_BEGIN_DECLARE_DBUS_TYPE(FcitxQtAddonState);
FCITX5_QT_DECLARE_FIELD(QString, uniqueName, setUniqueName);
FCITX5_QT_DECLARE_FIELD(bool, enabled, setEnabled);
FCITX5_QT_END_DECLARE_DBUS_TYPE(FcitxQtAddonState);
} // namespace fcitx
Q_DECLARE_METATYPE(fcitx::FcitxQtFormattedPreedit)
Q_DECLARE_METATYPE(fcitx::FcitxQtFormattedPreeditList)
Q_DECLARE_METATYPE(fcitx::FcitxQtStringKeyValue)
Q_DECLARE_METATYPE(fcitx::FcitxQtStringKeyValueList)
Q_DECLARE_METATYPE(fcitx::FcitxQtInputMethodEntry)
Q_DECLARE_METATYPE(fcitx::FcitxQtInputMethodEntryList)
Q_DECLARE_METATYPE(fcitx::FcitxQtFullInputMethodEntry)
Q_DECLARE_METATYPE(fcitx::FcitxQtFullInputMethodEntryList)
Q_DECLARE_METATYPE(fcitx::FcitxQtVariantInfo)
Q_DECLARE_METATYPE(fcitx::FcitxQtVariantInfoList)
Q_DECLARE_METATYPE(fcitx::FcitxQtLayoutInfo)
Q_DECLARE_METATYPE(fcitx::FcitxQtLayoutInfoList)
Q_DECLARE_METATYPE(fcitx::FcitxQtConfigOption)
Q_DECLARE_METATYPE(fcitx::FcitxQtConfigOptionList)
Q_DECLARE_METATYPE(fcitx::FcitxQtConfigType)
Q_DECLARE_METATYPE(fcitx::FcitxQtConfigTypeList)
Q_DECLARE_METATYPE(fcitx::FcitxQtAddonInfo)
Q_DECLARE_METATYPE(fcitx::FcitxQtAddonInfoList)
Q_DECLARE_METATYPE(fcitx::FcitxQtAddonInfoV2)
Q_DECLARE_METATYPE(fcitx::FcitxQtAddonInfoV2List)
Q_DECLARE_METATYPE(fcitx::FcitxQtAddonState)
Q_DECLARE_METATYPE(fcitx::FcitxQtAddonStateList)
#endif // _DBUSADDONS_FCITXQTDBUSTYPES_H_

View File

@@ -0,0 +1,140 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include "fcitxqtinputcontextproxy_p.h"
#include <QCoreApplication>
#include <QDBusConnectionInterface>
#include <QDBusInterface>
#include <QDBusMetaType>
#include <QFileInfo>
#include <QTimer>
namespace fcitx {
FcitxQtInputContextProxy::FcitxQtInputContextProxy(FcitxQtWatcher *watcher,
QObject *parent)
: QObject(parent),
d_ptr(new FcitxQtInputContextProxyPrivate(watcher, this)) {}
FcitxQtInputContextProxy::~FcitxQtInputContextProxy() { delete d_ptr; }
void FcitxQtInputContextProxy::setDisplay(const QString &display) {
Q_D(FcitxQtInputContextProxy);
d->display_ = display;
}
const QString &FcitxQtInputContextProxy::display() const {
Q_D(const FcitxQtInputContextProxy);
return d->display_;
}
bool FcitxQtInputContextProxy::isValid() const {
Q_D(const FcitxQtInputContextProxy);
return d->isValid();
}
QDBusPendingReply<> FcitxQtInputContextProxy::focusIn() {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->FocusIn();
}
QDBusPendingReply<> FcitxQtInputContextProxy::focusOut() {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->FocusOut();
}
QDBusPendingReply<> FcitxQtInputContextProxy::hideVirtualKeyboard() {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->HideVirtualKeyboard();
}
QDBusPendingReply<bool> FcitxQtInputContextProxy::processKeyEvent(
unsigned int keyval, unsigned int keycode, unsigned int state, bool type,
unsigned int time) {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->ProcessKeyEvent(keyval, keycode, state, type, time);
}
QDBusPendingReply<> FcitxQtInputContextProxy::reset() {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->Reset();
}
QDBusPendingReply<>
FcitxQtInputContextProxy::setSupportedCapability(qulonglong caps) {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->SetSupportedCapability(caps);
}
QDBusPendingReply<> FcitxQtInputContextProxy::setCapability(qulonglong caps) {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->SetCapability(caps);
}
QDBusPendingReply<> FcitxQtInputContextProxy::setCursorRect(int x, int y, int w,
int h) {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->SetCursorRect(x, y, w, h);
}
QDBusPendingReply<> FcitxQtInputContextProxy::setCursorRectV2(int x, int y,
int w, int h,
double scale) {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->SetCursorRectV2(x, y, w, h, scale);
}
QDBusPendingReply<> FcitxQtInputContextProxy::setSurroundingText(
const QString &text, unsigned int cursor, unsigned int anchor) {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->SetSurroundingText(text, cursor, anchor);
}
QDBusPendingReply<>
FcitxQtInputContextProxy::setSurroundingTextPosition(unsigned int cursor,
unsigned int anchor) {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->SetSurroundingTextPosition(cursor, anchor);
}
QDBusPendingReply<> FcitxQtInputContextProxy::showVirtualKeyboard() {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->ShowVirtualKeyboard();
}
QDBusPendingReply<> FcitxQtInputContextProxy::prevPage() {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->PrevPage();
}
QDBusPendingReply<> FcitxQtInputContextProxy::nextPage() {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->NextPage();
}
QDBusPendingReply<> FcitxQtInputContextProxy::selectCandidate(int i) {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->SelectCandidate(i);
}
QDBusPendingReply<> FcitxQtInputContextProxy::invokeAction(unsigned int action,
int cursor) {
Q_D(FcitxQtInputContextProxy);
return d->icproxy_->InvokeAction(action, cursor);
}
bool FcitxQtInputContextProxy::isVirtualKeyboardVisible() {
Q_D(FcitxQtInputContextProxy);
return d->isVirtualKeyboardVisible_;
}
bool FcitxQtInputContextProxy::supportInvokeAction() const {
Q_D(const FcitxQtInputContextProxy);
return d->supportInvokeAction_;
}
} // namespace fcitx

View File

@@ -0,0 +1,90 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef _DBUSADDONS_FCITXQTINPUTCONTEXTPROXY_H_
#define _DBUSADDONS_FCITXQTINPUTCONTEXTPROXY_H_
#include "fcitx5qt6dbusaddons_export.h"
#include "fcitxqtdbustypes.h"
#include <QDBusConnection>
#include <QDBusPendingReply>
#include <QDBusServiceWatcher>
#include <QObject>
class QDBusPendingCallWatcher;
namespace fcitx {
class FcitxQtWatcher;
class FcitxQtInputContextProxyPrivate;
class FCITX5QT6DBUSADDONS_EXPORT FcitxQtInputContextProxy : public QObject {
Q_OBJECT
public:
FcitxQtInputContextProxy(FcitxQtWatcher *watcher, QObject *parent);
~FcitxQtInputContextProxy();
bool isValid() const;
void setDisplay(const QString &display);
const QString &display() const;
public Q_SLOTS:
QDBusPendingReply<> focusIn();
QDBusPendingReply<> focusOut();
QDBusPendingReply<> hideVirtualKeyboard();
QDBusPendingReply<bool> processKeyEvent(unsigned int keyval,
unsigned int keycode,
unsigned int state, bool type,
unsigned int time);
QDBusPendingReply<> reset();
QDBusPendingReply<> setSupportedCapability(qulonglong caps);
QDBusPendingReply<> setCapability(qulonglong caps);
QDBusPendingReply<> setCursorRect(int x, int y, int w, int h);
QDBusPendingReply<> setCursorRectV2(int x, int y, int w, int h,
double scale);
QDBusPendingReply<> setSurroundingText(const QString &text,
unsigned int cursor,
unsigned int anchor);
QDBusPendingReply<> setSurroundingTextPosition(unsigned int cursor,
unsigned int anchor);
QDBusPendingReply<> showVirtualKeyboard();
QDBusPendingReply<> prevPage();
QDBusPendingReply<> nextPage();
QDBusPendingReply<> selectCandidate(int i);
QDBusPendingReply<> invokeAction(unsigned int action, int cursor);
bool isVirtualKeyboardVisible();
bool supportInvokeAction() const;
Q_SIGNALS:
void commitString(const QString &str);
void currentIM(const QString &name, const QString &uniqueName,
const QString &langCode);
void deleteSurroundingText(int offset, unsigned int nchar);
void forwardKey(unsigned int keyval, unsigned int state, bool isRelease);
void updateFormattedPreedit(const FcitxQtFormattedPreeditList &str,
int cursorpos);
void updateClientSideUI(const FcitxQtFormattedPreeditList &preedit,
int cursorpos,
const FcitxQtFormattedPreeditList &auxUp,
const FcitxQtFormattedPreeditList &auxDown,
const FcitxQtStringKeyValueList &candidates,
int candidateIndex, int layoutHint, bool hasPrev,
bool hasNext);
void inputContextCreated(const QByteArray &uuid);
void inputContextCreationFailed();
void notifyFocusOut();
void virtualKeyboardVisibilityChanged(bool visible);
private:
FcitxQtInputContextProxyPrivate *const d_ptr;
Q_DECLARE_PRIVATE(FcitxQtInputContextProxy);
};
} // namespace fcitx
#endif // _DBUSADDONS_FCITXQTINPUTCONTEXTPROXY_H_

View File

@@ -0,0 +1,271 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef _DBUSADDONS_FCITXQTINPUTCONTEXTPROXY_P_H_
#define _DBUSADDONS_FCITXQTINPUTCONTEXTPROXY_P_H_
#include "fcitxqtinputcontextproxy.h"
#include "fcitxqtinputcontextproxyimpl.h"
#include "fcitxqtinputmethodproxy.h"
#include "fcitxqtwatcher.h"
#include <QDBusServiceWatcher>
#include <cstddef>
namespace fcitx {
class FcitxQtInputContextProxyPrivate {
public:
FcitxQtInputContextProxyPrivate(FcitxQtWatcher *watcher,
FcitxQtInputContextProxy *q)
: q_ptr(q), fcitxWatcher_(watcher), watcher_(q) {
registerFcitxQtDBusTypes();
QObject::connect(fcitxWatcher_, &FcitxQtWatcher::availabilityChanged, q,
[this]() { availabilityChanged(); });
watcher_.setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
QObject::connect(&watcher_, &QDBusServiceWatcher::serviceUnregistered,
q, [this]() {
cleanUp();
availabilityChanged();
});
availabilityChanged();
}
~FcitxQtInputContextProxyPrivate() {
Q_Q(FcitxQtInputContextProxy);
if (isValid()) {
icproxy_->DestroyIC();
}
QObject::disconnect(
q, &FcitxQtInputContextProxy::virtualKeyboardVisibilityChanged,
nullptr, nullptr);
cleanUp();
}
bool isValid() const { return (icproxy_ && icproxy_->isValid()); }
void availabilityChanged() {
QTimer::singleShot(100, q_ptr, [this]() { recheck(); });
}
void recheck() {
if (!isValid() && fcitxWatcher_->availability()) {
createInputContext();
}
if (!fcitxWatcher_->availability()) {
cleanUp();
}
}
void cleanUp() {
auto services = watcher_.watchedServices();
for (const auto &service : services) {
watcher_.removeWatchedService(service);
}
delete improxy_;
improxy_ = nullptr;
delete icproxy_;
icproxy_ = nullptr;
delete createInputContextWatcher_;
createInputContextWatcher_ = nullptr;
delete introspectWatcher_;
introspectWatcher_ = nullptr;
delete queryWatcher_;
queryWatcher_ = nullptr;
setVirtualKeyboardVisible(false);
supportInvokeAction_ = false;
}
void createInputContext() {
Q_Q(FcitxQtInputContextProxy);
if (!fcitxWatcher_->availability()) {
return;
}
cleanUp();
auto service = fcitxWatcher_->serviceName();
auto connection = fcitxWatcher_->connection();
auto owner = connection.interface()->serviceOwner(service);
if (!owner.isValid()) {
return;
}
watcher_.setConnection(connection);
watcher_.setWatchedServices(QStringList() << owner);
// Avoid race, query again.
if (!connection.interface()->isServiceRegistered(owner)) {
cleanUp();
return;
}
QFileInfo info(QCoreApplication::applicationFilePath());
improxy_ = new FcitxQtInputMethodProxy(
owner, "/org/freedesktop/portal/inputmethod", connection, q);
FcitxQtStringKeyValueList list;
FcitxQtStringKeyValue arg;
arg.setKey("program");
arg.setValue(info.fileName());
list << arg;
if (!display_.isEmpty()) {
FcitxQtStringKeyValue arg2;
arg2.setKey("display");
arg2.setValue(display_);
list << arg2;
}
// Qt has good support for showing virtual keyboard, so we should
// disable the default behavior supported by fcitx5
FcitxQtStringKeyValue clientControlVirtualkeyboardShow;
clientControlVirtualkeyboardShow.setKey(
"clientControlVirtualkeyboardShow");
clientControlVirtualkeyboardShow.setValue("true");
list << clientControlVirtualkeyboardShow;
// Qt has poor support for hiding virtual keyboard, so we should enable
// the default behavior supported by fcitx5
FcitxQtStringKeyValue clientControlVirtualkeyboardHide;
clientControlVirtualkeyboardHide.setKey(
"clientControlVirtualkeyboardHide");
clientControlVirtualkeyboardHide.setValue("false");
list << clientControlVirtualkeyboardHide;
auto result = improxy_->CreateInputContext(list);
createInputContextWatcher_ = new QDBusPendingCallWatcher(result);
QObject::connect(createInputContextWatcher_,
&QDBusPendingCallWatcher::finished, q,
[this]() { createInputContextFinished(); });
}
void createInputContextFinished() {
Q_Q(FcitxQtInputContextProxy);
if (createInputContextWatcher_->isError()) {
cleanUp();
Q_EMIT q->inputContextCreationFailed();
return;
}
QDBusPendingReply<QDBusObjectPath, QByteArray> reply(
*createInputContextWatcher_);
icproxy_ = new FcitxQtInputContextProxyImpl(improxy_->service(),
reply.value().path(),
improxy_->connection(), q);
QObject::connect(icproxy_, &FcitxQtInputContextProxyImpl::CommitString,
q, &FcitxQtInputContextProxy::commitString);
QObject::connect(icproxy_, &FcitxQtInputContextProxyImpl::CurrentIM, q,
&FcitxQtInputContextProxy::currentIM);
QObject::connect(icproxy_,
&FcitxQtInputContextProxyImpl::DeleteSurroundingText,
q, &FcitxQtInputContextProxy::deleteSurroundingText);
QObject::connect(icproxy_, &FcitxQtInputContextProxyImpl::ForwardKey, q,
&FcitxQtInputContextProxy::forwardKey);
QObject::connect(icproxy_,
&FcitxQtInputContextProxyImpl::UpdateFormattedPreedit,
q, &FcitxQtInputContextProxy::updateFormattedPreedit);
QObject::connect(icproxy_,
&FcitxQtInputContextProxyImpl::UpdateClientSideUI, q,
&FcitxQtInputContextProxy::updateClientSideUI);
QObject::connect(icproxy_,
&FcitxQtInputContextProxyImpl::NotifyFocusOut, q,
&FcitxQtInputContextProxy::notifyFocusOut);
QObject::connect(
icproxy_,
&FcitxQtInputContextProxyImpl::VirtualKeyboardVisibilityChanged, q,
[this](bool visible) {
if (queryWatcher_) {
queryWatcher_->deleteLater();
queryWatcher_ = nullptr;
}
setVirtualKeyboardVisible(visible);
});
delete createInputContextWatcher_;
createInputContextWatcher_ = nullptr;
Q_EMIT q->inputContextCreated(reply.argumentAt<1>());
introspect();
virtualKeyboardVisibilityQuery();
}
void introspect() {
Q_Q(FcitxQtInputContextProxy);
if (introspectWatcher_) {
delete introspectWatcher_;
introspectWatcher_ = nullptr;
}
QDBusMessage call = QDBusMessage::createMethodCall(
icproxy_->service(), icproxy_->path(),
"org.freedesktop.DBus.Introspectable", "Introspect");
introspectWatcher_ = new QDBusPendingCallWatcher(
fcitxWatcher_->connection().asyncCall(call));
QObject::connect(introspectWatcher_, &QDBusPendingCallWatcher::finished,
q, [this]() { introspectFinished(); });
}
void introspectFinished() {
if (introspectWatcher_->isFinished() &&
!introspectWatcher_->isError()) {
QDBusPendingReply<QString> reply = *introspectWatcher_;
if (reply.value().contains("InvokeAction")) {
supportInvokeAction_ = true;
}
}
delete introspectWatcher_;
introspectWatcher_ = nullptr;
}
void virtualKeyboardVisibilityQuery() {
Q_Q(FcitxQtInputContextProxy);
if (queryWatcher_) {
delete queryWatcher_;
queryWatcher_ = nullptr;
}
queryWatcher_ =
new QDBusPendingCallWatcher(icproxy_->IsVirtualKeyboardVisible());
QObject::connect(
queryWatcher_, &QDBusPendingCallWatcher::finished, q,
[this]() { virtualKeyboardVisibilityQueryFinished(); });
}
void virtualKeyboardVisibilityQueryFinished() {
if (queryWatcher_ && queryWatcher_->isFinished() &&
!queryWatcher_->isError()) {
QDBusPendingReply<bool> reply = *queryWatcher_;
setVirtualKeyboardVisible(reply.value());
}
delete queryWatcher_;
queryWatcher_ = nullptr;
}
void setVirtualKeyboardVisible(bool visible) {
Q_Q(FcitxQtInputContextProxy);
if (isVirtualKeyboardVisible_ != visible) {
isVirtualKeyboardVisible_ = visible;
Q_EMIT q->virtualKeyboardVisibilityChanged(
isVirtualKeyboardVisible_);
}
}
FcitxQtInputContextProxy *q_ptr;
Q_DECLARE_PUBLIC(FcitxQtInputContextProxy);
FcitxQtWatcher *fcitxWatcher_;
QDBusServiceWatcher watcher_;
FcitxQtInputMethodProxy *improxy_ = nullptr;
FcitxQtInputContextProxyImpl *icproxy_ = nullptr;
bool isVirtualKeyboardVisible_ = false;
bool supportInvokeAction_ = false;
QDBusPendingCallWatcher *createInputContextWatcher_ = nullptr;
QDBusPendingCallWatcher *introspectWatcher_ = nullptr;
QDBusPendingCallWatcher *queryWatcher_ = nullptr;
QString display_;
};
} // namespace fcitx
#endif // _DBUSADDONS_FCITXQTINPUTCONTEXTPROXY_P_H_

View File

@@ -0,0 +1,31 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
* Command line was: qdbusxml2cpp -N -p fcitxqtinputcontextproxyimpl -c
* FcitxQtInputContextProxyImpl interfaces/org.fcitx.Fcitx.InputContext1.xml -i
* fcitxqtdbustypes.h -i fcitx5qt6dbusaddons_export.h
*
* qdbusxml2cpp is Copyright (C) 2023 The Qt Company Ltd and other contributors.
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
* before re-generating it.
*/
#include "fcitxqtinputcontextproxyimpl.h"
namespace fcitx {
/*
* Implementation of interface class FcitxQtInputContextProxyImpl
*/
FcitxQtInputContextProxyImpl::FcitxQtInputContextProxyImpl(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
: QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
{
}
FcitxQtInputContextProxyImpl::~FcitxQtInputContextProxyImpl()
{
}
}

View File

@@ -0,0 +1,177 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
* Command line was: qdbusxml2cpp -N -p fcitxqtinputcontextproxyimpl -c
* FcitxQtInputContextProxyImpl interfaces/org.fcitx.Fcitx.InputContext1.xml -i
* fcitxqtdbustypes.h -i fcitx5qt6dbusaddons_export.h
*
* qdbusxml2cpp is Copyright (C) 2023 The Qt Company Ltd and other contributors.
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
*/
#ifndef FCITXQTINPUTCONTEXTPROXYIMPL_H
#define FCITXQTINPUTCONTEXTPROXYIMPL_H
#include <QtCore/QObject>
#include <QtCore/QByteArray>
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <QtDBus/QtDBus>
#include "fcitxqtdbustypes.h"
#include "fcitx5qt6dbusaddons_export.h"
namespace fcitx {
/*
* Proxy class for interface org.fcitx.Fcitx.InputContext1
*/
class FCITX5QT6DBUSADDONS_EXPORT FcitxQtInputContextProxyImpl: public QDBusAbstractInterface
{
Q_OBJECT
public:
static inline const char *staticInterfaceName()
{ return "org.fcitx.Fcitx.InputContext1"; }
public:
FcitxQtInputContextProxyImpl(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr);
~FcitxQtInputContextProxyImpl();
public Q_SLOTS: // METHODS
inline QDBusPendingReply<> DestroyIC()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("DestroyIC"), argumentList);
}
inline QDBusPendingReply<> FocusIn()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("FocusIn"), argumentList);
}
inline QDBusPendingReply<> FocusOut()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("FocusOut"), argumentList);
}
inline QDBusPendingReply<> HideVirtualKeyboard() {
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("HideVirtualKeyboard"),
argumentList);
}
inline QDBusPendingReply<> InvokeAction(unsigned int action, int cursor) {
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(action)
<< QVariant::fromValue(cursor);
return asyncCallWithArgumentList(QStringLiteral("InvokeAction"),
argumentList);
}
inline QDBusPendingReply<bool> IsVirtualKeyboardVisible() {
QList<QVariant> argumentList;
return asyncCallWithArgumentList(
QStringLiteral("IsVirtualKeyboardVisible"), argumentList);
}
inline QDBusPendingReply<> NextPage()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("NextPage"), argumentList);
}
inline QDBusPendingReply<> PrevPage()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("PrevPage"), argumentList);
}
inline QDBusPendingReply<bool>
ProcessKeyEvent(unsigned int keyval, unsigned int keycode,
unsigned int state, bool type, unsigned int time) {
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(keyval) << QVariant::fromValue(keycode) << QVariant::fromValue(state) << QVariant::fromValue(type) << QVariant::fromValue(time);
return asyncCallWithArgumentList(QStringLiteral("ProcessKeyEvent"), argumentList);
}
inline QDBusPendingReply<> Reset()
{
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("Reset"), argumentList);
}
inline QDBusPendingReply<> SelectCandidate(int index)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(index);
return asyncCallWithArgumentList(QStringLiteral("SelectCandidate"), argumentList);
}
inline QDBusPendingReply<> SetCapability(qulonglong caps)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(caps);
return asyncCallWithArgumentList(QStringLiteral("SetCapability"), argumentList);
}
inline QDBusPendingReply<> SetCursorRect(int x, int y, int w, int h)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(x) << QVariant::fromValue(y) << QVariant::fromValue(w) << QVariant::fromValue(h);
return asyncCallWithArgumentList(QStringLiteral("SetCursorRect"), argumentList);
}
inline QDBusPendingReply<> SetCursorRectV2(int x, int y, int w, int h, double scale)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(x) << QVariant::fromValue(y) << QVariant::fromValue(w) << QVariant::fromValue(h) << QVariant::fromValue(scale);
return asyncCallWithArgumentList(QStringLiteral("SetCursorRectV2"), argumentList);
}
inline QDBusPendingReply<> SetSupportedCapability(qulonglong caps) {
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(caps);
return asyncCallWithArgumentList(
QStringLiteral("SetSupportedCapability"), argumentList);
}
inline QDBusPendingReply<> SetSurroundingText(const QString &text,
unsigned int cursor,
unsigned int anchor) {
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(text) << QVariant::fromValue(cursor) << QVariant::fromValue(anchor);
return asyncCallWithArgumentList(QStringLiteral("SetSurroundingText"), argumentList);
}
inline QDBusPendingReply<> SetSurroundingTextPosition(unsigned int cursor,
unsigned int anchor) {
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(cursor) << QVariant::fromValue(anchor);
return asyncCallWithArgumentList(QStringLiteral("SetSurroundingTextPosition"), argumentList);
}
inline QDBusPendingReply<> ShowVirtualKeyboard() {
QList<QVariant> argumentList;
return asyncCallWithArgumentList(QStringLiteral("ShowVirtualKeyboard"),
argumentList);
}
Q_SIGNALS: // SIGNALS
void CommitString(const QString &str);
void CurrentIM(const QString &name, const QString &uniqueName, const QString &langCode);
void DeleteSurroundingText(int offset, unsigned int nchar);
void ForwardKey(unsigned int keyval, unsigned int state, bool type);
void NotifyFocusOut();
void UpdateClientSideUI(FcitxQtFormattedPreeditList preedit, int cursorpos, FcitxQtFormattedPreeditList auxUp, FcitxQtFormattedPreeditList auxDown, FcitxQtStringKeyValueList candidates, int candidateIndex, int layoutHint, bool hasPrev, bool hasNext);
void UpdateFormattedPreedit(FcitxQtFormattedPreeditList str, int cursorpos);
void VirtualKeyboardVisibilityChanged(bool visible);
};
}
#endif

View File

@@ -0,0 +1,31 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
* Command line was: qdbusxml2cpp -N -p fcitxqtinputmethodproxy -c
* FcitxQtInputMethodProxy interfaces/org.fcitx.Fcitx.InputMethod1.xml -i
* fcitxqtdbustypes.h -i fcitx5qt6dbusaddons_export.h
*
* qdbusxml2cpp is Copyright (C) 2023 The Qt Company Ltd and other contributors.
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
* before re-generating it.
*/
#include "fcitxqtinputmethodproxy.h"
namespace fcitx {
/*
* Implementation of interface class FcitxQtInputMethodProxy
*/
FcitxQtInputMethodProxy::FcitxQtInputMethodProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent)
: QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
{
}
FcitxQtInputMethodProxy::~FcitxQtInputMethodProxy()
{
}
}

View File

@@ -0,0 +1,68 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
* Command line was: qdbusxml2cpp -N -p fcitxqtinputmethodproxy -c
* FcitxQtInputMethodProxy interfaces/org.fcitx.Fcitx.InputMethod1.xml -i
* fcitxqtdbustypes.h -i fcitx5qt6dbusaddons_export.h
*
* qdbusxml2cpp is Copyright (C) 2023 The Qt Company Ltd and other contributors.
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
*/
#ifndef FCITXQTINPUTMETHODPROXY_H
#define FCITXQTINPUTMETHODPROXY_H
#include <QtCore/QObject>
#include <QtCore/QByteArray>
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVariant>
#include <QtDBus/QtDBus>
#include "fcitxqtdbustypes.h"
#include "fcitx5qt6dbusaddons_export.h"
namespace fcitx {
/*
* Proxy class for interface org.fcitx.Fcitx.InputMethod1
*/
class FCITX5QT6DBUSADDONS_EXPORT FcitxQtInputMethodProxy: public QDBusAbstractInterface
{
Q_OBJECT
public:
static inline const char *staticInterfaceName()
{ return "org.fcitx.Fcitx.InputMethod1"; }
public:
FcitxQtInputMethodProxy(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr);
~FcitxQtInputMethodProxy();
public Q_SLOTS: // METHODS
inline QDBusPendingReply<QDBusObjectPath, QByteArray> CreateInputContext(FcitxQtStringKeyValueList in0)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
return asyncCallWithArgumentList(QStringLiteral("CreateInputContext"), argumentList);
}
inline QDBusReply<QDBusObjectPath> CreateInputContext(FcitxQtStringKeyValueList in0, QByteArray &out1)
{
QList<QVariant> argumentList;
argumentList << QVariant::fromValue(in0);
QDBusMessage reply = callWithArgumentList(QDBus::Block, QStringLiteral("CreateInputContext"), argumentList);
if (reply.type() == QDBusMessage::ReplyMessage &&
reply.arguments().size() == 2) {
out1 = qdbus_cast<QByteArray>(reply.arguments().at(1));
}
return reply;
}
Q_SIGNALS: // SIGNALS
};
}
#endif

View File

@@ -0,0 +1,139 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include "fcitxqtwatcher_p.h"
#include <QDBusConnection>
#include <QDBusConnectionInterface>
#include <QDBusServiceWatcher>
namespace fcitx {
FcitxQtWatcher::FcitxQtWatcher(QObject *parent)
: QObject(parent), d_ptr(new FcitxQtWatcherPrivate(this)) {}
FcitxQtWatcher::FcitxQtWatcher(const QDBusConnection &connection,
QObject *parent)
: FcitxQtWatcher(parent) {
setConnection(connection);
}
FcitxQtWatcher::~FcitxQtWatcher() { delete d_ptr; }
bool FcitxQtWatcher::availability() const {
Q_D(const FcitxQtWatcher);
return d->availability_;
}
void FcitxQtWatcher::setConnection(const QDBusConnection &connection) {
Q_D(FcitxQtWatcher);
return d->serviceWatcher_.setConnection(connection);
}
QDBusConnection FcitxQtWatcher::connection() const {
Q_D(const FcitxQtWatcher);
return d->serviceWatcher_.connection();
}
void FcitxQtWatcher::setWatchPortal(bool portal) {
Q_D(FcitxQtWatcher);
d->watchPortal_ = portal;
}
bool FcitxQtWatcher::watchPortal() const {
Q_D(const FcitxQtWatcher);
return d->watchPortal_;
}
QString FcitxQtWatcher::serviceName() const {
Q_D(const FcitxQtWatcher);
if (d->mainPresent_) {
return FCITX_MAIN_SERVICE_NAME;
}
if (d->portalPresent_) {
return FCITX_PORTAL_SERVICE_NAME;
}
return QString();
}
void FcitxQtWatcher::setAvailability(bool availability) {
Q_D(FcitxQtWatcher);
if (d->availability_ != availability) {
d->availability_ = availability;
Q_EMIT availabilityChanged(d->availability_);
}
}
void FcitxQtWatcher::watch() {
Q_D(FcitxQtWatcher);
if (d->watched_) {
return;
}
connect(&d->serviceWatcher_, &QDBusServiceWatcher::serviceOwnerChanged,
this, &FcitxQtWatcher::imChanged);
d->serviceWatcher_.addWatchedService(FCITX_MAIN_SERVICE_NAME);
if (d->watchPortal_) {
d->serviceWatcher_.addWatchedService(FCITX_PORTAL_SERVICE_NAME);
}
if (connection().interface()->isServiceRegistered(
FCITX_MAIN_SERVICE_NAME)) {
d->mainPresent_ = true;
}
if (d->watchPortal_ && connection().interface()->isServiceRegistered(
FCITX_PORTAL_SERVICE_NAME)) {
d->portalPresent_ = true;
}
updateAvailability();
d->watched_ = true;
}
void FcitxQtWatcher::unwatch() {
Q_D(FcitxQtWatcher);
if (!d->watched_) {
return;
}
disconnect(&d->serviceWatcher_, &QDBusServiceWatcher::serviceOwnerChanged,
this, &FcitxQtWatcher::imChanged);
d->mainPresent_ = false;
d->portalPresent_ = false;
d->watched_ = false;
updateAvailability();
}
bool FcitxQtWatcher::isWatching() const {
Q_D(const FcitxQtWatcher);
return d->watched_;
}
void FcitxQtWatcher::imChanged(const QString &service, const QString &,
const QString &newOwner) {
Q_D(FcitxQtWatcher);
if (service == FCITX_MAIN_SERVICE_NAME) {
if (!newOwner.isEmpty()) {
d->mainPresent_ = true;
} else {
d->mainPresent_ = false;
}
} else if (service == FCITX_PORTAL_SERVICE_NAME) {
if (!newOwner.isEmpty()) {
d->portalPresent_ = true;
} else {
d->portalPresent_ = false;
}
}
updateAvailability();
}
void FcitxQtWatcher::updateAvailability() {
Q_D(FcitxQtWatcher);
setAvailability(d->mainPresent_ || d->portalPresent_);
}
} // namespace fcitx

View File

@@ -0,0 +1,54 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef _DBUSADDONS_FCITXQTWATCHER_H_
#define _DBUSADDONS_FCITXQTWATCHER_H_
#include "fcitx5qt6dbusaddons_export.h"
#include <QDBusConnection>
#include <QObject>
namespace fcitx {
class FcitxQtWatcherPrivate;
class FCITX5QT6DBUSADDONS_EXPORT FcitxQtWatcher : public QObject {
Q_OBJECT
public:
explicit FcitxQtWatcher(QObject *parent = nullptr);
explicit FcitxQtWatcher(const QDBusConnection &connection,
QObject *parent = nullptr);
~FcitxQtWatcher();
void watch();
void unwatch();
void setConnection(const QDBusConnection &connection);
QDBusConnection connection() const;
void setWatchPortal(bool portal);
bool watchPortal() const;
bool isWatching() const;
bool availability() const;
QString serviceName() const;
Q_SIGNALS:
void availabilityChanged(bool);
private Q_SLOTS:
void imChanged(const QString &service, const QString &oldOwner,
const QString &newOwner);
private:
void setAvailability(bool availability);
void updateAvailability();
FcitxQtWatcherPrivate *const d_ptr;
Q_DECLARE_PRIVATE(FcitxQtWatcher);
};
} // namespace fcitx
#endif // _DBUSADDONS_FCITXQTWATCHER_H_

View File

@@ -0,0 +1,32 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef _DBUSADDONS_FCITXQTWATCHER_P_H_
#define _DBUSADDONS_FCITXQTWATCHER_P_H_
#include "fcitxqtwatcher.h"
#include <QDBusServiceWatcher>
#define FCITX_MAIN_SERVICE_NAME "org.fcitx.Fcitx5"
#define FCITX_PORTAL_SERVICE_NAME "org.freedesktop.portal.Fcitx"
namespace fcitx {
class FcitxQtWatcherPrivate {
public:
FcitxQtWatcherPrivate(FcitxQtWatcher *q) : serviceWatcher_(q) {}
QDBusServiceWatcher serviceWatcher_;
bool watchPortal_ = false;
bool availability_ = false;
bool mainPresent_ = false;
bool portalPresent_ = false;
bool watched_ = false;
};
} // namespace fcitx
#endif // _DBUSADDONS_FCITXQTWATCHER_P_H_

View File

@@ -0,0 +1,5 @@
#!/bin/sh
qdbusxml2cpp-qt6 -N -p fcitxqtinputcontextproxyimpl -c FcitxQtInputContextProxyImpl interfaces/org.fcitx.Fcitx.InputContext1.xml -i fcitxqtdbustypes.h -i fcitx5qt6dbusaddons_export.h
qdbusxml2cpp-qt6 -N -p fcitxqtinputmethodproxy -c FcitxQtInputMethodProxy interfaces/org.fcitx.Fcitx.InputMethod1.xml -i fcitxqtdbustypes.h -i fcitx5qt6dbusaddons_export.h
qdbusxml2cpp-qt6 -N -p fcitxqtcontrollerproxy -c FcitxQtControllerProxy interfaces/org.fcitx.Fcitx.Controller1.xml -i fcitxqtdbustypes.h -i fcitx5qt6dbusaddons_export.h

View File

@@ -0,0 +1 @@
../../qt5/dbusaddons/interfaces/

View File

@@ -0,0 +1,25 @@
set(QT_WRAPPER_SRCS
main.cpp
wrapperapp.cpp
mainwindow.cpp
)
add_executable(fcitx5-qt6-gui-wrapper ${QT_WRAPPER_SRCS})
set_target_properties(fcitx5-qt6-gui-wrapper
PROPERTIES AUTOMOC TRUE AUTOUIC TRUE AUTOUIC_OPTIONS "-tr=fcitx::tr2fcitx;--include=fcitxqti18nhelper.h")
target_link_libraries(fcitx5-qt6-gui-wrapper
Fcitx5::Utils
Qt6::Core
Qt6::Gui
Qt6::Widgets
Fcitx5Qt6::DBusAddons
Fcitx5Qt6::WidgetsAddons
)
install(TARGETS fcitx5-qt6-gui-wrapper DESTINATION "${CMAKE_INSTALL_LIBEXECDIR}")
configure_file(org.fcitx.fcitx5-qt6-gui-wrapper.desktop.in.in ${CMAKE_CURRENT_BINARY_DIR}/org.fcitx.fcitx5-qt6-gui-wrapper.desktop.in @ONLY)
fcitx5_translate_desktop_file(${CMAKE_CURRENT_BINARY_DIR}/org.fcitx.fcitx5-qt6-gui-wrapper.desktop.in
org.fcitx.fcitx5-qt6-gui-wrapper.desktop)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.fcitx.fcitx5-qt6-gui-wrapper.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)

View File

@@ -0,0 +1 @@
../../qt5/guiwrapper/main.cpp

View File

@@ -0,0 +1 @@
../../qt5/guiwrapper/mainwindow.cpp

View File

@@ -0,0 +1 @@
../../qt5/guiwrapper/mainwindow.h

View File

@@ -0,0 +1 @@
../../qt5/guiwrapper/mainwindow.ui

View File

@@ -0,0 +1,9 @@
[Desktop Entry]
Name=Fcitx 5 Qt6 Gui Wrapper
GenericName=Input Method Configuration helper
Comment=Load configuration plugin for Fcitx Addon
Icon=fcitx
Exec=@CMAKE_INSTALL_FULL_LIBEXECDIR@/fcitx5-qt6-gui-wrapper
Type=Application
Categories=Settings;
NoDisplay=true

View File

@@ -0,0 +1 @@
../../qt5/guiwrapper/wrapperapp.cpp

View File

@@ -0,0 +1 @@
../../qt5/guiwrapper/wrapperapp.h

View File

@@ -0,0 +1,5 @@
add_executable(fcitx5-qt6-immodule-probing main.cpp)
target_include_directories(fcitx5-qt6-immodule-probing PRIVATE ${Qt6Gui_PRIVATE_INCLUDE_DIRS})
target_link_libraries(fcitx5-qt6-immodule-probing Qt6::Gui)
install(TARGETS fcitx5-qt6-immodule-probing DESTINATION "${CMAKE_INSTALL_BINDIR}")

View File

@@ -0,0 +1,29 @@
/*
* SPDX-FileCopyrightText: 2023~2023 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
*/
#include <QGuiApplication>
#include <iostream>
#include <private/qguiapplication_p.h>
#include <qpa/qplatforminputcontext.h>
#include <qpa/qplatforminputcontextfactory_p.h>
#include <qpa/qplatformintegration.h>
int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
std::cout << "QT_QPA_PLATFORM=" << app.platformName().toStdString()
<< std::endl;
std::cout << "QT_IM_MODULE="
<< QPlatformInputContextFactory::requested().toStdString()
<< std::endl;
auto inputContext =
QGuiApplicationPrivate::platformIntegration()->inputContext();
std::cout << "IM_MODULE_CLASSNAME=";
if (inputContext) {
std::cout << inputContext->metaObject()->className();
}
std::cout << std::endl;
return 0;
}

View File

@@ -0,0 +1,78 @@
set(FCITX5_QT_EXTRA_PLUGIN_NAME "")
if (WITH_FCITX_PLUGIN_NAME)
set(FCITX5_QT_EXTRA_PLUGIN_NAME "\"fcitx\",")
endif()
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/fcitx5.json.in" "${CMAKE_CURRENT_BINARY_DIR}/fcitx5.json")
set(plugin_SRCS
fcitx4watcher.cpp
fcitx4inputcontextproxy.cpp
fcitx4inputcontextproxyimpl.cpp
fcitx4inputmethodproxy.cpp
hybridinputcontext.cpp
qfcitxplatforminputcontext.cpp
fcitxcandidatewindow.cpp
fcitxtheme.cpp
font.cpp
qtkey.cpp
main.cpp
)
if (BUILD_ONLY_PLUGIN AND BUILD_STATIC_PLUGIN)
set(plugin_SRCS ${plugin_SRCS} $<TARGET_OBJECTS:Fcitx5Qt6DBusAddons>)
endif()
add_library(fcitx5platforminputcontextplugin-qt6 ${PLUGIN_LIBRARY_TYPE} ${plugin_SRCS})
set_target_properties(fcitx5platforminputcontextplugin-qt6 PROPERTIES
OUTPUT_NAME fcitx5platforminputcontextplugin
AUTOMOC TRUE
)
target_include_directories(fcitx5platforminputcontextplugin-qt6 PRIVATE "${PROJECT_SOURCE_DIR}/common")
if (BUILD_ONLY_PLUGIN AND BUILD_STATIC_PLUGIN)
target_compile_definitions(fcitx5platforminputcontextplugin-qt6 PRIVATE "-DQT_STATICPLUGIN")
endif()
target_compile_definitions(fcitx5platforminputcontextplugin-qt6 PRIVATE "-DFCITX_PLUGIN_DATA_FILE_PATH=\"${CMAKE_CURRENT_BINARY_DIR}/fcitx5.json\"")
if (WITH_FCITX_PLUGIN_NAME)
# This is not really necessary, but can trigger a cmake rebuild.
target_compile_definitions(fcitx5platforminputcontextplugin-qt6 PRIVATE "-DFCITX5_QT_WITH_FCITX_NAME")
endif()
target_link_libraries(fcitx5platforminputcontextplugin-qt6
Qt6::Core
Qt6::Gui
Qt6::GuiPrivate
Qt6::DBus
Qt6::Widgets
Fcitx5Qt6::DBusAddons
XKBCommon::XKBCommon
)
if (ENABLE_X11)
target_link_libraries(fcitx5platforminputcontextplugin-qt6 XCB::XCB)
target_compile_definitions(fcitx5platforminputcontextplugin-qt6 PRIVATE "-DENABLE_X11")
endif()
if (ENABLE_QT6_WAYLAND_WORKAROUND)
target_compile_definitions(fcitx5platforminputcontextplugin-qt6 PRIVATE "-DFCITX_ENABLE_QT6_WAYLAND_WORKAROUND")
target_link_libraries(fcitx5platforminputcontextplugin-qt6
Qt6::GuiPrivate
Qt6::WaylandGlobalPrivate
Qt6::WaylandClient
Qt6::WaylandClientPrivate)
endif()
get_target_property(_QT6_QMAKE_EXECUTABLE Qt6::qmake LOCATION)
execute_process(
COMMAND ${_QT6_QMAKE_EXECUTABLE} -query "QT_INSTALL_PLUGINS"
RESULT_VARIABLE return_code
OUTPUT_VARIABLE _QT6PLUGINDIR
)
if(return_code EQUAL 0)
string(STRIP "${_QT6PLUGINDIR}" _QT6PLUGINDIR)
else()
message(FATAL_ERROR "QMake Qt6 call failed: ${return_code}")
endif()
set(CMAKE_INSTALL_QT6PLUGINDIR ${_QT6PLUGINDIR} CACHE PATH "Qt6 plugin dir")
install(TARGETS fcitx5platforminputcontextplugin-qt6 DESTINATION ${CMAKE_INSTALL_QT6PLUGINDIR}/platforminputcontexts)

View File

@@ -0,0 +1 @@
../../qt5/platforminputcontext/fcitx4inputcontextproxy.cpp

View File

@@ -0,0 +1 @@
../../qt5/platforminputcontext/fcitx4inputcontextproxy.h

View File

@@ -0,0 +1 @@
../../qt5/platforminputcontext/fcitx4inputcontextproxy_p.h

View File

@@ -0,0 +1 @@
../../qt5/platforminputcontext/fcitx4inputcontextproxyimpl.cpp

View File

@@ -0,0 +1 @@
../../qt5/platforminputcontext/fcitx4inputcontextproxyimpl.h

View File

@@ -0,0 +1 @@
../../qt5/platforminputcontext/fcitx4inputmethodproxy.cpp

View File

@@ -0,0 +1 @@
../../qt5/platforminputcontext/fcitx4inputmethodproxy.h

View File

@@ -0,0 +1 @@
../../qt5/platforminputcontext/fcitx4watcher.cpp

View File

@@ -0,0 +1 @@
../../qt5/platforminputcontext/fcitx4watcher.h

View File

@@ -0,0 +1 @@
../../qt5/platforminputcontext/fcitx5.json.in

View File

@@ -0,0 +1 @@
../../qt5/platforminputcontext/fcitxcandidatewindow.cpp

View File

@@ -0,0 +1 @@
../../qt5/platforminputcontext/fcitxcandidatewindow.h

View File

@@ -0,0 +1 @@
../../qt5/platforminputcontext/fcitxtheme.cpp

View File

@@ -0,0 +1 @@
../../qt5/platforminputcontext/fcitxtheme.h

View File

@@ -0,0 +1 @@
../../qt5/platforminputcontext/font.cpp

View File

@@ -0,0 +1 @@
../../qt5/platforminputcontext/font.h

View File

@@ -0,0 +1 @@
../../qt5/platforminputcontext/hybridinputcontext.cpp

View File

@@ -0,0 +1 @@
../../qt5/platforminputcontext/hybridinputcontext.h

View File

@@ -0,0 +1 @@
../../qt5/platforminputcontext/main.cpp

View File

@@ -0,0 +1 @@
../../qt5/platforminputcontext/main.h

View File

@@ -0,0 +1 @@
../../qt5/platforminputcontext/qfcitxplatforminputcontext.cpp

View File

@@ -0,0 +1 @@
../../qt5/platforminputcontext/qfcitxplatforminputcontext.h

View File

@@ -0,0 +1 @@
../../qt5/platforminputcontext/qtkey.cpp

View File

@@ -0,0 +1 @@
../../qt5/platforminputcontext/qtkey.h

View File

@@ -0,0 +1,25 @@
find_package(Qt6Concurrent REQUIRED)
set(QUICKPHRASE_EDITOR_SRCS
main.cpp
model.cpp
editor.cpp
editordialog.cpp
batchdialog.cpp
filelistmodel.cpp
)
add_library(fcitx-quickphrase-editor5
MODULE ${QUICKPHRASE_EDITOR_SRCS})
set_target_properties(fcitx-quickphrase-editor5 PROPERTIES
AUTOMOC TRUE AUTOUIC TRUE AUTOUIC_OPTIONS "-tr=fcitx::tr2fcitx;--include=fcitxqti18nhelper.h"
)
target_link_libraries(fcitx-quickphrase-editor5
Fcitx5::Utils
Qt6::Core
Qt6::Gui
Qt6::Concurrent
Fcitx5Qt6::WidgetsAddons
)
install(TARGETS fcitx-quickphrase-editor5 DESTINATION ${CMAKE_INSTALL_LIBDIR}/fcitx5/qt6)

View File

@@ -0,0 +1,24 @@
/*
* SPDX-FileCopyrightText: 2013~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
*/
#include "batchdialog.h"
#include "ui_batchdialog.h"
#include <QIcon>
#include <fcitx-utils/i18n.h>
namespace fcitx {
BatchDialog::BatchDialog(QWidget *parent) : QDialog(parent) {
setupUi(this);
iconLabel->setPixmap(QIcon::fromTheme("dialog-information").pixmap(22, 22));
}
BatchDialog::~BatchDialog() {}
void BatchDialog::setText(const QString &s) { plainTextEdit->setPlainText(s); }
QString BatchDialog::text() const { return plainTextEdit->toPlainText(); }
} // namespace fcitx

View File

@@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2013~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
*/
#ifndef _QUICKPHRASE_EDITOR_BATCHDIALOG_H_
#define _QUICKPHRASE_EDITOR_BATCHDIALOG_H_
#include "ui_batchdialog.h"
#include <QDialog>
namespace fcitx {
class BatchDialog : public QDialog, public Ui::BatchDialog {
Q_OBJECT
public:
explicit BatchDialog(QWidget *parent = 0);
virtual ~BatchDialog();
QString text() const;
void setText(const QString &s);
};
} // namespace fcitx
#endif // _QUICKPHRASE_EDITOR_BATCHDIALOG_H_

View File

@@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>BatchDialog</class>
<widget class="QDialog" name="BatchDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>473</width>
<height>344</height>
</rect>
</property>
<property name="windowTitle">
<string>Batch editing</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPlainTextEdit" name="plainTextEdit"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="iconLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>22</width>
<height>22</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>22</width>
<height>22</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="infoLabel">
<property name="text">
<string>Use &lt;Keyword&gt; &lt;Phrase&gt; format on every line.</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>BatchDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>BatchDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -0,0 +1,286 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
*/
#include "editor.h"
#include "batchdialog.h"
#include "editordialog.h"
#include "filelistmodel.h"
#include "model.h"
#include <QCloseEvent>
#include <QDebug>
#include <QFileDialog>
#include <QInputDialog>
#include <QMenu>
#include <QMessageBox>
#include <QtConcurrentRun>
#include <fcitx-utils/i18n.h>
#include <fcitx-utils/standardpath.h>
namespace fcitx {
ListEditor::ListEditor(QWidget *parent)
: FcitxQtConfigUIWidget(parent), model_(new QuickPhraseModel(this)),
fileListModel_(new FileListModel(this)) {
setupUi(this);
macroTableView->setModel(model_);
fileListComboBox->setModel(fileListModel_);
operationMenu_ = new QMenu(this);
operationMenu_->addAction(_("Add File"), this,
&ListEditor::addFileTriggered);
operationMenu_->addAction(_("Remove File"), this,
&ListEditor::removeFileTriggered);
operationMenu_->addAction(_("Refresh List"), this,
&ListEditor::refreshListTriggered);
operationButton->setMenu(operationMenu_);
loadFileList();
itemFocusChanged();
connect(addButton, &QPushButton::clicked, this, &ListEditor::addWord);
connect(batchEditButton, &QPushButton::clicked, this,
&ListEditor::batchEditWord);
connect(deleteButton, &QPushButton::clicked, this, &ListEditor::deleteWord);
connect(clearButton, &QPushButton::clicked, this,
&ListEditor::deleteAllWord);
connect(importButton, &QPushButton::clicked, this, &ListEditor::importData);
connect(exportButton, &QPushButton::clicked, this, &ListEditor::exportData);
connect(fileListComboBox, qOverload<int>(&QComboBox::activated), this,
&ListEditor::changeFile);
connect(macroTableView->selectionModel(),
&QItemSelectionModel::selectionChanged, this,
&ListEditor::itemFocusChanged);
connect(model_, &QuickPhraseModel::needSaveChanged, this,
&ListEditor::changed);
}
void ListEditor::load() {
lastFile_ = currentFile();
model_->load(currentFile(), false);
}
void ListEditor::load(const QString &file) { model_->load(file, true); }
void ListEditor::save(const QString &file) { model_->save(file); }
void ListEditor::save() {
// QFutureWatcher< bool >* futureWatcher =
// m_model->save("data/QuickPhrase.mb");
QFutureWatcher<bool> *futureWatcher = model_->save(currentFile());
connect(futureWatcher, &QFutureWatcherBase::finished, this,
&ListEditor::saveFinished);
}
bool ListEditor::asyncSave() { return true; }
void ListEditor::changeFile(int) {
if (model_->needSave()) {
int ret = QMessageBox::question(
this, _("Save Changes"),
_("The content has changed.\n"
"Do you want to save the changes or discard them?"),
QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
if (ret == QMessageBox::Save) {
// save(fileListComboBox->itemText(lastFileIndex));
save(lastFile_);
} else if (ret == QMessageBox::Cancel) {
fileListComboBox->setCurrentIndex(
fileListModel_->findFile(lastFile_));
return;
}
}
load();
}
QString ListEditor::title() { return _("Quick Phrase Editor"); }
void ListEditor::itemFocusChanged() {
deleteButton->setEnabled(macroTableView->currentIndex().isValid());
}
void ListEditor::deleteWord() {
if (!macroTableView->currentIndex().isValid())
return;
int row = macroTableView->currentIndex().row();
model_->deleteItem(row);
}
void ListEditor::deleteAllWord() { model_->deleteAllItem(); }
void ListEditor::addWord() {
EditorDialog *dialog = new EditorDialog(this);
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
dialog->open();
connect(dialog, &QDialog::accepted, this, &ListEditor::addWordAccepted);
}
void ListEditor::batchEditWord() {
BatchDialog *dialog = new BatchDialog(this);
QString text;
QTextStream stream(&text);
model_->saveDataToStream(stream);
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
dialog->setText(text);
dialog->open();
connect(dialog, &QDialog::accepted, this, &ListEditor::batchEditAccepted);
}
void ListEditor::addWordAccepted() {
const EditorDialog *dialog =
qobject_cast<const EditorDialog *>(QObject::sender());
model_->addItem(dialog->key(), dialog->value());
QModelIndex last = model_->index(model_->rowCount() - 1, 0);
macroTableView->setCurrentIndex(last);
macroTableView->scrollTo(last);
}
void ListEditor::batchEditAccepted() {
const BatchDialog *dialog =
qobject_cast<const BatchDialog *>(QObject::sender());
QString s = dialog->text();
QTextStream stream(&s);
model_->loadData(stream);
QModelIndex last = model_->index(model_->rowCount() - 1, 0);
macroTableView->setCurrentIndex(last);
macroTableView->scrollTo(last);
}
void ListEditor::importData() {
QFileDialog *dialog = new QFileDialog(this);
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
dialog->setFileMode(QFileDialog::ExistingFile);
dialog->setAcceptMode(QFileDialog::AcceptOpen);
dialog->open();
connect(dialog, &QDialog::accepted, this, &ListEditor::importFileSelected);
}
void ListEditor::exportData() {
QFileDialog *dialog = new QFileDialog(this);
dialog->setAttribute(Qt::WA_DeleteOnClose, true);
dialog->setAcceptMode(QFileDialog::AcceptSave);
dialog->open();
connect(dialog, &QDialog::accepted, this, &ListEditor::exportFileSelected);
}
void ListEditor::importFileSelected() {
const QFileDialog *dialog =
qobject_cast<const QFileDialog *>(QObject::sender());
if (dialog->selectedFiles().length() <= 0)
return;
QString file = dialog->selectedFiles()[0];
load(file);
}
void ListEditor::exportFileSelected() {
const QFileDialog *dialog =
qobject_cast<const QFileDialog *>(QObject::sender());
if (dialog->selectedFiles().length() <= 0)
return;
QString file = dialog->selectedFiles()[0];
save(file);
}
void ListEditor::loadFileList() {
int row = fileListComboBox->currentIndex();
int col = fileListComboBox->modelColumn();
QString lastFileName =
fileListModel_->data(fileListModel_->index(row, col), Qt::UserRole)
.toString();
fileListModel_->loadFileList();
fileListComboBox->setCurrentIndex(fileListModel_->findFile(lastFileName));
load();
}
QString ListEditor::currentFile() {
int row = fileListComboBox->currentIndex();
int col = fileListComboBox->modelColumn();
return fileListModel_->data(fileListModel_->index(row, col), Qt::UserRole)
.toString();
}
QString ListEditor::currentName() {
int row = fileListComboBox->currentIndex();
int col = fileListComboBox->modelColumn();
return fileListModel_
->data(fileListModel_->index(row, col), Qt::DisplayRole)
.toString();
}
void ListEditor::addFileTriggered() {
bool ok;
QString filename = QInputDialog::getText(
this, _("Create new file"), _("Please input a filename for newfile"),
QLineEdit::Normal, "newfile", &ok);
if (filename.contains('/')) {
QMessageBox::warning(this, _("Invalid filename"),
_("File name should not contain '/'."));
return;
}
filename.append(".mb");
if (!StandardPath::global().safeSave(
StandardPath::Type::PkgData,
stringutils::joinPath(QUICK_PHRASE_CONFIG_DIR,
filename.toLocal8Bit().constData()),
[](int) { return true; })) {
QMessageBox::warning(
this, _("File Operation Failed"),
QString(_("Cannot create file %1.")).arg(filename));
return;
}
fileListModel_->loadFileList();
fileListComboBox->setCurrentIndex(fileListModel_->findFile(
filename.prepend(QUICK_PHRASE_CONFIG_DIR "/")));
load();
}
void ListEditor::refreshListTriggered() { loadFileList(); }
void ListEditor::removeFileTriggered() {
QString filename = currentFile();
QString curName = currentName();
auto fullname = stringutils::joinPath(
StandardPath::global().userDirectory(StandardPath::Type::PkgData),
filename.toLocal8Bit().constData());
QFile f(fullname.data());
if (!f.exists()) {
int ret = QMessageBox::question(
this, _("Cannot remove system file"),
QString(_("%1 is a system file, do you want to delete all phrases "
"instead?"))
.arg(curName),
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
if (ret == QMessageBox::Yes) {
deleteAllWord();
}
return;
}
int ret = QMessageBox::question(
this, _("Confirm deletion"),
QString(_("Are you sure to delete %1?")).arg(curName),
QMessageBox::Ok | QMessageBox::Cancel);
if (ret == QMessageBox::Ok) {
bool ok = f.remove();
if (!ok) {
QMessageBox::warning(
this, _("File Operation Failed"),
QString(_("Error while deleting %1.")).arg(curName));
}
}
loadFileList();
load();
}
} // namespace fcitx

View File

@@ -0,0 +1,66 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
*/
#ifndef _QUICKPHRASE_EDITOR_EDITOR_H_
#define _QUICKPHRASE_EDITOR_EDITOR_H_
#include "fcitxqtconfiguiwidget.h"
#include "model.h"
#include "ui_editor.h"
#include <QDir>
#include <QMainWindow>
#include <QMutex>
class QAbstractItemModel;
namespace fcitx {
class FileListModel;
class ListEditor final : public FcitxQtConfigUIWidget, Ui::Editor {
Q_OBJECT
public:
explicit ListEditor(QWidget *parent = 0);
void load() override;
void save() override;
QString title() override;
bool asyncSave() override;
void loadFileList();
public Q_SLOTS:
void batchEditAccepted();
void removeFileTriggered();
void addFileTriggered();
void refreshListTriggered();
void changeFile(int);
private Q_SLOTS:
void addWord();
void batchEditWord();
void deleteWord();
void deleteAllWord();
void itemFocusChanged();
void addWordAccepted();
void importData();
void exportData();
void importFileSelected();
void exportFileSelected();
private:
void load(const QString &file);
void save(const QString &file);
QString currentFile();
QString currentName();
QuickPhraseModel *model_;
FileListModel *fileListModel_;
QMenu *operationMenu_;
QString lastFile_;
};
} // namespace fcitx
#endif // _QUICKPHRASE_EDITOR_EDITOR_H_

View File

@@ -0,0 +1,141 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Editor</class>
<widget class="QWidget" name="Editor">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>358</width>
<height>389</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QComboBox" name="fileListComboBox"/>
</item>
<item>
<widget class="QTableView" name="macroTableView">
<property name="editTriggers">
<set>QAbstractItemView::DoubleClicked</set>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="operationButton">
<property name="text">
<string>&amp;Operation</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="addButton">
<property name="text">
<string>&amp;Add</string>
</property>
<property name="icon">
<iconset theme="list-add">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="batchEditButton">
<property name="text">
<string>&amp;Batch Edit</string>
</property>
<property name="icon">
<iconset theme="document-edit">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="deleteButton">
<property name="text">
<string>&amp;Delete</string>
</property>
<property name="icon">
<iconset theme="list-remove">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clearButton">
<property name="text">
<string>De&amp;lete All</string>
</property>
<property name="icon">
<iconset theme="edit-delete">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="importButton">
<property name="text">
<string>&amp;Import</string>
</property>
<property name="icon">
<iconset theme="document-import">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="exportButton">
<property name="text">
<string>E&amp;xport</string>
</property>
<property name="icon">
<iconset theme="document-export">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,23 @@
/*
* SPDX-FileCopyrightText: 2017~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
*/
#include "editordialog.h"
#include <fcitx-utils/i18n.h>
namespace fcitx {
EditorDialog::EditorDialog(QWidget *parent) : QDialog(parent) { setupUi(this); }
EditorDialog::~EditorDialog() {}
void EditorDialog::setKey(const QString &s) { keyLineEdit->setText(s); }
void EditorDialog::setValue(const QString &s) { valueLineEdit->setText(s); }
QString EditorDialog::key() const { return keyLineEdit->text(); }
QString EditorDialog::value() const { return valueLineEdit->text(); }
} // namespace fcitx

View File

@@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
*/
#ifndef _QUICKPHRASE_EDITOR_EDITORDIALOG_H_
#define _QUICKPHRASE_EDITOR_EDITORDIALOG_H_
#include "ui_editordialog.h"
#include <QDialog>
namespace fcitx {
class EditorDialog : public QDialog, public Ui::EditorDialog {
Q_OBJECT
public:
explicit EditorDialog(QWidget *parent = 0);
virtual ~EditorDialog();
QString key() const;
QString value() const;
void setValue(const QString &s);
void setKey(const QString &s);
};
} // namespace fcitx
#endif // _QUICKPHRASE_EDITOR_EDITORDIALOG_H_

View File

@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>EditorDialog</class>
<widget class="QDialog" name="EditorDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>334</width>
<height>133</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="1">
<widget class="QLineEdit" name="keyLineEdit"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="keyLabel">
<property name="text">
<string notr="true">Keyword:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="valueLineEdit"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="valueLabel">
<property name="text">
<string notr="true">Phrase:</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>keyLineEdit</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>EditorDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>EditorDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -0,0 +1,67 @@
/*
* SPDX-FileCopyrightText: 2013~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
*/
#include "filelistmodel.h"
#include <fcitx-utils/i18n.h>
#include <fcitx-utils/standardpath.h>
#include <fcntl.h>
fcitx::FileListModel::FileListModel(QObject *parent)
: QAbstractListModel(parent) {}
fcitx::FileListModel::~FileListModel() {}
int fcitx::FileListModel::rowCount(const QModelIndex &parent) const {
return parent.isValid() ? 0 : fileList_.size();
}
QVariant fcitx::FileListModel::data(const QModelIndex &index, int role) const {
if (!index.isValid() || index.row() >= fileList_.size())
return QVariant();
switch (role) {
case Qt::DisplayRole:
if (fileList_[index.row()] == QUICK_PHRASE_CONFIG_FILE) {
return _("Default");
} else {
// remove "data/quickphrase.d/"
const size_t length = strlen(QUICK_PHRASE_CONFIG_DIR);
return fileList_[index.row()].mid(length + 1,
fileList_[index.row()].size() -
length - strlen(".mb") - 1);
}
case Qt::UserRole:
return fileList_[index.row()];
default:
break;
}
return QVariant();
}
void fcitx::FileListModel::loadFileList() {
beginResetModel();
fileList_.clear();
fileList_.append(QUICK_PHRASE_CONFIG_FILE);
auto files = StandardPath::global().multiOpen(
StandardPath::Type::PkgData, QUICK_PHRASE_CONFIG_DIR, O_RDONLY,
filter::Suffix(".mb"));
for (auto &file : files) {
fileList_.append(QString::fromLocal8Bit(
stringutils::joinPath(QUICK_PHRASE_CONFIG_DIR, file.first).data()));
}
endResetModel();
}
int fcitx::FileListModel::findFile(const QString &lastFileName) {
int idx = fileList_.indexOf(lastFileName);
if (idx < 0) {
return 0;
}
return idx;
}

View File

@@ -0,0 +1,36 @@
/*
* SPDX-FileCopyrightText: 2017~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
*/
#ifndef _QUICKPHRASE_EDITOR_FILELISTMODEL_H_
#define _QUICKPHRASE_EDITOR_FILELISTMODEL_H_
#include <QAbstractListModel>
#include <QStringList>
#define QUICK_PHRASE_CONFIG_DIR "data/quickphrase.d"
#define QUICK_PHRASE_CONFIG_FILE "data/QuickPhrase.mb"
namespace fcitx {
class FileListModel : public QAbstractListModel {
Q_OBJECT
public:
explicit FileListModel(QObject *parent = 0);
virtual ~FileListModel();
QVariant data(const QModelIndex &index,
int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
void loadFileList();
int findFile(const QString &lastFileName);
private:
QStringList fileList_;
};
} // namespace fcitx
#endif // _QUICKPHRASE_EDITOR_FILELISTMODEL_H_

View File

@@ -0,0 +1,18 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
*/
#include "main.h"
#include "editor.h"
#include "model.h"
QuickPhraseEditorPlugin::QuickPhraseEditorPlugin(QObject *parent)
: fcitx::FcitxQtConfigUIPlugin(parent) {}
fcitx::FcitxQtConfigUIWidget *
QuickPhraseEditorPlugin::create(const QString &key) {
Q_UNUSED(key);
return new fcitx::ListEditor;
}

View File

@@ -0,0 +1,21 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
*/
#ifndef _QUICKPHRASE_EDITOR_MAIN_H_
#define _QUICKPHRASE_EDITOR_MAIN_H_
#include "fcitxqtconfiguiplugin.h"
class QuickPhraseEditorPlugin : public fcitx::FcitxQtConfigUIPlugin {
Q_OBJECT
public:
Q_PLUGIN_METADATA(IID FcitxQtConfigUIFactoryInterface_iid FILE
"quickphrase-editor.json")
explicit QuickPhraseEditorPlugin(QObject *parent = 0);
fcitx::FcitxQtConfigUIWidget *create(const QString &key) override;
};
#endif // _QUICKPHRASE_EDITOR_MAIN_H_

View File

@@ -0,0 +1,293 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
*/
#include "model.h"
#include "editor.h"
#include "filelistmodel.h"
#include <QApplication>
#include <QFile>
#include <QFutureWatcher>
#include <QtConcurrentRun>
#include <fcitx-utils/i18n.h>
#include <fcitx-utils/standardpath.h>
#include <fcitx-utils/utf8.h>
#include <fcntl.h>
namespace fcitx {
namespace {
std::optional<std::pair<std::string, std::string>>
parseLine(const std::string &strBuf) {
auto [start, end] = stringutils::trimInplace(strBuf);
if (start == end) {
return std::nullopt;
}
std::string_view text(strBuf.data() + start, end - start);
if (!utf8::validate(text)) {
return std::nullopt;
}
auto pos = text.find_first_of(FCITX_WHITESPACE);
if (pos == std::string::npos) {
return std::nullopt;
}
auto word = text.find_first_not_of(FCITX_WHITESPACE, pos);
if (word == std::string::npos) {
return std::nullopt;
}
std::string key(text.begin(), text.begin() + pos);
auto wordString =
stringutils::unescapeForValue(std::string_view(text).substr(word));
if (!wordString) {
return std::nullopt;
}
return std::make_pair(key, *wordString);
}
QString escapeValue(const QString &v) {
return QString::fromStdString(stringutils::escapeForValue(v.toStdString()));
}
} // namespace
typedef QPair<QString, QString> ItemType;
QuickPhraseModel::QuickPhraseModel(QObject *parent)
: QAbstractTableModel(parent), needSave_(false), futureWatcher_(0) {}
QuickPhraseModel::~QuickPhraseModel() {}
bool QuickPhraseModel::needSave() { return needSave_; }
QVariant QuickPhraseModel::headerData(int section, Qt::Orientation orientation,
int role) const {
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
if (section == 0)
return _("Keyword");
else if (section == 1)
return _("Phrase");
}
return QVariant();
}
int QuickPhraseModel::rowCount(const QModelIndex &parent) const {
Q_UNUSED(parent);
return list_.count();
}
int QuickPhraseModel::columnCount(const QModelIndex &parent) const {
Q_UNUSED(parent);
return 2;
}
QVariant QuickPhraseModel::data(const QModelIndex &index, int role) const {
do {
if ((role == Qt::DisplayRole || role == Qt::EditRole) &&
index.row() < list_.count()) {
if (index.column() == 0) {
return list_[index.row()].first;
} else if (index.column() == 1) {
return list_[index.row()].second;
}
}
} while (0);
return QVariant();
}
void QuickPhraseModel::addItem(const QString &macro, const QString &word) {
beginInsertRows(QModelIndex(), list_.size(), list_.size());
list_.append(QPair<QString, QString>(macro, word));
endInsertRows();
setNeedSave(true);
}
void QuickPhraseModel::deleteItem(int row) {
if (row >= list_.count())
return;
QPair<QString, QString> item = list_.at(row);
QString key = item.first;
beginRemoveRows(QModelIndex(), row, row);
list_.removeAt(row);
endRemoveRows();
setNeedSave(true);
}
void QuickPhraseModel::deleteAllItem() {
if (list_.count())
setNeedSave(true);
beginResetModel();
list_.clear();
endResetModel();
}
Qt::ItemFlags QuickPhraseModel::flags(const QModelIndex &index) const {
if (!index.isValid())
return {};
return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
bool QuickPhraseModel::setData(const QModelIndex &index, const QVariant &value,
int role) {
if (role != Qt::EditRole)
return false;
if (index.column() == 0) {
list_[index.row()].first = value.toString();
Q_EMIT dataChanged(index, index);
setNeedSave(true);
return true;
} else if (index.column() == 1) {
list_[index.row()].second = value.toString();
Q_EMIT dataChanged(index, index);
setNeedSave(true);
return true;
} else
return false;
}
void QuickPhraseModel::load(const QString &file, bool append) {
if (futureWatcher_) {
return;
}
beginResetModel();
if (!append) {
list_.clear();
setNeedSave(false);
} else
setNeedSave(true);
futureWatcher_ = new QFutureWatcher<QStringPairList>(this);
futureWatcher_->setFuture(
QtConcurrent::run([this, file]() { return parse(file); }));
connect(futureWatcher_, &QFutureWatcherBase::finished, this,
&QuickPhraseModel::loadFinished);
}
QStringPairList QuickPhraseModel::parse(const QString &file) {
QByteArray fileNameArray = file.toLocal8Bit();
QStringPairList list;
do {
auto fp = fcitx::StandardPath::global().open(
fcitx::StandardPath::Type::PkgData, fileNameArray.constData(),
O_RDONLY);
if (fp.fd() < 0)
break;
QFile file;
if (!file.open(fp.fd(), QFile::ReadOnly)) {
break;
}
QByteArray line;
while (!(line = file.readLine()).isNull()) {
auto l = line.toStdString();
auto parsed = parseLine(l);
if (!parsed)
continue;
auto [key, value] = *parsed;
if (key.empty() || value.empty()) {
continue;
}
list_.append(
{QString::fromStdString(key), QString::fromStdString(value)});
}
file.close();
} while (0);
return list;
}
void QuickPhraseModel::loadFinished() {
list_.append(futureWatcher_->future().result());
endResetModel();
futureWatcher_->deleteLater();
futureWatcher_ = 0;
}
QFutureWatcher<bool> *QuickPhraseModel::save(const QString &file) {
auto *futureWatcher = new QFutureWatcher<bool>(this);
futureWatcher->setFuture(QtConcurrent::run(
[this, file, list = list_]() { return saveData(file, list); }));
connect(futureWatcher, &QFutureWatcherBase::finished, this,
&QuickPhraseModel::saveFinished);
return futureWatcher;
}
void QuickPhraseModel::saveDataToStream(QTextStream &dev) {
for (int i = 0; i < list_.size(); i++) {
dev << list_[i].first << "\t" << escapeValue(list_[i].second) << "\n";
}
}
void QuickPhraseModel::loadData(QTextStream &stream) {
beginResetModel();
list_.clear();
setNeedSave(true);
QString s;
while (!(s = stream.readLine()).isNull()) {
auto line = s.toStdString();
auto parsed = parseLine(line);
if (!parsed)
continue;
auto [key, value] = *parsed;
if (key.empty() || value.empty()) {
continue;
}
list_.append(
{QString::fromStdString(key), QString::fromStdString(value)});
}
endResetModel();
}
bool QuickPhraseModel::saveData(const QString &file,
const QStringPairList &list) {
QByteArray filenameArray = file.toLocal8Bit();
fs::makePath(stringutils::joinPath(
StandardPath::global().userDirectory(StandardPath::Type::PkgData),
QUICK_PHRASE_CONFIG_DIR));
return StandardPath::global().safeSave(
StandardPath::Type::PkgData, filenameArray.constData(),
[&list](int fd) {
QFile tempFile;
if (!tempFile.open(fd, QIODevice::WriteOnly)) {
return false;
}
for (int i = 0; i < list.size(); i++) {
tempFile.write(list[i].first.toUtf8());
tempFile.write("\t");
tempFile.write(escapeValue(list[i].second).toUtf8());
tempFile.write("\n");
}
tempFile.close();
return true;
});
}
void QuickPhraseModel::saveFinished() {
QFutureWatcher<bool> *watcher =
static_cast<QFutureWatcher<bool> *>(sender());
QFuture<bool> future = watcher->future();
if (future.result()) {
setNeedSave(false);
}
watcher->deleteLater();
}
void QuickPhraseModel::setNeedSave(bool needSave) {
if (needSave_ != needSave) {
needSave_ = needSave;
Q_EMIT needSaveChanged(needSave_);
}
}
} // namespace fcitx

View File

@@ -0,0 +1,61 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
*/
#ifndef _QUICKPHRASE_EDITOR_MODEL_H_
#define _QUICKPHRASE_EDITOR_MODEL_H_
#include <QAbstractTableModel>
#include <QFutureWatcher>
#include <QSet>
#include <QTextStream>
class QFile;
namespace fcitx {
typedef QList<QPair<QString, QString>> QStringPairList;
class QuickPhraseModel : public QAbstractTableModel {
Q_OBJECT
public:
explicit QuickPhraseModel(QObject *parent = 0);
virtual ~QuickPhraseModel();
Qt::ItemFlags flags(const QModelIndex &index) const override;
bool setData(const QModelIndex &index, const QVariant &value,
int role = Qt::EditRole) override;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index,
int role = Qt::DisplayRole) const override;
void load(const QString &file, bool append);
void loadData(QTextStream &stream);
void addItem(const QString &macro, const QString &word);
void deleteItem(int row);
void deleteAllItem();
QFutureWatcher<bool> *save(const QString &file);
void saveDataToStream(QTextStream &dev);
bool needSave();
Q_SIGNALS:
void needSaveChanged(bool needSave);
private Q_SLOTS:
void loadFinished();
void saveFinished();
private:
QStringPairList parse(const QString &file);
bool saveData(const QString &file, const fcitx::QStringPairList &list);
void setNeedSave(bool needSave);
bool needSave_;
QStringPairList list_;
QFutureWatcher<QStringPairList> *futureWatcher_;
};
} // namespace fcitx
#endif // _QUICKPHRASE_EDITOR_MODEL_H_

View File

@@ -0,0 +1,4 @@
{
"addon": "quickphrase",
"files": ["editor"]
}

View File

@@ -0,0 +1,70 @@
ecm_setup_version(PROJECT VARIABLE_PREFIX FCITX5QT6WIDGETSADDONS
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/fcitx5qt6widgetsaddons_version.h"
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/Fcitx5Qt6WidgetsAddonsConfigVersion.cmake"
SOVERSION 2)
# create a Config.cmake and a ConfigVersion.cmake file and install them
set(CMAKECONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/Fcitx5Qt6WidgetsAddons")
configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/Fcitx5Qt6WidgetsAddonsConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/Fcitx5Qt6WidgetsAddonsConfig.cmake"
INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}
)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/Fcitx5Qt6WidgetsAddonsConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/Fcitx5Qt6WidgetsAddonsConfigVersion.cmake"
DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
COMPONENT Devel )
install(EXPORT Fcitx5Qt6WidgetsAddonsTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE Fcitx5Qt6WidgetsAddonsTargets.cmake NAMESPACE Fcitx5Qt6:: )
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/fcitx5qt6widgetsaddons_version.h
DESTINATION ${Fcitx5Qt6_INCLUDE_INSTALL_DIR} COMPONENT Devel )
set(widgetsaddons_SOURCES
fcitxqtconfiguifactory.cpp
fcitxqtconfiguiplugin.cpp
fcitxqtconfiguiwidget.cpp
fcitxqtkeysequencewidget.cpp
)
set(widgetsaddons_HEADERS
fcitxqtconfiguifactory.h
fcitxqtconfiguiplugin.h
fcitxqtconfiguiwidget.h
fcitxqtkeysequencewidget.h
fcitxqti18nhelper.h
)
set(fcitxqtwidgetsaddons_INCLUDE_DIRS
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
${FCITX54_FCITX5_UTILS_INCLUDE_DIRS}
)
add_library(Fcitx5Qt6WidgetsAddons SHARED ${widgetsaddons_SOURCES})
generate_export_header(Fcitx5Qt6WidgetsAddons BASE_NAME Fcitx5Qt6WidgetsAddons)
add_library(Fcitx5Qt6::WidgetsAddons ALIAS Fcitx5Qt6WidgetsAddons)
target_include_directories(Fcitx5Qt6WidgetsAddons PUBLIC "$<BUILD_INTERFACE:${fcitxqtwidgetsaddons_INCLUDE_DIRS}>")
target_include_directories(Fcitx5Qt6WidgetsAddons INTERFACE "$<INSTALL_INTERFACE:${Fcitx5Qt6_INCLUDE_INSTALL_DIR}/Fcitx5QtWidgetsAddons>")
set_target_properties(Fcitx5Qt6WidgetsAddons
PROPERTIES VERSION ${FCITX5QT6WIDGETSADDONS_VERSION}
AUTOMOC TRUE
SOVERSION ${FCITX5QT6WIDGETSADDONS_SOVERSION}
EXPORT_NAME WidgetsAddons
)
target_link_libraries(Fcitx5Qt6WidgetsAddons
PUBLIC
Fcitx5::Utils
Qt6::Core
Qt6::Widgets
)
install(TARGETS Fcitx5Qt6WidgetsAddons EXPORT Fcitx5Qt6WidgetsAddonsTargets LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}")
install(FILES ${widgetsaddons_HEADERS}
${CMAKE_CURRENT_BINARY_DIR}/fcitx5qt6widgetsaddons_export.h
DESTINATION "${Fcitx5Qt6_INCLUDE_INSTALL_DIR}/Fcitx5QtWidgetsAddons")

View File

@@ -0,0 +1,16 @@
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
find_dependency(Fcitx5Utils)
find_dependency(Qt6Core @REQUIRED_QT6_VERSION@)
find_dependency(Qt6Gui @REQUIRED_QT6_VERSION@)
find_dependency(Qt6Widgets @REQUIRED_QT6_VERSION@)
include("${CMAKE_CURRENT_LIST_DIR}/Fcitx5Qt6WidgetsAddonsTargets.cmake")
if(NOT TARGET Fcitx5Qt6::gui-wrapper)
add_executable(Fcitx5Qt6::gui-wrapper IMPORTED)
set_target_properties(Fcitx5Qt6::gui-wrapper PROPERTIES
IMPORTED_LOCATION "@CMAKE_INSTALL_FULL_LIBEXECDIR@/fcitx5-qt6-gui-wrapper")
endif()

View File

@@ -0,0 +1,109 @@
/*
* SPDX-FileCopyrightText: 2017~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "fcitxqtconfiguifactory.h"
#include "fcitxqtconfiguifactory_p.h"
#include "fcitxqtconfiguiplugin.h"
#include <QDebug>
#include <QDir>
#include <QLibrary>
#include <QPluginLoader>
#include <QStandardPaths>
#include <fcitx-utils/i18n.h>
#include <fcitx-utils/standardpath.h>
namespace fcitx {
namespace {
constexpr char addonConfigPrefix[] = "fcitx://config/addon/";
QString normalizePath(const QString &file) {
auto path = file;
if (path.startsWith(addonConfigPrefix)) {
path.remove(0, sizeof(addonConfigPrefix) - 1);
}
return path;
}
} // namespace
FcitxQtConfigUIFactoryPrivate::FcitxQtConfigUIFactoryPrivate(
FcitxQtConfigUIFactory *factory)
: QObject(factory), q_ptr(factory) {}
FcitxQtConfigUIFactoryPrivate::~FcitxQtConfigUIFactoryPrivate() {}
FcitxQtConfigUIFactory::FcitxQtConfigUIFactory(QObject *parent)
: QObject(parent), d_ptr(new FcitxQtConfigUIFactoryPrivate(this)) {
Q_D(FcitxQtConfigUIFactory);
d->scan();
}
FcitxQtConfigUIFactory::~FcitxQtConfigUIFactory() {}
FcitxQtConfigUIWidget *FcitxQtConfigUIFactory::create(const QString &file) {
Q_D(FcitxQtConfigUIFactory);
auto path = normalizePath(file);
auto loader = d->plugins_.value(path);
if (!loader) {
return nullptr;
}
auto instance =
qobject_cast<FcitxQtConfigUIFactoryInterface *>(loader->instance());
if (!instance) {
return nullptr;
}
return instance->create(path.section('/', 1));
}
bool FcitxQtConfigUIFactory::test(const QString &file) {
Q_D(FcitxQtConfigUIFactory);
auto path = normalizePath(file);
return d->plugins_.contains(path);
}
void FcitxQtConfigUIFactoryPrivate::scan() {
fcitx::StandardPath::global().scanFiles(
fcitx::StandardPath::Type::Addon, "qt6",
[this](const std::string &path, const std::string &dirPath, bool user) {
do {
if (user) {
break;
}
QDir dir(QString::fromLocal8Bit(dirPath.c_str()));
QFileInfo fi(
dir.filePath(QString::fromLocal8Bit(path.c_str())));
QString filePath = fi.filePath(); // file name with path
QString fileName = fi.fileName(); // just file name
if (!QLibrary::isLibrary(filePath)) {
break;
}
QPluginLoader *loader = new QPluginLoader(filePath, this);
if (loader->metaData().value("IID") !=
QLatin1String(FcitxQtConfigUIFactoryInterface_iid)) {
delete loader;
break;
}
auto metadata = loader->metaData().value("MetaData").toObject();
auto files = metadata.value("files").toVariant().toStringList();
auto addon = metadata.value("addon").toVariant().toString();
for (const auto &file : files) {
plugins_[addon + "/" + file] = loader;
}
} while (0);
return true;
});
}
} // namespace fcitx

View File

@@ -0,0 +1,55 @@
/*
* SPDX-FileCopyrightText: 2017~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef _WIDGETSADDONS_FCITXQTCONFIGUIFACTORY_H_
#define _WIDGETSADDONS_FCITXQTCONFIGUIFACTORY_H_
#include <QMap>
#include <QObject>
#include <QStringList>
#include "fcitx5qt6widgetsaddons_export.h"
#include "fcitxqtconfiguiplugin.h"
#include "fcitxqtconfiguiwidget.h"
namespace fcitx {
class FcitxQtConfigUIFactoryPrivate;
/**
* ui plugin factory.
**/
class FCITX5QT6WIDGETSADDONS_EXPORT FcitxQtConfigUIFactory : public QObject {
Q_OBJECT
public:
/**
* create a plugin factory
*
* @param parent object parent
**/
explicit FcitxQtConfigUIFactory(QObject *parent = 0);
virtual ~FcitxQtConfigUIFactory();
/**
* create widget based on file name, it might return 0 if there is no match
*
* @param file file name need to be configured
* @return FcitxQtConfigUIWidget*
**/
FcitxQtConfigUIWidget *create(const QString &file);
/**
* a simplified version of create, but it just test if there is a valid
*entry or not
*
* @param file file name
* @return bool
**/
bool test(const QString &file);
private:
FcitxQtConfigUIFactoryPrivate *d_ptr;
Q_DECLARE_PRIVATE(FcitxQtConfigUIFactory);
};
} // namespace fcitx
#endif // _WIDGETSADDONS_FCITXQTCONFIGUIFACTORY_H_

View File

@@ -0,0 +1,30 @@
/*
* SPDX-FileCopyrightText: 2017~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef _WIDGETSADDONS_FCITXQTCONFIGUIFACTORY_P_H_
#define _WIDGETSADDONS_FCITXQTCONFIGUIFACTORY_P_H_
#include "fcitxqtconfiguifactory.h"
#include <QObject>
#include <QPluginLoader>
#include <qpluginloader.h>
namespace fcitx {
class FcitxQtConfigUIFactoryPrivate : public QObject {
Q_OBJECT
public:
FcitxQtConfigUIFactoryPrivate(FcitxQtConfigUIFactory *conn);
virtual ~FcitxQtConfigUIFactoryPrivate();
FcitxQtConfigUIFactory *const q_ptr;
Q_DECLARE_PUBLIC(FcitxQtConfigUIFactory);
private:
void scan();
QMap<QString, QPluginLoader *> plugins_;
};
} // namespace fcitx
#endif // _WIDGETSADDONS_FCITXQTCONFIGUIFACTORY_P_H_

View File

@@ -0,0 +1,15 @@
/*
* SPDX-FileCopyrightText: 2017~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "fcitxqtconfiguiplugin.h"
namespace fcitx {
FcitxQtConfigUIPlugin::FcitxQtConfigUIPlugin(QObject *parent)
: QObject(parent) {}
FcitxQtConfigUIPlugin::~FcitxQtConfigUIPlugin() {}
} // namespace fcitx

View File

@@ -0,0 +1,54 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef _WIDGETSADDONS_FCITXQTCONFIGUIPLUGIN_H_
#define _WIDGETSADDONS_FCITXQTCONFIGUIPLUGIN_H_
#include "fcitx5qt6widgetsaddons_export.h"
#include <QObject>
#include <QString>
#include <QStringList>
namespace fcitx {
class FcitxQtConfigUIWidget;
/**
* interface for qt config ui
*/
struct FCITX5QT6WIDGETSADDONS_EXPORT FcitxQtConfigUIFactoryInterface {
/**
* create new widget based on key
*
* @see FcitxQtConfigUIPlugin::files
*
* @return plugin name
*/
virtual FcitxQtConfigUIWidget *create(const QString &key) = 0;
};
#define FcitxQtConfigUIFactoryInterface_iid \
"org.fcitx.Fcitx.FcitxQtConfigUIFactoryInterface"
} // namespace fcitx
Q_DECLARE_INTERFACE(fcitx::FcitxQtConfigUIFactoryInterface,
FcitxQtConfigUIFactoryInterface_iid)
namespace fcitx {
/**
* base class for qt config ui
*/
class FCITX5QT6WIDGETSADDONS_EXPORT FcitxQtConfigUIPlugin
: public QObject,
public FcitxQtConfigUIFactoryInterface {
Q_OBJECT
Q_INTERFACES(fcitx::FcitxQtConfigUIFactoryInterface)
public:
explicit FcitxQtConfigUIPlugin(QObject *parent = 0);
virtual ~FcitxQtConfigUIPlugin();
};
} // namespace fcitx
#endif // _WIDGETSADDONS_FCITXQTCONFIGUIPLUGIN_H_

View File

@@ -0,0 +1,17 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "fcitxqtconfiguiwidget.h"
namespace fcitx {
FcitxQtConfigUIWidget::FcitxQtConfigUIWidget(QWidget *parent)
: QWidget(parent) {}
QString FcitxQtConfigUIWidget::icon() { return QLatin1String("fcitx"); }
bool FcitxQtConfigUIWidget::asyncSave() { return false; }
} // namespace fcitx

View File

@@ -0,0 +1,81 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#ifndef _WIDGETSADDONS_FCITXQTCONFIGUIWIDGET_H_
#define _WIDGETSADDONS_FCITXQTCONFIGUIWIDGET_H_
#include "fcitx5qt6widgetsaddons_export.h"
#include <QtWidgets/QWidget>
namespace fcitx {
/**
* embedded gui for custom configuration
**/
class FCITX5QT6WIDGETSADDONS_EXPORT FcitxQtConfigUIWidget : public QWidget {
Q_OBJECT
public:
explicit FcitxQtConfigUIWidget(QWidget *parent = 0);
/**
* load the configuration, usually, this is being called upon a "reset"
*button clicked
* the outer gui will not call it for you for the first time, your
*initialization might
* want to call it by yourself.
*
* @return void
**/
virtual void load() = 0;
/**
* save the configuration
*
* @see asyncSave saveFinished
**/
virtual void save() = 0;
/**
* window title
*
* @return window title
**/
virtual QString title() = 0;
/**
* return the icon name of the window, see QIcon::fromTheme
*
* @return icon name
**/
virtual QString icon();
/**
* return the save function is async or not, default implementation is false
*
* @return bool
**/
virtual bool asyncSave();
Q_SIGNALS:
/**
* the configuration is changed or not, used to indicate parent gui
*
* @param changed is config changed
**/
void changed(bool changed);
/**
* if asyncSave return true, be sure to Q_EMIT this signal on all case
*
* @see asyncSave
**/
void saveFinished();
/// Save config for a specified path.
void saveSubConfig(const QString &path);
};
} // namespace fcitx
#endif // _WIDGETSADDONS_FCITXQTCONFIGUIWIDGET_H_

View File

@@ -0,0 +1,26 @@
/*
* SPDX-FileCopyrightText: 2017~2017 CSSlayer <wengxt@gmail.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
*/
#ifndef _WIDGETSADDONS_FCITXQTI18NHELPER_H_
#define _WIDGETSADDONS_FCITXQTI18NHELPER_H_
#include <QString>
#include <fcitx-utils/i18n.h>
namespace fcitx {
inline QString tr2fcitx(const char *message, const char *comment = nullptr) {
if (comment && comment[0] && message && message[0]) {
return QString(C_(comment, message));
} else if (message && message[0]) {
return QString(_(message));
} else {
return QString();
}
}
} // namespace fcitx
#endif // _WIDGETSADDONS_FCITXQTI18NHELPER_H_

View File

@@ -0,0 +1,555 @@
/*
* SPDX-FileCopyrightText: 2013~2020 CSSlayer <wengxt@gmail.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; see the file COPYING. If not,
* see <http://www.gnu.org/licenses/>.
*/
/* this is forked from kdelibs/kdeui/kkeysequencewidget.cpp */
/*
Original Copyright header
SPDX-FileCopyrightText: 1998 Mark Donohoe <donohoe@kde.org>
SPDX-FileCopyrightText: 2001 Ellis Whitehead <ellis@kde.org>
SPDX-FileCopyrightText: 2007 Andreas Hartmetz <ahartmetz@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "fcitxqtkeysequencewidget.h"
#include "fcitxqtkeysequencewidget_p.h"
#include <QApplication>
#include <QHBoxLayout>
#include <QHash>
#include <QKeyEvent>
#include <QLoggingCategory>
#include <QMessageBox>
#include <QTimer>
#include <QToolButton>
#include <fcitx-utils/i18n.h>
#include <fcitx-utils/key.h>
Q_LOGGING_CATEGORY(fcitx5qtKeysequenceWidget, "fcitx5.qt.keysequencewidget")
namespace fcitx {
namespace {
bool isX11LikePlatform() {
return QGuiApplication::platformName() == "xcb" ||
QGuiApplication::platformName().startsWith("wayland");
}
} // namespace
class FcitxQtKeySequenceWidgetPrivate {
public:
FcitxQtKeySequenceWidgetPrivate(FcitxQtKeySequenceWidget *q);
void init();
static bool isOkWhenModifierless(int keyQt);
void updateShortcutDisplay();
void startRecording();
void controlModifierlessTimout() {
if (keySequence_.size() != 0 && !modifierKeys_) {
// No modifier key pressed currently. Start the timout
modifierlessTimeout_.start(600);
} else {
// A modifier is pressed. Stop the timeout
modifierlessTimeout_.stop();
}
}
void cancelRecording() {
keySequence_ = oldKeySequence_;
doneRecording();
}
// private slot
void doneRecording();
// members
FcitxQtKeySequenceWidget *const q;
QHBoxLayout *layout_ = nullptr;
FcitxQtKeySequenceButton *keyButton_ = nullptr;
QToolButton *clearButton_ = nullptr;
QAction *keyCodeModeAction_ = nullptr;
QList<Key> keySequence_;
QList<Key> oldKeySequence_;
QTimer modifierlessTimeout_;
bool allowModifierless_ = false;
KeyStates modifierKeys_;
unsigned int qtModifierKeys_ = 0;
bool isRecording_ = false;
bool multiKeyShortcutsAllowed_ = false;
bool allowModifierOnly_ = false;
bool modifierAllowed_ = true;
bool keycodeAllowed_ = true;
};
FcitxQtKeySequenceWidgetPrivate::FcitxQtKeySequenceWidgetPrivate(
FcitxQtKeySequenceWidget *q)
: q(q) {}
FcitxQtKeySequenceWidget::FcitxQtKeySequenceWidget(QWidget *parent)
: QWidget(parent), d(new FcitxQtKeySequenceWidgetPrivate(this)) {
d->init();
setFocusProxy(d->keyButton_);
connect(d->keyButton_, &QPushButton::clicked, this,
&FcitxQtKeySequenceWidget::captureKeySequence);
connect(d->clearButton_, &QPushButton::clicked, this,
&FcitxQtKeySequenceWidget::clearKeySequence);
connect(&d->modifierlessTimeout_, &QTimer::timeout, this,
[this]() { d->doneRecording(); });
d->updateShortcutDisplay();
}
void FcitxQtKeySequenceWidgetPrivate::init() {
layout_ = new QHBoxLayout(q);
layout_->setContentsMargins(0, 0, 0, 0);
keyButton_ = new FcitxQtKeySequenceButton(this, q);
keyButton_->setFocusPolicy(Qt::StrongFocus);
keyButton_->setIcon(QIcon::fromTheme("configure"));
layout_->addWidget(keyButton_);
clearButton_ = new QToolButton(q);
layout_->addWidget(clearButton_);
keyCodeModeAction_ = new QAction(_("Key code mode"));
keyCodeModeAction_->setCheckable(true);
keyCodeModeAction_->setEnabled(isX11LikePlatform());
q->setContextMenuPolicy(Qt::ActionsContextMenu);
q->addAction(keyCodeModeAction_);
if (qApp->isLeftToRight())
clearButton_->setIcon(QIcon::fromTheme("edit-clear-locationbar-rtl"));
else
clearButton_->setIcon(QIcon::fromTheme("edit-clear-locationbar-ltr"));
q->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
}
FcitxQtKeySequenceWidget::~FcitxQtKeySequenceWidget() { delete d; }
bool FcitxQtKeySequenceWidget::multiKeyShortcutsAllowed() const {
return d->multiKeyShortcutsAllowed_;
}
void FcitxQtKeySequenceWidget::setMultiKeyShortcutsAllowed(bool allowed) {
d->multiKeyShortcutsAllowed_ = allowed;
}
bool FcitxQtKeySequenceWidget::isModifierAllowed() const {
return d->modifierAllowed_;
}
void FcitxQtKeySequenceWidget::setModifierAllowed(bool allowed) {
d->modifierAllowed_ = allowed;
}
bool FcitxQtKeySequenceWidget::isKeycodeAllowed() const {
return d->keycodeAllowed_;
}
void FcitxQtKeySequenceWidget::setKeycodeAllowed(bool allowed) {
if (d->keycodeAllowed_ == allowed) {
return;
}
d->keycodeAllowed_ = allowed;
if (allowed) {
d->keyCodeModeAction_->setChecked(false);
addAction(d->keyCodeModeAction_);
} else {
removeAction(d->keyCodeModeAction_);
}
}
void FcitxQtKeySequenceWidget::setModifierlessAllowed(bool allow) {
d->allowModifierless_ = allow;
}
bool FcitxQtKeySequenceWidget::isModifierlessAllowed() {
return d->allowModifierless_;
}
bool FcitxQtKeySequenceWidget::isModifierOnlyAllowed() {
return d->allowModifierOnly_;
}
bool FcitxQtKeySequenceWidget::isModifierlessAllowed() const {
return d->allowModifierless_;
}
bool FcitxQtKeySequenceWidget::isModifierOnlyAllowed() const {
return d->allowModifierOnly_;
}
void FcitxQtKeySequenceWidget::setModifierOnlyAllowed(bool allow) {
d->allowModifierOnly_ = allow;
}
void FcitxQtKeySequenceWidget::setClearButtonShown(bool show) {
d->clearButton_->setVisible(show);
}
bool FcitxQtKeySequenceWidget::isClearButtonVisible() const {
return d->clearButton_->isVisible();
}
// slot
void FcitxQtKeySequenceWidget::captureKeySequence() { d->startRecording(); }
const QList<Key> &FcitxQtKeySequenceWidget::keySequence() const {
return d->keySequence_;
}
// slot
void FcitxQtKeySequenceWidget::setKeySequence(const QList<Key> &seq) {
// oldKeySequence holds the key sequence before recording started, if
// setKeySequence()
// is called while not recording then set oldKeySequence to the existing
// sequence so
// that the keySequenceChanged() signal is emitted if the new and previous
// key
// sequences are different
if (!d->isRecording_) {
d->oldKeySequence_ = d->keySequence_;
}
d->keySequence_ = QList<Key>();
for (auto key : seq) {
d->keySequence_ << key;
}
d->doneRecording();
}
// slot
void FcitxQtKeySequenceWidget::clearKeySequence() {
setKeySequence(QList<Key>());
}
void FcitxQtKeySequenceWidgetPrivate::startRecording() {
modifierKeys_ = 0;
oldKeySequence_ = keySequence_;
keySequence_ = QList<Key>();
isRecording_ = true;
keyButton_->grabKeyboard();
if (!QWidget::keyboardGrabber()) {
qWarning() << "Failed to grab the keyboard! Most likely qt's nograb "
"option is active";
}
keyButton_->setDown(true);
updateShortcutDisplay();
}
void FcitxQtKeySequenceWidgetPrivate::doneRecording() {
modifierlessTimeout_.stop();
isRecording_ = false;
keyButton_->releaseKeyboard();
keyButton_->setDown(false);
if (keySequence_ == oldKeySequence_ && !allowModifierOnly_) {
// The sequence hasn't changed
updateShortcutDisplay();
return;
}
Q_EMIT q->keySequenceChanged(keySequence_);
updateShortcutDisplay();
}
void FcitxQtKeySequenceWidgetPrivate::updateShortcutDisplay() {
QString s = QString::fromUtf8(
Key::keyListToString(keySequence_, KeyStringFormat::Localized).c_str());
s.replace('&', QLatin1String("&&"));
if (isRecording_) {
if (modifierKeys_) {
if (!s.isEmpty())
s.append(",");
if (modifierKeys_ & KeyState::Super)
s += "Super+";
if (modifierKeys_ & KeyState::Ctrl)
s += "Control+";
if (modifierKeys_ & KeyState::Alt)
s += "Alt+";
if (modifierKeys_ & KeyState::Shift)
s += "Shift+";
if (modifierKeys_ & KeyState::Hyper)
s += "Hyper+";
} else if (keySequence_.size() == 0) {
s = "...";
}
// make it clear that input is still going on
s.append(" ...");
}
if (s.isEmpty()) {
s = _("Empty");
}
s.prepend(' ');
s.append(' ');
keyButton_->setText(s);
}
FcitxQtKeySequenceButton::~FcitxQtKeySequenceButton() {}
// prevent Qt from special casing Tab and Backtab
bool FcitxQtKeySequenceButton::event(QEvent *e) {
if (d->isRecording_ && e->type() == QEvent::KeyPress) {
keyPressEvent(static_cast<QKeyEvent *>(e));
return true;
}
// The shortcut 'alt+c' ( or any other dialog local action shortcut )
// ended the recording and triggered the action associated with the
// action. In case of 'alt+c' ending the dialog. It seems that those
// ShortcutOverride events get sent even if grabKeyboard() is active.
if (d->isRecording_ && e->type() == QEvent::ShortcutOverride) {
e->accept();
return true;
}
return QPushButton::event(e);
}
void FcitxQtKeySequenceButton::keyPressEvent(QKeyEvent *e) {
int keyQt = e->key();
if (keyQt == -1) {
// Qt sometimes returns garbage keycodes, I observed -1, if it doesn't
// know a key. We cannot do anything useful with those (several keys
// have -1, indistinguishable) and QKeySequence.toString() will also
// yield a garbage string.
QMessageBox::warning(
this, _("The key you just pressed is not supported by Qt."),
_("Unsupported Key"));
return d->cancelRecording();
}
// Same as Key::normalize();
unsigned int newQtModifiers =
e->modifiers() & (Qt::META | Qt::ALT | Qt::CTRL | Qt::SHIFT);
KeyStates newModifiers;
if (isX11LikePlatform()) {
newModifiers = KeyStates(e->nativeModifiers()) &
KeyStates{KeyState::Ctrl_Alt_Shift, KeyState::Hyper,
KeyState::Super};
newModifiers |=
Key::keySymToStates(static_cast<KeySym>(e->nativeVirtualKey()));
} else {
if (newQtModifiers & Qt::META) {
newModifiers |= KeyState::Super;
}
if (newQtModifiers & Qt::ALT) {
newModifiers |= KeyState::Alt;
}
if (newQtModifiers & Qt::CTRL) {
newModifiers |= KeyState::Ctrl;
}
if (newQtModifiers & Qt::SHIFT) {
newModifiers |= KeyState::Shift;
}
}
// don't have the return or space key appear as first key of the sequence
// when they
// were pressed to start editing - catch and them and imitate their effect
if (!d->isRecording_ &&
((keyQt == Qt::Key_Return || keyQt == Qt::Key_Space))) {
d->startRecording();
d->modifierKeys_ = newModifiers;
d->qtModifierKeys_ = newQtModifiers;
d->updateShortcutDisplay();
return;
}
// We get events even if recording isn't active.
if (!d->isRecording_)
return QPushButton::keyPressEvent(e);
e->accept();
d->modifierKeys_ = newModifiers;
d->qtModifierKeys_ = newQtModifiers;
switch (keyQt) {
case Qt::Key_AltGr: // or else we get unicode salad
return;
case Qt::Key_Shift:
case Qt::Key_Control:
case Qt::Key_Alt:
case Qt::Key_Super_L:
case Qt::Key_Super_R:
case Qt::Key_Hyper_L:
case Qt::Key_Hyper_R:
case Qt::Key_Meta:
case Qt::Key_Menu: // unused (yes, but why?)
d->controlModifierlessTimout();
d->updateShortcutDisplay();
break;
default:
// We now have a valid key press.
if (keyQt) {
if ((keyQt == Qt::Key_Backtab) &&
d->modifierKeys_.test(KeyState::Shift)) {
keyQt = Qt::Key_Tab | d->qtModifierKeys_;
} else {
keyQt |= d->qtModifierKeys_;
}
Key key;
if (d->keyCodeModeAction_->isChecked()) {
key = Key::fromKeyCode(e->nativeScanCode(), d->modifierKeys_);
} else {
if (isX11LikePlatform()) {
key = Key(static_cast<KeySym>(e->nativeVirtualKey()),
KeyStates(e->nativeModifiers()))
.normalize();
} else {
qCWarning(fcitx5qtKeysequenceWidget)
<< "Unsupported platform";
}
}
// Check the first key.
if (d->keySequence_.size() == 0) {
if (!d->allowModifierless_ && key.states() == 0) {
return;
}
if (!d->modifierAllowed_ && key.states() != 0) {
return;
}
}
if (key.isValid()) {
d->keySequence_ << key;
}
if ((!d->multiKeyShortcutsAllowed_) ||
(d->keySequence_.size() >= 4)) {
d->doneRecording();
return;
}
d->controlModifierlessTimout();
d->updateShortcutDisplay();
}
}
}
void FcitxQtKeySequenceButton::keyReleaseEvent(QKeyEvent *e) {
if (e->key() == -1) {
// ignore garbage, see keyPressEvent()
return;
}
if (!d->isRecording_)
return QPushButton::keyReleaseEvent(e);
e->accept();
if (!d->multiKeyShortcutsAllowed_ && d->allowModifierOnly_ &&
(e->key() == Qt::Key_Shift || e->key() == Qt::Key_Control ||
e->key() == Qt::Key_Meta || e->key() == Qt::Key_Alt)) {
Key key;
if (isX11LikePlatform()) {
if (d->keyCodeModeAction_->isChecked()) {
key = Key::fromKeyCode(e->nativeScanCode(), key.states());
} else {
key = Key(static_cast<KeySym>(e->nativeVirtualKey()),
KeyStates(e->nativeModifiers()))
.normalize();
}
d->keySequence_ = QList<Key>({key});
}
d->doneRecording();
return;
}
unsigned int newQtModifiers =
e->modifiers() & (Qt::META | Qt::ALT | Qt::CTRL | Qt::SHIFT);
KeyStates newModifiers;
if (isX11LikePlatform()) {
newModifiers = KeyStates(e->nativeModifiers()) &
KeyStates{KeyState::Ctrl_Alt_Shift, KeyState::Hyper,
KeyState::Super};
newModifiers &=
~Key::keySymToStates(static_cast<KeySym>(e->nativeVirtualKey()));
} else {
if (newQtModifiers & Qt::META) {
newModifiers |= KeyState::Super;
}
if (newQtModifiers & Qt::ALT) {
newModifiers |= KeyState::Alt;
}
if (newQtModifiers & Qt::CTRL) {
newModifiers |= KeyState::Ctrl;
}
if (newQtModifiers & Qt::SHIFT) {
newModifiers |= KeyState::Shift;
}
}
// if a modifier that belongs to the shortcut was released...
if ((newModifiers & d->modifierKeys_) < d->modifierKeys_) {
d->modifierKeys_ = newModifiers;
d->controlModifierlessTimout();
d->updateShortcutDisplay();
}
}
// static
bool FcitxQtKeySequenceWidgetPrivate::isOkWhenModifierless(int keyQt) {
// this whole function is a hack, but especially the first line of code
if (QKeySequence(keyQt).toString().length() == 1)
return false;
switch (keyQt) {
case Qt::Key_Return:
case Qt::Key_Space:
case Qt::Key_Tab:
case Qt::Key_Backtab: // does this ever happen?
case Qt::Key_Backspace:
case Qt::Key_Delete:
return false;
default:
return true;
}
}
} // namespace fcitx
#include "moc_fcitxqtkeysequencewidget.cpp"

View File

@@ -0,0 +1,152 @@
/*
* SPDX-FileCopyrightText: 2013~2017 CSSlayer <wengxt@gmail.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; see the file COPYING. If not,
* see <http://www.gnu.org/licenses/>.
*/
#ifndef _WIDGETSADDONS_FCITXQTKEYSEQUENCEWIDGET_H_
#define _WIDGETSADDONS_FCITXQTKEYSEQUENCEWIDGET_H_
/* this is forked from kdelibs/kdeui/kkeysequencewidget.h */
/*
Original Copyright header
This file is part of the KDE libraries
SPDX-FileCopyrightText: 2001, 2002 Ellis Whitehead <ellis@kde.org>
SPDX-FileCopyrightText: 2007 Andreas Hartmetz <ahartmetz@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <QList>
#include <QPushButton>
#include <fcitx-utils/key.h>
#include "fcitx5qt6widgetsaddons_export.h"
namespace fcitx {
class FcitxQtKeySequenceWidgetPrivate;
class FCITX5QT6WIDGETSADDONS_EXPORT FcitxQtKeySequenceWidget : public QWidget {
Q_OBJECT
Q_PROPERTY(bool multiKeyShortcutsAllowed READ multiKeyShortcutsAllowed WRITE
setMultiKeyShortcutsAllowed)
Q_PROPERTY(bool modifierlessAllowed READ isModifierlessAllowed WRITE
setModifierlessAllowed)
Q_PROPERTY(
bool modifierAllowed READ isModifierAllowed WRITE setModifierAllowed)
Q_PROPERTY(
bool keycodeAllowed READ isKeycodeAllowed WRITE setKeycodeAllowed)
Q_PROPERTY(bool modifierOnlyAllowed READ isModifierOnlyAllowed WRITE
setModifierOnlyAllowed)
public:
/**
* Constructor.
*/
explicit FcitxQtKeySequenceWidget(QWidget *parent = 0);
/**
* Destructs the widget.
*/
virtual ~FcitxQtKeySequenceWidget();
/**
* @brief Set whether allow multiple shortcuts.
*
* @param allow
*/
void setMultiKeyShortcutsAllowed(bool allow);
bool multiKeyShortcutsAllowed() const;
/**
* @brief Set whether allow modifier less that produce text, such as just
* key A.
*
* @param allow
*/
void setModifierlessAllowed(bool allow);
// FIXME: remove this
bool isModifierlessAllowed();
bool isModifierlessAllowed() const;
/**
* @brief Set whether allow key that has modifier.
*
* @param allow
* @since 5.0.12
*/
void setModifierAllowed(bool allow);
bool isModifierAllowed() const;
/**
* @brief Set whether allow key to use key code.
*
* @param allow
* @since 5.0.12
*/
void setKeycodeAllowed(bool allow);
bool isKeycodeAllowed() const;
/**
* @brief Set whether allow modifier only key, such as only left control.
*
* @param allow allow modifier only key to be captured.
*/
void setModifierOnlyAllowed(bool allow);
// FIXME: remove this
bool isModifierOnlyAllowed();
bool isModifierOnlyAllowed() const;
void setClearButtonShown(bool show);
bool isClearButtonVisible() const;
const QList<Key> &keySequence() const;
Q_SIGNALS:
void keySequenceChanged(const QList<Key> &seq);
public Q_SLOTS:
void captureKeySequence();
void setKeySequence(const QList<Key> &seq);
void clearKeySequence();
private:
friend class FcitxQtKeySequenceWidgetPrivate;
FcitxQtKeySequenceWidgetPrivate *const d;
Q_DISABLE_COPY(FcitxQtKeySequenceWidget)
};
} // namespace fcitx
#endif // _WIDGETSADDONS_FCITXQTKEYSEQUENCEWIDGET_H_

View File

@@ -0,0 +1,75 @@
/*
* SPDX-FileCopyrightText: 2012~2017 CSSlayer <wengxt@gmail.com>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; see the file COPYING. If not,
* see <http://www.gnu.org/licenses/>.
*/
#ifndef _WIDGETSADDONS_FCITXQTKEYSEQUENCEWIDGET_P_H_
#define _WIDGETSADDONS_FCITXQTKEYSEQUENCEWIDGET_P_H_
/* this is forked from kdelibs/kdeui/kkeysequencewidget_p.h */
/*
Original Copyright header
SPDX-FileCopyrightText: 2001, 2002 Ellis Whitehead <ellis@kde.org>
SPDX-FileCopyrightText: 2007 Andreas Hartmetz <ahartmetz@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <QAction>
#include <QHBoxLayout>
#include <QPushButton>
#include <QToolButton>
namespace fcitx {
class FcitxQtKeySequenceWidgetPrivate;
class FcitxQtKeySequenceButton : public QPushButton {
Q_OBJECT
public:
explicit FcitxQtKeySequenceButton(FcitxQtKeySequenceWidgetPrivate *d,
QWidget *parent)
: QPushButton(parent), d(d) {}
virtual ~FcitxQtKeySequenceButton();
protected:
/**
* Reimplemented for internal reasons.
*/
bool event(QEvent *event) override;
void keyPressEvent(QKeyEvent *event) override;
void keyReleaseEvent(QKeyEvent *event) override;
private:
FcitxQtKeySequenceWidgetPrivate *const d;
};
} // namespace fcitx
#endif // _WIDGETSADDONS_FCITXQTKEYSEQUENCEWIDGET_P_H_