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 Implementation of entry widget
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
41 G_DEFINE_TYPE_WITH_CODE(EailEntry,
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));
50 * @brief handler for event which is raised when entry content is being changed
52 * @param data passed to callback
53 * @param obj object that raised event
54 * @param event_info additional event info
57 _eail_entry_handle_changed_event(void *data,
62 (ATK_OBJECT(data), "visible-data-changed", ATK_TYPE_OBJECT);
66 * @brief handler for event which is raised when entry content is being pressed
68 * @param data passed to callback
69 * @param obj object that raised event
70 * @param event_info additional event info
73 _eail_entry_handle_pressed_event(void *data,
77 atk_object_notify_state_change(ATK_OBJECT(data), ATK_STATE_PRESSED, TRUE);
81 * @brief Initializer for AtkObject
83 * @param obj an AtkObject
84 * @param data Initialization data
87 eail_entry_initialize(AtkObject *obj, gpointer data)
89 Evas_Object *nested_widget = NULL;
90 ATK_OBJECT_CLASS(eail_entry_parent_class)->initialize(obj, data);
92 obj->role = ATK_ROLE_ENTRY;
94 g_return_if_fail(EAIL_IS_WIDGET(obj));
95 nested_widget = eail_widget_get_widget(EAIL_WIDGET(obj));
98 ERR("No evas object inside EailWidget was found");
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);
111 * @brief Class destructor
113 * @param obj object instance
116 eail_entry_finalize(GObject *obj)
121 * @brief Implementation of AtkObject->ref_state_set callback
124 * Gets a reference to the state set of the accessible; the caller must
125 * unreference it when it is no longer needed.
127 * @param obj an AtkObject
129 * @returns a reference to an AtkStateSet which is the state set of the
133 eail_entry_ref_state_set(AtkObject *obj)
135 AtkStateSet *state_set;
136 Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(obj));
141 state_set = ATK_OBJECT_CLASS(eail_entry_parent_class)->ref_state_set(obj);
143 if (elm_entry_editable_get(widget))
144 atk_state_set_add_state(state_set, ATK_STATE_EDITABLE);
146 if (elm_entry_single_line_get(widget))
147 atk_state_set_add_state(state_set, ATK_STATE_SINGLE_LINE);
149 atk_state_set_add_state(state_set, ATK_STATE_MULTI_LINE);
155 * @brief Initializer for EailEntry GObject implementation
157 * @param entry an EailEntry
160 eail_entry_init(EailEntry *entry)
162 entry->selection_start = 0;
163 entry->selection_end = 0;
167 * @brief Initializer for EailPopup GObject class (defines callbacks for
170 * @param klass an EailEntryClass
173 eail_entry_class_init(EailEntryClass *klass)
175 AtkObjectClass *class = ATK_OBJECT_CLASS(klass);
176 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
178 class->initialize = eail_entry_initialize;
179 class->ref_state_set = eail_entry_ref_state_set;
180 gobject_class->finalize = eail_entry_finalize;
184 * @brief Gets caret offset
186 * @param text an AtkText
187 * @return caret offset
190 eail_entry_get_caret_offset(AtkText *text)
194 widget = eail_widget_get_widget(EAIL_WIDGET(text));
198 return elm_entry_cursor_pos_get(widget);
202 * @brief Sets offset for caret
204 * Implementation of AtkTextIface->set_caret_offset callback<br>
206 * Sets the caret (cursor) position to the specified offset.
208 * @param text an AtkText
209 * @param offset starting position
211 * @returns TRUE if 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 an AtkText
232 * @returns number of selected text regions
235 eail_entry_get_n_selections(AtkText *text)
239 widget = eail_widget_get_widget(EAIL_WIDGET(text));
240 if (!widget) return 0;
242 if (elm_entry_selection_get(widget)) return 1;
248 * @brief Gets text selection from entry
250 * Implementation of AtkTextIface->get_selection callback
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
261 * @returns a newly allocated string containing the selected text. Use g_free()
262 * to free the returned string.
265 eail_entry_get_selection(AtkText *text,
270 const char* selection;
273 widget = eail_widget_get_widget(EAIL_WIDGET(text));
277 if (0 != selection_num)
280 selection = elm_entry_selection_get(widget);
283 *start_offset = EAIL_ENTRY(text)->selection_start;
284 *end_offset = EAIL_ENTRY(text)->selection_end;
285 return g_strdup(selection);
292 * @brief Adds a selection bounded by the specified offsets
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
300 eail_entry_add_selection(AtkText *text,
306 widget = eail_widget_get_widget(EAIL_WIDGET(text));
307 if (!widget) return FALSE;
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);
314 EAIL_ENTRY(text)->selection_start = start_offset;
315 EAIL_ENTRY(text)->selection_end = end_offset;
321 * @brief Removes text selection
323 * Only one selection is supported, so
324 * selection_number equals 0.
326 * @param text an AtkText
327 * @param selection_num selection number
328 * @return TRUE on success, FALSE otherwise
331 eail_entry_remove_selection(AtkText *text,
336 widget = eail_widget_get_widget(EAIL_WIDGET(text));
337 if (!widget) return FALSE;
339 if (selection_num != 0 || !elm_entry_selection_get(widget)) return FALSE;
341 elm_entry_select_none(widget);
342 EAIL_ENTRY(text)->selection_start = 0;
343 EAIL_ENTRY(text)->selection_end = 0;
349 * @brief Sets text selection for entry
351 * Implementation of AtkTextIface->set_selection callback
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
362 * @returns TRUE if success, FALSE otherwise
365 eail_entry_set_selection(AtkText *text,
370 if (0 != selection_num)
373 return eail_entry_add_selection(text, start_pos, end_pos);
377 * @brief Gets text bounded by start_offset and end_offset
379 * Use g_free() to free the returned string
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
388 eail_entry_get_text(AtkText *text,
392 const gchar *string = NULL;
393 Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
396 string = elm_entry_entry_get(widget);
398 return eail_get_substring(string, start_offset, end_offset);
404 * @brief Returns the position that is count characters from the
407 * count may be positive or negative.
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
415 _eail_move_chars(const Evas_Object *textblock,
419 Evas_Textblock_Cursor *cur;
423 dir = count > 0 ? 1 : -1;
424 cur = evas_object_textblock_cursor_new(textblock);
425 evas_textblock_cursor_pos_set(cur, offset);
429 res = dir > 0 ? evas_textblock_cursor_char_next(cur) :
430 evas_textblock_cursor_char_prev(cur);
436 offset = evas_textblock_cursor_pos_get(cur);
437 evas_textblock_cursor_free(cur);
443 * @brief Gets utf8 character at offset
445 * @param textblock an evas textblock
446 * @param offset a character offset
447 * @returns a utf8 character
450 _eail_get_unichar_at_offset(const Evas_Object *textblock,
453 Evas_Textblock_Cursor *cur;
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);
462 evas_textblock_cursor_free(cur);
469 * @brief Checks whether character at offset in textblock is a word start
471 * @param textblock an evas textblock
472 * @param offset a character offset
473 * @returns TRUE on success, FALSE otherwise
476 _eail_is_word_start(const Evas_Object *textblock,
479 /* first character in a word */
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;
490 * @brief Checks whether character at offset in textblock is a word end
492 * @param textblock an evas textblock
493 * @param offset a character offset
494 * @return TRUE on success, FALSE otherwise
497 _eail_is_word_end(const Evas_Object *textblock,
500 /* is first non-word char after a word */
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;
511 * @brief Check whether character at offset in textblock is inside a word
513 * @param textblock an evas textblock
514 * @param offset a character offset
515 * @returns TRUE on success, FALSE otherwise
518 _eail_is_inside_word(const Evas_Object *textblock,
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))
529 if (g_unichar_isalnum(c1) && g_unichar_isalnum(c2) && g_unichar_isspace(c3))
532 if (g_unichar_isspace(c1) && g_unichar_isalnum(c2) && g_unichar_isalnum(c3))
535 if (g_unichar_isspace(c1) && g_unichar_isalnum(c2) && g_unichar_isspace(c3))
542 * @brief Gets texblock length
544 * @param textblock an evas textblock
545 * @returns a textblock length
548 _eail_get_len(const Evas_Object *textblock)
550 Evas_Textblock_Cursor *cur;
553 cur = evas_object_textblock_cursor_new(textblock);
554 while (evas_textblock_cursor_char_next(cur))
557 evas_textblock_cursor_free(cur);
563 * @brief Returns the position that is count words from the given offset.
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.
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
574 _eail_move_words(const Evas_Object *textblock,
578 gint len = _eail_get_len(textblock);
580 while (count > 0 && offset < len)
584 while (offset < len && !_eail_is_word_end(textblock, offset));
588 while (count < 0 && offset > 0)
592 while (offset > 0 && !_eail_is_word_start(textblock, offset));
601 * @brief Gets position of first character in line
603 * @param cur an Evas_Textblock_Cursor
604 * @returns TRUE on success, FALSE otherwise
607 _eail_get_line_start(Evas_Textblock_Cursor *cur)
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);
621 * @brief Gets position of last character in line
623 * @param cur an Evas_Textblock_Cursor
624 * @returns TRUE on success, FALSE otherwise
627 _eail_get_line_end(Evas_Textblock_Cursor *cur)
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);
641 * @brief Moves cursor to the beginning of the next line
643 * @param cur an Evas_Textblock_Cursor
644 * @returns TRUE on success, FALSE otherwise
647 _eail_iter_next_line(Evas_Textblock_Cursor *cur)
649 evas_textblock_cursor_line_char_last(cur);
651 return evas_textblock_cursor_char_next(cur);
655 * @brief Gets length of the line shown by cursor cur
657 * @param cur an Evas_Textblock_Cursor
658 * @return line length
661 _eail_get_line_length(Evas_Textblock_Cursor *cur)
666 start = _eail_get_line_start(cur);
667 end = _eail_get_line_end(cur);
669 return end - start + 1;
673 * @brief Gets before at offset
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
683 _eail_get_line_before(Evas_Object *entry,
684 AtkTextBoundary boundary_type,
689 Evas_Object *textblock;
690 Evas_Textblock_Cursor *cur, *prev_cur = NULL, *prev_prev_cur = NULL;
691 gint index, start_index, end_index;
693 gboolean found = FALSE;
695 textblock = elm_entry_textblock_get(entry);
696 cur = evas_object_textblock_cursor_new(textblock);
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;
703 start_index = _eail_get_line_start(cur);
704 end_index = start_index + _eail_get_line_length(cur);
706 if (index >= start_index && index <= end_index)
708 /* Found line for offset */
711 switch (boundary_type)
713 case ATK_TEXT_BOUNDARY_LINE_START:
714 end_index = start_index;
715 start_index = _eail_get_line_start(prev_cur);
717 case ATK_TEXT_BOUNDARY_LINE_END:
719 start_index = _eail_get_line_start(prev_prev_cur) +
720 _eail_get_line_length(prev_prev_cur);
723 end_index = _eail_get_line_start(prev_cur) +
724 _eail_get_line_length(prev_cur);
727 g_assert_not_reached();
731 start_index = end_index = 0;
737 prev_prev_cur = prev_cur;
740 while (_eail_iter_next_line(cur));
744 start_index = _eail_get_line_start(prev_cur) +
745 _eail_get_line_length(prev_cur);
746 end_index = start_index;
748 evas_textblock_cursor_free(cur);
750 *start_offset = g_utf8_pointer_to_offset(text, text + start_index);
751 *end_offset = g_utf8_pointer_to_offset(text, text + end_index);
755 * @brief Gets line after offset
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
765 _eail_get_line_after (Evas_Object *entry,
766 AtkTextBoundary boundary_type,
771 Evas_Object *textblock;
772 Evas_Textblock_Cursor *cur, *prev_cur = NULL;
773 gint index, start_index, end_index;
775 gboolean found = FALSE;
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));
782 index = g_utf8_offset_to_pointer (text, offset) - text;
785 start_index = _eail_get_line_start(cur);
786 end_index = start_index + _eail_get_line_length(cur);
788 if (index >= start_index && index <= end_index)
790 /* Found line for offset */
791 if (_eail_iter_next_line (cur))
793 switch (boundary_type)
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);
800 end_index = start_index + _eail_get_line_length(cur);
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);
808 g_assert_not_reached();
812 start_index = end_index;
820 while (_eail_iter_next_line (cur));
824 start_index = _eail_get_line_start(prev_cur) +
825 _eail_get_line_length(prev_cur);
826 end_index = start_index;
828 evas_textblock_cursor_free(cur);
830 *start_offset = g_utf8_pointer_to_offset (text, text + start_index);
831 *end_offset = g_utf8_pointer_to_offset (text, text + end_index);
835 * @brief Gets line at offset
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
845 _eail_get_line_at (Evas_Object *entry,
846 AtkTextBoundary boundary_type,
851 Evas_Object *textblock;
852 Evas_Textblock_Cursor *cur, *prev_cur = NULL;
853 gint index, start_index, end_index;
855 gboolean found = FALSE;
857 textblock = elm_entry_textblock_get(entry);
858 cur = evas_object_textblock_cursor_new(textblock);
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);
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);
870 if (index >= start_index && index <= end_index)
872 /* Found line for offset */
873 switch (boundary_type)
875 case ATK_TEXT_BOUNDARY_LINE_START:
876 if (_eail_iter_next_line (cur))
877 end_index = _eail_get_line_start(cur);
879 case ATK_TEXT_BOUNDARY_LINE_END:
881 start_index = _eail_get_line_start(prev_cur) +
882 _eail_get_line_length(prev_cur);
885 g_assert_not_reached();
894 while (_eail_iter_next_line (cur));
898 start_index = _eail_get_line_start(prev_cur) +
899 _eail_get_line_length(prev_cur);
900 end_index = start_index;
902 evas_textblock_cursor_free(cur);
904 *start_offset = g_utf8_pointer_to_offset (text, text + start_index);
905 *end_offset = g_utf8_pointer_to_offset (text, text + end_index);
909 * @brief Gets a slice of the text from entry after offset
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.
920 _eail_get_text_after(Evas_Object *entry,
922 AtkTextBoundary boundary_type,
929 Evas_Object *textblock;
931 if (!entry) return g_strdup("");
933 textblock = elm_entry_textblock_get(entry);
935 text = evas_textblock_text_markup_to_utf8(
936 textblock, evas_object_textblock_text_markup_get(textblock));
946 len = _eail_get_len(textblock);
948 switch (boundary_type)
950 case ATK_TEXT_BOUNDARY_CHAR:
951 start = _eail_move_chars(textblock, start, 1);
953 end = _eail_move_chars(textblock, end, 1);
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);
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);
970 case ATK_TEXT_BOUNDARY_WORD_END:
971 end = _eail_move_words(textblock, end, 1);
974 end = _eail_move_words(textblock, end, 1);
977 case ATK_TEXT_BOUNDARY_SENTENCE_START:
978 case ATK_TEXT_BOUNDARY_SENTENCE_END:
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);
987 *start_offset = start;
989 g_assert(start <= end);
991 return g_utf8_substring(text, start, end);
995 * @brief Gets a slice of the text from entry at offset
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().
1006 _eail_get_text_at(Evas_Object *entry,
1008 AtkTextBoundary boundary_type,
1015 Evas_Object *textblock;
1017 if (!entry) return g_strdup("");
1019 textblock = elm_entry_textblock_get(entry);
1021 text = evas_textblock_text_markup_to_utf8(
1022 textblock, evas_object_textblock_text_markup_get(textblock));
1027 return g_strdup("");
1032 len = _eail_get_len(textblock);
1034 switch (boundary_type)
1036 case ATK_TEXT_BOUNDARY_CHAR:
1037 end = _eail_move_chars(textblock, end, 1);
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);
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);
1058 case ATK_TEXT_BOUNDARY_SENTENCE_START:
1059 case ATK_TEXT_BOUNDARY_SENTENCE_END:
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);
1068 *start_offset = start;
1070 g_assert(start <= end);
1072 return g_utf8_substring(text, start, end);
1076 * @brief Gets a slice of the text from entry before offset
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().
1087 _eail_get_text_before(Evas_Object *entry,
1089 AtkTextBoundary boundary_type,
1095 Evas_Object *textblock;
1097 if (!entry) return g_strdup("");
1099 textblock = elm_entry_textblock_get(entry);
1101 text = evas_textblock_text_markup_to_utf8(
1102 textblock, evas_object_textblock_text_markup_get(textblock));
1107 return g_strdup("");
1113 switch (boundary_type)
1115 case ATK_TEXT_BOUNDARY_CHAR:
1116 start = _eail_move_chars(textblock, start, -1);
1119 case ATK_TEXT_BOUNDARY_WORD_START:
1120 if (!_eail_is_word_start(textblock, start))
1121 start = _eail_move_words(textblock, start, -1);
1123 start = _eail_move_words(textblock, start, -1);
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);
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);
1138 case ATK_TEXT_BOUNDARY_SENTENCE_START:
1139 case ATK_TEXT_BOUNDARY_SENTENCE_END:
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);
1148 *start_offset = start;
1150 g_assert(start <= end);
1152 return g_utf8_substring(text, start, end);
1156 * @brief Gets the specified text
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
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.
1168 eail_entry_get_text_after_offset(AtkText *text,
1170 AtkTextBoundary boundary_type,
1174 Evas_Object *widget;
1176 widget = eail_widget_get_widget(EAIL_WIDGET(text));
1177 if (!widget) return NULL;
1179 return _eail_get_text_after(widget, offset, boundary_type, start_offset,
1185 * @brief Gets the specified text
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
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.
1197 eail_entry_get_text_at_offset(AtkText *text,
1199 AtkTextBoundary boundary_type,
1203 Evas_Object *widget;
1205 widget = eail_widget_get_widget(EAIL_WIDGET(text));
1206 if (!widget) return NULL;
1208 return _eail_get_text_at(widget, offset, boundary_type, start_offset,
1213 * @brief Gets the specified text
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
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.
1225 eail_entry_get_text_before_offset(AtkText *text,
1227 AtkTextBoundary boundary_type,
1231 Evas_Object *widget;
1233 widget = eail_widget_get_widget(EAIL_WIDGET(text));
1234 if (!widget) return NULL;
1236 return _eail_get_text_before(widget, offset, boundary_type, start_offset,
1241 * @brief Gets character at offset
1243 * @param text an AtkText
1244 * @param offset character offset
1245 * @return character at offset
1248 eail_entry_get_character_at_offset(AtkText *text,
1251 gunichar character = '\0';
1252 Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
1255 character = g_utf8_get_char(
1256 g_utf8_offset_to_pointer(elm_entry_entry_get(widget), offset));
1262 * @brief Gets text length
1264 * @param text an AtkText
1265 * @return text length
1268 eail_entry_get_character_count(AtkText *text)
1271 const gchar *string_text = NULL;
1273 Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
1275 if (!widget) return count;
1277 string_text = elm_object_text_get(widget);
1278 if (!string_text) return count;
1280 count = g_utf8_strlen(string_text, -1);
1286 * @brief Adds attribute to attribute set
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
1292 * Creates an AtkAttribute from attr and value, and adds it
1295 * @returns: A pointer to the new AtkAttributeSet.
1298 eail_entry_add_attribute(AtkAttributeSet *attrib_set,
1299 AtkTextAttribute attr,
1302 AtkAttributeSet *return_set;
1303 AtkAttribute *at = g_malloc (sizeof (AtkAttribute));
1304 at->name = g_strdup (atk_text_attribute_get_name (attr));
1306 return_set = g_slist_prepend(attrib_set, at);
1311 * @brief Creates an AtkAttributeSet which consists of the default values of
1312 * attributes for the text.
1314 * @param text an AtkText
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()
1321 eail_entry_get_default_attributes(AtkText *text)
1323 AtkAttributeSet *at_set = NULL;
1325 at_set = eail_entry_add_attribute
1326 (at_set, ATK_TEXT_ATTR_WRAP_MODE,
1328 (atk_text_attribute_get_value(ATK_TEXT_ATTR_WRAP_MODE, 0)));
1330 at_set = eail_entry_add_attribute
1331 (at_set, ATK_TEXT_ATTR_EDITABLE,
1333 (atk_text_attribute_get_value
1334 (ATK_TEXT_ATTR_EDITABLE, TRUE)));
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.
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)
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()
1358 eail_entry_get_run_attributes(AtkText *text,
1363 AtkAttributeSet *at_set = NULL;
1364 Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
1366 if (!widget || offset >= eail_entry_get_character_count(text))
1375 *end_offset = eail_entry_get_character_count(text);
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,
1383 (atk_text_attribute_get_value
1384 (ATK_TEXT_ATTR_WRAP_MODE, wrap_type)));
1386 Eina_Bool editable = elm_entry_editable_get(widget);
1387 at_set = eail_entry_add_attribute
1388 (at_set, ATK_TEXT_ATTR_EDITABLE,
1390 (atk_text_attribute_get_value
1391 (ATK_TEXT_ATTR_EDITABLE, editable)));
1397 * @brief Initializes AtkTextIface interface
1399 * @param iface an AtkTextIface
1402 atk_text_interface_init(AtkTextIface *iface)
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;
1422 * Implementation of the *AtkEditableText* interface
1426 * @brief Set text content for entry
1427 * @param text an AtkEditableText
1428 * @param string string to be set
1431 eail_entry_set_text_contents(AtkEditableText *text,
1432 const gchar *string)
1434 Evas_Object *widget;
1436 widget = eail_widget_get_widget(EAIL_WIDGET(text));
1437 if (widget && elm_entry_editable_get(widget))
1438 elm_object_text_set(widget, string);
1442 * @brief Copies text content from entry to clipboard
1444 * @param text an AtkEditableText
1445 * @param start_pos start position of cursor
1446 * @param end_pos end position of cursor
1449 eail_entry_copy_text(AtkEditableText *text,
1453 Evas_Object *widget;
1454 const char *entry_text;
1457 widget = eail_widget_get_widget(EAIL_WIDGET(text));
1458 if (!widget) return;
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);
1467 * @brief Cuts text content from entry to clipboard
1469 * @param text an AtkEditableText
1470 * @param start_pos start position of cursor
1471 * @param end_pos end position of cursor
1474 eail_entry_cut_text(AtkEditableText *text,
1478 Evas_Object *widget;
1479 const char *entry_text;
1483 widget = eail_widget_get_widget(EAIL_WIDGET(text));
1484 if (!widget || !elm_entry_editable_get(widget))
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);
1492 s = g_string_new(entry_text);
1493 s = g_string_erase(s, start_pos, end_pos - start_pos);
1495 elm_entry_entry_set(widget, s->str);
1496 g_string_free(s, TRUE);
1500 * @brief Pastes text content from clipboard into entry
1502 * @param text an AtkEditableText
1503 * @param position start position of cursor
1506 eail_entry_paste_text(AtkEditableText *text,
1509 Evas_Object *widget;
1513 widget = eail_widget_get_widget(EAIL_WIDGET(text));
1514 if (!widget || !elm_entry_editable_get(widget))
1517 clip = eail_clipboard_get_text();
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);
1527 * @brief Deletes text between start_pos and end_pos but not
1530 * @param text an AtkEditableText
1531 * @param start_pos start position
1532 * @param end_pos end position
1535 eail_entry_delete_text(AtkEditableText *text,
1539 Evas_Object *widget;
1540 GString *entry_text;
1542 widget = eail_widget_get_widget(EAIL_WIDGET(text));
1543 if (!widget || !elm_entry_editable_get(widget))
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);
1549 elm_entry_entry_set(widget, entry_text->str);
1550 g_string_free(entry_text, TRUE);
1554 * @brief Inserts text at given position
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.
1563 eail_entry_insert_text(AtkEditableText *text,
1564 const gchar *string,
1568 Evas_Object *widget;
1569 GString *entry_text;
1571 widget = eail_widget_get_widget(EAIL_WIDGET(text));
1572 if (!widget || !elm_entry_editable_get(widget))
1575 entry_text = g_string_new(elm_entry_entry_get(widget));
1576 entry_text = g_string_insert_len(entry_text, *position, string,
1578 elm_entry_entry_set(widget, entry_text->str);
1579 *position += length;
1580 g_string_free(entry_text, TRUE);
1584 * @brief Initialization for AtkEditableTextIface interface
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.
1590 * @param iface an AtkEditableTextIface
1593 atk_editable_text_interface_init(AtkEditableTextIface *iface)
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;