diff options
Diffstat (limited to 'src')
35 files changed, 874 insertions, 107 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 8098b2a..a241bea 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -80,6 +80,7 @@ ibus_engine_libpinyin_h_sources = \ PYPSuggestionCandidates.h \ PYPEmojiTable.h \ PYPEmojiCandidates.h \ + PYXMLUtil.h \ $(NULL) ibus_engine_libpinyin_c_sources += \ @@ -97,6 +98,7 @@ ibus_engine_libpinyin_c_sources += \ PYPSuggestionEditor.cc \ PYPSuggestionCandidates.cc \ PYPEmojiCandidates.cc \ + PYXMLUtil.cc \ $(NULL) @@ -204,17 +206,28 @@ ibus_engine_libpinyin_LDADD += \ endif if IBUS_BUILD_ENGLISH_INPUT_MODE - ibus_engine_libpinyin_CXXFLAGS += \ +ibus_engine_libpinyin_CXXFLAGS += \ -DIBUS_BUILD_ENGLISH_INPUT_MODE \ $(NULL) endif if IBUS_BUILD_TABLE_INPUT_MODE - ibus_engine_libpinyin_CXXFLAGS += \ +ibus_engine_libpinyin_CXXFLAGS += \ -DIBUS_BUILD_TABLE_INPUT_MODE \ $(NULL) endif +if ENABLE_LIBNOTIFY +ibus_engine_libpinyin_CXXFLAGS += \ + @LIBNOTIFY_CFLAGS@ \ + -DENABLE_LIBNOTIFY \ + $(NULL) + +ibus_engine_libpinyin_LDADD += \ + @LIBNOTIFY_LIBS@ \ + $(NULL) +endif + BUILT_SOURCES = \ $(ibus_engine_built_c_sources) \ $(ibus_engine_built_h_sources) \ @@ -225,12 +238,19 @@ component_DATA = \ $(NULL) componentdir = @datadir@/ibus/component +engine_DATA = \ + default.xml \ + $(NULL) +enginedir = ${pkgdatadir} + EXTRA_DIST = \ - libpinyin.xml.in \ + libpinyin.inputmethod.xml.in \ + default.inputmethod.xml.in \ $(NULL) CLEANFILES = \ libpinyin.xml \ + default.xml \ $(NULL) PYPunctTable.h: @@ -248,14 +268,10 @@ update-simptrad-table: $(MAKE) -C $(top_srcdir)/scripts ZhConversion.py $(MAKE) PYSimpTradConverterTable.h -libpinyin.xml: libpinyin.xml.in - $(AM_V_GEN) \ - ( \ - libexecdir=${libexecdir}; \ - pkgdatadir=${pkgdatadir}; \ - s=`cat $<`; \ - eval "echo \"$${s}\""; \ - ) > $@ +%.xml: %.inputmethod.xml.in + sed -e "s|\@LIBEXECDIR\@|$(libexecdir)|g" \ + -e "s|\@PKGDATADIR\@|$(pkgdatadir)|g" \ + $< > $@ test: ibus-engine-libpinyin $(ENV) \ diff --git a/src/PYConfig.cc b/src/PYConfig.cc index 1ba6704..e5f93b1 100644 --- a/src/PYConfig.cc +++ b/src/PYConfig.cc @@ -48,6 +48,7 @@ Config::initDefaultValues (void) m_shift_select_candidate = FALSE; m_minus_equal_page = TRUE; m_comma_period_page = FALSE; + m_square_bracket_page = FALSE; m_auto_commit = FALSE; m_double_pinyin = FALSE; @@ -79,6 +80,9 @@ Config::initDefaultValues (void) m_english_candidate = TRUE; m_suggestion_candidate = FALSE; + m_export_user_phrase = TRUE; + m_export_bigram_phrase = TRUE; + m_network_dictionary_start_timestamp = 0; m_network_dictionary_end_timestamp = 0; diff --git a/src/PYConfig.h b/src/PYConfig.h index 4929e7a..e04fd2d 100644 --- a/src/PYConfig.h +++ b/src/PYConfig.h @@ -62,6 +62,7 @@ public: gboolean shiftSelectCandidate (void) const { return m_shift_select_candidate; } gboolean minusEqualPage (void) const { return m_minus_equal_page; } gboolean commaPeriodPage (void) const { return m_comma_period_page; } + gboolean squareBracketPage (void) const { return m_square_bracket_page; } gboolean autoCommit (void) const { return m_auto_commit; } gboolean doublePinyin (void) const { return m_double_pinyin; } DoublePinyinScheme doublePinyinSchema (void) const { return m_double_pinyin_schema; } @@ -84,6 +85,9 @@ public: gboolean englishCandidate (void) const { return m_english_candidate; } gboolean suggestionCandidate (void) const { return m_suggestion_candidate; } + gboolean exportUserPhrase (void) const { return m_export_user_phrase; } + gboolean exportBigramPhrase (void) const { return m_export_bigram_phrase; } + std::string mainSwitch (void) const { return m_main_switch; } std::string letterSwitch (void) const { return m_letter_switch; } std::string punctSwitch (void) const { return m_punct_switch; } @@ -98,6 +102,9 @@ public: public: /* write option */ + virtual gboolean luaConverter (std::string converter) + { return FALSE; } + virtual gboolean networkDictionaryStartTimestamp (gint64 timestamp) { return FALSE; } virtual gboolean networkDictionaryEndTimestamp (gint64 timestamp) @@ -149,6 +156,7 @@ protected: gboolean m_shift_select_candidate; gboolean m_minus_equal_page; gboolean m_comma_period_page; + gboolean m_square_bracket_page; gboolean m_auto_commit; gboolean m_double_pinyin; @@ -176,6 +184,9 @@ protected: gboolean m_english_candidate; gboolean m_suggestion_candidate; + gboolean m_export_user_phrase; + gboolean m_export_bigram_phrase; + std::string m_main_switch; std::string m_letter_switch; std::string m_punct_switch; diff --git a/src/PYEnglishDatabase.cc b/src/PYEnglishDatabase.cc index c027a51..b68b407 100644 --- a/src/PYEnglishDatabase.cc +++ b/src/PYEnglishDatabase.cc @@ -45,6 +45,8 @@ EnglishDatabase::init () (PKGDATADIR G_DIR_SEPARATOR_S "db" G_DIR_SEPARATOR_S "english.db", path); if (!result) g_warning ("can't open English word list database.\n"); + + g_free (path); } @@ -52,7 +54,7 @@ EnglishDatabase::init () EnglishDatabase::EnglishDatabase(){ m_sqlite = NULL; m_sql = ""; - m_user_db = ""; + m_user_db = NULL; m_timeout_id = 0; m_timer = g_timer_new (); } @@ -69,6 +71,7 @@ EnglishDatabase::~EnglishDatabase(){ m_sqlite = NULL; } m_sql = ""; + g_free (m_user_db); m_user_db = NULL; } @@ -164,7 +167,7 @@ EnglishDatabase::openDatabase(const char *system_db, const char *user_db){ return FALSE; } /* cache the user db name. */ - m_user_db = user_db; + m_user_db = g_strdup (user_db); /* do database attach here. :) */ if (sqlite3_open_v2 (system_db, &m_sqlite, diff --git a/src/PYEnglishDatabase.h b/src/PYEnglishDatabase.h index 002a474..ca1407c 100644 --- a/src/PYEnglishDatabase.h +++ b/src/PYEnglishDatabase.h @@ -59,7 +59,7 @@ private: private: sqlite3 *m_sqlite; String m_sql; - const char *m_user_db; + gchar *m_user_db; guint m_timeout_id; GTimer *m_timer; diff --git a/src/PYEnglishEditor.cc b/src/PYEnglishEditor.cc index 7e6e52b..9b9aaac 100644 --- a/src/PYEnglishEditor.cc +++ b/src/PYEnglishEditor.cc @@ -97,6 +97,12 @@ EnglishEditor::processKeyEvent (guint keyval, guint keycode, guint modifiers) m_text.insert (m_cursor, keyval); m_cursor ++; } + + if (!m_config.squareBracketPage () && + (IBUS_bracketleft == keyval || IBUS_bracketright == keyval)) { + m_text.insert (m_cursor, keyval); + m_cursor ++; + } } /* Deal other staff with updateStateFromInput (). */ @@ -140,6 +146,12 @@ EnglishEditor::processPageKey (guint keyval) return TRUE; } break; + case IBUS_bracketleft: + if (m_config.squareBracketPage ()) { + pageUp (); + return TRUE; + } + break; case IBUS_period: if (m_config.commaPeriodPage ()) { pageDown (); @@ -152,6 +164,13 @@ EnglishEditor::processPageKey (guint keyval) return TRUE; } break; + case IBUS_bracketright: + if (m_config.squareBracketPage ()) { + pageDown (); + return TRUE; + } + break; + case IBUS_Up: case IBUS_KP_Up: cursorUp (); diff --git a/src/PYEnglishEditor.h b/src/PYEnglishEditor.h index 780c8c7..8f00ed2 100644 --- a/src/PYEnglishEditor.h +++ b/src/PYEnglishEditor.h @@ -29,7 +29,7 @@ namespace PY { class EnglishDatabase; -static const std::string EnglishSymbols = "`~!@*()+[]{}\\|:\"/<>?"; +static const std::string EnglishSymbols = "`~!@*()+{}\\|:\"/<>?"; class EnglishEditor : public Editor { private: diff --git a/src/PYExtEditor.cc b/src/PYExtEditor.cc index 44aecf0..6630b2c 100644 --- a/src/PYExtEditor.cc +++ b/src/PYExtEditor.cc @@ -271,6 +271,14 @@ ExtEditor::processPageKey (guint keyval) return TRUE; } break; +#endif + case IBUS_bracketleft: + if (m_config.squareBracketPage ()) { + pageUp (); + return TRUE; + } + break; +#if 0 //For "2.5" input. case IBUS_period: if (m_config.commaPeriodPage ()) { @@ -285,6 +293,13 @@ ExtEditor::processPageKey (guint keyval) return TRUE; } break; + case IBUS_bracketright: + if (m_config.squareBracketPage ()) { + pageDown (); + return TRUE; + } + break; + case IBUS_Up: case IBUS_KP_Up: cursorUp (); diff --git a/src/PYLibPinyin.cc b/src/PYLibPinyin.cc index 0a60612..d4f47c0 100644 --- a/src/PYLibPinyin.cc +++ b/src/PYLibPinyin.cc @@ -277,20 +277,13 @@ LibPinyinBackEnd::importPinyinDictionary (const char *filename) } gboolean -LibPinyinBackEnd::exportPinyinDictionary (const char *filename) +LibPinyinBackEnd::exportUserPhrase (FILE *dictfile) { - /* user phrase library should be already loaded here. */ - FILE * dictfile = fopen (filename, "w"); - if (NULL == dictfile) - return FALSE; - export_iterator_t * iter = pinyin_begin_get_phrases (m_pinyin_context, USER_DICTIONARY); - if (NULL == iter) { - fclose(dictfile); + if (NULL == iter) return FALSE; - } /* use " " as the separator. */ while (pinyin_iterator_has_next_phrase (iter)) { @@ -308,6 +301,54 @@ LibPinyinBackEnd::exportPinyinDictionary (const char *filename) } pinyin_end_get_phrases(iter); + return TRUE; +} + +gboolean +LibPinyinBackEnd::exportBigramPhrase (FILE *dictfile) +{ + bigram_export_iterator_t * iter = pinyin_begin_get_bigram_phrases + (m_pinyin_context); + + if (NULL == iter) + return FALSE; + + /* use " " as the separator. */ + while (pinyin_bigram_iterator_has_next_phrase (iter)) { + gchar * phrase = NULL; gchar * pinyin = NULL; + gint count = -1; + + check_result (pinyin_bigram_iterator_get_next_phrase (iter, &phrase, &pinyin, &count)); + + if (-1 == count) /* skip output the default count. */ + fprintf (dictfile, "%s %s\n", phrase, pinyin); + else /* output the count. */ + fprintf (dictfile, "%s %s %d\n", phrase, pinyin, count); + + g_free (phrase); g_free (pinyin); + } + + pinyin_end_get_bigram_phrases(iter); + return TRUE; +} + +gboolean +LibPinyinBackEnd::exportPinyinDictionary (const char *filename) +{ + if (NULL == m_pinyin_context) + return FALSE; + + /* user phrase library should be already loaded here. */ + FILE * dictfile = fopen (filename, "w"); + if (NULL == dictfile) + return FALSE; + + if (PinyinConfig::instance ().exportUserPhrase ()) + exportUserPhrase (dictfile); + + if (PinyinConfig::instance ().exportBigramPhrase ()) + exportBigramPhrase (dictfile); + fclose (dictfile); return TRUE; } diff --git a/src/PYLibPinyin.h b/src/PYLibPinyin.h index e623f27..f8e0866 100644 --- a/src/PYLibPinyin.h +++ b/src/PYLibPinyin.h @@ -24,6 +24,7 @@ #include <memory> #include <time.h> #include <glib.h> +#include <stdio.h> typedef struct _pinyin_context_t pinyin_context_t; typedef struct _pinyin_instance_t pinyin_instance_t; @@ -50,6 +51,9 @@ public: void freeChewingInstance (pinyin_instance_t *instance); void modified (void); + gboolean exportUserPhrase (FILE *dictfile); + gboolean exportBigramPhrase (FILE *dictfile); + gboolean importPinyinDictionary (const char *filename); gboolean exportPinyinDictionary (const char *filename); gboolean clearPinyinUserData (const char *target); diff --git a/src/PYMain.cc b/src/PYMain.cc index a1c3040..7568e53 100644 --- a/src/PYMain.cc +++ b/src/PYMain.cc @@ -37,6 +37,10 @@ #ifdef IBUS_BUILD_TABLE_INPUT_MODE #include "PYTableDatabase.h" #endif +#include "PYXMLUtil.h" +#ifdef ENABLE_LIBNOTIFY +#include <libnotify/notify.h> +#endif using namespace PY; @@ -46,6 +50,7 @@ static Pointer<IBusFactory> factory; /* options */ static gboolean ibus = FALSE; +static gboolean xml = FALSE; static gboolean verbose = FALSE; static void @@ -60,6 +65,7 @@ static const GOptionEntry entries[] = { "version", 'V', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) show_version_and_quit, "Show the application's version.", NULL }, { "ibus", 'i', 0, G_OPTION_ARG_NONE, &ibus, "component is executed by ibus", NULL }, + { "xml", 'x', 0, G_OPTION_ARG_NONE, &xml, "list engines", NULL }, { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "verbose", NULL }, { NULL }, }; @@ -162,6 +168,10 @@ sigterm_cb (int sig) { LibPinyinBackEnd::finalize (); +#ifdef ENABLE_LIBNOTIFY + notify_uninit(); +#endif + ::exit (EXIT_FAILURE); } @@ -169,6 +179,69 @@ static void atexit_cb (void) { LibPinyinBackEnd::finalize (); + +#ifdef ENABLE_LIBNOTIFY + notify_uninit(); +#endif +} + +static void +print_engine_xml (void) +{ + gboolean success = FALSE; + gchar * content = NULL; + + /* check the user engines.xml first. */ + gchar * user_config = g_build_filename (g_get_user_config_dir (), + "ibus", "libpinyin", "engines.xml", NULL); + gchar * system_config = g_build_filename (PKGDATADIR, "default.xml", NULL); + + /* if not, print the default.xml and exit. */ + if (!g_file_test (user_config, G_FILE_TEST_IS_REGULAR)) { + if (!g_file_test (system_config, G_FILE_TEST_IS_REGULAR)) { + g_free (system_config); + g_free (user_config); + return; + } + content = load_file_content (system_config); + printf ("%s", content); + g_free (content); + g_free (system_config); + g_free (user_config); + + return; + } + + /* if the engines.xml exists, compare the version of two xml files. */ + gchar * system_version = NULL; + success = parse_engine_version (system_config, &system_version); + gchar * user_version = NULL; + success = success && parse_engine_version (user_config, &user_version); + success = success && 0 == g_strcmp0 (system_version, user_version); + g_free (system_version); + g_free (user_version); + if (success) { + content = load_file_content (user_config); + printf ("%s", content); + g_free (content); + g_free (system_config); + g_free (user_config); + return; + } + + /* if the version mis-match, create the new engines.xml by ibus-setup-libpinyin. */ + g_spawn_command_line_sync (LIBEXECDIR"/ibus-setup-libpinyin resync-engine", + NULL, NULL, NULL, NULL); + + /* print the user engines.xml. */ + if (g_file_test (user_config, G_FILE_TEST_IS_REGULAR)) { + content = load_file_content (user_config); + printf ("%s", content); + g_free (content); + g_free (system_config); + g_free (user_config); + return; + } } int @@ -192,10 +265,23 @@ main (gint argc, gchar **argv) exit (-1); } + if (xml) { + print_engine_xml (); + return 0; + } + ::signal (SIGTERM, sigterm_cb); ::signal (SIGINT, sigterm_cb); atexit (atexit_cb); +#ifdef ENABLE_LIBNOTIFY + if (!notify_init("ibus-libpinyin")) { + g_error("notify_init failed"); + exit(1); + } +#endif + start_component (); + return 0; } diff --git a/src/PYPBopomofoEditor.cc b/src/PYPBopomofoEditor.cc index 1e03b12..b91b594 100644 --- a/src/PYPBopomofoEditor.cc +++ b/src/PYPBopomofoEditor.cc @@ -73,6 +73,8 @@ BopomofoEditor::insert (gint ch) return TRUE; m_text.insert (m_cursor++, ch); + m_lookup_cursor = 0; + updatePinyin (); update (); diff --git a/src/PYPCloudCandidates.cc b/src/PYPCloudCandidates.cc index f553ff9..3e2ef4c 100644 --- a/src/PYPCloudCandidates.cc +++ b/src/PYPCloudCandidates.cc @@ -496,6 +496,15 @@ CloudCandidates::selectCandidate (EnhancedCandidate & enhanced) } void +releaseUserData (gpointer user_data) +{ + CloudAsyncRequestUserData *data = static_cast<CloudAsyncRequestUserData *> (user_data); + if (data->event_id != 0) { + g_free (user_data); + } +} + +void CloudCandidates::delayedCloudAsyncRequest (const gchar* pinyin) { gpointer user_data; @@ -514,9 +523,11 @@ CloudCandidates::delayedCloudAsyncRequest (const gchar* pinyin) data->cloud_candidates = this; /* record the latest timer */ - m_source_event_id = g_timeout_add (m_editor->m_config.cloudRequestDelayTime (), - delayedCloudAsyncRequestCallBack, - user_data); + m_source_event_id = g_timeout_add_full (G_PRIORITY_DEFAULT, + m_editor->m_config.cloudRequestDelayTime (), + delayedCloudAsyncRequestCallBack, + user_data, + releaseUserData); data->event_id = m_source_event_id; data->message = NULL; data->cancel_message = NULL; @@ -537,6 +548,7 @@ CloudCandidates::delayedCloudAsyncRequestCallBack (gpointer user_data) /* only send with a latest timer */ if (data->event_id == cloud_candidates->m_source_event_id) { + data->event_id = 0; cloud_candidates->m_source_event_id = 0; cloud_candidates->cloudAsyncRequest (user_data); } @@ -564,7 +576,7 @@ CloudCandidates::cloudAsyncRequest (gpointer user_data) m_cancel_message = g_cancellable_new (); data->cancel_message = m_cancel_message; - SoupMessage *m_message = soup_message_new ("GET", query_request); + m_message = soup_message_new ("GET", query_request); soup_session_send_async (m_session, m_message, SOUP_MESSAGE_PRIORITY_NORMAL, m_cancel_message, cloudResponseCallBack, user_data); data->message = m_message; @@ -576,23 +588,34 @@ CloudCandidates::cloudAsyncRequest (gpointer user_data) void CloudCandidates::cloudResponseCallBack (GObject *source_object, GAsyncResult *result, gpointer user_data) { - GInputStream *stream = soup_session_send_finish (SOUP_SESSION (source_object), result, NULL); + GError *error = NULL; + GInputStream *stream = soup_session_send_finish (SOUP_SESSION (source_object), result, &error); CloudAsyncRequestUserData *data = static_cast<CloudAsyncRequestUserData *> (user_data); CloudCandidates *cloud_candidates = data->cloud_candidates; - /* process results */ - cloud_candidates->processCloudResponse (stream, cloud_candidates->m_editor->m_candidates, data->requested_pinyin); + if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + /* process results */ + cloud_candidates->processCloudResponse (stream, cloud_candidates->m_editor->m_candidates, data->requested_pinyin); + + cloud_candidates->updateLookupTable (); - cloud_candidates->updateLookupTable (); + /* reset m_message pointer only when it is not replaced with a new m_message */ + cloud_candidates->m_message = NULL; + cloud_candidates->m_cancel_message = NULL; + } + + if (error) { + g_error_free (error); + } else { + g_object_unref (stream); + } /* clean up message */ g_object_unref (data->message); - cloud_candidates->m_message = NULL; /* clean up cancellable */ g_object_unref (data->cancel_message); - cloud_candidates->m_cancel_message = NULL; g_free (user_data); } diff --git a/src/PYPConfig.cc b/src/PYPConfig.cc index 06b3ff8..f472ea9 100644 --- a/src/PYPConfig.cc +++ b/src/PYPConfig.cc @@ -20,8 +20,10 @@ #include "PYPConfig.h" #include <string.h> +#include <libintl.h> #include <pinyin.h> #include "PYBus.h" +#include "PYXMLUtil.h" #include "PYLibPinyin.h" #include "PYTableDatabase.h" @@ -29,6 +31,9 @@ namespace PY { +#define _(text) (dgettext (GETTEXT_PACKAGE, text)) +#define N_(text) text + const gchar * const CONFIG_CORRECT_PINYIN = "correct-pinyin"; const gchar * const CONFIG_FUZZY_PINYIN = "fuzzy-pinyin"; const gchar * const CONFIG_ORIENTATION = "lookup-table-orientation"; @@ -39,6 +44,7 @@ const gchar * const CONFIG_SORT_OPTION = "sort-candidate-option"; const gchar * const CONFIG_SHIFT_SELECT_CANDIDATE = "shift-select-candidate"; const gchar * const CONFIG_MINUS_EQUAL_PAGE = "minus-equal-page"; const gchar * const CONFIG_COMMA_PERIOD_PAGE = "comma-period-page"; +const gchar * const CONFIG_SQUARE_BRACKET_PAGE = "square-bracket-page"; const gchar * const CONFIG_AUTO_COMMIT = "auto-commit"; const gchar * const CONFIG_DOUBLE_PINYIN = "double-pinyin"; const gchar * const CONFIG_DOUBLE_PINYIN_SCHEMA = "double-pinyin-schema"; @@ -63,6 +69,8 @@ const gchar * const CONFIG_USE_CUSTOM_TABLE = "use-custom-table"; const gchar * const CONFIG_EMOJI_CANDIDATE = "emoji-candidate"; const gchar * const CONFIG_ENGLISH_CANDIDATE = "english-candidate"; const gchar * const CONFIG_SUGGESTION_CANDIDATE = "suggestion-candidate"; +const gchar * const CONFIG_EXPORT_USER_PHRASE = "export-user-phrase"; +const gchar * const CONFIG_EXPORT_BIGRAM_PHRASE = "export-bigram-phrase"; const gchar * const CONFIG_IMPORT_CUSTOM_TABLE = "import-custom-table"; const gchar * const CONFIG_EXPORT_CUSTOM_TABLE = "export-custom-table"; const gchar * const CONFIG_CLEAR_CUSTOM_TABLE = "clear-custom-table"; @@ -109,6 +117,14 @@ LibPinyinConfig::~LibPinyinConfig (void) } gboolean +LibPinyinConfig::luaConverter (std::string converter) +{ + m_lua_converter = converter; + return write (CONFIG_LUA_CONVERTER, converter.c_str ()); +} + + +gboolean LibPinyinConfig::networkDictionaryStartTimestamp (gint64 timestamp) { m_network_dictionary_start_timestamp = timestamp; @@ -138,6 +154,9 @@ LibPinyinConfig::initDefaultValues (void) m_english_candidate = TRUE; m_suggestion_candidate = FALSE; + m_export_user_phrase = TRUE; + m_export_bigram_phrase = TRUE; + m_shift_select_candidate = FALSE; m_minus_equal_page = TRUE; m_comma_period_page = FALSE; @@ -576,6 +595,7 @@ PinyinConfig::readDefaultValues (void) m_shift_select_candidate = read (CONFIG_SHIFT_SELECT_CANDIDATE, false); m_minus_equal_page = read (CONFIG_MINUS_EQUAL_PAGE, true); m_comma_period_page = read (CONFIG_COMMA_PERIOD_PAGE, false); + m_square_bracket_page = read (CONFIG_SQUARE_BRACKET_PAGE, false); m_auto_commit = read (CONFIG_AUTO_COMMIT, false); m_lua_extension = read (CONFIG_LUA_EXTENSION, true); @@ -583,6 +603,10 @@ PinyinConfig::readDefaultValues (void) m_table_input_mode = read (CONFIG_TABLE_INPUT_MODE, true); m_use_custom_table = read (CONFIG_USE_CUSTOM_TABLE, false); + /* export phrases */ + m_export_user_phrase = read (CONFIG_EXPORT_USER_PHRASE, true); + m_export_bigram_phrase = read (CONFIG_EXPORT_BIGRAM_PHRASE, true); + /* lua */ m_lua_converter = read (CONFIG_LUA_CONVERTER, ""); @@ -646,6 +670,8 @@ PinyinConfig::valueChanged (const std::string &schema_id, m_minus_equal_page = normalizeGVariant (value, true); else if (CONFIG_COMMA_PERIOD_PAGE == name) m_comma_period_page = normalizeGVariant (value, false); + else if (CONFIG_SQUARE_BRACKET_PAGE == name) + m_square_bracket_page = normalizeGVariant (value, false); else if (CONFIG_LUA_CONVERTER == name) m_lua_converter = normalizeGVariant (value, std::string ("")); else if (CONFIG_AUTO_COMMIT == name) @@ -658,15 +684,23 @@ PinyinConfig::valueChanged (const std::string &schema_id, m_table_input_mode = normalizeGVariant (value, true); else if (CONFIG_USE_CUSTOM_TABLE == name) m_use_custom_table = normalizeGVariant (value, false); + else if (CONFIG_EXPORT_USER_PHRASE == name) + m_export_user_phrase = normalizeGVariant (value, true); + else if (CONFIG_EXPORT_BIGRAM_PHRASE == name) + m_export_bigram_phrase = normalizeGVariant (value, true); else if (CONFIG_IMPORT_CUSTOM_TABLE == name) { std::string filename = normalizeGVariant (value, std::string("")); - if (!filename.empty ()) + if (!filename.empty ()) { TableDatabase::userInstance ().importTable (filename.c_str ()); + show_message (_("The table file is imported."), NULL); + } } else if (CONFIG_EXPORT_CUSTOM_TABLE == name) { std::string filename = normalizeGVariant (value, std::string("")); - if (!filename.empty ()) + if (!filename.empty ()) { TableDatabase::userInstance ().exportTable (filename.c_str ()); + show_message (_("The table file is exported."), NULL); + } } else if (CONFIG_CLEAR_CUSTOM_TABLE == name) { std::string target = normalizeGVariant (value, std::string("")); @@ -675,13 +709,17 @@ PinyinConfig::valueChanged (const std::string &schema_id, } else if (CONFIG_IMPORT_DICTIONARY == name) { std::string filename = normalizeGVariant (value, std::string("")); - if (!filename.empty ()) + if (!filename.empty ()) { LibPinyinBackEnd::instance ().importPinyinDictionary (filename.c_str ()); + show_message (_("The pinyin dictionary file is imported."), NULL); + } } else if (CONFIG_EXPORT_DICTIONARY == name) { std::string filename = normalizeGVariant (value, std::string("")); - if (!filename.empty ()) + if (!filename.empty ()) { LibPinyinBackEnd::instance ().exportPinyinDictionary (filename.c_str ()); + show_message (_("The pinyin dictionary file is exported."), NULL); + } } else if (CONFIG_CLEAR_USER_DATA == name) { std::string target = normalizeGVariant (value, std::string("")); diff --git a/src/PYPConfig.h b/src/PYPConfig.h index b08fd5a..b1a2dfd 100644 --- a/src/PYPConfig.h +++ b/src/PYPConfig.h @@ -39,6 +39,7 @@ protected: virtual ~LibPinyinConfig (void); public: + virtual gboolean luaConverter (std::string converter); virtual gboolean networkDictionaryStartTimestamp (gint64 timestamp); virtual gboolean networkDictionaryEndTimestamp (gint64 timestamp); diff --git a/src/PYPDoublePinyinEditor.cc b/src/PYPDoublePinyinEditor.cc index 22aa401..fe53ab1 100644 --- a/src/PYPDoublePinyinEditor.cc +++ b/src/PYPDoublePinyinEditor.cc @@ -73,6 +73,8 @@ DoublePinyinEditor::insert (gint ch) #endif m_text.insert (m_cursor++, ch); + m_lookup_cursor = 0; + updatePinyin (); update (); diff --git a/src/PYPEnhancedCandidates.h b/src/PYPEnhancedCandidates.h index e5bc62f..bffdac9 100644 --- a/src/PYPEnhancedCandidates.h +++ b/src/PYPEnhancedCandidates.h @@ -42,7 +42,8 @@ enum CandidateType { CANDIDATE_LUA_CONVERTER, CANDIDATE_CLOUD_INPUT, CANDIDATE_EMOJI, - CANDIDATE_ENGLISH + CANDIDATE_ENGLISH, + CANDIDATE_PREDICTED_PUNCTUATION }; enum SelectCandidateAction { diff --git a/src/PYPFullPinyinEditor.cc b/src/PYPFullPinyinEditor.cc index bd41572..b20a47c 100644 --- a/src/PYPFullPinyinEditor.cc +++ b/src/PYPFullPinyinEditor.cc @@ -58,6 +58,7 @@ FullPinyinEditor::insert (gint ch) #endif m_text.insert (m_cursor++, ch); + m_lookup_cursor = 0; updatePinyin (); update (); diff --git a/src/PYPLibPinyinCandidates.cc b/src/PYPLibPinyinCandidates.cc index dd3d409..6726739 100644 --- a/src/PYPLibPinyinCandidates.cc +++ b/src/PYPLibPinyinCandidates.cc @@ -167,7 +167,12 @@ LibPinyinCandidates::selectCandidate (EnhancedCandidate & enhanced) guint16 begin = 0; pinyin_get_pinyin_key_rest_positions (instance, pos, &begin, NULL); - m_editor->m_cursor = begin; + + /* The cursor is at the end of the text input. */ + if (m_editor->m_cursor == m_editor->m_text.length ()) + m_editor->m_lookup_cursor = begin; + else + m_editor->m_cursor = begin; return SELECT_CANDIDATE_UPDATE; } diff --git a/src/PYPPhoneticEditor.cc b/src/PYPPhoneticEditor.cc index 00fa610..42d759c 100644 --- a/src/PYPPhoneticEditor.cc +++ b/src/PYPPhoneticEditor.cc @@ -31,6 +31,7 @@ PhoneticEditor::PhoneticEditor (PinyinProperties &props, : Editor (props, config), m_pinyin_len (0), m_lookup_table (m_config.pageSize ()), + m_lookup_cursor (0), m_libpinyin_candidates (this), #ifdef IBUS_BUILD_LUA_EXTENSION m_lua_trigger_candidates (this), @@ -379,12 +380,13 @@ PhoneticEditor::getPinyinCursor () guint PhoneticEditor::getLookupCursor (void) { - guint lookup_cursor = getPinyinCursor (); + guint pinyin_cursor = getPinyinCursor (); - /* show candidates when pinyin cursor is at end. */ - if (lookup_cursor == m_text.length ()) - lookup_cursor = 0; - return lookup_cursor; + /* show candidates when pinyin cursor is at the end. */ + if (m_cursor == m_text.length ()) + return m_lookup_cursor; + + return pinyin_cursor; } int @@ -564,6 +566,8 @@ PhoneticEditor::removeCharBefore (void) return FALSE; m_cursor --; + m_lookup_cursor = 0; + m_text.erase (m_cursor, 1); updatePinyin (); @@ -579,6 +583,7 @@ PhoneticEditor::removeCharAfter (void) return FALSE; m_text.erase (m_cursor, 1); + m_lookup_cursor = 0; updatePinyin (); update (); @@ -593,6 +598,8 @@ PhoneticEditor::moveCursorLeft (void) return FALSE; m_cursor --; + m_lookup_cursor = 0; + update (); return TRUE; } @@ -604,6 +611,8 @@ PhoneticEditor::moveCursorRight (void) return FALSE; m_cursor ++; + m_lookup_cursor = 0; + update (); return TRUE; } @@ -615,6 +624,8 @@ PhoneticEditor::moveCursorToBegin (void) return FALSE; m_cursor = 0; + m_lookup_cursor = 0; + update (); return TRUE; } @@ -626,6 +637,8 @@ PhoneticEditor::moveCursorToEnd (void) return FALSE; m_cursor = m_text.length (); + m_lookup_cursor = 0; + update (); return TRUE; } @@ -670,6 +683,8 @@ PhoneticEditor::removeWordBefore (void) guint cursor = getCursorLeftByWord (); m_text.erase (cursor, m_cursor - cursor); m_cursor = cursor; + m_lookup_cursor = 0; + updatePinyin (); update (); return TRUE; @@ -683,6 +698,8 @@ PhoneticEditor::removeWordAfter (void) guint cursor = getCursorRightByWord (); m_text.erase (m_cursor, cursor - m_cursor); + m_lookup_cursor = 0; + updatePinyin (); update (); return TRUE; @@ -697,6 +714,8 @@ PhoneticEditor::moveCursorLeftByWord (void) guint cursor = getCursorLeftByWord (); m_cursor = cursor; + m_lookup_cursor = 0; + update (); return TRUE; } @@ -710,6 +729,8 @@ PhoneticEditor::moveCursorRightByWord (void) guint cursor = getCursorRightByWord (); m_cursor = cursor; + m_lookup_cursor = 0; + update (); return TRUE; } diff --git a/src/PYPPhoneticEditor.h b/src/PYPPhoneticEditor.h index 03e61aa..2032cf1 100644 --- a/src/PYPPhoneticEditor.h +++ b/src/PYPPhoneticEditor.h @@ -117,6 +117,7 @@ protected: /* varibles */ guint m_pinyin_len; LookupTable m_lookup_table; + guint m_lookup_cursor; String m_buffer; /* use LibPinyinBackEnd here. */ diff --git a/src/PYPPinyinEditor.cc b/src/PYPPinyinEditor.cc index 99efbe3..f2b2d7e 100644 --- a/src/PYPPinyinEditor.cc +++ b/src/PYPPinyinEditor.cc @@ -109,6 +109,12 @@ PinyinEditor::processPunct (guint keyval, guint keycode, return TRUE; } break; + case IBUS_bracketleft: + if (m_config.squareBracketPage ()) { + pageUp (); + return TRUE; + } + break; case IBUS_period: if (m_config.commaPeriodPage ()) { pageDown (); @@ -121,6 +127,12 @@ PinyinEditor::processPunct (guint keyval, guint keycode, return TRUE; } break; + case IBUS_bracketright: + if (m_config.squareBracketPage ()) { + pageDown (); + return TRUE; + } + break; } if (m_config.autoCommit ()) { diff --git a/src/PYPPinyinEngine.cc b/src/PYPPinyinEngine.cc index 2e06d13..16366f2 100644 --- a/src/PYPPinyinEngine.cc +++ b/src/PYPPinyinEngine.cc @@ -75,6 +75,12 @@ PinyinEngine::PinyinEngine (IBusEngine *engine) #endif } +#ifdef IBUS_BUILD_LUA_EXTENSION + m_props.setLuaPlugin (m_lua_plugin); + if (PinyinConfig::instance ().luaExtension ()) + m_props.appendLuaConverter (); +#endif + m_editors[MODE_PUNCT].reset (new PunctEditor (m_props, PinyinConfig::instance ())); m_editors[MODE_RAW].reset @@ -377,6 +383,9 @@ PinyinEngine::processKeyEvent (guint keyval, guint keycode, guint modifiers) /* For full pinyin, "'" is used. */ (PinyinConfig::instance ().doublePinyin () && IBUS_apostrophe == keyval) || + /* Use square brackets to flip page */ + (!PinyinConfig::instance ().squareBracketPage () && + (IBUS_bracketleft == keyval || IBUS_bracketright == keyval)) || /* For double pinyin, ";" is used. */ (!PinyinConfig::instance ().doublePinyin () && IBUS_semicolon == keyval)) && @@ -430,6 +439,9 @@ PinyinEngine::processKeyEvent (guint keyval, guint keycode, guint modifiers) m_input_mode != MODE_INIT && m_editors[m_input_mode]->text ().empty ())) m_input_mode = MODE_INIT; + + if (G_UNLIKELY (!retval && m_input_mode == MODE_SUGGESTION)) + m_input_mode = MODE_INIT; } if (G_UNLIKELY (!retval)) diff --git a/src/PYPSuggestionCandidates.cc b/src/PYPSuggestionCandidates.cc index 7f8aa1c..84b3f0a 100644 --- a/src/PYPSuggestionCandidates.cc +++ b/src/PYPSuggestionCandidates.cc @@ -47,6 +47,9 @@ SuggestionCandidates::processCandidates (std::vector<EnhancedCandidate> & candid case PREDICTED_PREFIX_CANDIDATE: candidate_type = CANDIDATE_PREDICTED_PREFIX; break; + case PREDICTED_PUNCTUATION_CANDIDATE: + candidate_type = CANDIDATE_PREDICTED_PUNCTUATION; + break; default: assert(FALSE); } @@ -70,7 +73,8 @@ SuggestionCandidates::selectCandidate (EnhancedCandidate & enhanced) { pinyin_instance_t * instance = m_editor->m_instance; assert (CANDIDATE_PREDICTED_BIGRAM == enhanced.m_candidate_type || - CANDIDATE_PREDICTED_PREFIX == enhanced.m_candidate_type); + CANDIDATE_PREDICTED_PREFIX == enhanced.m_candidate_type || + CANDIDATE_PREDICTED_PUNCTUATION == enhanced.m_candidate_type); guint len = 0; pinyin_get_n_candidate (instance, &len); diff --git a/src/PYPSuggestionEditor.cc b/src/PYPSuggestionEditor.cc index 85c35ec..129c093 100644 --- a/src/PYPSuggestionEditor.cc +++ b/src/PYPSuggestionEditor.cc @@ -113,6 +113,12 @@ SuggestionEditor::processPageKey (guint keyval) return TRUE; } break; + case IBUS_bracketleft: + if (m_config.squareBracketPage ()) { + pageUp (); + return TRUE; + } + break; case IBUS_period: if (m_config.commaPeriodPage ()) { pageDown (); @@ -125,6 +131,12 @@ SuggestionEditor::processPageKey (guint keyval) return TRUE; } break; + case IBUS_bracketright: + if (m_config.squareBracketPage ()) { + pageDown (); + return TRUE; + } + break; case IBUS_Up: case IBUS_KP_Up: @@ -262,7 +274,7 @@ SuggestionEditor::cursorDown (void) void SuggestionEditor::update (void) { - pinyin_guess_predicted_candidates (m_instance, m_text); + pinyin_guess_predicted_candidates_with_punctuations (m_instance, m_text); updateLookupTable (); updatePreeditText (); @@ -347,6 +359,7 @@ SuggestionEditor::selectCandidateInternal (EnhancedCandidate & candidate) switch (candidate.m_candidate_type) { case CANDIDATE_PREDICTED_BIGRAM: case CANDIDATE_PREDICTED_PREFIX: + case CANDIDATE_PREDICTED_PUNCTUATION: return m_suggestion_candidates.selectCandidate (candidate); case CANDIDATE_TRADITIONAL_CHINESE: diff --git a/src/PYPinyinProperties.cc b/src/PYPinyinProperties.cc index fe0a7a0..edc2b88 100644 --- a/src/PYPinyinProperties.cc +++ b/src/PYPinyinProperties.cc @@ -21,6 +21,9 @@ #include <libintl.h> #include "PYText.h" #include "PYConfig.h" +#ifdef IBUS_BUILD_LUA_EXTENSION +#include "lua-plugin.h" +#endif namespace PY { @@ -94,6 +97,29 @@ PinyinProperties::PinyinProperties (Config & config) m_props.append (m_prop_simp); m_props.append (m_prop_setup); +#ifdef IBUS_BUILD_LUA_EXTENSION + m_prop_lua_converter = NULL; +#endif +} + +PinyinProperties::~PinyinProperties (void) +{ +#ifdef IBUS_BUILD_LUA_EXTENSION + if (m_prop_lua_converter) { + delete m_prop_lua_converter; + m_prop_lua_converter = NULL; + } + + for (auto iter = m_props_lua_converter_vec.begin (); + iter != m_props_lua_converter_vec.end (); ++iter) { + delete *iter; + } + + for (auto iter = m_lua_converter_names.begin (); + iter != m_lua_converter_names.end (); ++iter) { + delete *iter; + } +#endif } void @@ -119,6 +145,9 @@ PinyinProperties::toggleModeChinese (void) m_prop_full_punct.setSensitive (m_mode_chinese); updateProperty (m_prop_full_punct); + + m_prop_simp.setSensitive (m_mode_chinese); + updateProperty (m_prop_simp); } void @@ -209,8 +238,103 @@ PinyinProperties::propertyActivate (const gchar *prop_name, guint prop_state) { toggleModeSimp (); return TRUE; } + +#ifdef IBUS_BUILD_LUA_EXTENSION + const int len = strlen("LuaConverter."); + if (0 == strncmp (prop_name, "LuaConverter.", len)) { + toggleLuaConverter (len, prop_name, prop_state); + return TRUE; + } +#endif + return FALSE; } +#ifdef IBUS_BUILD_LUA_EXTENSION +gboolean +PinyinProperties::setLuaPlugin (IBusEnginePlugin *plugin) { + m_lua_plugin = plugin; + return TRUE; +} + +void +PinyinProperties::toggleLuaConverter (const int prefix_len, + const gchar *prop_name, + guint prop_state) { + if (prop_state == PROP_STATE_CHECKED) { + std::string name = prop_name + prefix_len; + if (name == "None") + m_config.luaConverter (""); + else + m_config.luaConverter (name); + } + + for (auto iter = m_props_lua_converter_vec.begin (); + iter != m_props_lua_converter_vec.end (); ++iter) { + Property *prop = *iter; + if (0 == g_strcmp0 (prop->getKey (), prop_name)) { + prop->setState ((IBusPropState) prop_state); + updateProperty (*prop); + } + } +} + +gboolean +PinyinProperties::appendLuaConverter (void) { + if (!m_lua_plugin) + return FALSE; + + const GArray * converters = + ibus_engine_plugin_get_available_converters (m_lua_plugin); + if (converters->len == 0) + return FALSE; + + m_prop_lua_converter = new Property ("LuaConverter", + PROP_TYPE_MENU, + StaticText (_("Lua Converter")), + PKGDATADIR"/icons/lua-converter.svg", + StaticText (_("Use the Lua Convertor"))); + + Property * prop = NULL; + + /* Add the None converter. */ + prop = new Property ("LuaConverter.None", + PROP_TYPE_RADIO, + StaticText (_("None"))); + + if (m_config.luaConverter ().empty ()) + prop->setState (PROP_STATE_CHECKED); + + m_props_lua_converter_vec.push_back (prop); + m_props_lua_converter_list.append (*prop); + + /* Add the User Lua Converters. */ + for (int i = 0; i < converters->len; i++) { + lua_converter_t *converter = &g_array_index + (converters, lua_converter_t, i); + + const gchar *name = converter->lua_function_name; + gchar *key = g_strdup_printf ("LuaConverter.%s", name); + m_lua_converter_names.push_back (key); + + prop = new Property (key, + PROP_TYPE_RADIO, + Text (converter->description)); + + if (!m_config.luaConverter ().empty () && + m_config.luaConverter () == name) + prop->setState (PROP_STATE_CHECKED); + + m_props_lua_converter_vec.push_back (prop); + m_props_lua_converter_list.append (*prop); + } + + m_prop_lua_converter->setSubProps (m_props_lua_converter_list); + m_props.append (*m_prop_lua_converter); + + return TRUE; +} + +#endif }; diff --git a/src/PYPinyinProperties.h b/src/PYPinyinProperties.h index 58f39bd..6706032 100644 --- a/src/PYPinyinProperties.h +++ b/src/PYPinyinProperties.h @@ -22,6 +22,12 @@ #include "PYSignal.h" #include "PYProperty.h" +#include <vector> +#include <glib.h> + +G_BEGIN_DECLS +typedef struct _IBusEnginePlugin IBusEnginePlugin; +G_END_DECLS namespace PY { @@ -30,6 +36,7 @@ class Config; class PinyinProperties { public: PinyinProperties (Config & config); + virtual ~PinyinProperties (void); void toggleModeChinese (void); void toggleModeFull (void); @@ -74,6 +81,23 @@ private: Property m_prop_simp; Property m_prop_setup; PropList m_props; + +#ifdef IBUS_BUILD_LUA_EXTENSION + Pointer<IBusEnginePlugin> m_lua_plugin; + Property *m_prop_lua_converter; + std::vector<Property *> m_props_lua_converter_vec; + std::vector<gchar *> m_lua_converter_names; + PropList m_props_lua_converter_list; + +public: + gboolean setLuaPlugin (IBusEnginePlugin *plugin); + + void toggleLuaConverter (const int prefix_len, + const gchar *prop_name, + guint prop_state); + + gboolean appendLuaConverter (void); +#endif }; }; diff --git a/src/PYProperty.h b/src/PYProperty.h index c30d3c2..24923e4 100644 --- a/src/PYProperty.h +++ b/src/PYProperty.h @@ -39,6 +39,11 @@ public: IBusPropList *props = NULL) : Object (ibus_property_new (key, type, label, icon, tooltip, sensitive, visible, state, props)) { } + const gchar * getKey (void) + { + return ibus_property_get_key (get<IBusProperty> ()); + } + void setLabel (IBusText *text) { ibus_property_set_label (get<IBusProperty> (), text); @@ -79,6 +84,16 @@ public: setTooltip (Text (text)); } + void setState (IBusPropState state) + { + ibus_property_set_state (get<IBusProperty> (), state); + } + + void setSubProps (IBusPropList *props) + { + ibus_property_set_sub_props (get<IBusProperty> (), props); + } + operator IBusProperty * (void) const { return get<IBusProperty> (); diff --git a/src/PYTableDatabase.cc b/src/PYTableDatabase.cc index a6f8209..0e55b6e 100644 --- a/src/PYTableDatabase.cc +++ b/src/PYTableDatabase.cc @@ -57,6 +57,8 @@ TableDatabase::init () if (!result) g_warning ("can't open user table database.\n"); + + g_free (path); } TableDatabase::TableDatabase(){ @@ -269,12 +271,16 @@ TableDatabase::importTable (const char *filename){ "SELECT MAX(id) FROM phrases;"; m_sql = SQL_DB_SELECT; int result = sqlite3_prepare_v2 (m_sqlite, m_sql.c_str (), -1, &stmt, &tail); - if (result != SQLITE_OK) + if (result != SQLITE_OK) { + fclose (input); return FALSE; + } result = sqlite3_step (stmt); - if (result != SQLITE_ROW) + if (result != SQLITE_ROW) { + fclose (input); return FALSE; + } int id = 0; result = sqlite3_column_type (stmt, 0); @@ -286,8 +292,10 @@ TableDatabase::importTable (const char *filename){ g_warning ("Can't find id for user table database."); m_sql = "BEGIN TRANSACTION;"; - if (!executeSQL (m_sqlite)) + if (!executeSQL (m_sqlite)) { + fclose (input); return FALSE; + } /* Open the table file with format: "tabkeys phrase freq". */ @@ -311,8 +319,10 @@ TableDatabase::importTable (const char *filename){ } m_sql = "COMMIT;"; - if (!executeSQL (m_sqlite)) + if (!executeSQL (m_sqlite)) { + fclose (input); return FALSE; + } fclose (input); return TRUE; @@ -343,18 +353,24 @@ TableDatabase::exportTable (const char *filename){ while (result == SQLITE_ROW){ /* write one line. */ result = sqlite3_column_type (stmt, 0); - if (result != SQLITE_TEXT) + if (result != SQLITE_TEXT) { + fclose (output); return FALSE; + } const char *tabkeys = (const char *)sqlite3_column_text (stmt, 0); result = sqlite3_column_type (stmt, 1); - if (result != SQLITE_TEXT) + if (result != SQLITE_TEXT) { + fclose (output); return FALSE; + } const char *phrase = (const char *)sqlite3_column_text (stmt, 1); result = sqlite3_column_type (stmt, 2); - if (result != SQLITE_INTEGER) + if (result != SQLITE_INTEGER) { + fclose (output); return FALSE; + } const int freq = sqlite3_column_int (stmt, 2); fprintf (output, "%s\t%s\t%d\n", tabkeys, phrase, freq); diff --git a/src/PYTableEditor.cc b/src/PYTableEditor.cc index ddaab57..4c79983 100644 --- a/src/PYTableEditor.cc +++ b/src/PYTableEditor.cc @@ -135,6 +135,12 @@ TableEditor::processPageKey (guint keyval) return TRUE; } break; + case IBUS_bracketleft: + if (m_config.squareBracketPage ()) { + pageUp (); + return TRUE; + } + break; case IBUS_period: if (m_config.commaPeriodPage ()) { pageDown (); @@ -147,6 +153,12 @@ TableEditor::processPageKey (guint keyval) return TRUE; } break; + case IBUS_bracketright: + if (m_config.squareBracketPage ()) { + pageDown (); + return TRUE; + } + break; case IBUS_Up: case IBUS_KP_Up: diff --git a/src/PYXMLUtil.cc b/src/PYXMLUtil.cc new file mode 100644 index 0000000..dcefc14 --- /dev/null +++ b/src/PYXMLUtil.cc @@ -0,0 +1,188 @@ +/* vim:set et ts=4 sts=4: + * + * ibus-libpinyin - Intelligent Pinyin engine based on libpinyin for IBus + * + * Copyright (c) 2024 Peng Wu <alexepico@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "PYXMLUtil.h" +#include <glib.h> +#include <gio/gio.h> +#ifdef ENABLE_LIBNOTIFY +#include <libnotify/notify.h> +#endif + +namespace PY { + +struct EngineXMLVersion{ + gboolean in_version_tag; + /* There are two versions in the XML file, only keep the first version here. */ + gchar * first_version; +}; + +static void engine_parser_start_element (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, + GError **error); +static void engine_parser_end_element (GMarkupParseContext *context, + const gchar *element_name, + gpointer user_data, + GError **error); +static void engine_parser_characters (GMarkupParseContext *context, + const gchar *text, + gsize text_len, + gpointer user_data, + GError **error); +static void engine_parser_passthrough (GMarkupParseContext *context, + const gchar *passthrough_text, + gsize text_len, + gpointer user_data, + GError **error); +static void engine_parser_error (GMarkupParseContext *context, + GError *error, + gpointer user_data); + + +/* + * Parser + */ +static const GMarkupParser engine_xml_parser = { + engine_parser_start_element, + engine_parser_end_element, + engine_parser_characters, + engine_parser_passthrough, + engine_parser_error +}; + +struct EngineXMLFile{ + gboolean in_version_tag; + gchar * first_version; +}; + +static void +engine_parser_start_element (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, + GError **error) +{ + EngineXMLFile * xmlfile = (EngineXMLFile *) user_data; + if (0 == strcmp(element_name, "version")) + xmlfile->in_version_tag = TRUE; +} + +static void +engine_parser_end_element (GMarkupParseContext *context, + const gchar *element_name, + gpointer user_data, + GError **error) +{ + EngineXMLFile * xmlfile = (EngineXMLFile *) user_data; + if (0 == strcmp(element_name, "version")) + xmlfile->in_version_tag = FALSE; +} + +static void +engine_parser_characters (GMarkupParseContext *context, + const gchar *text, + gsize text_len, + gpointer user_data, + GError **error) +{ + EngineXMLFile * xmlfile = (EngineXMLFile *) user_data; + if (xmlfile->in_version_tag && xmlfile->first_version == NULL) + xmlfile->first_version = g_strdup(text); +} + +static void +engine_parser_passthrough (GMarkupParseContext *context, + const gchar *passthrough_text, + gsize text_len, + gpointer user_data, + GError **error) +{ +} + +static void +engine_parser_error (GMarkupParseContext *context, + GError *error, + gpointer user_data) +{ + g_printerr ("ERROR: %s\n", error->message); +} + +gchar * +load_file_content(const gchar * filename) +{ + gboolean success = FALSE; + GError *error = NULL; + + GFile *file = NULL; + char *data = NULL; + gsize len = 0; + + file = g_file_new_for_path (filename); + success = g_file_load_contents (file, NULL, &data, &len, NULL, &error); + g_object_unref (file); + + return data; +} + +gboolean +parse_engine_version(const char * filename, gchar ** version) +{ + GMarkupParseContext *context = NULL; + gboolean success = FALSE; + GError *error = NULL; + + GFile *file = NULL; + char *data = NULL; + gsize len = 0; + + EngineXMLFile xmlfile; + memset(&xmlfile, 0, sizeof(EngineXMLFile)); + + file = g_file_new_for_path (filename); + success = g_file_load_contents (file, NULL, &data, &len, NULL, &error); + g_object_unref (file); + context = g_markup_parse_context_new (&engine_xml_parser, G_MARKUP_DEFAULT_FLAGS, &xmlfile, NULL); + success = g_markup_parse_context_parse (context, data, len, NULL); + g_markup_parse_context_free (context); + g_free (data); + + *version = xmlfile.first_version; + return TRUE; +} + +void +show_message(const char* summary, const char* details) +{ +#ifdef ENABLE_LIBNOTIFY + NotifyNotification* notice = notify_notification_new (summary, details, NULL); + notify_notification_show (notice, NULL); + g_object_unref (notice); +#else + if (details == NULL) + g_message ("%s\n", summary); + else + g_message ("%s\n%s\n", summary, details); +#endif +} + +}; diff --git a/src/PYXMLUtil.h b/src/PYXMLUtil.h new file mode 100644 index 0000000..10fe4f6 --- /dev/null +++ b/src/PYXMLUtil.h @@ -0,0 +1,43 @@ +/* vim:set et ts=4 sts=4: + * + * ibus-libpinyin - Intelligent Pinyin engine based on libpinyin for IBus + * + * Copyright (c) 2024 Peng Wu <alexepico@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __PY_XML_UTIL_H_ +#define __PY_XML_UTIL_H_ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <glib.h> + +namespace PY { + +gchar * +load_file_content(const gchar * filename); + +gboolean +parse_engine_version(const char * filename, gchar ** version); + +void +show_message(const char* summary, const char* details); + +}; + +#endif diff --git a/src/default.inputmethod.xml.in.in b/src/default.inputmethod.xml.in.in new file mode 100644 index 0000000..c68a61d --- /dev/null +++ b/src/default.inputmethod.xml.in.in @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- filename: default.xml --> +<engines> + <engine> + <name>libpinyin</name> + <language>zh_CN</language> + <license>GPL</license> + <author> + Peng Wu <alexepico@gmail.com> + Peng Huang <shawn.p.huang@gmail.com> + BYVoid <byvoid1@gmail.com> + </author> + <icon>@PKGDATADIR@/icons/ibus-pinyin.svg</icon> + <layout>default</layout> + <longname>Intelligent Pinyin</longname> + <description>Intelligent Pinyin input method</description> + <rank>99</rank> + <symbol>拼</symbol> + @ICON_PROP_KEY_XML@ + <setup>@LIBEXECDIR@/ibus-setup-libpinyin libpinyin</setup> + <version>@VERSION@</version> + <textdomain>ibus-libpinyin</textdomain> + </engine> + <engine> + <name>libbopomofo</name> + <language>zh_TW</language> + <license>GPL</license> + <author> + Peng Wu <alexepico@gmail.com> + Peng Huang <shawn.p.huang@gmail.com> + BYVoid <byvoid1@gmail.com> + </author> + <icon>@PKGDATADIR@/icons/ibus-bopomofo.svg</icon> + <layout>default</layout> + <longname>Bopomofo</longname> + <description>Bopomofo input method</description> + <rank>98</rank> + <symbol>ㄉ</symbol> + @ICON_PROP_KEY_XML@ + <setup>@LIBEXECDIR@/ibus-setup-libpinyin libbopomofo</setup> + <version>@VERSION@</version> + <textdomain>ibus-libpinyin</textdomain> + </engine> +</engines> diff --git a/src/libpinyin.inputmethod.xml.in.in b/src/libpinyin.inputmethod.xml.in.in new file mode 100644 index 0000000..b7c4c3e --- /dev/null +++ b/src/libpinyin.inputmethod.xml.in.in @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- filename: pinyin.xml --> +<component> + <name>org.freedesktop.IBus.Libpinyin</name> + <description>Libpinyin Component</description> + <exec>@LIBEXECDIR@/ibus-engine-libpinyin --ibus</exec> + <version>@VERSION@</version> + <author>Peng Wu <alexepico@gmail.com></author> + <license>GPL</license> + <homepage>https://github.com/libpinyin/ibus-libpinyin</homepage> + <textdomain>ibus-libpinyin</textdomain> + + <!-- for engines --> + <observed-paths> + <path>~/.config/ibus/libpinyin/engines.xml</path> + <path>@PKGDATADIR@/default.xml</path> + </observed-paths> + <engines exec="@LIBEXECDIR@/ibus-engine-libpinyin --xml" /> +</component> diff --git a/src/libpinyin.xml.in.in b/src/libpinyin.xml.in.in deleted file mode 100644 index d548375..0000000 --- a/src/libpinyin.xml.in.in +++ /dev/null @@ -1,53 +0,0 @@ -<?xml version=\"1.0\" encoding=\"utf-8\"?> -<!-- filename: pinyin.xml --> -<component> - <name>org.freedesktop.IBus.Libpinyin</name> - <description>Libpinyin Component</description> - <exec>${libexecdir}/ibus-engine-libpinyin --ibus</exec> - <version>@VERSION@</version> - <author>Peng Wu <alexepico@gmail.com></author> - <license>GPL</license> - <homepage>https://github.com/libpinyin/ibus-libpinyin</homepage> - <textdomain>ibus-libpinyin</textdomain> - - <engines> - <engine> - <name>libpinyin</name> - <language>zh_CN</language> - <license>GPL</license> - <author> - Peng Wu <alexepico@gmail.com> - Peng Huang <shawn.p.huang@gmail.com> - BYVoid <byvoid1@gmail.com> - </author> - <icon>${pkgdatadir}/icons/ibus-pinyin.svg</icon> - <layout>default</layout> - <longname>Intelligent Pinyin</longname> - <description>Intelligent Pinyin input method</description> - <rank>99</rank> - <symbol>拼</symbol> - @ICON_PROP_KEY_XML@ - <setup>${libexecdir}/ibus-setup-libpinyin libpinyin</setup> - <textdomain>ibus-libpinyin</textdomain> - </engine> - <engine> - <name>libbopomofo</name> - <language>zh_TW</language> - <license>GPL</license> - <author> - Peng Wu <alexepico@gmail.com> - Peng Huang <shawn.p.huang@gmail.com> - BYVoid <byvoid1@gmail.com> - </author> - <icon>${pkgdatadir}/icons/ibus-bopomofo.svg</icon> - <layout>default</layout> - <longname>Bopomofo</longname> - <description>Bopomofo input method</description> - <rank>98</rank> - <symbol>ㄉ</symbol> - @ICON_PROP_KEY_XML@ - <setup>${libexecdir}/ibus-setup-libpinyin libbopomofo</setup> - <textdomain>ibus-libpinyin</textdomain> - </engine> - </engines> -</component> |