Merge "custom eail widget implementation" into tizen
[platform/core/uifw/eail.git] / eail / eail_multibuttonentry.c
1 /*
2  * Copyright (c) 2013 Samsung Electronics Co., Ltd.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 /**
21  * @file eail_multibuttonentry.c
22  * @brief EailMultibuttonentry implementation
23  */
24
25 #include <Elementary.h>
26
27 #include "eail_multibuttonentry.h"
28 #include "eail_factory.h"
29 #include "eail_item_parent.h"
30 #include "eail_priv.h"
31 #include "eail_utils.h"
32 #include "eail_clipboard.h"
33
34 static void eail_item_parent_interface_init(EailItemParentIface *iface);
35 static void atk_editable_text_interface_init(AtkEditableTextIface *iface);
36 static void atk_text_interface_init(AtkTextIface *iface);
37
38 /**
39  * @brief EailMultibuttonentry type definition
40  */
41 G_DEFINE_TYPE_WITH_CODE(EailMultibuttonentry,
42                         eail_multibuttonentry,
43                         EAIL_TYPE_ACTION_WIDGET,
44                         G_IMPLEMENT_INTERFACE(ATK_TYPE_TEXT,
45                                               atk_text_interface_init)
46                         G_IMPLEMENT_INTERFACE(ATK_TYPE_EDITABLE_TEXT,
47                                               atk_editable_text_interface_init)
48                         G_IMPLEMENT_INTERFACE(EAIL_TYPE_ITEM_PARENT,
49                                               eail_item_parent_interface_init));
50
51 /**
52  * @brief Checks if content get is supported
53  *
54  * Implementation of EailItemParent->is_content_get_supported callback.
55  *
56  * @param parent EailItemParent instance
57  * @param item EailItem instance
58  * @returns always FALSE
59  */
60 gboolean
61 eail_multibuttonentry_content_get_support(EailItemParent   *parent,
62                                           EailItem         *item)
63 {
64    return FALSE;
65 }
66
67 /**
68  * @brief Gets the name of a multibuttonentry's child
69  *
70  * Implementation of get_item_name callback of EailItemParent interface.
71  *
72  * @param parent EailItemParent instance representing a multibuttonentry
73  * @param item Multibuttonentry EailItem instance representing a child
74  *
75  * @returns string representing the name of the child
76  */
77 static const gchar *
78 eail_multibuttonentry_item_name_get(EailItemParent *parent, EailItem *item)
79 {
80    Elm_Object_Item *it = eail_item_get_item(item);
81    /*that will work only for default theme*/
82    if (!it) return NULL;
83
84    return elm_object_item_part_text_get(it, NULL);
85 }
86
87 /**
88  * @brief EailItemParent interface initializer
89  *
90  * Initialization of callbacks used by EailItemParent interface.
91  *
92  * @param iface EailItemParentIface instance
93  */
94 static void
95 eail_item_parent_interface_init(EailItemParentIface *iface)
96 {
97    iface->is_content_get_supported = eail_multibuttonentry_content_get_support;
98    iface->get_item_name = eail_multibuttonentry_item_name_get;
99 }
100
101 /**
102  * @brief Helper function for getting multibuttonentry text
103  *
104  * @param text an AtkText (EailMultibutton object)
105  *
106  * @return string representation of multibutton entry text
107  */
108 static const gchar*
109 _eail_multibuttonentry_get_entry_string(AtkText *text)
110 {
111    const gchar *string = NULL;
112    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
113    Evas_Object *entry = elm_multibuttonentry_entry_get(widget);
114
115    if (entry)
116      string = elm_entry_entry_get(entry);
117
118    /* if entry string is empty then trying to return "guide" part*/
119    if (!string || 0 == g_strcmp0(string, ""))
120      {
121         /* If there are some children of widget, then it means that guide
122          * is not visible. So returning guide as text only if no children
123          * exist */
124         if (!elm_multibuttonentry_items_get(widget))
125           string = elm_object_part_text_get(widget, "guide");
126      }
127
128    return string;
129 }
130
131 /**
132  * @brief Gets text bounded by start_offset and end_offset
133  *
134  * Use g_free() to free the returned string.
135  *
136  * @param text AtkText instance
137  * @param start_offset start position
138  * @param end_offset end position or -1 for the end of the string
139  * @return string containing text from start_offset up to, but not including
140  * end_offset
141  */
142 static gchar*
143 eail_multibuttonentry_get_text(AtkText   *text,
144                    gint       start_offset,
145                    gint       end_offset)
146 {
147    const gchar *string = NULL;
148
149    string = _eail_multibuttonentry_get_entry_string(text);
150
151    return eail_get_substring(string, start_offset, end_offset);
152 }
153
154 /**
155  * @brief Gets the character at offset
156  *
157  * @param text AtkText instance
158  * @param offset offset to obtain the character from
159  * @return char representing the character at given offset
160  */
161 static gunichar
162 eail_multibuttonentry_get_character_at_offset(AtkText    *text,
163                                               gint        offset)
164 {
165    gunichar character = '\0';
166
167    character = g_utf8_get_char(
168          g_utf8_offset_to_pointer
169                      (_eail_multibuttonentry_get_entry_string(text), offset));
170
171    return character;
172 }
173
174 /**
175  * @brief Gets the length of text
176  *
177  * @param text AtkText instance
178  * @return integer representing text's length
179  */
180 static gint
181 eail_multibuttonentry_get_character_count(AtkText *text)
182 {
183    gint count = 0;
184    const gchar *string_text = NULL;
185
186    string_text = _eail_multibuttonentry_get_entry_string(text);
187    if (!string_text) return count;
188
189    count = g_utf8_strlen(string_text, -1);
190
191    return count;
192 }
193
194 /**
195  * @brief Gets caret offset
196  *
197  * @param text an AtkText
198  * @return caret offset
199  */
200 static gint
201 eail_multibuttonentry_get_caret_offset(AtkText *text)
202 {
203    Evas_Object *widget;
204    Evas_Object *entry;
205
206    widget = eail_widget_get_widget(EAIL_WIDGET(text));
207    if (!widget)
208      return 0;
209
210    entry = elm_multibuttonentry_entry_get(widget);
211    if (!entry)
212      return 0;
213
214    return elm_entry_cursor_pos_get(entry);
215 }
216
217 /**
218  * @brief Sets offset for caret
219  *
220  * Implementation of AtkTextIface->set_caret_offset callback
221  * ATK doc says:
222  * Sets the caret (cursor) position to the specified offset.
223  *
224  * @param text an AtkText
225  * @param offset starting position
226  *
227  * @returns TRUE if success, FALSE otherwise.
228  */
229 static gboolean
230 eail_multibuttonentry_set_caret_offset (AtkText *text,
231                              gint     offset)
232 {
233    Evas_Object *widget;
234    Evas_Object *entry;
235
236    widget = eail_widget_get_widget(EAIL_WIDGET(text));
237    if (!widget)
238      return FALSE;
239
240    entry = elm_multibuttonentry_entry_get(widget);
241    if (!entry)
242      return FALSE;
243
244    elm_entry_cursor_pos_set(entry,offset);
245
246    return TRUE;
247 }
248
249 /**
250  * @brief Get the bounding box containing the glyph
251  *  representing the character at a particular text offset.
252  *
253  * @param text AtkText instance
254  * @param offset The offset of the text character for which
255  * bounding information is required.
256  * @param x Pointer for the x cordinate of the bounding box
257  * @param y Pointer for the y cordinate of the bounding box
258  * @param width Pointer for the width of the bounding box
259  * @param height Pointer for the height of the bounding box
260  * @param coords specify whether coordinates are relative to the
261  * screen or widget window
262  *
263  */
264 static void
265 eail_multibuttonentry_get_character_extents(AtkText *text,
266                                             gint offset,
267                                             gint *x,
268                                             gint *y,
269                                             gint *width,
270                                             gint *height,
271                                             AtkCoordType coords)
272 {
273    int result = -1;
274    Evas_Object *textblock = NULL;
275    Evas_Textblock_Cursor *cur = NULL;
276    Evas_Object *entry = NULL;
277
278    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
279
280    if (!widget) return;
281
282    entry = elm_multibuttonentry_entry_get(widget);
283
284    if (!entry) return;
285
286    textblock = elm_entry_textblock_get(entry);
287    cur = evas_object_textblock_cursor_new(textblock);
288    evas_textblock_cursor_pos_set(cur, offset);
289
290    result = evas_textblock_cursor_char_geometry_get(cur, x, y, width, height);
291
292    evas_textblock_cursor_free(cur);
293
294    if (-1 == result) return;
295
296    if (coords == ATK_XY_SCREEN)
297    {
298       int ee_x, ee_y;
299       Ecore_Evas *ee= ecore_evas_ecore_evas_get(evas_object_evas_get(widget));
300
301       ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
302       *x += ee_x;
303       *y += ee_y;
304     }
305 }
306
307 /*
308  * @brief Gets the offset of the character located at coordinates
309  * x and y. x and y are interpreted as being relative to the
310  *  screen or this widget's window depending on coords.
311  *
312  * @param text AtkText instance
313  * @param x screen x-position of character
314  * @param y screen y-position of character
315  * @param coords specify whether coordinates are relative to the
316  * screen or widget window
317  *
318  * @returns the offset to the character which is located at the
319  * specified x and y coordinates.
320  */
321 static gint
322 eail_multibuttonentry_get_offset_at_point(AtkText *text,
323                                           gint x,
324                                           gint y,
325                                           AtkCoordType coords)
326 {
327    Eina_Bool result = EINA_FALSE;
328    Evas_Object *textblock = NULL;
329    Evas_Textblock_Cursor *cur = NULL;
330    gint offset = -1;
331
332    Evas_Object *entry = NULL;
333    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
334
335    if (!widget) return offset;
336
337    entry = elm_multibuttonentry_entry_get(widget);
338
339    if (!entry) return offset;
340
341    if (coords == ATK_XY_SCREEN)
342    {
343       int ee_x, ee_y;
344       Ecore_Evas *ee= ecore_evas_ecore_evas_get(evas_object_evas_get(entry));
345
346       ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
347       x -= ee_x;
348       y -= ee_y;
349     }
350
351    textblock = elm_entry_textblock_get(entry);
352    if (!textblock) return offset;
353
354    cur = evas_object_textblock_cursor_new(textblock);
355    if (!cur) return offset;
356    result = evas_textblock_cursor_char_coord_set(cur, x, y);
357
358    if (result == EINA_FALSE)
359    {
360       evas_textblock_cursor_free(cur);
361       return offset;
362    }
363
364    offset = evas_textblock_cursor_pos_get(cur);
365    evas_textblock_cursor_free(cur);
366
367    return offset;
368 }
369
370 /**
371  * @brief Adds a selection bounded by the specified offsets
372  *
373  * @param text AtkText instance
374  * @param start_offset start position of the selection
375  * @param end_offset offset of the first character after selection
376  * @returns TRUE on success, FALSE otherwise
377  */
378 static gboolean
379 eail_multibuttonentry_add_selection(AtkText *text,
380                          gint start_offset,
381                          gint end_offset)
382 {
383    Evas_Object *widget;
384    Evas_Object *entry;
385
386    widget = eail_widget_get_widget(EAIL_WIDGET(text));
387    if (!widget)
388      return FALSE;
389
390    entry = elm_multibuttonentry_entry_get(widget);
391    if (!entry)
392      return FALSE;
393
394    elm_entry_cursor_pos_set(entry, start_offset);
395    elm_entry_cursor_selection_begin(entry);
396    elm_entry_cursor_pos_set(entry, end_offset);
397    elm_entry_cursor_selection_end(entry);
398
399    EAIL_MULTIBUTTONENTRY(text)->selection_start = start_offset;
400    EAIL_MULTIBUTTONENTRY(text)->selection_end = end_offset;
401
402    return TRUE;
403 }
404
405 /**
406  * @brief Removes text selection
407  *
408  * This widget supports only one selection
409  * so selection_num should always be 0.
410  *
411  * @param text AtkText instance
412  * @param selection_num selection number
413  * @return TRUE on success, FALSE otherwise
414  */
415 static gboolean
416 eail_multibuttonentry_remove_selection(AtkText *text,
417                             gint selection_num)
418 {
419    Evas_Object *widget;
420    Evas_Object *entry;
421
422    widget = eail_widget_get_widget(EAIL_WIDGET(text));
423    if (!widget)
424      return FALSE;
425
426    entry = elm_multibuttonentry_entry_get(widget);
427    if (!entry)
428      return FALSE;
429
430    if (selection_num != 0 || !elm_entry_selection_get(entry))
431      return FALSE;
432
433    elm_entry_select_none(entry);
434    EAIL_MULTIBUTTONENTRY(text)->selection_start = 0;
435    EAIL_MULTIBUTTONENTRY(text)->selection_end = 0;
436
437    return TRUE;
438 }
439
440 /**
441  * @brief Sets text selection for multibuttonentry
442  *
443  * This widget supports only one selection
444  * so selection_num should always be 0.
445  *
446  * @param text AtkText instance
447  * @param selection_num selection number
448  * @param start_pos start position of the selected region
449  * @param end_pos end position of the selected region
450  *
451  * @returns TRUE on success, FALSE otherwise
452  */
453 static gboolean
454 eail_multibuttonentry_set_selection(AtkText *text,
455                          gint     selection_num,
456                          gint     start_pos,
457                          gint     end_pos)
458 {
459    if (0 != selection_num)
460      return FALSE;
461
462    return eail_multibuttonentry_add_selection(text, start_pos, end_pos);
463 }
464
465 /**
466  * @brief Gets text selection from multibuttonentry
467  *
468  * Use g_free() to free the returned string.
469  *
470  * This widget supports only one selection
471  * so selection_num should always be 0.
472  *
473  * @param text AtkText instance
474  * @param selection_num selection number
475  * @param start_offset start position of the selected region
476  * @param end_offset end position of the selected region
477  *
478  * @returns newly allocated string containing the selected text
479  */
480 static gchar *
481 eail_multibuttonentry_get_selection(AtkText *text,
482                          gint     selection_num,
483                          gint    *start_offset,
484                          gint    *end_offset)
485 {
486    const char* selection;
487    Evas_Object *widget;
488    Evas_Object *entry;
489
490    if (0 != selection_num)
491      return g_strdup("");
492
493    widget = eail_widget_get_widget(EAIL_WIDGET(text));
494    if (!widget)
495      return g_strdup("");
496
497    entry = elm_multibuttonentry_entry_get(widget);
498    if (!widget)
499      return g_strdup("");
500
501    selection = elm_entry_selection_get(entry);
502    if (selection)
503    {
504      *start_offset = EAIL_MULTIBUTTONENTRY(text)->selection_start;
505      *end_offset = EAIL_MULTIBUTTONENTRY(text)->selection_end;
506      return g_strdup(selection);
507    }
508
509    return g_strdup("");
510 }
511
512
513 /**
514  * @brief Gets the number of selected text regions
515  *
516  * Only one selection is supported by this widget
517  * so the returned value is 0 or 1.
518  *
519  * @param text AtkText instance
520  * @returns integer representing the number of
521  * selected text regions
522  */
523 static gint
524 eail_multibuttonentry_get_n_selections(AtkText *text)
525 {
526    Evas_Object *widget;
527    Evas_Object *entry;
528
529    widget = eail_widget_get_widget(EAIL_WIDGET(text));
530    if (!widget)
531      return 0;
532
533    entry = elm_multibuttonentry_entry_get(widget);
534    if (!entry)
535      return 0;
536
537    if (elm_entry_selection_get(entry))
538      return 1;
539
540    return 0;
541 }
542
543 /*
544  * @brief Gets the specified text after offset
545  *
546  * Use g_free() to free the returned string.
547  *
548  * @param text AtkText instance
549  * @param offset character offset
550  * @param boundary_type AtkTextBoundary instance
551  * @param [out] start_offset start offset of the returned string
552  * @param [out] end_offset offset of the first character after the returned
553  * substring
554  * @returns newly allocated string containing the text after offset bounded
555  * by the specified boundary_type
556  */
557 static gchar *
558 eail_multibuttonentry_get_text_after_offset(AtkText *text,
559                                             gint offset,
560                                             AtkTextBoundary boundary_type,
561                                             gint *start_offset,
562                                             gint *end_offset)
563 {
564    Evas_Object *widget;
565    Evas_Object *textblock;
566    Evas_Object *entry = NULL;
567
568    widget = eail_widget_get_widget(EAIL_WIDGET(text));
569    if (!widget) return NULL;
570
571    entry = elm_multibuttonentry_entry_get(widget);
572    if (!entry) return NULL;
573
574    textblock = elm_entry_textblock_get(entry);
575
576    return eail_get_text_after(textblock, offset, boundary_type, start_offset,
577                               end_offset);
578
579 }
580
581 /**
582  * @brief Gets the specified text at offset
583  *
584  * Use g_free() to free the returned string.
585  *
586  * @param text AtkText instance
587  * @param offset character offset
588  * @param boundary_type AtkTextBoundary instance
589  * @param [out] start_offset start offset of the returned string
590  * @param [out] end_offset offset of the first character after the returned
591  * substring
592  * @returns newly allocated string containing the text after offset bounded
593  * by the specified boundary_type
594  */
595 static gchar *
596 eail_multibuttonentry_get_text_at_offset(AtkText *text,
597                                          gint offset,
598                                          AtkTextBoundary boundary_type,
599                                          gint *start_offset,
600                                          gint *end_offset)
601 {
602    Evas_Object *widget;
603    Evas_Object *textblock;
604    Evas_Object *entry = NULL;
605
606    widget = eail_widget_get_widget(EAIL_WIDGET(text));
607    if (!widget) return NULL;
608
609    entry = elm_multibuttonentry_entry_get(widget);
610    if (!entry) return NULL;
611
612    textblock = elm_entry_textblock_get(entry);
613
614    return eail_get_text_at(textblock, offset, boundary_type, start_offset,
615                            end_offset);
616 }
617
618 /**
619  * @brief Gets the specified text before offset
620  *
621  * Use g_free() to free the returned string.
622  *
623  * @param text AtkText instance
624  * @param offset character offset
625  * @param boundary_type AtkTextBoundary instance
626  * @param [out] start_offset start offset of the returned string
627  * @param [out] end_offset offset of the first character after the returned
628  * substring
629  * @returns newly allocated string containing the text after offset bounded
630  * by the specified boundary_type
631  */
632 static gchar *
633 eail_multibuttonentry_get_text_before_offset(AtkText *text,
634                                              gint offset,
635                                              AtkTextBoundary boundary_type,
636                                              gint *start_offset,
637                                              gint *end_offset)
638 {
639    Evas_Object *widget;
640    Evas_Object *textblock;
641    Evas_Object *entry = NULL;
642
643    widget = eail_widget_get_widget(EAIL_WIDGET(text));
644    if (!widget) return NULL;
645
646    entry = elm_multibuttonentry_entry_get(widget);
647    if (!entry) return NULL;
648
649    textblock = elm_entry_textblock_get(entry);
650
651    return eail_get_text_before(textblock, offset, boundary_type, start_offset,
652                                end_offset);
653 }
654
655 /**
656  * @brief Creates an AtkAttributeSet which consists of the default values of
657  * attributes for the text
658  *
659  * The returned AtkAttributeSet should be freed by a call to
660  * atk_attribute_set_free().
661  *
662  * @param text AtkText instance
663  *
664  * @returns AtkAttributeSet which contains the default values of attributes
665  * at offset
666  */
667 static AtkAttributeSet *
668 eail_multibuttonentry_get_default_attributes(AtkText *text)
669 {
670    AtkAttributeSet *at_set = NULL;
671
672    at_set = eail_utils_text_add_attribute
673        (at_set, ATK_TEXT_ATTR_WRAP_MODE,
674         atk_text_attribute_get_value(ATK_TEXT_ATTR_WRAP_MODE, 0));
675
676    at_set = eail_utils_text_add_attribute
677        (at_set, ATK_TEXT_ATTR_EDITABLE,
678         atk_text_attribute_get_value
679          (ATK_TEXT_ATTR_EDITABLE, TRUE));
680
681    return at_set;
682 }
683
684 /**
685  * @brief Creates an AtkAttributeSet which consists of the attributes
686  * explicitly set at the position offset in the text
687  *
688  * start_offset and end_offset are set to the start and end of the range
689  * around offset where the attributes are invariant. Note that end_offset
690  * is the offset of the first character after the range.
691  *
692  * The returned AtkAttributeSet should be freed by a call to
693  * atk_attribute_set_free()
694  *
695  * @param text AtkText instance
696  * @param offset offset at which to get the attributes
697  * @param [out] start_offset start offset of the range
698  * @param [out] end_offset end offset of the range
699  *
700  * @returns AtkAttributeSet which contains the attributes explicitly set at
701  * offset
702  */
703 static AtkAttributeSet *
704 eail_multibuttonentry_get_run_attributes(AtkText *text,
705                                          gint offset,
706                                          gint *start_offset,
707                                          gint *end_offset)
708 {
709    AtkAttributeSet *at_set = NULL;
710    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
711    Evas_Object *entry = NULL;
712
713    if (!widget || offset >= eail_multibuttonentry_get_character_count(text))
714      {
715         *start_offset = -1;
716         *end_offset = -1;
717
718         return NULL;
719      }
720
721    entry = elm_multibuttonentry_entry_get(widget);
722    if (!entry) return NULL;
723
724
725    *start_offset = 0;
726    *end_offset = eail_multibuttonentry_get_character_count(text);
727
728    /* NOTE: Elm_Wrap_Type value is in 100% compatible with ATK wrap modes, so
729     * no additional conversion is needed*/
730    Elm_Wrap_Type wrap_type = elm_entry_line_wrap_get(entry);
731    at_set = eail_utils_text_add_attribute
732        (at_set, ATK_TEXT_ATTR_WRAP_MODE,
733         atk_text_attribute_get_value
734          (ATK_TEXT_ATTR_WRAP_MODE, wrap_type));
735
736    Eina_Bool editable = elm_entry_editable_get(entry);
737    at_set = eail_utils_text_add_attribute
738        (at_set, ATK_TEXT_ATTR_EDITABLE,
739         atk_text_attribute_get_value
740          (ATK_TEXT_ATTR_EDITABLE, editable));
741
742    return at_set;
743 }
744
745 /**
746  * @brief AktText initialization function
747  *
748  * @param iface AtkTextIface instance
749  */
750 static void
751 atk_text_interface_init(AtkTextIface *iface)
752 {
753    iface->get_text = eail_multibuttonentry_get_text;
754    iface->get_character_at_offset = eail_multibuttonentry_get_character_at_offset;
755    iface->get_character_count = eail_multibuttonentry_get_character_count;
756    iface->get_caret_offset = eail_multibuttonentry_get_caret_offset;
757    iface->set_caret_offset = eail_multibuttonentry_set_caret_offset;
758    iface->get_character_extents = eail_multibuttonentry_get_character_extents;
759    iface->add_selection    = eail_multibuttonentry_add_selection;
760    iface->remove_selection = eail_multibuttonentry_remove_selection;
761    iface->get_selection    = eail_multibuttonentry_get_selection;
762    iface->set_selection    = eail_multibuttonentry_set_selection;
763    iface->get_n_selections = eail_multibuttonentry_get_n_selections;
764    iface->get_text_after_offset = eail_multibuttonentry_get_text_after_offset;
765    iface->get_text_at_offset = eail_multibuttonentry_get_text_at_offset;
766    iface->get_text_before_offset = eail_multibuttonentry_get_text_before_offset;
767    iface->get_run_attributes = eail_multibuttonentry_get_run_attributes;
768    iface->get_default_attributes = eail_multibuttonentry_get_default_attributes;
769    iface->get_offset_at_point = eail_multibuttonentry_get_offset_at_point;
770 }
771
772 /**
773  * @brief Sets text contents of text
774  *
775  * @param text AtkEditableText instance
776  * @param string new text to be set
777  */
778 static void
779 eail_multibuttonentry_set_text_contents(AtkEditableText *text,
780                                         const gchar *string)
781 {
782    Evas_Object *entry;
783    Evas_Object *widget;
784
785    widget = eail_widget_get_widget(EAIL_WIDGET(text));
786    if (!widget) return;
787
788    entry = elm_multibuttonentry_entry_get(widget);
789    if (!entry) return;
790
791    if (elm_multibuttonentry_editable_get(widget))
792      elm_entry_entry_set(entry, string);
793 }
794
795 /**
796  * @brief Copies text content from entry to clipboard
797  *
798  * @param text AtkEditableText instance
799  * @param start_pos index of copied text's first character
800  * @param end_pos index of last copied text's last character
801  */
802 static void
803 eail_multibuttonentry_copy_text(AtkEditableText *text,
804                      gint             start_pos,
805                      gint             end_pos)
806 {
807    Evas_Object *widget;
808    Evas_Object *entry;
809    const char *entry_text;
810    char *tmp;
811
812
813    widget = eail_widget_get_widget(EAIL_WIDGET(text));
814    if (!widget) return;
815
816    entry = elm_multibuttonentry_entry_get(widget);
817    entry_text = elm_entry_entry_get(entry);
818    tmp = eail_get_substring(entry_text, start_pos, end_pos);
819    eail_clipboard_set_text(tmp);
820    g_free(tmp);
821 }
822
823 /**
824  * @brief Cuts text content from entry to clipboard
825  *
826  * @param text AtkEditableText instance
827  * @param start_pos index of cut text's first character
828  * @param end_pos index of cut text's last character
829  */
830 static void
831 eail_multibuttonentry_cut_text(AtkEditableText *text,
832                     gint             start_pos,
833                     gint             end_pos)
834 {
835    Evas_Object *widget;
836    Evas_Object *entry;
837    const char *entry_text;
838    char *tmp;
839    GString *s;
840
841
842    widget = eail_widget_get_widget(EAIL_WIDGET(text));
843    if (!widget || !elm_multibuttonentry_editable_get(widget)) return;
844
845    entry = elm_multibuttonentry_entry_get(widget);
846    entry_text = elm_entry_entry_get(entry);
847    tmp = eail_get_substring(entry_text, start_pos, end_pos);
848    eail_clipboard_set_text(tmp);
849    g_free(tmp);
850
851    s = g_string_new(entry_text);
852    s = g_string_erase(s, start_pos, end_pos - start_pos);
853
854    elm_entry_entry_set(entry, s->str);
855    g_string_free(s, TRUE);
856 }
857
858 /**
859  * @brief Pastes text content from clipboard into entry
860  *
861  * @param text AtkEditableText instance
862  * @param position index of pasted text's first character
863  */
864 static void
865 eail_multibuttonentry_paste_text(AtkEditableText *text,
866                                  gint position)
867 {
868    Evas_Object *widget;
869    Evas_Object *entry = NULL;
870    GString *s;
871    const char *tmp;
872
873    widget = eail_widget_get_widget(EAIL_WIDGET(text));
874    if (!widget || !elm_multibuttonentry_editable_get(entry))
875      return;
876
877    entry = elm_multibuttonentry_entry_get(widget);
878    s = g_string_new(elm_entry_entry_get(entry));
879    tmp = eail_clipboard_get_text();
880    s = g_string_insert(s, position, tmp);
881    elm_entry_entry_set(entry, s->str);
882    g_string_free(s, TRUE);
883 }
884
885 /**
886  * @brief Deletes text between start_pos and end_pos but not
887  * including end_pos
888  *
889  * @param text AtkEditableText instance
890  * @param start_pos start position
891  * @param end_pos end position
892  */
893 static void
894 eail_multibuttonentry_delete_text(AtkEditableText *text,
895                        gint start_pos,
896                        gint end_pos)
897 {
898    Evas_Object *widget;
899    Evas_Object *entry;
900    GString *s;
901
902    widget = eail_widget_get_widget(EAIL_WIDGET(text));
903    if (!widget || !elm_multibuttonentry_editable_get(widget)) return;
904
905    entry = elm_multibuttonentry_entry_get(widget);
906    s = g_string_new(elm_entry_entry_get(entry));
907    s = g_string_erase(s, start_pos, end_pos-start_pos);
908    elm_entry_entry_set(entry, s->str);
909    g_string_free(s, TRUE);
910 }
911
912 /**
913  * @brief Inserts text at the given position
914  *
915  * After the call it points at the position after the newly inserted text.
916  *
917  * @param text AtkEditableText instance
918  * @param string string to insert
919  * @param length string length
920  * @param [out] position position to insert the text
921  *
922  */
923 static void
924 eail_multibuttonentry_insert_text(AtkEditableText *text,
925                        const gchar *string,
926                        gint length,
927                        gint *position)
928 {
929    Evas_Object *widget;
930    Evas_Object *entry;
931    GString *s;
932
933    widget = eail_widget_get_widget(EAIL_WIDGET(text));
934    if (!widget || !elm_multibuttonentry_editable_get(widget))
935      return;
936
937    entry = elm_multibuttonentry_entry_get(widget);
938    s = g_string_new(elm_entry_entry_get(entry));
939    s = g_string_insert_len(s, *position, string, length);
940    elm_entry_entry_set(entry, s->str);
941    g_string_free(s, TRUE);
942    *position += length;
943 }
944
945 /**
946  * @brief Initialization for AtkEditableTextIface interface
947  *
948  * Function called upon instance creation.
949  *
950  * It initializes AtkText interface
951  * implementation i.e hooks method pointers in the interface structure
952  * to the implementing class's implementation.
953  *
954  * @param iface AtkEditableTextIface instance
955  */
956 static void
957 atk_editable_text_interface_init(AtkEditableTextIface *iface)
958 {
959    iface->set_text_contents = eail_multibuttonentry_set_text_contents;
960    iface->copy_text = eail_multibuttonentry_copy_text;
961    iface->cut_text = eail_multibuttonentry_cut_text;
962    iface->paste_text = eail_multibuttonentry_paste_text;
963    iface->delete_text = eail_multibuttonentry_delete_text;
964    iface->insert_text = eail_multibuttonentry_insert_text;
965 }
966
967 /**
968  * @brief 'expand' action callback
969  *
970  * @param action AtkAction instance
971  * @param data user data passed to callback
972  *
973  * @returns TRUE on action success, FALSE otherwise
974  */
975 static gboolean
976 eail_multibuttonentry_action_expand_cb(AtkAction *action, void *data)
977 {
978    Evas_Object *widget;
979
980    widget = eail_widget_get_widget(EAIL_WIDGET(action));
981    if (!widget) return FALSE;
982
983    if ((elm_object_disabled_get(widget)) || (!evas_object_visible_get(widget)))
984      return FALSE;
985
986    if (elm_multibuttonentry_expanded_get(widget)) return FALSE;
987
988    elm_multibuttonentry_expanded_set(widget, EINA_TRUE);
989    atk_object_notify_state_change(ATK_OBJECT(action), ATK_STATE_EXPANDED, TRUE);
990
991    return TRUE;
992 }
993
994 /**
995  * @brief 'shrink' action callback
996  *
997  * @param action AtkAction instance
998  * @param data user data passed to callback
999  *
1000  * @returns TRUE on action success, FALSE otherwise
1001  */
1002 static gboolean
1003 eail_multibuttonentry_action_shrink_cb(AtkAction *action, void *data)
1004 {
1005    Evas_Object *widget;
1006
1007    widget = eail_widget_get_widget(EAIL_WIDGET(action));
1008    if (!widget) return FALSE;
1009
1010    if ((elm_object_disabled_get(widget)) || (!evas_object_visible_get(widget)))
1011      return FALSE;
1012
1013    if (!elm_multibuttonentry_expanded_get(widget)) return FALSE;
1014
1015    elm_multibuttonentry_expanded_set(widget, EINA_FALSE);
1016    atk_object_notify_state_change(ATK_OBJECT(action), ATK_STATE_EXPANDED, FALSE);
1017
1018    return TRUE;
1019 }
1020
1021 /**
1022  * @brief Registers multibuttonentry's actions
1023  *
1024  * @param action_widget EailActionWidget instance
1025  */
1026 static void eail_multibuttonentry_actions_init(EailActionWidget *action_widget)
1027 {
1028    eail_action_widget_action_append(action_widget, "expand", NULL,
1029                                     eail_multibuttonentry_action_expand_cb);
1030    eail_action_widget_action_append(action_widget, "shrink", NULL,
1031                                     eail_multibuttonentry_action_shrink_cb);
1032 }
1033
1034 /**
1035  * @brief Handler for "item,added" event, used to notify about multibuttonentry
1036  * content changes
1037  *
1038  * @param data passed to callback
1039  * @param obj object that raised event
1040  * @param event_info additional event info (item is passed here)
1041  */
1042 static void
1043 eail_multibuttonentry_item_handle_added_event(void *data,
1044                                               Evas_Object *obj,
1045                                               void *event_info)
1046 {
1047    Elm_Object_Item *item = (Elm_Object_Item *) event_info;
1048    AtkObject *atk_item = NULL, *atk_parent = NULL;
1049
1050    atk_parent = ATK_OBJECT(data);
1051    if (!atk_parent) return;
1052
1053    atk_item = eail_factory_get_item_atk_obj
1054                                          (item, ATK_ROLE_LABEL, atk_parent);
1055
1056    if (!atk_item) return;
1057
1058    eail_emit_children_changed_obj(TRUE, atk_parent, atk_item);
1059 }
1060
1061 /**
1062  * @brief Handler for "item,deleted" event, used to notify about
1063  * multibuttonentry content changes
1064  *
1065  * @param data passed to callback
1066  * @param obj object that raised event
1067  * @param event_info additional event info (item is passed here)
1068  */
1069 static void
1070 eail_multibuttonentry_item_handle_removed_event(void *data,
1071                                                 Evas_Object *obj,
1072                                                 void *event_info)
1073 {
1074    Elm_Object_Item *item = (Elm_Object_Item *) event_info;
1075    AtkObject *atk_item = NULL, *atk_parent = NULL;
1076
1077    atk_parent = ATK_OBJECT(data);
1078    if (!atk_parent) return;
1079
1080    atk_item = eail_factory_get_item_atk_obj
1081                                          (item, ATK_ROLE_LABEL, atk_parent);
1082
1083    if (!atk_item) return;
1084
1085    eail_emit_children_changed_obj(FALSE, atk_parent, atk_item);
1086    atk_object_notify_state_change(atk_item, ATK_STATE_DEFUNCT, TRUE);
1087
1088    DBG("Unregistering item from cache...");
1089    eail_factory_unregister_item_from_cache(item);
1090 }
1091
1092 /**
1093  * @brief handler for event which is raised when entry cusror position is being changed
1094  *
1095  * @param data passed to callback
1096  * @param obj object that raised event
1097  * @param event_info additional event info
1098  */
1099 void
1100 _eail_multibuttonentry_handle_cursor_changed_event(void *data,
1101                                  Evas_Object *obj,
1102                                  void *event_info)
1103 {
1104    g_signal_emit_by_name (ATK_OBJECT(data), "text_caret_moved",
1105                                  elm_entry_cursor_pos_get(obj));
1106 }
1107
1108 /**
1109  * @brief EailMultibuttonentry type initializer
1110  * @param obj AtkObject instance
1111  * @param data initialization data
1112  */
1113 void
1114 eail_multibuttonentry_initialize(AtkObject *obj, gpointer data)
1115 {
1116    Evas_Object *nested_widget = NULL;
1117    ATK_OBJECT_CLASS(eail_multibuttonentry_parent_class)->initialize(obj, data);
1118    obj->role = ATK_ROLE_ENTRY;
1119
1120    eail_multibuttonentry_actions_init(EAIL_ACTION_WIDGET(obj));
1121
1122    nested_widget = eail_widget_get_widget(EAIL_WIDGET(obj));
1123    if (!nested_widget)
1124      {
1125         ERR("No evas object inside EailWidget was found");
1126         return;
1127      }
1128
1129    evas_object_smart_callback_add(nested_widget, "item,added",
1130                           eail_multibuttonentry_item_handle_added_event, obj);
1131    evas_object_smart_callback_add(nested_widget, "item,deleted",
1132                           eail_multibuttonentry_item_handle_removed_event, obj);
1133    evas_object_smart_callback_add(elm_multibuttonentry_entry_get(nested_widget),
1134                           "cursor,changed",
1135                           _eail_multibuttonentry_handle_cursor_changed_event, obj);
1136 }
1137
1138 /**
1139  * @brief EailMultibuttonentry instance initializer
1140  *
1141  * @param multibuttonentry EailMultibuttonentry instance
1142  */
1143 static void
1144 eail_multibuttonentry_init(EailMultibuttonentry *multibuttonentry)
1145 {
1146    multibuttonentry->selection_start = 0;
1147    multibuttonentry->selection_end = 0;
1148 }
1149
1150 /**
1151  * @brief Gets obj's state set
1152  *
1153  * The caller must unreference it when it is no longer needed.
1154  *
1155  * @param obj AtkObject instance
1156  * @return AtkStateSet containing object's state set
1157  */
1158 static AtkStateSet *
1159 eail_multibuttonentry_ref_state_set(AtkObject *obj)
1160 {
1161    AtkStateSet *state_set;
1162    Evas_Object *widget;
1163
1164    g_return_val_if_fail(EAIL_MULTIBUTTONENTRY(obj), NULL);
1165
1166    widget = eail_widget_get_widget(EAIL_WIDGET(obj));
1167    state_set = ATK_OBJECT_CLASS(eail_multibuttonentry_parent_class)->ref_state_set(obj);
1168
1169    if (!widget) return state_set;
1170
1171    if (elm_multibuttonentry_expanded_get(widget))
1172      {
1173         atk_state_set_add_state(state_set, ATK_STATE_EXPANDED);
1174
1175         if (elm_multibuttonentry_editable_get(widget))
1176             atk_state_set_add_state(state_set, ATK_STATE_EDITABLE);
1177      }
1178    else
1179      {
1180         atk_state_set_add_state(state_set, ATK_STATE_DEFAULT);
1181      }
1182
1183    return state_set;
1184 }
1185
1186 /**
1187  * @brief Gets the list of multibuttonentry's items
1188  *
1189  * @param multibuttonentry EailMultibuttonentry instance
1190  * @return Eina_List containing multibuttonentry's items
1191  * */
1192 static const Eina_List *
1193 eail_multibuttonentry_get_items(EailMultibuttonentry *multibuttonentry)
1194 {
1195    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(multibuttonentry));
1196    if (!widget) return NULL;
1197
1198    return elm_multibuttonentry_items_get(widget);
1199 }
1200
1201 /**
1202  * @brief Gets the number of accessible children of the accessible
1203  *
1204  * @param obj AtkObject instance
1205  * @return integer representing the number of accessible children of the accessible
1206  */
1207 static gint
1208 eail_multibuttonentry_get_n_children(AtkObject *obj)
1209 {
1210    gint n_items;
1211    const Eina_List *items;
1212
1213    items = eail_multibuttonentry_get_items(EAIL_MULTIBUTTONENTRY(obj));
1214    n_items = eina_list_count(items);
1215
1216    return n_items;
1217 }
1218
1219 /**
1220  * @brief Gets a reference to the specified child of obj
1221  *
1222  * The caller must unreference it when it is no longer needed.
1223  *
1224  * @param obj AtkObject instance
1225  * @param i child index
1226  * @return AtkObject containing reference to the specified child of obj
1227  */
1228 static AtkObject *
1229 eail_multibuttonentry_ref_child(AtkObject *obj, gint i)
1230 {
1231    const Eina_List *items;
1232    AtkObject *child = NULL;
1233
1234    items = eail_multibuttonentry_get_items(EAIL_MULTIBUTTONENTRY(obj));
1235    if (eina_list_count(items) > i)
1236      {
1237         child = eail_factory_get_item_atk_obj
1238             (eina_list_nth(items, i), ATK_ROLE_LABEL, obj);
1239
1240         g_object_ref(child);
1241      }
1242    else
1243      ERR("Tried to ref child with index %d out of bounds!", i);
1244
1245    return child;
1246 }
1247
1248 /**
1249  * @brief EailMultibuttonentry class initializer
1250  *
1251  * @param klass EailMultibuttonentryClass instance
1252  */
1253 static void
1254 eail_multibuttonentry_class_init(EailMultibuttonentryClass *klass)
1255 {
1256    AtkObjectClass *atk_class = ATK_OBJECT_CLASS(klass);
1257
1258    atk_class->initialize = eail_multibuttonentry_initialize;
1259    atk_class->get_n_children = eail_multibuttonentry_get_n_children;
1260    atk_class->ref_child = eail_multibuttonentry_ref_child;
1261    atk_class->ref_state_set = eail_multibuttonentry_ref_state_set;
1262 }