/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ /* vim:set et sts=4: */ /* IBus - The Input Bus * Copyright (C) 2008-2010 Peng Huang * Copyright (C) 2008-2010 Red Hat, Inc. * * 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.1 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; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA */ #include "ibuslookuptable.h" /* functions prototype */ static void ibus_lookup_table_destroy (IBusLookupTable *table); static gboolean ibus_lookup_table_serialize (IBusLookupTable *table, GVariantBuilder *builder); static gint ibus_lookup_table_deserialize (IBusLookupTable *table, GVariant *variant); static gboolean ibus_lookup_table_copy (IBusLookupTable *dest, IBusLookupTable *src); G_DEFINE_TYPE (IBusLookupTable, ibus_lookup_table, IBUS_TYPE_SERIALIZABLE) static void ibus_lookup_table_class_init (IBusLookupTableClass *class) { IBusObjectClass *object_class = IBUS_OBJECT_CLASS (class); IBusSerializableClass *serializable_class = IBUS_SERIALIZABLE_CLASS (class); object_class->destroy = (IBusObjectDestroyFunc) ibus_lookup_table_destroy; serializable_class->serialize = (IBusSerializableSerializeFunc) ibus_lookup_table_serialize; serializable_class->deserialize = (IBusSerializableDeserializeFunc) ibus_lookup_table_deserialize; serializable_class->copy = (IBusSerializableCopyFunc) ibus_lookup_table_copy; } static void ibus_lookup_table_init (IBusLookupTable *table) { table->candidates = g_array_new (TRUE, TRUE, sizeof (IBusText *)); table->labels = g_array_new (TRUE, TRUE, sizeof (IBusText *)); } static void ibus_lookup_table_destroy (IBusLookupTable *table) { IBusText **p; gint i; if (table->candidates != NULL) { p = (IBusText **) g_array_free (table->candidates, FALSE); table->candidates = NULL; for (i = 0; p[i] != NULL; i++) { g_object_unref (p[i]); } g_free (p); } if (table->labels != NULL) { p = (IBusText **) g_array_free (table->labels, FALSE); table->labels = NULL; for (i = 0; p[i] != NULL; i++) { g_object_unref (p[i]); } g_free (p); } IBUS_OBJECT_CLASS (ibus_lookup_table_parent_class)->destroy ((IBusObject *) table); } static gboolean ibus_lookup_table_serialize (IBusLookupTable *table, GVariantBuilder *builder) { gboolean retval; guint i; retval = IBUS_SERIALIZABLE_CLASS (ibus_lookup_table_parent_class)->serialize ((IBusSerializable *)table, builder); g_return_val_if_fail (retval, 0); g_return_val_if_fail (IBUS_IS_LOOKUP_TABLE (table), 0); g_variant_builder_add (builder, "u", table->page_size); g_variant_builder_add (builder, "u", table->cursor_pos); g_variant_builder_add (builder, "b", table->cursor_visible); g_variant_builder_add (builder, "b", table->round); g_variant_builder_add (builder, "i", table->orientation); GVariantBuilder array; /* append candidates */ g_variant_builder_init (&array, G_VARIANT_TYPE ("av")); for (i = 0;; i++) { IBusText *text = ibus_lookup_table_get_candidate (table, i); if (text == NULL) break; g_variant_builder_add (&array, "v", ibus_serializable_serialize ((IBusSerializable *)text)); } g_variant_builder_add (builder, "av", &array); /* append labels */ g_variant_builder_init (&array, G_VARIANT_TYPE ("av")); for (i = 0;; i++) { IBusText *text = ibus_lookup_table_get_label (table, i); if (text == NULL) break; g_variant_builder_add (&array, "v", ibus_serializable_serialize ((IBusSerializable *)text)); } g_variant_builder_add (builder, "av", &array); return TRUE; } static gint ibus_lookup_table_deserialize (IBusLookupTable *table, GVariant *variant) { gint retval; retval = IBUS_SERIALIZABLE_CLASS (ibus_lookup_table_parent_class)->deserialize ((IBusSerializable *)table, variant); g_return_val_if_fail (retval, 0); g_return_val_if_fail (IBUS_IS_LOOKUP_TABLE (table), 0); g_variant_get_child (variant, retval++, "u", &table->page_size); g_variant_get_child (variant, retval++, "u", &table->cursor_pos); g_variant_get_child (variant, retval++, "b", &table->cursor_visible); g_variant_get_child (variant, retval++, "b", &table->round); g_variant_get_child (variant, retval++, "i", &table->orientation); GVariant *var; // deserialize candidates GVariantIter *iter = NULL; g_variant_get_child (variant, retval++, "av", &iter); while (g_variant_iter_loop (iter, "v", &var)) { ibus_lookup_table_append_candidate (table, IBUS_TEXT (ibus_serializable_deserialize (var))); } g_variant_iter_free (iter); // deserialize labels iter = NULL; g_variant_get_child (variant, retval++, "av", &iter); while (g_variant_iter_loop (iter, "v", &var)) { ibus_lookup_table_append_label (table, IBUS_TEXT (ibus_serializable_deserialize (var))); } g_variant_iter_free (iter); return retval; } static gboolean ibus_lookup_table_copy (IBusLookupTable *dest, IBusLookupTable *src) { gboolean retval; guint i; retval = IBUS_SERIALIZABLE_CLASS (ibus_lookup_table_parent_class)->copy ((IBusSerializable *)dest, (IBusSerializable *)src); g_return_val_if_fail (retval, FALSE); g_return_val_if_fail (IBUS_IS_LOOKUP_TABLE (dest), FALSE); g_return_val_if_fail (IBUS_IS_LOOKUP_TABLE (src), FALSE); // copy candidates for (i = 0;; i++) { IBusText *text; text = ibus_lookup_table_get_candidate (src, i); if (text == NULL) break; text = (IBusText *) ibus_serializable_copy ((IBusSerializable *) text); ibus_lookup_table_append_candidate (dest, text); } // copy labels for (i = 0;; i++) { IBusText *text; text = ibus_lookup_table_get_label (src, i); if (text == NULL) break; text = (IBusText *) ibus_serializable_copy ((IBusSerializable *) text); ibus_lookup_table_append_label (dest, text); } return TRUE; } IBusLookupTable * ibus_lookup_table_new (guint page_size, guint cursor_pos, gboolean cursor_visible, gboolean round) { g_assert (page_size > 0); g_assert (page_size <= 16); IBusLookupTable *table; table= g_object_new (IBUS_TYPE_LOOKUP_TABLE, NULL); table->page_size = page_size; table->cursor_pos = cursor_pos; table->cursor_visible = cursor_visible; table->round = round; table->orientation = IBUS_ORIENTATION_SYSTEM; return table; } guint ibus_lookup_table_get_number_of_candidates (IBusLookupTable *table) { g_assert (IBUS_IS_LOOKUP_TABLE (table)); return table->candidates->len; } void ibus_lookup_table_append_candidate (IBusLookupTable *table, IBusText *text) { g_assert (IBUS_IS_LOOKUP_TABLE (table)); g_assert (IBUS_IS_TEXT (text)); g_object_ref_sink (text); g_array_append_val (table->candidates, text); } IBusText * ibus_lookup_table_get_candidate (IBusLookupTable *table, guint index) { g_assert (IBUS_IS_LOOKUP_TABLE (table)); if (index >= table->candidates->len) return NULL; return g_array_index (table->candidates, IBusText *, index); } void ibus_lookup_table_append_label (IBusLookupTable *table, IBusText *text) { g_assert (IBUS_IS_LOOKUP_TABLE (table)); g_assert (IBUS_IS_TEXT (text)); g_object_ref_sink (text); g_array_append_val (table->labels, text); } void ibus_lookup_table_set_label (IBusLookupTable *table, guint index, IBusText *text) { g_assert (IBUS_IS_LOOKUP_TABLE (table)); g_assert (IBUS_IS_TEXT (text)); if (table->labels->len <= index) { g_array_set_size (table->labels, index + 1); } IBusText *old = ibus_lookup_table_get_label (table, index); if (old != NULL) { g_object_unref (old); } g_object_ref_sink (text); g_array_index (table->labels, IBusText *, index) = text; } IBusText * ibus_lookup_table_get_label (IBusLookupTable *table, guint index) { g_assert (IBUS_IS_LOOKUP_TABLE (table)); if (index >= table->labels->len) return NULL; return g_array_index (table->labels, IBusText *, index); } void ibus_lookup_table_clear (IBusLookupTable *table) { g_assert (IBUS_IS_LOOKUP_TABLE (table)); gint index; for (index = 0; index < table->candidates->len; index ++) { g_object_unref (g_array_index (table->candidates, IBusText *, index)); } g_array_set_size (table->candidates, 0); table->cursor_pos = 0; } void ibus_lookup_table_set_cursor_pos (IBusLookupTable *table, guint cursor_pos) { g_assert (IBUS_IS_LOOKUP_TABLE (table)); g_assert (cursor_pos < table->candidates->len); table->cursor_pos = cursor_pos; } guint ibus_lookup_table_get_cursor_pos (IBusLookupTable *table) { g_assert (IBUS_IS_LOOKUP_TABLE (table)); return table->cursor_pos; } guint ibus_lookup_table_get_cursor_in_page (IBusLookupTable *table) { g_assert (IBUS_IS_LOOKUP_TABLE (table)); return table->cursor_pos % table->page_size; } void ibus_lookup_table_set_cursor_visible (IBusLookupTable *table, gboolean visible) { g_assert (IBUS_IS_LOOKUP_TABLE (table)); table->cursor_visible = visible; } gboolean ibus_lookup_table_is_cursor_visible (IBusLookupTable *table) { g_assert (IBUS_IS_LOOKUP_TABLE (table)); return table->cursor_visible; } void ibus_lookup_table_set_page_size (IBusLookupTable *table, guint page_size) { g_assert (IBUS_IS_LOOKUP_TABLE (table)); g_assert (page_size > 0); table->page_size = page_size; } guint ibus_lookup_table_get_page_size (IBusLookupTable *table) { g_assert (IBUS_IS_LOOKUP_TABLE (table)); return table->page_size; } void ibus_lookup_table_set_round (IBusLookupTable *table, gboolean round) { g_assert (IBUS_IS_LOOKUP_TABLE (table)); table->round = round ? TRUE: FALSE; } gboolean ibus_lookup_table_is_round (IBusLookupTable *table) { g_assert (IBUS_IS_LOOKUP_TABLE (table)); return table->round; } void ibus_lookup_table_set_orientation (IBusLookupTable *table, gint orientation) { g_assert (IBUS_IS_LOOKUP_TABLE (table)); g_assert (orientation == IBUS_ORIENTATION_HORIZONTAL || orientation == IBUS_ORIENTATION_VERTICAL || orientation == IBUS_ORIENTATION_SYSTEM); table->orientation = orientation; } gint ibus_lookup_table_get_orientation (IBusLookupTable *table) { g_assert (IBUS_IS_LOOKUP_TABLE (table)); return table->orientation; } gboolean ibus_lookup_table_page_up (IBusLookupTable *table) { g_assert (IBUS_IS_LOOKUP_TABLE (table)); if (table->cursor_pos < table->page_size) { gint i; gint page_nr; if (!table->round) { return FALSE; } /* cursor index in page */ i = table->cursor_pos % table->page_size; page_nr = (table->candidates->len + table->page_size - 1) / table->page_size; table->cursor_pos = page_nr * table->page_size + i; if (table->cursor_pos >= table->candidates->len) { table->cursor_pos = table->candidates->len - 1; } return TRUE; } table->cursor_pos -= table->page_size; return TRUE; } gboolean ibus_lookup_table_page_down (IBusLookupTable *table) { g_assert (IBUS_IS_LOOKUP_TABLE (table)); gint i; gint page; gint page_nr; /* cursor index in page */ i = table->cursor_pos % table->page_size; page = table->cursor_pos / table->page_size; page_nr = (table->candidates->len + table->page_size - 1) / table->page_size; if (page == page_nr - 1) { if (!table->round) return FALSE; table->cursor_pos = i; return TRUE; } table->cursor_pos += table->page_size; if (table->cursor_pos > table->candidates->len - 1) { table->cursor_pos = table->candidates->len - 1; } return TRUE; } gboolean ibus_lookup_table_cursor_up (IBusLookupTable *table) { g_assert (IBUS_IS_LOOKUP_TABLE (table)); if (table->cursor_pos == 0) { if (!table->round) return FALSE; table->cursor_pos = table->candidates->len - 1; return TRUE; } table->cursor_pos --; return TRUE; } gboolean ibus_lookup_table_cursor_down (IBusLookupTable *table) { g_assert (IBUS_IS_LOOKUP_TABLE (table)); if (table->cursor_pos == table->candidates->len - 1) { if (!table->round) return FALSE; table->cursor_pos = 0; return TRUE; } table->cursor_pos ++; return TRUE; }