Add Ctrl+space customization.
[platform/upstream/ibus.git] / src / ibuslookuptable.c
1 /* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
2 /* vim:set et sts=4: */
3 /* IBus - The Input Bus
4  * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
5  * Copyright (C) 2008-2010 Red Hat, Inc.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22 #include "ibuslookuptable.h"
23
24 /* functions prototype */
25 static void         ibus_lookup_table_destroy       (IBusLookupTable        *table);
26 static gboolean     ibus_lookup_table_serialize     (IBusLookupTable        *table,
27                                                      GVariantBuilder        *builder);
28 static gint         ibus_lookup_table_deserialize   (IBusLookupTable        *table,
29                                                      GVariant               *variant);
30 static gboolean     ibus_lookup_table_copy          (IBusLookupTable        *dest,
31                                                      IBusLookupTable        *src);
32
33 G_DEFINE_TYPE (IBusLookupTable, ibus_lookup_table, IBUS_TYPE_SERIALIZABLE)
34
35 static void
36 ibus_lookup_table_class_init (IBusLookupTableClass *class)
37 {
38     IBusObjectClass *object_class = IBUS_OBJECT_CLASS (class);
39     IBusSerializableClass *serializable_class = IBUS_SERIALIZABLE_CLASS (class);
40
41     object_class->destroy = (IBusObjectDestroyFunc) ibus_lookup_table_destroy;
42
43     serializable_class->serialize   = (IBusSerializableSerializeFunc) ibus_lookup_table_serialize;
44     serializable_class->deserialize = (IBusSerializableDeserializeFunc) ibus_lookup_table_deserialize;
45     serializable_class->copy        = (IBusSerializableCopyFunc) ibus_lookup_table_copy;
46 }
47
48 static void
49 ibus_lookup_table_init (IBusLookupTable *table)
50 {
51     table->candidates = g_array_new (TRUE, TRUE, sizeof (IBusText *));
52     table->labels = g_array_new (TRUE, TRUE, sizeof (IBusText *));
53 }
54
55 static void
56 ibus_lookup_table_destroy (IBusLookupTable *table)
57 {
58     IBusText **p;
59     gint i;
60
61     if (table->candidates != NULL) {
62         p = (IBusText **) g_array_free (table->candidates, FALSE);
63         table->candidates = NULL;
64
65         for (i = 0; p[i] != NULL; i++) {
66             g_object_unref (p[i]);
67         }
68         g_free (p);
69     }
70
71     if (table->labels != NULL) {
72         p = (IBusText **) g_array_free (table->labels, FALSE);
73         table->labels = NULL;
74         for (i = 0; p[i] != NULL; i++) {
75             g_object_unref (p[i]);
76         }
77         g_free (p);
78     }
79
80     IBUS_OBJECT_CLASS (ibus_lookup_table_parent_class)->destroy ((IBusObject *) table);
81 }
82
83 static gboolean
84 ibus_lookup_table_serialize (IBusLookupTable *table,
85                              GVariantBuilder *builder)
86 {
87     gboolean retval;
88     guint i;
89
90     retval = IBUS_SERIALIZABLE_CLASS (ibus_lookup_table_parent_class)->serialize ((IBusSerializable *)table, builder);
91     g_return_val_if_fail (retval, 0);
92
93     g_return_val_if_fail (IBUS_IS_LOOKUP_TABLE (table), 0);
94
95     g_variant_builder_add (builder, "u", table->page_size);
96     g_variant_builder_add (builder, "u", table->cursor_pos);
97     g_variant_builder_add (builder, "b", table->cursor_visible);
98     g_variant_builder_add (builder, "b", table->round);
99     g_variant_builder_add (builder, "i", table->orientation);
100
101     GVariantBuilder array;
102     /* append candidates */
103     g_variant_builder_init (&array, G_VARIANT_TYPE ("av"));
104     for (i = 0;; i++) {
105         IBusText *text = ibus_lookup_table_get_candidate (table, i);
106         if (text == NULL)
107             break;
108         g_variant_builder_add (&array, "v", ibus_serializable_serialize ((IBusSerializable *)text));
109     }
110     g_variant_builder_add (builder, "av", &array);
111
112     /* append labels */
113     g_variant_builder_init (&array, G_VARIANT_TYPE ("av"));
114     for (i = 0;; i++) {
115         IBusText *text = ibus_lookup_table_get_label (table, i);
116         if (text == NULL)
117             break;
118
119         g_variant_builder_add (&array, "v", ibus_serializable_serialize ((IBusSerializable *)text));
120     }
121     g_variant_builder_add (builder, "av", &array);
122
123     return TRUE;
124 }
125
126 static gint
127 ibus_lookup_table_deserialize (IBusLookupTable *table,
128                                GVariant        *variant)
129 {
130     gint retval;
131
132     retval = IBUS_SERIALIZABLE_CLASS (ibus_lookup_table_parent_class)->deserialize ((IBusSerializable *)table, variant);
133     g_return_val_if_fail (retval, 0);
134
135     g_return_val_if_fail (IBUS_IS_LOOKUP_TABLE (table), 0);
136
137     g_variant_get_child (variant, retval++, "u", &table->page_size);
138     g_variant_get_child (variant, retval++, "u", &table->cursor_pos);
139     g_variant_get_child (variant, retval++, "b", &table->cursor_visible);
140     g_variant_get_child (variant, retval++, "b", &table->round);
141     g_variant_get_child (variant, retval++, "i", &table->orientation);
142
143     GVariant *var;
144     // deserialize candidates
145     GVariantIter *iter = NULL;
146     g_variant_get_child (variant, retval++, "av", &iter);
147     while (g_variant_iter_loop (iter, "v", &var)) {
148         ibus_lookup_table_append_candidate (table, IBUS_TEXT (ibus_serializable_deserialize (var)));
149     }
150     g_variant_iter_free (iter);
151
152     // deserialize labels
153     iter = NULL;
154     g_variant_get_child (variant, retval++, "av", &iter);
155     while (g_variant_iter_loop (iter, "v", &var)) {
156         ibus_lookup_table_append_label (table, IBUS_TEXT (ibus_serializable_deserialize (var)));
157     }
158     g_variant_iter_free (iter);
159
160     return retval;
161 }
162
163 static gboolean
164 ibus_lookup_table_copy (IBusLookupTable *dest,
165                         IBusLookupTable *src)
166 {
167     gboolean retval;
168     guint i;
169
170     retval = IBUS_SERIALIZABLE_CLASS (ibus_lookup_table_parent_class)->copy ((IBusSerializable *)dest, (IBusSerializable *)src);
171     g_return_val_if_fail (retval, FALSE);
172
173     g_return_val_if_fail (IBUS_IS_LOOKUP_TABLE (dest), FALSE);
174     g_return_val_if_fail (IBUS_IS_LOOKUP_TABLE (src), FALSE);
175
176     // copy candidates
177     for (i = 0;; i++) {
178         IBusText *text;
179
180         text = ibus_lookup_table_get_candidate (src, i);
181         if (text == NULL)
182             break;
183
184         text = (IBusText *) ibus_serializable_copy ((IBusSerializable *) text);
185
186         ibus_lookup_table_append_candidate (dest, text);
187     }
188
189     // copy labels
190     for (i = 0;; i++) {
191         IBusText *text;
192
193         text = ibus_lookup_table_get_label (src, i);
194         if (text == NULL)
195             break;
196
197         text = (IBusText *) ibus_serializable_copy ((IBusSerializable *) text);
198
199         ibus_lookup_table_append_label (dest, text);
200     }
201
202     return TRUE;
203 }
204
205 IBusLookupTable *
206 ibus_lookup_table_new (guint page_size,
207                        guint cursor_pos,
208                        gboolean cursor_visible,
209                        gboolean round)
210 {
211     g_assert (page_size > 0);
212     g_assert (page_size <= 16);
213
214     IBusLookupTable *table;
215
216     table= g_object_new (IBUS_TYPE_LOOKUP_TABLE, NULL);
217
218     table->page_size = page_size;
219     table->cursor_pos = cursor_pos;
220     table->cursor_visible = cursor_visible;
221     table->round = round;
222     table->orientation = IBUS_ORIENTATION_SYSTEM;
223
224     return table;
225 }
226
227 guint
228 ibus_lookup_table_get_number_of_candidates (IBusLookupTable *table)
229 {
230     g_assert (IBUS_IS_LOOKUP_TABLE (table));
231
232     return table->candidates->len;
233 }
234
235 void
236 ibus_lookup_table_append_candidate (IBusLookupTable *table,
237                                     IBusText        *text)
238 {
239     g_assert (IBUS_IS_LOOKUP_TABLE (table));
240     g_assert (IBUS_IS_TEXT (text));
241
242     g_object_ref_sink (text);
243     g_array_append_val (table->candidates, text);
244 }
245
246 IBusText *
247 ibus_lookup_table_get_candidate (IBusLookupTable *table,
248                                  guint            index)
249 {
250     g_assert (IBUS_IS_LOOKUP_TABLE (table));
251
252     if (index >= table->candidates->len)
253         return NULL;
254
255     return g_array_index (table->candidates, IBusText *, index);
256 }
257
258 void
259 ibus_lookup_table_append_label (IBusLookupTable *table,
260                                 IBusText        *text)
261 {
262     g_assert (IBUS_IS_LOOKUP_TABLE (table));
263     g_assert (IBUS_IS_TEXT (text));
264
265     g_object_ref_sink (text);
266     g_array_append_val (table->labels, text);
267 }
268
269 void
270 ibus_lookup_table_set_label (IBusLookupTable *table,
271                              guint            index,
272                              IBusText        *text)
273 {
274     g_assert (IBUS_IS_LOOKUP_TABLE (table));
275     g_assert (IBUS_IS_TEXT (text));
276
277     if (table->labels->len <= index) {
278         g_array_set_size (table->labels, index + 1);
279     }
280
281     IBusText *old = ibus_lookup_table_get_label (table, index);
282     if (old != NULL) {
283         g_object_unref (old);
284     }
285
286     g_object_ref_sink (text);
287     g_array_index (table->labels, IBusText *, index) = text;
288 }
289
290 IBusText *
291 ibus_lookup_table_get_label (IBusLookupTable *table,
292                              guint            index)
293 {
294     g_assert (IBUS_IS_LOOKUP_TABLE (table));
295
296     if (index >= table->labels->len)
297         return NULL;
298
299     return g_array_index (table->labels, IBusText *, index);
300 }
301
302 void
303 ibus_lookup_table_clear (IBusLookupTable *table)
304 {
305     g_assert (IBUS_IS_LOOKUP_TABLE (table));
306
307     gint index;
308
309     for (index = 0; index < table->candidates->len; index ++) {
310         g_object_unref (g_array_index (table->candidates, IBusText *, index));
311     }
312
313     g_array_set_size (table->candidates, 0);
314
315     table->cursor_pos = 0;
316 }
317
318 void
319 ibus_lookup_table_set_cursor_pos (IBusLookupTable *table,
320                                   guint            cursor_pos)
321 {
322     g_assert (IBUS_IS_LOOKUP_TABLE (table));
323     g_assert (cursor_pos < table->candidates->len);
324
325     table->cursor_pos = cursor_pos;
326 }
327
328 guint
329 ibus_lookup_table_get_cursor_pos (IBusLookupTable *table)
330 {
331     g_assert (IBUS_IS_LOOKUP_TABLE (table));
332
333     return table->cursor_pos;
334 }
335
336 guint
337 ibus_lookup_table_get_cursor_in_page (IBusLookupTable *table)
338 {
339     g_assert (IBUS_IS_LOOKUP_TABLE (table));
340
341     return table->cursor_pos % table->page_size;
342 }
343
344 void
345 ibus_lookup_table_set_cursor_visible (IBusLookupTable *table,
346                                       gboolean         visible)
347 {
348     g_assert (IBUS_IS_LOOKUP_TABLE (table));
349
350     table->cursor_visible = visible;
351 }
352
353 gboolean
354 ibus_lookup_table_is_cursor_visible (IBusLookupTable *table)
355 {
356     g_assert (IBUS_IS_LOOKUP_TABLE (table));
357
358     return table->cursor_visible;
359 }
360
361 void
362 ibus_lookup_table_set_page_size  (IBusLookupTable *table,
363                                   guint            page_size)
364 {
365     g_assert (IBUS_IS_LOOKUP_TABLE (table));
366     g_assert (page_size > 0);
367
368     table->page_size = page_size;
369 }
370
371 guint
372 ibus_lookup_table_get_page_size (IBusLookupTable *table)
373 {
374     g_assert (IBUS_IS_LOOKUP_TABLE (table));
375
376     return table->page_size;
377 }
378
379 void
380 ibus_lookup_table_set_round (IBusLookupTable *table,
381                              gboolean         round)
382 {
383     g_assert (IBUS_IS_LOOKUP_TABLE (table));
384
385     table->round = round ? TRUE: FALSE;
386 }
387
388 gboolean
389 ibus_lookup_table_is_round (IBusLookupTable *table)
390 {
391     g_assert (IBUS_IS_LOOKUP_TABLE (table));
392
393     return table->round;
394 }
395
396 void
397 ibus_lookup_table_set_orientation (IBusLookupTable *table,
398                                    gint             orientation)
399 {
400     g_assert (IBUS_IS_LOOKUP_TABLE (table));
401     g_assert (orientation == IBUS_ORIENTATION_HORIZONTAL ||
402               orientation == IBUS_ORIENTATION_VERTICAL ||
403               orientation == IBUS_ORIENTATION_SYSTEM);
404
405     table->orientation = orientation;
406 }
407
408 gint
409 ibus_lookup_table_get_orientation (IBusLookupTable *table)
410 {
411     g_assert (IBUS_IS_LOOKUP_TABLE (table));
412
413     return table->orientation;
414 }
415
416
417 gboolean
418 ibus_lookup_table_page_up (IBusLookupTable *table)
419 {
420     g_assert (IBUS_IS_LOOKUP_TABLE (table));
421
422     if (table->cursor_pos < table->page_size) {
423         gint i;
424         gint page_nr;
425
426         if (!table->round) {
427             return FALSE;
428         }
429
430         /* cursor index in page */
431         i = table->cursor_pos % table->page_size;
432         page_nr = (table->candidates->len + table->page_size - 1) / table->page_size;
433
434         table->cursor_pos = page_nr * table->page_size + i;
435         if (table->cursor_pos >= table->candidates->len) {
436             table->cursor_pos = table->candidates->len - 1;
437         }
438         return TRUE;
439     }
440
441     table->cursor_pos -= table->page_size;
442     return TRUE;
443 }
444
445 gboolean
446 ibus_lookup_table_page_down (IBusLookupTable *table)
447 {
448     g_assert (IBUS_IS_LOOKUP_TABLE (table));
449
450     gint i;
451     gint page;
452     gint page_nr;
453
454     /* cursor index in page */
455     i = table->cursor_pos % table->page_size;
456     page = table->cursor_pos  / table->page_size;
457     page_nr = (table->candidates->len + table->page_size - 1) / table->page_size;
458
459     if (page == page_nr - 1) {
460         if (!table->round)
461             return FALSE;
462
463         table->cursor_pos = i;
464         return TRUE;
465     }
466
467     table->cursor_pos += table->page_size;
468     if (table->cursor_pos > table->candidates->len - 1) {
469         table->cursor_pos = table->candidates->len - 1;
470     }
471     return TRUE;
472 }
473
474 gboolean
475 ibus_lookup_table_cursor_up (IBusLookupTable *table)
476 {
477     g_assert (IBUS_IS_LOOKUP_TABLE (table));
478
479     if (table->cursor_pos == 0) {
480         if (!table->round)
481             return FALSE;
482
483         table->cursor_pos = table->candidates->len - 1;
484         return TRUE;
485     }
486
487     table->cursor_pos --;
488
489     return TRUE;
490 }
491
492 gboolean
493 ibus_lookup_table_cursor_down (IBusLookupTable *table)
494 {
495     g_assert (IBUS_IS_LOOKUP_TABLE (table));
496
497     if (table->cursor_pos == table->candidates->len - 1) {
498         if (!table->round)
499             return FALSE;
500
501         table->cursor_pos = 0;
502         return TRUE;
503     }
504
505     table->cursor_pos ++;
506     return TRUE;
507 }