First commit. EAIL ver. 1.0.0
[platform/core/uifw/eail.git] / eail / eail / eail_entry.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_entry.c
22  * @brief Implementation of entry widget
23  */
24
25 #include <Elementary.h>
26
27 #include "eail_entry.h"
28 #include "eail_utils.h"
29 #include "eail_priv.h"
30 #include "eail_clipboard.h"
31
32 static void atk_text_interface_init(AtkTextIface *iface);
33 static void atk_editable_text_interface_init(AtkEditableTextIface *iface);
34
35 /**
36  * @brief Definition of EailEntry as GObject
37  *
38  * EailEntry is extended EAIL_TYPE_TEXT with ATK_TYPE_TEXT and
39  * ATK_TYPE_EDITABLE_TEXT interfaces implemented
40  */
41 G_DEFINE_TYPE_WITH_CODE(EailEntry,
42                         eail_entry,
43                         EAIL_TYPE_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
49 /**
50  * @brief handler for event which is raised when entry content is being changed
51  *
52  * @param data passed to callback
53  * @param obj object that raised event
54  * @param event_info additional event info
55  */
56 void
57 _eail_entry_handle_changed_event(void *data,
58                                  Evas_Object *obj,
59                                  void *event_info)
60 {
61    eail_emit_atk_signal
62                   (ATK_OBJECT(data), "visible-data-changed", ATK_TYPE_OBJECT);
63 }
64
65 /**
66  * @brief handler for event which is raised when entry content is being pressed
67  *
68  * @param data passed to callback
69  * @param obj object that raised event
70  * @param event_info additional event info
71  */
72 void
73 _eail_entry_handle_pressed_event(void *data,
74                                  Evas_Object *obj,
75                                  void *event_info)
76 {
77    atk_object_notify_state_change(ATK_OBJECT(data), ATK_STATE_PRESSED, TRUE);
78 }
79
80 /**
81  * @brief Initializer for AtkObject
82  *
83  * @param obj an AtkObject
84  * @param data Initialization data
85  */
86 static void
87 eail_entry_initialize(AtkObject *obj, gpointer data)
88 {
89    Evas_Object *nested_widget = NULL;
90    ATK_OBJECT_CLASS(eail_entry_parent_class)->initialize(obj, data);
91
92    obj->role = ATK_ROLE_ENTRY;
93
94    g_return_if_fail(EAIL_IS_WIDGET(obj));
95    nested_widget = eail_widget_get_widget(EAIL_WIDGET(obj));
96    if (!nested_widget)
97      {
98         ERR("No evas object inside EailWidget was found");
99         return;
100      }
101
102    evas_object_smart_callback_add(nested_widget, "changed",
103                                   _eail_entry_handle_changed_event, obj);
104    evas_object_smart_callback_add(nested_widget, "cursor,changed",
105                                   _eail_entry_handle_changed_event, obj);
106    evas_object_smart_callback_add(nested_widget, "press",
107                                   _eail_entry_handle_pressed_event, obj);
108 }
109
110 /**
111  * @brief Class destructor
112  *
113  * @param obj object instance
114  */
115 static void
116 eail_entry_finalize(GObject *obj)
117 {
118 }
119
120 /**
121  * @brief Implementation of AtkObject->ref_state_set callback
122  *
123  * ATK doc says:\n
124  * Gets a reference to the state set of the accessible; the caller must
125  * unreference it when it is no longer needed.
126  *
127  * @param obj an AtkObject
128  *
129  * @returns a reference to an AtkStateSet which is the state set of the
130  * accessible.
131  */
132 static AtkStateSet *
133 eail_entry_ref_state_set(AtkObject *obj)
134 {
135    AtkStateSet *state_set;
136    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(obj));
137
138    if (!widget)
139      return NULL;
140
141    state_set = ATK_OBJECT_CLASS(eail_entry_parent_class)->ref_state_set(obj);
142
143    if (elm_entry_editable_get(widget))
144      atk_state_set_add_state(state_set, ATK_STATE_EDITABLE);
145
146    if (elm_entry_single_line_get(widget))
147      atk_state_set_add_state(state_set, ATK_STATE_SINGLE_LINE);
148    else
149      atk_state_set_add_state(state_set, ATK_STATE_MULTI_LINE);
150
151    return state_set;
152 }
153
154 /**
155  * @brief Initializer for EailEntry GObject implementation
156  *
157  * @param entry an EailEntry
158  */
159 static void
160 eail_entry_init(EailEntry *entry)
161 {
162    entry->selection_start = 0;
163    entry->selection_end = 0;
164 }
165
166 /**
167  * @brief Initializer for EailPopup GObject class (defines callbacks for
168  * base AtkObject)
169  *
170  * @param klass an EailEntryClass
171  */
172 static void
173 eail_entry_class_init(EailEntryClass *klass)
174 {
175    AtkObjectClass *class = ATK_OBJECT_CLASS(klass);
176    GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
177
178    class->initialize = eail_entry_initialize;
179    class->ref_state_set = eail_entry_ref_state_set;
180    gobject_class->finalize = eail_entry_finalize;
181 }
182
183 /**
184  * @brief Gets caret offset
185  *
186  * @param text an AtkText
187  * @return caret offset
188  */
189 static gint
190 eail_entry_get_caret_offset(AtkText *text)
191 {
192    Evas_Object *widget;
193
194    widget = eail_widget_get_widget(EAIL_WIDGET(text));
195    if (!widget)
196      return 0;
197
198    return elm_entry_cursor_pos_get(widget);
199 }
200
201 /**
202  * @brief Sets offset for caret
203  *
204  * Implementation of AtkTextIface->set_caret_offset callback<br>
205  * ATK doc says:
206  * Sets the caret (cursor) position to the specified offset.
207  *
208  * @param text an AtkText
209  * @param offset starting position
210  *
211  * @returns TRUE if success, FALSE otherwise.
212  */
213 static gboolean
214 eail_entry_set_caret_offset (AtkText *text,
215                              gint     offset)
216 {
217    Evas_Object *widget;
218
219    widget = eail_widget_get_widget(EAIL_WIDGET(text));
220    if (!widget)
221      return FALSE;
222
223    elm_entry_cursor_pos_set(widget, offset);
224
225    return TRUE;
226 }
227
228 /**
229  * @brief Gets the number of selected text regions
230  *
231  * @param text an AtkText
232  * @returns number of selected text regions
233  */
234 static gint
235 eail_entry_get_n_selections(AtkText *text)
236 {
237    Evas_Object *widget;
238
239    widget = eail_widget_get_widget(EAIL_WIDGET(text));
240    if (!widget) return 0;
241
242    if (elm_entry_selection_get(widget)) return 1;
243
244    return 0;
245 }
246
247 /**
248  * @brief Gets text selection from entry
249  *
250  * Implementation of AtkTextIface->get_selection callback
251  *
252  * @param text an AtkText
253  * @param selection_num The selection number. The selected regions are assigned
254  * numbers that correspond to how far the region is from the start of the text.
255  * The selected region closest to the beginning of the text region is assigned
256  * the number 0, etc. Note that adding, moving or deleting a selected region can
257  *  change the numbering.
258  * @param start_offset passes back the start position of the selected region
259  * @param end_offset passes back the end position of the selected region
260  *
261  * @returns a newly allocated string containing the selected text. Use g_free()
262  * to free the returned string.
263  */
264 static gchar *
265 eail_entry_get_selection(AtkText *text,
266                          gint     selection_num,
267                          gint    *start_offset,
268                          gint    *end_offset)
269 {
270    const char* selection;
271    Evas_Object *widget;
272
273    widget = eail_widget_get_widget(EAIL_WIDGET(text));
274    if (!widget)
275      return g_strdup("");
276
277    if (0 != selection_num)
278      return g_strdup("");
279
280    selection = elm_entry_selection_get(widget);
281    if (selection)
282      {
283         *start_offset = EAIL_ENTRY(text)->selection_start;
284         *end_offset = EAIL_ENTRY(text)->selection_end;
285         return g_strdup(selection);
286      }
287
288    return g_strdup("");
289 }
290
291 /**
292  * @brief Adds a selection bounded by the specified offsets
293  *
294  * @param text an AtkText
295  * @param start_offset start position of the selection
296  * @param end_offset offset of the first character after selection
297  * @returns TRUE on success, FALSE otherwise
298  */
299 static gboolean
300 eail_entry_add_selection(AtkText *text,
301                          gint start_offset,
302                          gint end_offset)
303 {
304    Evas_Object *widget;
305
306    widget = eail_widget_get_widget(EAIL_WIDGET(text));
307    if (!widget) return FALSE;
308
309    elm_entry_cursor_pos_set(widget, start_offset);
310    elm_entry_cursor_selection_begin(widget);
311    elm_entry_cursor_pos_set(widget, end_offset);
312    elm_entry_cursor_selection_end(widget);
313
314    EAIL_ENTRY(text)->selection_start = start_offset;
315    EAIL_ENTRY(text)->selection_end = end_offset;
316
317    return TRUE;
318 }
319
320 /**
321  * @brief Removes text selection
322  *
323  * Only one selection is supported, so
324  * selection_number equals 0.
325  *
326  * @param text an AtkText
327  * @param selection_num selection number
328  * @return TRUE on success, FALSE otherwise
329  */
330 static gboolean
331 eail_entry_remove_selection(AtkText *text,
332                             gint selection_num)
333 {
334    Evas_Object *widget;
335
336    widget = eail_widget_get_widget(EAIL_WIDGET(text));
337    if (!widget) return FALSE;
338
339    if (selection_num != 0 || !elm_entry_selection_get(widget)) return FALSE;
340
341    elm_entry_select_none(widget);
342    EAIL_ENTRY(text)->selection_start = 0;
343    EAIL_ENTRY(text)->selection_end = 0;
344
345    return TRUE;
346 }
347
348 /**
349  * @brief Sets text selection for entry
350  *
351  * Implementation of AtkTextIface->set_selection callback
352  *
353  * @param text an AtkText
354  * @param selection_num The selection number. The selected regions are assigned
355  * numbers that correspond to how far the region is from the start of the text.
356  * The selected region closest to the beginning of the text region is assigned
357  * the number 0, etc. Note that adding, moving or deleting a selected region can
358  *  change the numbering.
359  * @param start_pos start position of the selected region
360  * @param end_pos end position of the selected region
361  *
362  * @returns TRUE if success, FALSE otherwise
363  */
364 static gboolean
365 eail_entry_set_selection(AtkText *text,
366                          gint     selection_num,
367                          gint     start_pos,
368                          gint     end_pos)
369 {
370    if (0 != selection_num)
371      return FALSE;
372
373    return eail_entry_add_selection(text, start_pos, end_pos);
374 }
375
376 /**
377  * @brief Gets text bounded by start_offset and end_offset
378  *
379  * Use g_free() to free the returned string
380  *
381  * @param text an AtkText
382  * @param start_offset start position
383  * @param end_offset end position, -1 for the end of the string
384  * @return string containing text from start_offset up to, but not including
385  * end_offset
386  */
387 static gchar*
388 eail_entry_get_text(AtkText   *text,
389                     gint       start_offset,
390                     gint       end_offset)
391 {
392    const gchar *string = NULL;
393    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
394
395    if (widget)
396      string = elm_entry_entry_get(widget);
397
398    return eail_get_substring(string, start_offset, end_offset);
399 }
400
401
402
403 /**
404  * @brief Returns the position that is count characters from the
405  * given offset.
406  *
407  * count may be positive or negative.
408  *
409  * @param textblock an evas textblock
410  * @param offset a character offset
411  * @param count the number of characters to move from offset
412  * @returns a new position
413  */
414 static gint
415 _eail_move_chars(const Evas_Object *textblock,
416                  gint offset,
417                  gint count)
418 {
419    Evas_Textblock_Cursor *cur;
420    gint dir;
421    gboolean res;
422
423    dir = count > 0 ? 1 : -1;
424    cur = evas_object_textblock_cursor_new(textblock);
425    evas_textblock_cursor_pos_set(cur, offset);
426
427    while(count)
428      {
429         res = dir > 0 ? evas_textblock_cursor_char_next(cur) :
430             evas_textblock_cursor_char_prev(cur);
431         if (!res) break;
432
433         count -= dir;
434      }
435
436    offset = evas_textblock_cursor_pos_get(cur);
437    evas_textblock_cursor_free(cur);
438
439    return offset;
440 }
441
442 /**
443  * @brief Gets utf8 character at offset
444  *
445  * @param textblock an evas textblock
446  * @param offset a character offset
447  * @returns a utf8 character
448  */
449 static gunichar
450 _eail_get_unichar_at_offset(const Evas_Object *textblock,
451                             int offset)
452 {
453    Evas_Textblock_Cursor *cur;
454    gchar *s;
455    gunichar c;
456
457    cur = evas_object_textblock_cursor_new(textblock);
458    evas_textblock_cursor_pos_set(cur, offset);
459    s = evas_textblock_cursor_content_get(cur);
460    c = g_utf8_get_char(s);
461
462    evas_textblock_cursor_free(cur);
463    g_free(s);
464
465    return c;
466 }
467
468 /**
469  * @brief Checks whether character at offset in textblock is a word start
470  *
471  * @param textblock an evas textblock
472  * @param offset a character offset
473  * @returns TRUE on success, FALSE otherwise
474  */
475 static gboolean
476 _eail_is_word_start(const Evas_Object *textblock,
477                     gint offset)
478 {
479    /* first character in a word */
480    gunichar c1, c2;
481
482    c1 = _eail_get_unichar_at_offset(textblock, offset);
483    c2 = _eail_get_unichar_at_offset(textblock, offset - 1);
484    if (g_unichar_isalnum(c1) && g_unichar_isspace(c2)) return TRUE;
485
486    return FALSE;
487 }
488
489 /**
490  * @brief Checks whether character at offset in textblock is a word end
491  *
492  * @param textblock an evas textblock
493  * @param offset a character offset
494  * @return TRUE on success, FALSE otherwise
495  */
496 static gboolean
497 _eail_is_word_end(const Evas_Object *textblock,
498                   gint offset)
499 {
500    /* is first non-word char after a word */
501    gunichar c1, c2;
502
503    c1 = _eail_get_unichar_at_offset(textblock, offset - 1);
504    c2 = _eail_get_unichar_at_offset(textblock, offset);
505    if (g_unichar_isalnum(c1) && g_unichar_isspace(c2)) return TRUE;
506
507    return FALSE;
508 }
509
510 /**
511  * @brief Check whether character at offset in textblock is inside a word
512  *
513  * @param textblock an evas textblock
514  * @param offset a character offset
515  * @returns TRUE on success, FALSE otherwise
516  */
517 static gboolean
518 _eail_is_inside_word(const Evas_Object *textblock,
519                      gint offset)
520 {
521    gunichar c1, c2, c3;
522
523    c1 = _eail_get_unichar_at_offset(textblock, offset - 1);
524    c2 = _eail_get_unichar_at_offset(textblock, offset);
525    c3 = _eail_get_unichar_at_offset(textblock, offset + 1);
526    if (g_unichar_isalnum(c1) && g_unichar_isalnum(c2) && g_unichar_isalnum(c3))
527      return TRUE;
528
529    if (g_unichar_isalnum(c1) && g_unichar_isalnum(c2) && g_unichar_isspace(c3))
530      return TRUE;
531
532    if (g_unichar_isspace(c1) && g_unichar_isalnum(c2) && g_unichar_isalnum(c3))
533      return TRUE;
534
535    if (g_unichar_isspace(c1) && g_unichar_isalnum(c2) && g_unichar_isspace(c3))
536      return TRUE;
537
538    return FALSE;
539 }
540
541 /**
542  * @brief Gets texblock length
543  *
544  * @param textblock an evas textblock
545  * @returns a textblock length
546  */
547 static gint
548 _eail_get_len(const Evas_Object *textblock)
549 {
550    Evas_Textblock_Cursor *cur;
551    int ctr = 0;
552
553    cur = evas_object_textblock_cursor_new(textblock);
554    while (evas_textblock_cursor_char_next(cur))
555      ++ctr;
556
557    evas_textblock_cursor_free(cur);
558
559    return ctr;
560 }
561
562 /**
563  * @brief Returns the position that is count words from the given offset.
564  *
565  * count may  be positive or negative. If count is positive, the returned
566  * position will be a word end, otherwise it will be a word start.
567  *
568  * @param textblock an evas textblock
569  * @param offset a cahracter offset
570  * @param count the number of words to move from offset
571  * @returns a new position
572  */
573 static gint
574 _eail_move_words(const Evas_Object *textblock,
575                  gint offset,
576                  gint count)
577 {
578    gint len = _eail_get_len(textblock);
579
580    while (count > 0 && offset < len)
581      {
582         do
583           offset++;
584         while (offset < len && !_eail_is_word_end(textblock, offset));
585
586         count--;
587      }
588    while (count < 0 && offset > 0)
589      {
590         do
591           offset--;
592         while (offset > 0 && !_eail_is_word_start(textblock, offset));
593
594         count++;
595      }
596
597    return offset;
598 }
599
600 /**
601  * @brief Gets position of first character in line
602  *
603  * @param cur an Evas_Textblock_Cursor
604  * @returns TRUE on success, FALSE otherwise
605  */
606 static gint
607 _eail_get_line_start(Evas_Textblock_Cursor *cur)
608 {
609    gint start = 0;
610    gint pos;
611
612    pos = evas_textblock_cursor_pos_get(cur);
613    evas_textblock_cursor_line_char_first(cur);
614    start = evas_textblock_cursor_pos_get(cur);
615    evas_textblock_cursor_pos_set(cur, pos);
616
617    return start;
618 }
619
620 /**
621  * @brief Gets position of last character in line
622  *
623  * @param cur an Evas_Textblock_Cursor
624  * @returns TRUE on success, FALSE otherwise
625  */
626 static gint
627 _eail_get_line_end(Evas_Textblock_Cursor *cur)
628 {
629    gint end = 0;
630    gint pos;
631
632    pos = evas_textblock_cursor_pos_get(cur);
633    evas_textblock_cursor_line_char_last(cur);
634    end = evas_textblock_cursor_pos_get(cur);
635    evas_textblock_cursor_pos_set(cur, pos);
636
637    return end;
638 }
639
640 /**
641  * @brief Moves cursor to the beginning of the next line
642  *
643  * @param cur an Evas_Textblock_Cursor
644  * @returns TRUE on success, FALSE otherwise
645  */
646 static gboolean
647 _eail_iter_next_line(Evas_Textblock_Cursor *cur)
648 {
649    evas_textblock_cursor_line_char_last(cur);
650
651    return evas_textblock_cursor_char_next(cur);
652 }
653
654 /**
655  * @brief Gets length of the line shown by cursor cur
656  *
657  * @param cur an Evas_Textblock_Cursor
658  * @return line length
659  */
660 static gint
661 _eail_get_line_length(Evas_Textblock_Cursor *cur)
662 {
663    gint start;
664    gint end;
665
666    start = _eail_get_line_start(cur);
667    end = _eail_get_line_end(cur);
668
669    return end - start + 1;
670 }
671
672 /**
673  * @brief Gets before at offset
674  *
675  * @param entry an Evas_Object
676  * @param boundary_type an AtkTextBoundary
677  * @param offset position
678  * @param [out] start_offset the start offset of the returned string
679  * @param [out] end_offset the offset of the first character after the
680  * returned substring
681  */
682 static void
683 _eail_get_line_before(Evas_Object     *entry,
684                       AtkTextBoundary  boundary_type,
685                       gint             offset,
686                       gint            *start_offset,
687                       gint            *end_offset)
688 {
689    Evas_Object *textblock;
690    Evas_Textblock_Cursor *cur, *prev_cur = NULL, *prev_prev_cur = NULL;
691    gint index, start_index, end_index;
692    const gchar *text;
693    gboolean found = FALSE;
694
695    textblock = elm_entry_textblock_get(entry);
696    cur = evas_object_textblock_cursor_new(textblock);
697
698    text = evas_textblock_text_markup_to_utf8(
699        textblock, evas_object_textblock_text_markup_get(textblock));
700    index = g_utf8_offset_to_pointer (text, offset) - text;
701    do
702      {
703         start_index = _eail_get_line_start(cur);
704         end_index = start_index + _eail_get_line_length(cur);
705
706         if (index >= start_index && index <= end_index)
707           {
708              /* Found line for offset */
709              if (prev_cur)
710                {
711                   switch (boundary_type)
712                     {
713                       case ATK_TEXT_BOUNDARY_LINE_START:
714                           end_index = start_index;
715                           start_index = _eail_get_line_start(prev_cur);
716                           break;
717                       case ATK_TEXT_BOUNDARY_LINE_END:
718                           if (prev_prev_cur)
719                             start_index = _eail_get_line_start(prev_prev_cur) +
720                                 _eail_get_line_length(prev_prev_cur);
721                           else
722                             start_index = 0;
723                           end_index = _eail_get_line_start(prev_cur) +
724                               _eail_get_line_length(prev_cur);
725                           break;
726                       default:
727                           g_assert_not_reached();
728                     }
729                }
730              else
731                start_index = end_index = 0;
732
733              found = TRUE;
734              break;
735           }
736
737         prev_prev_cur = prev_cur;
738         prev_cur = cur;
739      }
740    while (_eail_iter_next_line(cur));
741
742    if (!found)
743      {
744         start_index = _eail_get_line_start(prev_cur) +
745             _eail_get_line_length(prev_cur);
746         end_index = start_index;
747      }
748    evas_textblock_cursor_free(cur);
749
750    *start_offset = g_utf8_pointer_to_offset(text, text + start_index);
751    *end_offset = g_utf8_pointer_to_offset(text, text + end_index);
752 }
753
754 /**
755  * @brief Gets line after offset
756  *
757  * @param entry an Evas_Object
758  * @param boundary_type an AtkTextBoundary
759  * @param offset position
760  * @param [out] start_offset the start offset of the returned string
761  * @param [out] end_offset the offset of the first character after the
762  * returned substring
763  */
764 static void
765 _eail_get_line_after (Evas_Object     *entry,
766                       AtkTextBoundary  boundary_type,
767                       gint             offset,
768                       gint            *start_offset,
769                       gint            *end_offset)
770 {
771    Evas_Object *textblock;
772    Evas_Textblock_Cursor *cur, *prev_cur = NULL;
773    gint index, start_index, end_index;
774    const gchar *text;
775    gboolean found = FALSE;
776
777    textblock = elm_entry_textblock_get(entry);
778    cur = evas_object_textblock_cursor_new(textblock);
779    text = evas_textblock_text_markup_to_utf8(
780        textblock, evas_object_textblock_text_markup_get(textblock));
781
782    index = g_utf8_offset_to_pointer (text, offset) - text;
783    do
784      {
785         start_index = _eail_get_line_start(cur);
786         end_index = start_index + _eail_get_line_length(cur);
787
788         if (index >= start_index && index <= end_index)
789           {
790              /* Found line for offset */
791              if (_eail_iter_next_line (cur))
792                {
793                   switch (boundary_type)
794                     {
795                       case ATK_TEXT_BOUNDARY_LINE_START:
796                           start_index = _eail_get_line_start(cur);
797                           if (_eail_iter_next_line (cur))
798                             end_index = _eail_get_line_start(cur);
799                           else
800                             end_index = start_index + _eail_get_line_length(cur);
801                           break;
802                       case ATK_TEXT_BOUNDARY_LINE_END:
803                           start_index = end_index;
804                           end_index = _eail_get_line_start(cur) +
805                               _eail_get_line_length(cur);
806                           break;
807                       default:
808                           g_assert_not_reached();
809                     }
810                }
811              else
812                start_index = end_index;
813
814              found = TRUE;
815              break;
816           }
817
818         prev_cur = cur;
819      }
820    while (_eail_iter_next_line (cur));
821
822    if (!found)
823      {
824         start_index = _eail_get_line_start(prev_cur) +
825             _eail_get_line_length(prev_cur);
826         end_index = start_index;
827      }
828    evas_textblock_cursor_free(cur);
829
830    *start_offset = g_utf8_pointer_to_offset (text, text + start_index);
831    *end_offset = g_utf8_pointer_to_offset (text, text + end_index);
832 }
833
834 /**
835  * @brief Gets line at offset
836  *
837  * @param entry an Evas_Object
838  * @param boundary_type an AtkTextBoundary
839  * @param offset position
840  * @param [out] start_offset the start offset of the returned string
841  * @param [out] end_offset the offset of the first character after the
842  * returned substring
843  */
844 static void
845 _eail_get_line_at (Evas_Object *entry,
846                    AtkTextBoundary  boundary_type,
847                    gint             offset,
848                    gint            *start_offset,
849                    gint            *end_offset)
850 {
851    Evas_Object *textblock;
852    Evas_Textblock_Cursor *cur, *prev_cur = NULL;
853    gint index, start_index, end_index;
854    const gchar *text;
855    gboolean found = FALSE;
856
857    textblock = elm_entry_textblock_get(entry);
858    cur = evas_object_textblock_cursor_new(textblock);
859
860    text = evas_textblock_text_markup_to_utf8(
861        textblock, evas_object_textblock_text_markup_get(textblock));
862    index = g_utf8_offset_to_pointer (text, offset) - text;
863    //iter = pango_layout_get_iter (layout);
864    do
865      {
866         //line = pango_layout_iter_get_line (iter);
867         start_index = _eail_get_line_start(cur);
868         end_index = start_index + _eail_get_line_end(cur);
869
870         if (index >= start_index && index <= end_index)
871           {
872              /* Found line for offset */
873              switch (boundary_type)
874                {
875                  case ATK_TEXT_BOUNDARY_LINE_START:
876                      if (_eail_iter_next_line (cur))
877                        end_index = _eail_get_line_start(cur);
878                      break;
879                  case ATK_TEXT_BOUNDARY_LINE_END:
880                      if (prev_cur)
881                        start_index = _eail_get_line_start(prev_cur) +
882                            _eail_get_line_length(prev_cur);
883                      break;
884                  default:
885                      g_assert_not_reached();
886                }
887
888              found = TRUE;
889              break;
890           }
891
892         prev_cur = cur;
893      }
894    while (_eail_iter_next_line (cur));
895
896    if (!found)
897      {
898         start_index = _eail_get_line_start(prev_cur) +
899             _eail_get_line_length(prev_cur);
900         end_index = start_index;
901      }
902    evas_textblock_cursor_free(cur);
903
904    *start_offset = g_utf8_pointer_to_offset (text, text + start_index);
905    *end_offset = g_utf8_pointer_to_offset (text, text + end_index);
906 }
907
908 /**
909  * @brief Gets a slice of the text from entry after offset
910  *
911  * @param entry an entry widget
912  * @param offset a character offset
913  * @param boundary_type an AtkTextBoundary
914  * @param [out] start_offset return location for the start of the returned text
915  * @param [out] end_offset return location for the end of the returned text
916  * @returns a newly allocated string containg a slice of text from textblock.
917  * Free with g_free()
918  */
919 static gchar *
920 _eail_get_text_after(Evas_Object *entry,
921                      gint offset,
922                      AtkTextBoundary boundary_type,
923                      gint *start_offset,
924                      gint *end_offset)
925 {
926    const gchar *text;
927    int len;
928    gint start, end;
929    Evas_Object *textblock;
930
931    if (!entry) return g_strdup("");
932
933    textblock = elm_entry_textblock_get(entry);
934
935    text = evas_textblock_text_markup_to_utf8(
936        textblock, evas_object_textblock_text_markup_get(textblock));
937    if (!text)
938      {
939         *start_offset = 0;
940         *end_offset = 0;
941         return g_strdup("");
942      }
943
944    start = offset;
945    end = offset;
946    len = _eail_get_len(textblock);
947
948    switch (boundary_type)
949      {
950        case ATK_TEXT_BOUNDARY_CHAR:
951            start = _eail_move_chars(textblock, start, 1);
952            end = start;
953            end = _eail_move_chars(textblock, end, 1);
954            break;
955
956        case ATK_TEXT_BOUNDARY_WORD_START:
957            if (_eail_is_inside_word(textblock, end))
958              end = _eail_move_words(textblock, end, 1);
959            while (!_eail_is_word_start(textblock, end) && end < len)
960              end = _eail_move_chars(textblock, end, 1);
961            start = end;
962            if (end < len)
963              {
964                 end = _eail_move_words(textblock, end, 1);
965                 while (!_eail_is_word_start(textblock, end) && end < len)
966                   end = _eail_move_chars(textblock, end, 1);
967              }
968            break;
969
970        case ATK_TEXT_BOUNDARY_WORD_END:
971            end = _eail_move_words(textblock, end, 1);
972            start = end;
973            if (end < len)
974              end = _eail_move_words(textblock, end, 1);
975            break;
976
977        case ATK_TEXT_BOUNDARY_SENTENCE_START:
978        case ATK_TEXT_BOUNDARY_SENTENCE_END:
979            break;
980
981        case ATK_TEXT_BOUNDARY_LINE_START:
982        case ATK_TEXT_BOUNDARY_LINE_END:
983            _eail_get_line_after (entry, boundary_type, offset, &start, &end);
984            break;
985      }
986
987    *start_offset = start;
988    *end_offset = end;
989    g_assert(start <= end);
990
991    return g_utf8_substring(text, start, end);
992 }
993
994 /**
995  * @brief Gets a slice of the text from entry at offset
996  *
997  * @param entry an entry widget
998  * @param offset a character offset in entry
999  * @param boundary_type an AtkTextBoundary
1000  * @param [out] start_offset return location for the start of the returned text
1001  * @param [out] end_offset return location for the end of the return text
1002  * @returns a newly allocated string containing a slice of text from entry.
1003  * Free with g_free().
1004  */
1005 static gchar *
1006 _eail_get_text_at(Evas_Object *entry,
1007                   gint offset,
1008                   AtkTextBoundary boundary_type,
1009                   gint *start_offset,
1010                   gint *end_offset)
1011 {
1012    const gchar *text;
1013    int len;
1014    gint start, end;
1015    Evas_Object *textblock;
1016
1017    if (!entry) return g_strdup("");
1018
1019    textblock = elm_entry_textblock_get(entry);
1020
1021    text = evas_textblock_text_markup_to_utf8(
1022        textblock, evas_object_textblock_text_markup_get(textblock));
1023    if (!text)
1024      {
1025         *start_offset = 0;
1026         *end_offset = 0;
1027         return g_strdup("");
1028      }
1029
1030    start = offset;
1031    end = offset;
1032    len = _eail_get_len(textblock);
1033
1034    switch (boundary_type)
1035      {
1036        case ATK_TEXT_BOUNDARY_CHAR:
1037            end = _eail_move_chars(textblock, end, 1);
1038            break;
1039
1040        case ATK_TEXT_BOUNDARY_WORD_START:
1041            if (!_eail_is_word_start(textblock, start))
1042              start = _eail_move_words(textblock, start, -1);
1043            if (_eail_is_inside_word(textblock, end))
1044              end = _eail_move_words(textblock, end, 1);
1045            while (!_eail_is_word_start(textblock, end) && end < len)
1046              end = _eail_move_chars(textblock, end, 1);
1047            break;
1048
1049        case ATK_TEXT_BOUNDARY_WORD_END:
1050            if (_eail_is_inside_word(textblock, start) &&
1051                !_eail_is_word_start(textblock, start))
1052              start = _eail_move_words(textblock, start, -1);
1053            while (!_eail_is_word_end(textblock, start) && start > 0)
1054              start = _eail_move_chars(textblock, start, -1);
1055            end = _eail_move_words(textblock, end, 1);
1056            break;
1057
1058        case ATK_TEXT_BOUNDARY_SENTENCE_START:
1059        case ATK_TEXT_BOUNDARY_SENTENCE_END:
1060            break;
1061
1062        case ATK_TEXT_BOUNDARY_LINE_START:
1063        case ATK_TEXT_BOUNDARY_LINE_END:
1064            _eail_get_line_at (entry, boundary_type, offset, &start, &end);
1065            break;
1066      }
1067
1068    *start_offset = start;
1069    *end_offset = end;
1070    g_assert(start <= end);
1071
1072    return g_utf8_substring(text, start, end);
1073 }
1074
1075 /**
1076  * @brief Gets a slice of the text from entry before offset
1077  *
1078  * @param entry an entry widget
1079  * @param offset a character offset
1080  * @param boundary_type an AtkTextBoundary
1081  * @param start_offset return location for the start of the returned text
1082  * @param end_offset return location for the end of the returned text
1083  * @returns a newly allocated string containing a slice of text from entry.
1084  * Free with g_free().
1085  */
1086 static gchar *
1087 _eail_get_text_before(Evas_Object *entry,
1088                       gint offset,
1089                       AtkTextBoundary boundary_type,
1090                       gint *start_offset,
1091                       gint *end_offset)
1092 {
1093    const gchar *text;
1094    gint start, end;
1095    Evas_Object *textblock;
1096
1097    if (!entry) return g_strdup("");
1098
1099    textblock = elm_entry_textblock_get(entry);
1100
1101    text = evas_textblock_text_markup_to_utf8(
1102        textblock, evas_object_textblock_text_markup_get(textblock));
1103    if (!text)
1104      {
1105         *start_offset = 0;
1106         *end_offset = 0;
1107         return g_strdup("");
1108      }
1109
1110    start = offset;
1111    end = offset;
1112
1113    switch (boundary_type)
1114      {
1115        case ATK_TEXT_BOUNDARY_CHAR:
1116            start = _eail_move_chars(textblock, start, -1);
1117            break;
1118
1119        case ATK_TEXT_BOUNDARY_WORD_START:
1120            if (!_eail_is_word_start(textblock, start))
1121              start = _eail_move_words(textblock, start, -1);
1122            end = start;
1123            start = _eail_move_words(textblock, start, -1);
1124            break;
1125
1126        case ATK_TEXT_BOUNDARY_WORD_END:
1127            if (_eail_is_inside_word(textblock, start) &&
1128                !_eail_is_word_start(textblock, start))
1129              start = _eail_move_words(textblock, start, -1);
1130            while (!_eail_is_word_end(textblock, start) && start > 0)
1131              start = _eail_move_chars(textblock, start, -1);
1132            end = start;
1133            start = _eail_move_words(textblock, start, -1);
1134            while (!_eail_is_word_end(textblock, start) && start > 0)
1135              start = _eail_move_chars(textblock, start, -1);
1136            break;
1137
1138        case ATK_TEXT_BOUNDARY_SENTENCE_START:
1139        case ATK_TEXT_BOUNDARY_SENTENCE_END:
1140            break;
1141
1142        case ATK_TEXT_BOUNDARY_LINE_START:
1143        case ATK_TEXT_BOUNDARY_LINE_END:
1144            _eail_get_line_before (entry, boundary_type, offset, &start, &end);
1145            break;
1146      }
1147
1148    *start_offset = start;
1149    *end_offset = end;
1150    g_assert(start <= end);
1151
1152    return g_utf8_substring(text, start, end);
1153 }
1154
1155 /**
1156  * @brief Gets the specified text
1157  *
1158  * @param text an AtkText
1159  * @param offset position
1160  * @param boundary_type an AtkTextBoundary
1161  * @param [out] start_offset the start offset of the returned string
1162  * @param [out] end_offset the offset of the first character after the returned
1163  * substring
1164  * @returns a newly allocated string containing the text after offset bounded
1165  * by the specified boundary_type. Use g_free() to free the returned string.
1166  */
1167 static gchar *
1168 eail_entry_get_text_after_offset(AtkText *text,
1169                                  gint offset,
1170                                  AtkTextBoundary boundary_type,
1171                                  gint *start_offset,
1172                                  gint *end_offset)
1173 {
1174    Evas_Object *widget;
1175
1176    widget = eail_widget_get_widget(EAIL_WIDGET(text));
1177    if (!widget) return NULL;
1178
1179    return _eail_get_text_after(widget, offset, boundary_type, start_offset,
1180                                end_offset);
1181
1182 }
1183
1184 /**
1185  * @brief Gets the specified text
1186  *
1187  * @param text an AtkText
1188  * @param offset position
1189  * @param boundary_type an AtkTextBoundary
1190  * @param [out] start_offset the start offset of the returned string
1191  * @param [out] end_offset the offset of the first character after the returned
1192  * substring
1193  * @returns a newly allocated string containing the text after offset bounded
1194  * by the specified boundary_type. Use g_free() to free the returned string.
1195  */
1196 static gchar *
1197 eail_entry_get_text_at_offset(AtkText *text,
1198                               gint offset,
1199                               AtkTextBoundary boundary_type,
1200                               gint *start_offset,
1201                               gint *end_offset)
1202 {
1203    Evas_Object *widget;
1204
1205    widget = eail_widget_get_widget(EAIL_WIDGET(text));
1206    if (!widget) return NULL;
1207
1208    return _eail_get_text_at(widget, offset, boundary_type, start_offset,
1209                             end_offset);
1210 }
1211
1212 /**
1213  * @brief Gets the specified text
1214  *
1215  * @param text an AtkText
1216  * @param offset position
1217  * @param boundary_type an AtkTextBoundary
1218  * @param [out] start_offset the start offset of the returned string
1219  * @param [out] end_offset the offset of the first character after the returned
1220  * substring
1221  * @returns a newly allocated string containing the text after offset bounded
1222  * by the specified boundary_type. Use g_free() to free the returned string.
1223  */
1224 static gchar *
1225 eail_entry_get_text_before_offset(AtkText *text,
1226                                   gint offset,
1227                                   AtkTextBoundary boundary_type,
1228                                   gint *start_offset,
1229                                   gint *end_offset)
1230 {
1231    Evas_Object *widget;
1232
1233    widget = eail_widget_get_widget(EAIL_WIDGET(text));
1234    if (!widget) return NULL;
1235
1236    return _eail_get_text_before(widget, offset, boundary_type, start_offset,
1237                                 end_offset);
1238 }
1239
1240 /**
1241  * @brief Gets character at offset
1242  *
1243  * @param text an AtkText
1244  * @param offset character offset
1245  * @return character at offset
1246  */
1247 static gunichar
1248 eail_entry_get_character_at_offset(AtkText    *text,
1249                                    gint        offset)
1250 {
1251    gunichar character = '\0';
1252    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
1253
1254    if (widget)
1255      character = g_utf8_get_char(
1256          g_utf8_offset_to_pointer(elm_entry_entry_get(widget), offset));
1257
1258    return character;
1259 }
1260
1261 /**
1262  * @brief Gets text length
1263  *
1264  * @param text an AtkText
1265  * @return text length
1266  */
1267 static gint
1268 eail_entry_get_character_count(AtkText *text)
1269 {
1270    gint count = 0;
1271    const gchar *string_text = NULL;
1272
1273    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
1274
1275    if (!widget) return count;
1276
1277    string_text = elm_object_text_get(widget);
1278    if (!string_text) return count;
1279
1280    count = g_utf8_strlen(string_text, -1);
1281
1282    return count;
1283 }
1284
1285 /**
1286  * @brief Adds attribute to attribute set
1287  *
1288  * @param attrib_set The AtkAttributeSet to add the attribute to
1289  * @param attr The AtkTextAttrribute which identifies the attribute to be added
1290  * @param value The attribute value
1291  *
1292  * Creates an AtkAttribute from attr and value, and adds it
1293  * to attrib_set.
1294  *
1295  * @returns: A pointer to the new AtkAttributeSet.
1296  **/
1297 AtkAttributeSet*
1298 eail_entry_add_attribute(AtkAttributeSet *attrib_set,
1299                          AtkTextAttribute attr,
1300                          gchar           *value)
1301 {
1302    AtkAttributeSet *return_set;
1303    AtkAttribute *at = g_malloc (sizeof (AtkAttribute));
1304    at->name = g_strdup (atk_text_attribute_get_name (attr));
1305    at->value = value;
1306    return_set = g_slist_prepend(attrib_set, at);
1307    return return_set;
1308 }
1309
1310 /**
1311  * @brief Creates an AtkAttributeSet which consists of the default values of
1312  * attributes for the text.
1313  *
1314  * @param text an AtkText
1315  *
1316  * @returns an AtkAttributeSet which contains the default values of attributes
1317  * at offset. this atkattributeset should be freed by a call to
1318  * atk_attribute_set_free()
1319  */
1320 AtkAttributeSet *
1321 eail_entry_get_default_attributes(AtkText *text)
1322 {
1323    AtkAttributeSet *at_set = NULL;
1324
1325    at_set = eail_entry_add_attribute
1326        (at_set, ATK_TEXT_ATTR_WRAP_MODE,
1327         g_strdup
1328         (atk_text_attribute_get_value(ATK_TEXT_ATTR_WRAP_MODE, 0)));
1329
1330    at_set = eail_entry_add_attribute
1331        (at_set, ATK_TEXT_ATTR_EDITABLE,
1332         g_strdup
1333         (atk_text_attribute_get_value
1334          (ATK_TEXT_ATTR_EDITABLE, TRUE)));
1335
1336    return at_set;
1337 }
1338
1339 /**
1340  * @brief Creates an AtkAttributeSet which consists of the attributes
1341  * explicitly set at the position offset in the text. start_offset and
1342  * end_offset are set to the start and end of the range around offset
1343  * where the attributes are invariant. Note that end_offset is the offset
1344  * of the first character after the range.
1345  *
1346  * @param text an AtkText
1347  * @param offset the offset at which to get the attributes
1348  * @param start_offset the address to put the start offset of the range (used to
1349  * store output value)
1350  * @param end_offset the address to put the end offset of the range (used to
1351  * store output value)
1352  *
1353  * @returns an AtkAttributeSet which contains the attributes explicitly set at
1354  * offset. This AtkAttributeSet should be freed by a call to
1355  * atk_attribute_set_free()
1356  */
1357 AtkAttributeSet *
1358 eail_entry_get_run_attributes(AtkText *text,
1359                               gint offset,
1360                               gint *start_offset,
1361                               gint *end_offset)
1362 {
1363    AtkAttributeSet *at_set = NULL;
1364    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
1365
1366    if (!widget || offset >= eail_entry_get_character_count(text))
1367      {
1368         *start_offset = -1;
1369         *end_offset = -1;
1370
1371         return NULL;
1372      }
1373
1374    *start_offset = 0;
1375    *end_offset = eail_entry_get_character_count(text);
1376
1377    /* NOTE: Elm_Wrap_Type value is in 100% compatible with ATK wrap modes, so
1378     * no additional conversion is needed*/
1379    Elm_Wrap_Type wrap_type = elm_entry_line_wrap_get(widget);
1380    at_set = eail_entry_add_attribute
1381        (at_set, ATK_TEXT_ATTR_WRAP_MODE,
1382         g_strdup
1383         (atk_text_attribute_get_value
1384          (ATK_TEXT_ATTR_WRAP_MODE, wrap_type)));
1385
1386    Eina_Bool editable = elm_entry_editable_get(widget);
1387    at_set = eail_entry_add_attribute
1388        (at_set, ATK_TEXT_ATTR_EDITABLE,
1389         g_strdup
1390         (atk_text_attribute_get_value
1391          (ATK_TEXT_ATTR_EDITABLE, editable)));
1392
1393    return at_set;
1394 }
1395
1396 /**
1397  * @brief Initializes AtkTextIface interface
1398  *
1399  * @param iface an AtkTextIface
1400  */
1401 static void
1402 atk_text_interface_init(AtkTextIface *iface)
1403 {
1404    iface->get_caret_offset = eail_entry_get_caret_offset;
1405    iface->set_caret_offset = eail_entry_set_caret_offset;
1406    iface->get_selection    = eail_entry_get_selection;
1407    iface->set_selection    = eail_entry_set_selection;
1408    iface->get_text         = eail_entry_get_text;
1409    iface->get_character_at_offset = eail_entry_get_character_at_offset;
1410    iface->get_character_count = eail_entry_get_character_count;
1411    iface->remove_selection = eail_entry_remove_selection;
1412    iface->get_n_selections = eail_entry_get_n_selections;
1413    iface->add_selection = eail_entry_add_selection;
1414    iface->get_run_attributes = eail_entry_get_run_attributes;
1415    iface->get_default_attributes = eail_entry_get_default_attributes;
1416    iface->get_text_after_offset = eail_entry_get_text_after_offset;
1417    iface->get_text_at_offset = eail_entry_get_text_at_offset;
1418    iface->get_text_before_offset = eail_entry_get_text_before_offset;
1419 }
1420
1421 /*
1422  * Implementation of the *AtkEditableText* interface
1423  */
1424
1425 /**
1426  * @brief Set text content for entry
1427  * @param text an AtkEditableText
1428  * @param string string to be set
1429  */
1430 static void
1431 eail_entry_set_text_contents(AtkEditableText *text,
1432                              const gchar     *string)
1433 {
1434    Evas_Object *widget;
1435
1436    widget = eail_widget_get_widget(EAIL_WIDGET(text));
1437    if (widget && elm_entry_editable_get(widget))
1438      elm_object_text_set(widget, string);
1439 }
1440
1441 /**
1442  * @brief Copies text content from entry to clipboard
1443  *
1444  * @param text an AtkEditableText
1445  * @param start_pos start position of cursor
1446  * @param end_pos end position of cursor
1447  */
1448 static void
1449 eail_entry_copy_text(AtkEditableText *text,
1450                      gint             start_pos,
1451                      gint             end_pos)
1452 {
1453    Evas_Object *widget;
1454    const char *entry_text;
1455    char *tmp;
1456
1457    widget = eail_widget_get_widget(EAIL_WIDGET(text));
1458    if (!widget) return;
1459
1460    entry_text = elm_entry_entry_get(widget);
1461    tmp = eail_get_substring(entry_text, start_pos, end_pos);
1462    eail_clipboard_set_text(tmp);
1463    g_free(tmp);
1464 }
1465
1466 /**
1467  * @brief Cuts text content from entry to clipboard
1468  *
1469  * @param text an AtkEditableText
1470  * @param start_pos start position of cursor
1471  * @param end_pos end position of cursor
1472  */
1473 static void
1474 eail_entry_cut_text(AtkEditableText *text,
1475                     gint             start_pos,
1476                     gint             end_pos)
1477 {
1478    Evas_Object *widget;
1479    const char *entry_text;
1480    char *tmp;
1481    GString *s;
1482
1483    widget = eail_widget_get_widget(EAIL_WIDGET(text));
1484    if (!widget || !elm_entry_editable_get(widget))
1485      return;
1486
1487    entry_text = elm_entry_entry_get(widget);
1488    tmp = eail_get_substring(entry_text, start_pos, end_pos);
1489    eail_clipboard_set_text(tmp);
1490    g_free(tmp);
1491
1492    s = g_string_new(entry_text);
1493    s = g_string_erase(s, start_pos, end_pos - start_pos);
1494
1495    elm_entry_entry_set(widget, s->str);
1496    g_string_free(s, TRUE);
1497 }
1498
1499 /**
1500  * @brief Pastes text content from clipboard into entry
1501  *
1502  * @param text an AtkEditableText
1503  * @param position start position of cursor
1504  */
1505 static void
1506 eail_entry_paste_text(AtkEditableText *text,
1507                       gint             position)
1508 {
1509    Evas_Object *widget;
1510    GString *s;
1511    const char *clip;
1512
1513    widget = eail_widget_get_widget(EAIL_WIDGET(text));
1514    if (!widget || !elm_entry_editable_get(widget))
1515      return;
1516
1517    clip = eail_clipboard_get_text();
1518    if (!clip) return;
1519
1520    s = g_string_new(elm_entry_entry_get(widget));
1521    s = g_string_insert(s, position, clip);
1522    elm_entry_entry_set(widget, s->str);
1523    g_string_free(s, TRUE);
1524 }
1525
1526 /**
1527  * @brief Deletes text between start_pos and end_pos but not
1528  * including end_pos
1529  *
1530  * @param text an AtkEditableText
1531  * @param start_pos start position
1532  * @param end_pos end position
1533  */
1534 static void
1535 eail_entry_delete_text(AtkEditableText *text,
1536                        gint start_pos,
1537                        gint end_pos)
1538 {
1539    Evas_Object *widget;
1540    GString *entry_text;
1541
1542    widget = eail_widget_get_widget(EAIL_WIDGET(text));
1543    if (!widget || !elm_entry_editable_get(widget))
1544      return;
1545
1546    entry_text = g_string_new(elm_entry_entry_get(widget));
1547    entry_text = g_string_erase(entry_text, start_pos, end_pos-start_pos);
1548
1549    elm_entry_entry_set(widget, entry_text->str);
1550    g_string_free(entry_text, TRUE);
1551 }
1552
1553 /**
1554  * @brief Inserts text at given position
1555  *
1556  * @param text an AtkEditableText
1557  * @param string string to insert
1558  * @param length string length
1559  * @param [out] position at witch text is inserted.
1560  * After the call it points at the position after the newly inserted text.
1561  */
1562 static void
1563 eail_entry_insert_text(AtkEditableText *text,
1564                        const gchar *string,
1565                        gint length,
1566                        gint *position)
1567 {
1568    Evas_Object *widget;
1569    GString *entry_text;
1570
1571    widget = eail_widget_get_widget(EAIL_WIDGET(text));
1572    if (!widget || !elm_entry_editable_get(widget))
1573      return;
1574
1575    entry_text = g_string_new(elm_entry_entry_get(widget));
1576    entry_text = g_string_insert_len(entry_text, *position, string,
1577                                     length);
1578    elm_entry_entry_set(widget, entry_text->str);
1579    *position += length;
1580    g_string_free(entry_text, TRUE);
1581 }
1582
1583 /**
1584  * @brief Initialization for AtkEditableTextIface interface
1585  *
1586  * Function called upon instance creation. It initializes AtkText interface
1587  * implementation i.e hooks method pointers in the interface structure
1588  * to the implementing class's implementation.
1589  *
1590  * @param iface an AtkEditableTextIface
1591  */
1592 static void
1593 atk_editable_text_interface_init(AtkEditableTextIface *iface)
1594 {
1595    iface->set_text_contents = eail_entry_set_text_contents;
1596    iface->copy_text = eail_entry_copy_text;
1597    iface->cut_text = eail_entry_cut_text;
1598    iface->paste_text = eail_entry_paste_text;
1599    iface->delete_text = eail_entry_delete_text;
1600    iface->insert_text = eail_entry_insert_text;
1601 }