2 * Copyright (c) 2013 Samsung Electronics Co., Ltd.
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.
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.
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.
22 * @brief EailEntry implementation
25 #include <Elementary.h>
27 #include "eail_entry.h"
28 #include "eail_utils.h"
29 #include "eail_priv.h"
30 #include "eail_clipboard.h"
32 static void atk_text_interface_init(AtkTextIface *iface);
33 static void atk_editable_text_interface_init(AtkEditableTextIface *iface);
36 * @brief Definition of EailEntry as GObject
38 * EailEntry is extended EAIL_TYPE_TEXT with ATK_TYPE_TEXT and
39 * ATK_TYPE_EDITABLE_TEXT interfaces implemented.
42 G_DEFINE_TYPE_WITH_CODE(EailEntry,
45 G_IMPLEMENT_INTERFACE(ATK_TYPE_TEXT,
46 atk_text_interface_init)
47 G_IMPLEMENT_INTERFACE(ATK_TYPE_EDITABLE_TEXT,
48 atk_editable_text_interface_init));
51 * @brief Handler for event which is raised when entry content has changed
53 * @param data data passed to callback
54 * @param obj Evas_Object that raised event
55 * @param event_info additional event info
58 _eail_entry_handle_changed_event(void *data,
63 (ATK_OBJECT(data), "visible-data-changed", ATK_TYPE_OBJECT);
67 * @brief handler for event which is raised when entry content is being pressed
69 * @param data passed to callback
70 * @param obj object that raised event
71 * @param event_info additional event info
74 _eail_entry_handle_pressed_event(void *data,
78 atk_object_notify_state_change(ATK_OBJECT(data), ATK_STATE_PRESSED, TRUE);
82 * @brief Initializer for AtkObject
84 * @param obj AtkObject instance
85 * @param data initialization data
88 eail_entry_initialize(AtkObject *obj, gpointer data)
90 Evas_Object *nested_widget = NULL;
91 ATK_OBJECT_CLASS(eail_entry_parent_class)->initialize(obj, data);
93 obj->role = ATK_ROLE_ENTRY;
95 g_return_if_fail(EAIL_IS_WIDGET(obj));
96 nested_widget = eail_widget_get_widget(EAIL_WIDGET(obj));
99 ERR("No evas object inside EailWidget was found");
103 evas_object_smart_callback_add(nested_widget, "changed",
104 _eail_entry_handle_changed_event, obj);
105 evas_object_smart_callback_add(nested_widget, "cursor,changed",
106 _eail_entry_handle_changed_event, obj);
107 evas_object_smart_callback_add(nested_widget, "press",
108 _eail_entry_handle_pressed_event, obj);
112 * @brief Class destructor
114 * @param obj GObject instance
117 eail_entry_finalize(GObject *obj)
122 * @brief Gets a reference to the state set of the accessible
124 * The caller must unreference it when it is no longer needed.
126 * Implementation of AtkObject->ref_state_set callback.
128 * @param obj AtkObject instance
130 * @returns AtkStateSet representing the state set of the
134 eail_entry_ref_state_set(AtkObject *obj)
136 AtkStateSet *state_set;
137 Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(obj));
142 state_set = ATK_OBJECT_CLASS(eail_entry_parent_class)->ref_state_set(obj);
144 if (elm_entry_editable_get(widget))
145 atk_state_set_add_state(state_set, ATK_STATE_EDITABLE);
147 if (elm_entry_single_line_get(widget))
148 atk_state_set_add_state(state_set, ATK_STATE_SINGLE_LINE);
150 atk_state_set_add_state(state_set, ATK_STATE_MULTI_LINE);
156 * @brief Initializer for EailEntry GObject implementation
158 * @param entry EailEntry instance
161 eail_entry_init(EailEntry *entry)
163 entry->selection_start = 0;
164 entry->selection_end = 0;
168 * @brief Initializer for EailPopup GObject class
170 * Defines callbacks for base AtkObject.
172 * @param klass EailEntryClass instance
175 eail_entry_class_init(EailEntryClass *klass)
177 AtkObjectClass *atk_class = ATK_OBJECT_CLASS(klass);
178 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
180 atk_class->initialize = eail_entry_initialize;
181 atk_class->ref_state_set = eail_entry_ref_state_set;
182 gobject_class->finalize = eail_entry_finalize;
186 * @brief Gets the caret offset
188 * @param text AtkText instance
189 * @return integer representing the caret offset
192 eail_entry_get_caret_offset(AtkText *text)
196 widget = eail_widget_get_widget(EAIL_WIDGET(text));
200 return elm_entry_cursor_pos_get(widget);
204 * @brief Sets the caret (cursor) position to the specified offset.
206 * Implementation of AtkTextIface->set_caret_offset callback.
208 * @param text AtkText instance
209 * @param offset starting position
211 * @returns TRUE on success, FALSE otherwise
214 eail_entry_set_caret_offset (AtkText *text,
219 widget = eail_widget_get_widget(EAIL_WIDGET(text));
223 elm_entry_cursor_pos_set(widget, offset);
229 * @brief Gets the number of selected text regions
231 * @param text AtkText instance
232 * @returns integer representing the number of
233 * selected text regions
236 eail_entry_get_n_selections(AtkText *text)
240 widget = eail_widget_get_widget(EAIL_WIDGET(text));
241 if (!widget) return 0;
243 if (elm_entry_selection_get(widget)) return 1;
249 * @brief Gets text selection from entry
251 * Use g_free() to free the returned string.
253 * 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.
259 * Implementation of AtkTextIface->get_selection callback.
261 * @param text AtkText instance
262 * @param selection_num selection number
263 * @param start_offset start position of the selected region
264 * @param end_offset end position of the selected region
266 * @returns newly allocated string containing the selected text
269 eail_entry_get_selection(AtkText *text,
274 const char* selection;
277 widget = eail_widget_get_widget(EAIL_WIDGET(text));
281 if (0 != selection_num)
284 selection = elm_entry_selection_get(widget);
287 *start_offset = EAIL_ENTRY(text)->selection_start;
288 *end_offset = EAIL_ENTRY(text)->selection_end;
289 return g_strdup(selection);
296 * @brief Adds a selection bounded by the specified offsets
298 * @param text AtkText instance
299 * @param start_offset start position of the selection
300 * @param end_offset offset of the first character after selection
301 * @returns TRUE on success, FALSE otherwise
304 eail_entry_add_selection(AtkText *text,
310 widget = eail_widget_get_widget(EAIL_WIDGET(text));
311 if (!widget) return FALSE;
313 elm_entry_cursor_pos_set(widget, start_offset);
314 elm_entry_cursor_selection_begin(widget);
315 elm_entry_cursor_pos_set(widget, end_offset);
316 elm_entry_cursor_selection_end(widget);
318 EAIL_ENTRY(text)->selection_start = start_offset;
319 EAIL_ENTRY(text)->selection_end = end_offset;
325 * @brief Removes text selection
327 * Only one selection is supported, so
328 * selection number equals 0.
330 * @param text AtkText instance
331 * @param selection_num selection number
332 * @return TRUE on success, FALSE otherwise
335 eail_entry_remove_selection(AtkText *text,
340 widget = eail_widget_get_widget(EAIL_WIDGET(text));
341 if (!widget) return FALSE;
343 if (selection_num != 0 || !elm_entry_selection_get(widget)) return FALSE;
345 elm_entry_select_none(widget);
346 EAIL_ENTRY(text)->selection_start = 0;
347 EAIL_ENTRY(text)->selection_end = 0;
353 * @brief Sets text selection for entry
355 * The selected regions are assigned
356 * numbers that correspond to how far the region is from the start of the text.
357 * The selected region closest to the beginning of the text region is assigned
358 * the number 0, etc. Note that adding, moving or deleting a selected region can
359 * change the numbering.
361 * Implementation of AtkTextIface->set_selection callback.
363 * @param text AtkText instance
364 * @param selection_num selection number
365 * @param start_pos start position of the selected region
366 * @param end_pos end position of the selected region
368 * @returns TRUE on success, FALSE otherwise
371 eail_entry_set_selection(AtkText *text,
376 if (0 != selection_num)
379 return eail_entry_add_selection(text, start_pos, end_pos);
383 * @brief Gets text bounded by start_offset and end_offset
385 * Use g_free() to free the returned string.
387 * @param text AtkText instance
388 * @param start_offset start position
389 * @param end_offset end position, -1 for the end of the string
390 * @return string containing text from start_offset up to,
391 * but not including end_offset
394 eail_entry_get_text(AtkText *text,
398 const gchar *string = NULL;
399 Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
402 string = elm_entry_entry_get(widget);
404 return eail_get_substring(string, start_offset, end_offset);
410 * @brief Returns the position that is obtained by adding count to the
413 * Count may be positive or negative.
415 * @param textblock Evas textblock
416 * @param offset character offset
417 * @param count number of characters to move from offset
418 * @returns integer representing the new position
421 _eail_move_chars(const Evas_Object *textblock,
425 Evas_Textblock_Cursor *cur;
429 dir = count > 0 ? 1 : -1;
430 cur = evas_object_textblock_cursor_new(textblock);
431 evas_textblock_cursor_pos_set(cur, offset);
435 res = dir > 0 ? evas_textblock_cursor_char_next(cur) :
436 evas_textblock_cursor_char_prev(cur);
442 offset = evas_textblock_cursor_pos_get(cur);
443 evas_textblock_cursor_free(cur);
449 * @brief Gets the utf8 character at offset
451 * @param textblock Evas textblock
452 * @param offset character offset
453 * @returns char representing the utf8 character
456 _eail_get_unichar_at_offset(const Evas_Object *textblock,
459 Evas_Textblock_Cursor *cur;
463 cur = evas_object_textblock_cursor_new(textblock);
464 evas_textblock_cursor_pos_set(cur, offset);
465 s = evas_textblock_cursor_content_get(cur);
466 c = g_utf8_get_char(s);
468 evas_textblock_cursor_free(cur);
475 * @brief Checks whether the character at offset in textblock is a word's start
477 * @param textblock Evas textblock
478 * @param offset character offset
479 * @returns TRUE on success, FALSE otherwise
482 _eail_is_word_start(const Evas_Object *textblock,
485 /* first character in a word */
488 c1 = _eail_get_unichar_at_offset(textblock, offset);
489 c2 = _eail_get_unichar_at_offset(textblock, offset - 1);
490 if (g_unichar_isalnum(c1) && g_unichar_isspace(c2)) return TRUE;
496 * @brief Checks whether the character at offset in textblock is a word's end
498 * @param textblock Evas textblock
499 * @param offset character offset
500 * @return TRUE on success, FALSE otherwise
503 _eail_is_word_end(const Evas_Object *textblock,
506 /* is first non-word char after a word */
509 c1 = _eail_get_unichar_at_offset(textblock, offset - 1);
510 c2 = _eail_get_unichar_at_offset(textblock, offset);
511 if (g_unichar_isalnum(c1) && g_unichar_isspace(c2)) return TRUE;
517 * @brief Checks whether the character at offset in textblock is inside a word
519 * @param textblock Evas textblock
520 * @param offset character offset
521 * @returns TRUE on success, FALSE otherwise
524 _eail_is_inside_word(const Evas_Object *textblock,
529 c1 = _eail_get_unichar_at_offset(textblock, offset - 1);
530 c2 = _eail_get_unichar_at_offset(textblock, offset);
531 c3 = _eail_get_unichar_at_offset(textblock, offset + 1);
532 if (g_unichar_isalnum(c1) && g_unichar_isalnum(c2) && g_unichar_isalnum(c3))
535 if (g_unichar_isalnum(c1) && g_unichar_isalnum(c2) && g_unichar_isspace(c3))
538 if (g_unichar_isspace(c1) && g_unichar_isalnum(c2) && g_unichar_isalnum(c3))
541 if (g_unichar_isspace(c1) && g_unichar_isalnum(c2) && g_unichar_isspace(c3))
548 * @brief Gets the texblock length
550 * @param textblock Evas textblock
551 * @returns integer representing the textblock length
554 _eail_get_len(const Evas_Object *textblock)
556 Evas_Textblock_Cursor *cur;
559 cur = evas_object_textblock_cursor_new(textblock);
560 while (evas_textblock_cursor_char_next(cur))
563 evas_textblock_cursor_free(cur);
569 * @brief Returns the position that is count words from the given offset
571 * Count may be positive or negative. If count is positive, the returned
572 * position will be a word end, otherwise it will be a word start.
574 * @param textblock Evas textblock
575 * @param offset a character offset
576 * @param count the number of words to move from offset
577 * @returns integer representing the new position
580 _eail_move_words(const Evas_Object *textblock,
584 gint len = _eail_get_len(textblock);
586 while (count > 0 && offset < len)
590 while (offset < len && !_eail_is_word_end(textblock, offset));
594 while (count < 0 && offset > 0)
598 while (offset > 0 && !_eail_is_word_start(textblock, offset));
607 * @brief Gets the position of the first character in line
609 * @param cur Evas_Textblock_Cursor instance
610 * @returns TRUE on success, FALSE otherwise
613 _eail_get_line_start(Evas_Textblock_Cursor *cur)
618 pos = evas_textblock_cursor_pos_get(cur);
619 evas_textblock_cursor_line_char_first(cur);
620 start = evas_textblock_cursor_pos_get(cur);
621 evas_textblock_cursor_pos_set(cur, pos);
627 * @brief Gets the position of the last character in line
629 * @param cur Evas_Textblock_Cursor instance
630 * @returns TRUE on success, FALSE otherwise
633 _eail_get_line_end(Evas_Textblock_Cursor *cur)
638 pos = evas_textblock_cursor_pos_get(cur);
639 evas_textblock_cursor_line_char_last(cur);
640 end = evas_textblock_cursor_pos_get(cur);
641 evas_textblock_cursor_pos_set(cur, pos);
647 * @brief Moves the cursor to the beginning of the next line
649 * @param cur Evas_Textblock_Cursor instance
650 * @returns TRUE on success, FALSE otherwise
653 _eail_iter_next_line(Evas_Textblock_Cursor *cur)
655 evas_textblock_cursor_line_char_last(cur);
657 return evas_textblock_cursor_char_next(cur);
661 * @brief Gets the length of the line shown by cursor cur
663 * @param cur Evas_Textblock_Cursor instance
664 * @return integer representing the length of the line
667 _eail_get_line_length(Evas_Textblock_Cursor *cur)
672 start = _eail_get_line_start(cur);
673 end = _eail_get_line_end(cur);
675 return end - start + 1;
679 * @brief Gets the line before offset
681 * @param entry Evas_Object instance
682 * @param boundary_type AtkTextBoundary instance
683 * @param offset character offset
684 * @param [out] start_offset start offset of the returned string
685 * @param [out] end_offset offset of the first character after the
689 _eail_get_line_before(Evas_Object *entry,
690 AtkTextBoundary boundary_type,
695 Evas_Object *textblock;
696 Evas_Textblock_Cursor *cur, *prev_cur = NULL, *prev_prev_cur = NULL;
697 gint index, start_index, end_index;
699 gboolean found = FALSE;
701 textblock = elm_entry_textblock_get(entry);
702 cur = evas_object_textblock_cursor_new(textblock);
704 text = evas_textblock_text_markup_to_utf8(
705 textblock, evas_object_textblock_text_markup_get(textblock));
706 index = g_utf8_offset_to_pointer (text, offset) - text;
709 start_index = _eail_get_line_start(cur);
710 end_index = start_index + _eail_get_line_length(cur);
712 if (index >= start_index && index <= end_index)
714 /* Found line for offset */
717 switch (boundary_type)
719 case ATK_TEXT_BOUNDARY_LINE_START:
720 end_index = start_index;
721 start_index = _eail_get_line_start(prev_cur);
723 case ATK_TEXT_BOUNDARY_LINE_END:
725 start_index = _eail_get_line_start(prev_prev_cur) +
726 _eail_get_line_length(prev_prev_cur);
729 end_index = _eail_get_line_start(prev_cur) +
730 _eail_get_line_length(prev_cur);
733 g_assert_not_reached();
737 start_index = end_index = 0;
743 prev_prev_cur = prev_cur;
746 while (_eail_iter_next_line(cur));
750 start_index = _eail_get_line_start(prev_cur) +
751 _eail_get_line_length(prev_cur);
752 end_index = start_index;
754 evas_textblock_cursor_free(cur);
756 *start_offset = g_utf8_pointer_to_offset(text, text + start_index);
757 *end_offset = g_utf8_pointer_to_offset(text, text + end_index);
761 * @brief Gets the line after offset
763 * @param entry Evas_Object instance
764 * @param boundary_type AtkTextBoundary instance
765 * @param offset character offset
766 * @param [out] start_offset start offset of the returned string
767 * @param [out] end_offset offset of the first character after the
771 _eail_get_line_after (Evas_Object *entry,
772 AtkTextBoundary boundary_type,
777 Evas_Object *textblock;
778 Evas_Textblock_Cursor *cur, *prev_cur = NULL;
779 gint index, start_index, end_index;
781 gboolean found = FALSE;
783 textblock = elm_entry_textblock_get(entry);
784 cur = evas_object_textblock_cursor_new(textblock);
785 text = evas_textblock_text_markup_to_utf8(
786 textblock, evas_object_textblock_text_markup_get(textblock));
788 index = g_utf8_offset_to_pointer (text, offset) - text;
791 start_index = _eail_get_line_start(cur);
792 end_index = start_index + _eail_get_line_length(cur);
794 if (index >= start_index && index <= end_index)
796 /* Found line for offset */
797 if (_eail_iter_next_line (cur))
799 switch (boundary_type)
801 case ATK_TEXT_BOUNDARY_LINE_START:
802 start_index = _eail_get_line_start(cur);
803 if (_eail_iter_next_line (cur))
804 end_index = _eail_get_line_start(cur);
806 end_index = start_index + _eail_get_line_length(cur);
808 case ATK_TEXT_BOUNDARY_LINE_END:
809 start_index = end_index;
810 end_index = _eail_get_line_start(cur) +
811 _eail_get_line_length(cur);
814 g_assert_not_reached();
818 start_index = end_index;
826 while (_eail_iter_next_line (cur));
830 start_index = _eail_get_line_start(prev_cur) +
831 _eail_get_line_length(prev_cur);
832 end_index = start_index;
834 evas_textblock_cursor_free(cur);
836 *start_offset = g_utf8_pointer_to_offset (text, text + start_index);
837 *end_offset = g_utf8_pointer_to_offset (text, text + end_index);
841 * @brief Gets the line at offset
843 * @param entry Evas_Object instance
844 * @param boundary_type AtkTextBoundary instance
845 * @param offset character offset
846 * @param [out] start_offset start offset of the returned string
847 * @param [out] end_offset offset of the first character after the
851 _eail_get_line_at (Evas_Object *entry,
852 AtkTextBoundary boundary_type,
857 Evas_Object *textblock;
858 Evas_Textblock_Cursor *cur, *prev_cur = NULL;
859 gint index, start_index, end_index;
861 gboolean found = FALSE;
863 textblock = elm_entry_textblock_get(entry);
864 cur = evas_object_textblock_cursor_new(textblock);
866 text = evas_textblock_text_markup_to_utf8(
867 textblock, evas_object_textblock_text_markup_get(textblock));
868 index = g_utf8_offset_to_pointer (text, offset) - text;
871 start_index = _eail_get_line_start(cur);
872 end_index = start_index + _eail_get_line_end(cur);
874 if (index >= start_index && index <= end_index)
876 /* Found line for offset */
877 switch (boundary_type)
879 case ATK_TEXT_BOUNDARY_LINE_START:
880 if (_eail_iter_next_line (cur))
881 end_index = _eail_get_line_start(cur);
883 case ATK_TEXT_BOUNDARY_LINE_END:
885 start_index = _eail_get_line_start(prev_cur) +
886 _eail_get_line_length(prev_cur);
889 g_assert_not_reached();
898 while (_eail_iter_next_line (cur));
902 start_index = _eail_get_line_start(prev_cur) +
903 _eail_get_line_length(prev_cur);
904 end_index = start_index;
906 evas_textblock_cursor_free(cur);
908 *start_offset = g_utf8_pointer_to_offset (text, text + start_index);
909 *end_offset = g_utf8_pointer_to_offset (text, text + end_index);
913 * @brief Gets a slice of the text from entry after offset
915 * Use g_free() to free the returned string.
917 * @param entry entry widget
918 * @param offset character offset
919 * @param boundary_type AtkTextBoundary instance
920 * @param [out] start_offset start position of the returned text
921 * @param [out] end_offset end position of the returned text
922 * @returns newly allocated string containg a slice of text from textblock
925 _eail_get_text_after(Evas_Object *entry,
927 AtkTextBoundary boundary_type,
934 Evas_Object *textblock;
936 if (!entry) return g_strdup("");
938 textblock = elm_entry_textblock_get(entry);
940 text = evas_textblock_text_markup_to_utf8(
941 textblock, evas_object_textblock_text_markup_get(textblock));
951 len = _eail_get_len(textblock);
953 switch (boundary_type)
955 case ATK_TEXT_BOUNDARY_CHAR:
956 start = _eail_move_chars(textblock, start, 1);
958 end = _eail_move_chars(textblock, end, 1);
961 case ATK_TEXT_BOUNDARY_WORD_START:
962 if (_eail_is_inside_word(textblock, end))
963 end = _eail_move_words(textblock, end, 1);
964 while (!_eail_is_word_start(textblock, end) && end < len)
965 end = _eail_move_chars(textblock, end, 1);
969 end = _eail_move_words(textblock, end, 1);
970 while (!_eail_is_word_start(textblock, end) && end < len)
971 end = _eail_move_chars(textblock, end, 1);
975 case ATK_TEXT_BOUNDARY_WORD_END:
976 end = _eail_move_words(textblock, end, 1);
979 end = _eail_move_words(textblock, end, 1);
982 case ATK_TEXT_BOUNDARY_SENTENCE_START:
983 case ATK_TEXT_BOUNDARY_SENTENCE_END:
986 case ATK_TEXT_BOUNDARY_LINE_START:
987 case ATK_TEXT_BOUNDARY_LINE_END:
988 _eail_get_line_after (entry, boundary_type, offset, &start, &end);
992 *start_offset = start;
994 g_assert(start <= end);
996 return g_utf8_substring(text, start, end);
1000 * @brief Gets a slice of the text from entry at offset
1002 * Use g_free() to free the returned string.
1004 * @param entry entry widget instance
1005 * @param offset character offset
1006 * @param boundary_type AtkTextBoundary instance
1007 * @param [out] start_offset start position of the returned text
1008 * @param [out] end_offset end position of the return text
1009 * @returns newly allocated string containing a slice of text from entry
1012 _eail_get_text_at(Evas_Object *entry,
1014 AtkTextBoundary boundary_type,
1021 Evas_Object *textblock;
1023 if (!entry) return g_strdup("");
1025 textblock = elm_entry_textblock_get(entry);
1027 text = evas_textblock_text_markup_to_utf8(
1028 textblock, evas_object_textblock_text_markup_get(textblock));
1033 return g_strdup("");
1038 len = _eail_get_len(textblock);
1040 switch (boundary_type)
1042 case ATK_TEXT_BOUNDARY_CHAR:
1043 end = _eail_move_chars(textblock, end, 1);
1046 case ATK_TEXT_BOUNDARY_WORD_START:
1047 if (!_eail_is_word_start(textblock, start))
1048 start = _eail_move_words(textblock, start, -1);
1049 if (_eail_is_inside_word(textblock, end))
1050 end = _eail_move_words(textblock, end, 1);
1051 while (!_eail_is_word_start(textblock, end) && end < len)
1052 end = _eail_move_chars(textblock, end, 1);
1055 case ATK_TEXT_BOUNDARY_WORD_END:
1056 if (_eail_is_inside_word(textblock, start) &&
1057 !_eail_is_word_start(textblock, start))
1058 start = _eail_move_words(textblock, start, -1);
1059 while (!_eail_is_word_end(textblock, start) && start > 0)
1060 start = _eail_move_chars(textblock, start, -1);
1061 end = _eail_move_words(textblock, end, 1);
1064 case ATK_TEXT_BOUNDARY_SENTENCE_START:
1065 case ATK_TEXT_BOUNDARY_SENTENCE_END:
1068 case ATK_TEXT_BOUNDARY_LINE_START:
1069 case ATK_TEXT_BOUNDARY_LINE_END:
1070 _eail_get_line_at (entry, boundary_type, offset, &start, &end);
1074 *start_offset = start;
1076 g_assert(start <= end);
1078 return g_utf8_substring(text, start, end);
1082 * @brief Gets a slice of the text from entry before offset
1084 * Use g_free() to free the returned string.
1086 * @param entry entry widget instance
1087 * @param offset character offset
1088 * @param boundary_type AtkTextBoundary instance
1089 * @param [out] start_offset start position of the returned text
1090 * @param [out] end_offset end position of the returned text
1091 * @returns newly allocated string containing a slice of text from entry
1094 _eail_get_text_before(Evas_Object *entry,
1096 AtkTextBoundary boundary_type,
1102 Evas_Object *textblock;
1104 if (!entry) return g_strdup("");
1106 textblock = elm_entry_textblock_get(entry);
1108 text = evas_textblock_text_markup_to_utf8(
1109 textblock, evas_object_textblock_text_markup_get(textblock));
1114 return g_strdup("");
1120 switch (boundary_type)
1122 case ATK_TEXT_BOUNDARY_CHAR:
1123 start = _eail_move_chars(textblock, start, -1);
1126 case ATK_TEXT_BOUNDARY_WORD_START:
1127 if (!_eail_is_word_start(textblock, start))
1128 start = _eail_move_words(textblock, start, -1);
1130 start = _eail_move_words(textblock, start, -1);
1133 case ATK_TEXT_BOUNDARY_WORD_END:
1134 if (_eail_is_inside_word(textblock, start) &&
1135 !_eail_is_word_start(textblock, start))
1136 start = _eail_move_words(textblock, start, -1);
1137 while (!_eail_is_word_end(textblock, start) && start > 0)
1138 start = _eail_move_chars(textblock, start, -1);
1140 start = _eail_move_words(textblock, start, -1);
1141 while (!_eail_is_word_end(textblock, start) && start > 0)
1142 start = _eail_move_chars(textblock, start, -1);
1145 case ATK_TEXT_BOUNDARY_SENTENCE_START:
1146 case ATK_TEXT_BOUNDARY_SENTENCE_END:
1149 case ATK_TEXT_BOUNDARY_LINE_START:
1150 case ATK_TEXT_BOUNDARY_LINE_END:
1151 _eail_get_line_before (entry, boundary_type, offset, &start, &end);
1155 *start_offset = start;
1157 g_assert(start <= end);
1159 return g_utf8_substring(text, start, end);
1163 * @brief Gets the specified text after offset
1165 * Use g_free() to free the returned string.
1167 * @param text AtkText instance
1168 * @param offset character offset
1169 * @param boundary_type AtkTextBoundary instance
1170 * @param [out] start_offset start offset of the returned string
1171 * @param [out] end_offset offset of the first character after the returned
1173 * @returns newly allocated string containing the text after offset bounded
1174 * by the specified boundary_type
1177 eail_entry_get_text_after_offset(AtkText *text,
1179 AtkTextBoundary boundary_type,
1183 Evas_Object *widget;
1185 widget = eail_widget_get_widget(EAIL_WIDGET(text));
1186 if (!widget) return NULL;
1188 return _eail_get_text_after(widget, offset, boundary_type, start_offset,
1194 * @brief Gets the specified text at offset
1196 * Use g_free() to free the returned string.
1198 * @param text AtkText instance
1199 * @param offset character offset
1200 * @param boundary_type AtkTextBoundary instance
1201 * @param [out] start_offset start offset of the returned string
1202 * @param [out] end_offset offset of the first character after the returned
1204 * @returns newly allocated string containing the text after offset bounded
1205 * by the specified boundary_type
1208 eail_entry_get_text_at_offset(AtkText *text,
1210 AtkTextBoundary boundary_type,
1214 Evas_Object *widget;
1216 widget = eail_widget_get_widget(EAIL_WIDGET(text));
1217 if (!widget) return NULL;
1219 return _eail_get_text_at(widget, offset, boundary_type, start_offset,
1224 * @brief Gets the specified text before offset
1226 * Use g_free() to free the returned string.
1228 * @param text AtkText instance
1229 * @param offset character offset
1230 * @param boundary_type AtkTextBoundary instance
1231 * @param [out] start_offset start offset of the returned string
1232 * @param [out] end_offset offset of the first character after the returned
1234 * @returns newly allocated string containing the text after offset bounded
1235 * by the specified boundary_type
1238 eail_entry_get_text_before_offset(AtkText *text,
1240 AtkTextBoundary boundary_type,
1244 Evas_Object *widget;
1246 widget = eail_widget_get_widget(EAIL_WIDGET(text));
1247 if (!widget) return NULL;
1249 return _eail_get_text_before(widget, offset, boundary_type, start_offset,
1254 * @brief Gets the character at offset
1256 * @param text AtkText instance
1257 * @param offset character offset
1258 * @return char representing the character at offset
1261 eail_entry_get_character_at_offset(AtkText *text,
1264 gunichar character = '\0';
1265 Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
1268 character = g_utf8_get_char(
1269 g_utf8_offset_to_pointer(elm_entry_entry_get(widget), offset));
1275 * @brief Gets the text's length
1277 * @param text AtkText instance
1278 * @return integer representing the text length
1281 eail_entry_get_character_count(AtkText *text)
1284 const gchar *string_text = NULL;
1286 Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
1288 if (!widget) return count;
1290 string_text = elm_object_text_get(widget);
1291 if (!string_text) return count;
1293 count = g_utf8_strlen(string_text, -1);
1299 * @brief Adds attribute to attribute set
1301 * Creates an AtkAttribute from attr and value, and adds it
1304 * @param attrib_set AtkAttributeSet instance to add the attribute to
1305 * @param attr AtkTextAttrribute instance which identifies the attribute to be added
1306 * @param value attribute value
1308 * @returns: AtkAttributeSet representing the new attribute set
1311 eail_entry_add_attribute(AtkAttributeSet *attrib_set,
1312 AtkTextAttribute attr,
1315 AtkAttributeSet *return_set;
1316 AtkAttribute *at = g_malloc (sizeof (AtkAttribute));
1317 at->name = g_strdup (atk_text_attribute_get_name (attr));
1319 return_set = g_slist_prepend(attrib_set, at);
1324 * @brief Creates an AtkAttributeSet which consists of the default values of
1325 * attributes for the text
1327 * The returned AtkAttributeSet should be freed by a call to
1328 * atk_attribute_set_free().
1330 * @param text AtkText instance
1332 * @returns AtkAttributeSet which contains the default values of attributes
1336 eail_entry_get_default_attributes(AtkText *text)
1338 AtkAttributeSet *at_set = NULL;
1340 at_set = eail_entry_add_attribute
1341 (at_set, ATK_TEXT_ATTR_WRAP_MODE,
1343 (atk_text_attribute_get_value(ATK_TEXT_ATTR_WRAP_MODE, 0)));
1345 at_set = eail_entry_add_attribute
1346 (at_set, ATK_TEXT_ATTR_EDITABLE,
1348 (atk_text_attribute_get_value
1349 (ATK_TEXT_ATTR_EDITABLE, TRUE)));
1355 * @brief Creates an AtkAttributeSet which consists of the attributes
1356 * explicitly set at the position offset in the text
1358 * start_offset and end_offset are set to the start and end of the range
1359 * around offset where the attributes are invariant. Note that end_offset
1360 * is the offset of the first character after the range.
1362 * The returned AtkAttributeSet should be freed by a call to
1363 * atk_attribute_set_free()
1365 * @param text AtkText instance
1366 * @param offset offset at which to get the attributes
1367 * @param [out] start_offset start offset of the range
1368 * @param [out] end_offset end offset of the range
1370 * @returns AtkAttributeSet which contains the attributes explicitly set at
1374 eail_entry_get_run_attributes(AtkText *text,
1379 AtkAttributeSet *at_set = NULL;
1380 Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
1382 if (!widget || offset >= eail_entry_get_character_count(text))
1391 *end_offset = eail_entry_get_character_count(text);
1393 /* NOTE: Elm_Wrap_Type value is in 100% compatible with ATK wrap modes, so
1394 * no additional conversion is needed*/
1395 Elm_Wrap_Type wrap_type = elm_entry_line_wrap_get(widget);
1396 at_set = eail_entry_add_attribute
1397 (at_set, ATK_TEXT_ATTR_WRAP_MODE,
1399 (atk_text_attribute_get_value
1400 (ATK_TEXT_ATTR_WRAP_MODE, wrap_type)));
1402 Eina_Bool editable = elm_entry_editable_get(widget);
1403 at_set = eail_entry_add_attribute
1404 (at_set, ATK_TEXT_ATTR_EDITABLE,
1406 (atk_text_attribute_get_value
1407 (ATK_TEXT_ATTR_EDITABLE, editable)));
1413 * @brief Initializes AtkTextIface interface
1415 * @param iface AtkTextIface instance
1418 atk_text_interface_init(AtkTextIface *iface)
1420 iface->get_caret_offset = eail_entry_get_caret_offset;
1421 iface->set_caret_offset = eail_entry_set_caret_offset;
1422 iface->get_selection = eail_entry_get_selection;
1423 iface->set_selection = eail_entry_set_selection;
1424 iface->get_text = eail_entry_get_text;
1425 iface->get_character_at_offset = eail_entry_get_character_at_offset;
1426 iface->get_character_count = eail_entry_get_character_count;
1427 iface->remove_selection = eail_entry_remove_selection;
1428 iface->get_n_selections = eail_entry_get_n_selections;
1429 iface->add_selection = eail_entry_add_selection;
1430 iface->get_run_attributes = eail_entry_get_run_attributes;
1431 iface->get_default_attributes = eail_entry_get_default_attributes;
1432 iface->get_text_after_offset = eail_entry_get_text_after_offset;
1433 iface->get_text_at_offset = eail_entry_get_text_at_offset;
1434 iface->get_text_before_offset = eail_entry_get_text_before_offset;
1438 * Implementation of the *AtkEditableText* interface
1442 * @brief Sets text content of entry
1444 * @param text AtkEditableText instance
1445 * @param string string to be set as the content of entry
1448 eail_entry_set_text_contents(AtkEditableText *text,
1449 const gchar *string)
1451 Evas_Object *widget;
1453 widget = eail_widget_get_widget(EAIL_WIDGET(text));
1454 if (widget && elm_entry_editable_get(widget))
1455 elm_object_text_set(widget, string);
1459 * @brief Copies text content from entry to clipboard
1461 * @param text AtkEditableText instance
1462 * @param start_pos start position of the cursor
1463 * @param end_pos end position of the cursor
1466 eail_entry_copy_text(AtkEditableText *text,
1470 Evas_Object *widget;
1471 const char *entry_text;
1474 widget = eail_widget_get_widget(EAIL_WIDGET(text));
1475 if (!widget) return;
1477 entry_text = elm_entry_entry_get(widget);
1478 tmp = eail_get_substring(entry_text, start_pos, end_pos);
1479 eail_clipboard_set_text(tmp);
1484 * @brief Cuts text content from entry to clipboard
1486 * @param text AtkEditableText instance
1487 * @param start_pos start position of the cursor
1488 * @param end_pos end position of the cursor
1491 eail_entry_cut_text(AtkEditableText *text,
1495 Evas_Object *widget;
1496 const char *entry_text;
1500 widget = eail_widget_get_widget(EAIL_WIDGET(text));
1501 if (!widget || !elm_entry_editable_get(widget))
1504 entry_text = elm_entry_entry_get(widget);
1505 tmp = eail_get_substring(entry_text, start_pos, end_pos);
1506 eail_clipboard_set_text(tmp);
1509 s = g_string_new(entry_text);
1510 s = g_string_erase(s, start_pos, end_pos - start_pos);
1512 elm_entry_entry_set(widget, s->str);
1513 g_string_free(s, TRUE);
1517 * @brief Pastes text content from clipboard into entry
1519 * @param text AtkEditableText instance
1520 * @param position start position of the cursor
1523 eail_entry_paste_text(AtkEditableText *text,
1526 Evas_Object *widget;
1530 widget = eail_widget_get_widget(EAIL_WIDGET(text));
1531 if (!widget || !elm_entry_editable_get(widget))
1534 clip = eail_clipboard_get_text();
1537 s = g_string_new(elm_entry_entry_get(widget));
1538 s = g_string_insert(s, position, clip);
1539 elm_entry_entry_set(widget, s->str);
1540 g_string_free(s, TRUE);
1544 * @brief Deletes text between start_pos and end_pos but not
1547 * @param text AtkEditableText instance
1548 * @param start_pos start position
1549 * @param end_pos end position
1552 eail_entry_delete_text(AtkEditableText *text,
1556 Evas_Object *widget;
1557 GString *entry_text;
1559 widget = eail_widget_get_widget(EAIL_WIDGET(text));
1560 if (!widget || !elm_entry_editable_get(widget))
1563 entry_text = g_string_new(elm_entry_entry_get(widget));
1564 entry_text = g_string_erase(entry_text, start_pos, end_pos-start_pos);
1566 elm_entry_entry_set(widget, entry_text->str);
1567 g_string_free(entry_text, TRUE);
1571 * @brief Inserts text at the specified position
1573 * After the call position points to the position after the newly inserted text.
1575 * @param text AtkEditableText instance
1576 * @param string string to insert
1577 * @param length string's length
1578 * @param [out] position position at which text is inserted
1581 eail_entry_insert_text(AtkEditableText *text,
1582 const gchar *string,
1586 Evas_Object *widget;
1587 GString *entry_text;
1589 widget = eail_widget_get_widget(EAIL_WIDGET(text));
1590 if (!widget || !elm_entry_editable_get(widget))
1593 entry_text = g_string_new(elm_entry_entry_get(widget));
1594 entry_text = g_string_insert_len(entry_text, *position, string,
1596 elm_entry_entry_set(widget, entry_text->str);
1597 *position += length;
1598 g_string_free(entry_text, TRUE);
1602 * @brief Initialization for AtkEditableTextIface interface
1604 * Function called upon instance creation. It initializes AtkText interface
1605 * implementation i.e hooks method pointers in the interface structure
1606 * to the implementing class's implementation.
1608 * @param iface AtkEditableTextIface instance
1611 atk_editable_text_interface_init(AtkEditableTextIface *iface)
1613 iface->set_text_contents = eail_entry_set_text_contents;
1614 iface->copy_text = eail_entry_copy_text;
1615 iface->cut_text = eail_entry_cut_text;
1616 iface->paste_text = eail_entry_paste_text;
1617 iface->delete_text = eail_entry_delete_text;
1618 iface->insert_text = eail_entry_insert_text;