Merge "custom eail widget implementation" into tizen
[platform/core/uifw/eail.git] / eail / eail_fileselector_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_fileselector_entry.c
22  * @brief EailFileselectorEntry implementation
23  */
24
25 #include <Elementary.h>
26
27 #include "eail_fileselector_entry.h"
28 #include "eail_factory.h"
29 #include "eail_utils.h"
30 #include "eail_priv.h"
31
32 static void atk_text_interface_init(AtkTextIface *iface);
33 static void eail_fileselector_entry_actions_init(EailActionWidget *widget);
34
35 #define ICON_CONTENT_NAME "button icon" /**< @brief content name for icon */
36 #define EAIL_FSE_ACTION_CLICK "click"/**< @brief 'click' action name */
37 #define EAIL_FSE_ACTION_LONGPRESS "longpress" /**< @brief 'longpress' action name */
38 #define EAIL_FSE_ACTION_PRESS "press" /**< @brief 'press' action name */
39 #define EAIL_FSE_ACTION_RELEASE "release" /**< @brief 'release' action name */
40
41 /**
42  * @brief Definition of EailFileselectorEntry as GObject
43  *
44  * EailFileselectorEntry is extended EAIL_TYPE_ACTION_WIDGET with ATK_TYPE_TEXT
45  * interface implemented.
46  */
47 G_DEFINE_TYPE_WITH_CODE(EailFileselectorEntry,
48                         eail_fileselector_entry,
49                         EAIL_TYPE_ACTION_WIDGET,
50                         G_IMPLEMENT_INTERFACE(ATK_TYPE_TEXT,
51                                               atk_text_interface_init));
52
53 /**
54  * @brief Initializer for AtkObject
55  *
56  * @param obj AtkObject instance
57  * @param data initialization data
58  */
59 static void
60 eail_fileselector_entry_initialize(AtkObject *obj, gpointer data)
61 {
62    ATK_OBJECT_CLASS(eail_fileselector_entry_parent_class) ->initialize(obj, data);
63    obj->role = ATK_ROLE_GROUPING;
64
65    EailActionWidget *action_widget = EAIL_ACTION_WIDGET(obj);
66
67    /* Initializing possible widget actions table*/
68    eail_fileselector_entry_actions_init(action_widget);
69 }
70
71 /**
72  * @brief Initializer for EailEntry GObject implementation
73  *
74  * @param fileselector_entry EailFileselectorEntry instance
75  */
76 static void
77 eail_fileselector_entry_init(EailFileselectorEntry *fileselector_entry)
78 {
79    fileselector_entry->selection_start = 0;
80    fileselector_entry->selection_end = 0;
81 }
82
83 /**
84  * @brief Gets the accessible name of FileselectorEntry
85  *
86  * Name is the label-text on the button.
87  *
88  * Implementation of get_name from AtkObject interface.
89  *
90  * @param obj AtkObject instance
91  *
92  * @returns character string representing the accessible name of
93  * the accessible
94  */
95 static const gchar *
96 eail_fileselector_entry_get_name(AtkObject *obj)
97 {
98    Evas_Object *fse_widget = NULL;
99    const gchar *atk_name = NULL;
100
101    /* returning name from ATK default implementation if available */
102    atk_name = ATK_OBJECT_CLASS(eail_fileselector_entry_parent_class)->get_name(obj);
103    if (atk_name)
104      return atk_name;
105
106    fse_widget = eail_widget_get_widget(EAIL_WIDGET(obj));
107    if (!fse_widget) return NULL;
108
109    return elm_object_part_text_get(fse_widget, "default");
110 }
111
112 /**
113  * @brief Gets nested button from FileSelectorEntry
114  *
115  * @param obj AtkObject instance
116  * @returns Evas_Object representing the file selector button
117  * or NULL if one was not found
118  */
119 static Evas_Object *
120 _eail_fileselector_entry_get_nested_button(AtkObject *obj)
121 {
122    Evas_Object *button_widget = NULL, *fse_widget = NULL;
123
124    fse_widget = eail_widget_get_widget(EAIL_WIDGET(obj));
125    if (!fse_widget) return NULL;
126
127    button_widget = elm_object_part_content_get(fse_widget, "elm.swallow.button");
128    if (!button_widget)
129      DBG("Button widget NOT found!");
130
131    return button_widget;
132 }
133
134 /**
135  * @brief Helper function for returning list of nested widgets in fileselector entry
136  *
137  * @param obj AtkObject instance
138  *
139  * @return Eina_list representing the list of Evas_Object* objects with nested widgets
140  */
141 static Eina_List *
142 _eail_fileselector_entry_get_items(AtkObject *obj)
143 {
144    Eina_List *items = NULL;
145    Evas_Object *icon_widget = NULL, *fse_widget = NULL;
146
147    fse_widget = eail_widget_get_widget(EAIL_WIDGET(obj));
148    if (!fse_widget) return NULL;
149
150    icon_widget = elm_object_part_content_get(fse_widget, ICON_CONTENT_NAME);
151    if (!icon_widget) return NULL;
152
153    items = eina_list_append(items, icon_widget);
154
155    return items;
156 }
157
158 /**
159  * @brief Gets the number of accessible children of the accessible
160  *
161  * Implementation of get_n_children from AtkObject interface.
162  *
163  * @param obj AtkObject instance
164  *
165  * @returns integer representing the number of accessible children of
166  * the accessible
167  */
168 static gint
169 eail_fileselector_entry_get_n_children(AtkObject *obj)
170 {
171    gint n_items;
172    Eina_List *items;
173
174    items = _eail_fileselector_entry_get_items(obj);
175    n_items = eina_list_count(items);
176
177    eina_list_free(items);
178
179    return n_items;
180 }
181
182 /**
183  * @brief Gets a reference to the specified accessible child of the object
184  *
185  * The accessible children are 0-based so the first accessible child
186  * is at index 0, the second at index 1 and so on.
187  *
188  * Implementation of get_n_children from AtkObject interface.
189  *
190  * @param obj AtkObject instance
191  * @param i index of the child
192  *
193  * @returns AtkObject representing the specified accessible child of the
194  * accessible
195  */
196 static AtkObject *
197 eail_fileselector_entry_ref_child(AtkObject *obj, gint i)
198 {
199    Eina_List *items = NULL;
200    AtkObject *child = NULL;
201
202    items = _eail_fileselector_entry_get_items(obj);
203    if (eina_list_count(items) > i)
204      {
205         child = eail_factory_get_accessible(eina_list_nth(items, i));
206         if (child)  g_object_ref(child);
207      }
208
209    eina_list_free(items);
210
211    return child;
212 }
213
214 /**
215  * @brief Destructor of FileselectorEntry class
216  *
217  * @param object GObject instance to be finalized
218  */
219 static void
220 eail_fileselector_entry_finalize(GObject *object)
221 {
222    G_OBJECT_CLASS(eail_fileselector_entry_parent_class)->finalize(object);
223 }
224
225 /**
226  * @brief Initializer for EailFileselectorEntry GObject class
227  *
228  * Defines callbacks for base AtkObject.
229  *
230  * @param klass EailFileselectorEntryClass instance
231  */
232 static void
233 eail_fileselector_entry_class_init(EailFileselectorEntryClass *klass)
234 {
235    AtkObjectClass *atk_class = ATK_OBJECT_CLASS(klass);
236    GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
237    atk_class->initialize = eail_fileselector_entry_initialize;
238    atk_class->get_name = eail_fileselector_entry_get_name;
239    atk_class->get_n_children = eail_fileselector_entry_get_n_children;
240    atk_class->ref_child = eail_fileselector_entry_ref_child;
241    gobject_class->finalize = eail_fileselector_entry_finalize;
242 }
243
244 /*
245  * Implementation of the *AtkText* interface
246  */
247
248 /**
249  * @brief Gets text content from item
250  *
251  * Implementation of get_text from AtkTextIface.
252  *
253  * Use g_free() to free the returned string.
254  *
255  * @param text AtkText instance
256  * @param start_offset start position
257  * @param end_offset end position, or -1 for the end of the string
258  *
259  * @returns newly allocated string containing the text from start_offset
260  * up to, but not including end_offset
261  */
262 static gchar*
263 eail_fileselector_entry_get_text(AtkText  *text,
264                                  gint      start_offset,
265                                  gint      end_offset)
266 {
267    gchar *ret_str = NULL;
268    Evas_Object *fse_widget = NULL;
269
270    fse_widget = eail_widget_get_widget(EAIL_WIDGET(text));
271    if (!fse_widget) return NULL;
272
273    ret_str = eail_get_substring
274                 (elm_fileselector_path_get(fse_widget),
275                  start_offset, end_offset);
276
277    return ret_str;
278 }
279
280 /**
281  * @brief Gets the character from popup at the given offset
282  *
283  * Implementation of get_character_at_offset from AtkTextIface.
284  *
285  * @param text AtkText instance
286  * @param offset character offset
287  *
288  * @returns char representing the character at offset
289  */
290 static gunichar
291 eail_fileselector_entry_get_character_at_offset(AtkText *text,
292                                                 gint     offset)
293 {
294    gunichar character = '\0';
295    gchar *entry_str = NULL;
296
297    entry_str = eail_fileselector_entry_get_text(text, 0, -1);
298    if (entry_str)
299       {
300          character = g_utf8_get_char
301                            (g_utf8_offset_to_pointer(entry_str, offset));
302          g_free(entry_str);
303       }
304
305    return character;
306 }
307
308 /**
309  * @brief Gets the number of characters from text content in item
310  *
311  * Implementation of get_character_count from AtkTextIface.
312  *
313  * @param text AtkText instance
314  *
315  * @returns integer representing the number of characters in text nontent
316  */
317 static gint
318 eail_fileselector_entry_get_character_count(AtkText *text)
319 {
320    gint count = 0;
321    gchar *entry_str = NULL;
322    entry_str = eail_fileselector_entry_get_text(text, 0, -1);
323
324     if (entry_str)
325       {
326          count = g_utf8_strlen(entry_str, -1);
327          g_free(entry_str);
328       }
329
330     return count;
331 }
332
333 /**
334  * @brief Gets the specified text after offset
335  *
336  * Use g_free() to free the returned string.
337  *
338  * @param text AtkText instance
339  * @param offset character offset
340  * @param boundary_type AtkTextBoundary instance
341  * @param [out] start_offset start offset of the returned string
342  * @param [out] end_offset offset of the first character after the returned
343  * substring
344  * @returns newly allocated string containing the text after offset bounded
345  * by the specified boundary_type
346  */
347 static gchar *
348 eail_fileselector_entry_get_text_after_offset(AtkText *text,
349                                               gint offset,
350                                               AtkTextBoundary boundary_type,
351                                               gint *start_offset,
352                                               gint *end_offset)
353 {
354    Evas_Object *widget;
355    Evas_Object *textblock;
356    Evas_Object *entry = NULL;
357    Evas_Object *fileselector_entry_edje_layer = NULL;
358
359    widget = eail_widget_get_widget(EAIL_WIDGET(text));
360    if (!widget) return NULL;
361
362    fileselector_entry_edje_layer = elm_layout_edje_get(widget);
363    if (!fileselector_entry_edje_layer) return NULL;
364
365    entry = edje_object_part_swallow_get(fileselector_entry_edje_layer,
366                                         "elm.swallow.entry");
367    if (!entry) return NULL;
368
369    textblock = elm_entry_textblock_get(entry);
370    if (!textblock) return NULL;
371
372    return eail_get_text_after(textblock, offset, boundary_type, start_offset,
373                               end_offset);
374
375 }
376
377 /**
378  * @brief Gets the specified text at offset
379  *
380  * Use g_free() to free the returned string.
381  *
382  * @param text AtkText instance
383  * @param offset character offset
384  * @param boundary_type AtkTextBoundary instance
385  * @param [out] start_offset start offset of the returned string
386  * @param [out] end_offset offset of the first character after the returned
387  * substring
388  * @returns newly allocated string containing the text after offset bounded
389  * by the specified boundary_type
390  */
391 static gchar *
392 eail_fileselector_entry_get_text_at_offset(AtkText *text,
393                                            gint offset,
394                                            AtkTextBoundary boundary_type,
395                                            gint *start_offset,
396                                            gint *end_offset)
397 {
398    Evas_Object *widget;
399    Evas_Object *textblock;
400    Evas_Object *entry = NULL;
401    Evas_Object *fileselector_entry_edje_layer = NULL;
402
403    widget = eail_widget_get_widget(EAIL_WIDGET(text));
404    if (!widget) return NULL;
405
406    fileselector_entry_edje_layer = elm_layout_edje_get(widget);
407    if (!fileselector_entry_edje_layer) return NULL;
408
409    entry = edje_object_part_swallow_get(fileselector_entry_edje_layer,
410                                         "elm.swallow.entry");
411    if (!entry) return NULL;
412
413    textblock = elm_entry_textblock_get(entry);
414    if (!textblock) return NULL;
415
416    return eail_get_text_at(textblock, offset, boundary_type, start_offset,
417                            end_offset);
418 }
419
420 /**
421  * @brief Gets the specified text before offset
422  *
423  * Use g_free() to free the returned string.
424  *
425  * @param text AtkText instance
426  * @param offset character offset
427  * @param boundary_type AtkTextBoundary instance
428  * @param [out] start_offset start offset of the returned string
429  * @param [out] end_offset offset of the first character after the returned
430  * substring
431  * @returns newly allocated string containing the text after offset bounded
432  * by the specified boundary_type
433  */
434 static gchar *
435 eail_fileselector_entry_get_text_before_offset(AtkText *text,
436                                                gint offset,
437                                                AtkTextBoundary boundary_type,
438                                                gint *start_offset,
439                                                gint *end_offset)
440 {
441    Evas_Object *widget;
442    Evas_Object *textblock;
443    Evas_Object *entry = NULL;
444    Evas_Object *fileselector_entry_edje_layer = NULL;
445
446    widget = eail_widget_get_widget(EAIL_WIDGET(text));
447    if (!widget) return NULL;
448
449    fileselector_entry_edje_layer = elm_layout_edje_get(widget);
450    if (!fileselector_entry_edje_layer) return NULL;
451
452    entry = edje_object_part_swallow_get(fileselector_entry_edje_layer,
453                                         "elm.swallow.entry");
454    if (!entry) return NULL;
455
456    textblock = elm_entry_textblock_get(entry);
457    if (!textblock) return NULL;
458
459    return eail_get_text_before(textblock, offset, boundary_type, start_offset,
460                                end_offset);
461 }
462
463 /*
464  * @brief Get the bounding box containing the glyph
465  *  representing the character at a particular text offset.
466  *
467  * @param text AtkText instance
468  * @param offset The offset of the text character for which
469  * bounding information is required.
470  * @param x Pointer for the x cordinate of the bounding box
471  * @param y Pointer for the y cordinate of the bounding box
472  * @param width Pointer for the width of the bounding box
473  * @param height Pointer for the height of the bounding box
474  * @param coords specify whether coordinates are relative to the
475  * screen or widget window
476  *
477  */
478 static void
479 eail_fileselector_entry_get_character_extents(AtkText *text,
480                                               gint offset,
481                                               gint *x,
482                                               gint *y,
483                                               gint *width,
484                                               gint *height,
485                                               AtkCoordType coords)
486 {
487    int result = -1;
488    const Evas_Object *textblock = NULL;
489    Evas_Textblock_Cursor *cur = NULL;
490    Evas_Object *entry = NULL;
491    Evas_Object *fileselector_entry_edje_layer = NULL;
492
493    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
494    if (!widget) return;
495
496    fileselector_entry_edje_layer = elm_layout_edje_get(widget);
497    if (!fileselector_entry_edje_layer) return;
498
499    entry = edje_object_part_swallow_get(fileselector_entry_edje_layer,
500                                         "elm.swallow.entry");
501    if (!entry) return;
502
503    textblock = elm_entry_textblock_get(entry);
504    if (!textblock) return;
505
506    cur = evas_object_textblock_cursor_new(textblock);
507    if (!cur) return;
508
509    evas_textblock_cursor_pos_set(cur, offset);
510
511    result = evas_textblock_cursor_char_geometry_get(cur, x, y, width, height);
512
513    evas_textblock_cursor_free(cur);
514
515    if (-1 == result) return;
516
517    if (coords == ATK_XY_SCREEN)
518    {
519       int ee_x, ee_y;
520       Ecore_Evas *ee= ecore_evas_ecore_evas_get(evas_object_evas_get(widget));
521
522       ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
523       *x += ee_x;
524       *y += ee_y;
525     }
526 }
527
528 /*
529  * @brief Adds a selection bounded by the specified offsets
530  *
531  * @param text AtkText instance
532  * @param start_offset start position of the selection
533  * @param end_offset offset of the first character after selection
534  * @returns TRUE on success, FALSE otherwise
535  */
536 static gboolean
537 eail_fileselector_entry_add_selection(AtkText *text,
538                                       gint start_offset,
539                                       gint end_offset)
540 {
541    Evas_Object *widget;
542    Evas_Object *entry;
543    Evas_Object *fileselector_entry_edje_layer = NULL;
544
545    widget = eail_widget_get_widget(EAIL_WIDGET(text));
546    if (!widget)
547      return FALSE;
548
549    fileselector_entry_edje_layer = elm_layout_edje_get(widget);
550    if (!fileselector_entry_edje_layer)
551      return FALSE;
552
553    entry = edje_object_part_swallow_get(fileselector_entry_edje_layer,
554                                         "elm.swallow.entry");
555    if (!entry)
556      return FALSE;
557
558    elm_entry_cursor_pos_set(entry, start_offset);
559    elm_entry_cursor_selection_begin(entry);
560    elm_entry_cursor_pos_set(entry, end_offset);
561    elm_entry_cursor_selection_end(entry);
562
563    EAIL_FILESELECTOR_ENTRY(text)->selection_start = start_offset;
564    EAIL_FILESELECTOR_ENTRY(text)->selection_end = end_offset;
565
566    return TRUE;
567 }
568
569 /**
570  * @brief Removes text selection
571  *
572  * This widget supports only one selection
573  * so selection_num should always be 0.
574  *
575  * @param text AtkText instance
576  * @param selection_num selection number
577  * @return TRUE on success, FALSE otherwise
578  */
579 static gboolean
580 eail_fileselector_entry_remove_selection(AtkText *text,
581                                          gint selection_num)
582 {
583    Evas_Object *widget;
584    Evas_Object *entry;
585    Evas_Object *fileselector_entry_edje_layer = NULL;
586
587    widget = eail_widget_get_widget(EAIL_WIDGET(text));
588    if (!widget)
589      return FALSE;
590
591    fileselector_entry_edje_layer = elm_layout_edje_get(widget);
592    if (!fileselector_entry_edje_layer)
593      return FALSE;
594
595    entry = edje_object_part_swallow_get(fileselector_entry_edje_layer,
596                                         "elm.swallow.entry");
597    if (!entry)
598      return FALSE;
599
600    if (selection_num != 0 || !elm_entry_selection_get(entry))
601      return FALSE;
602
603    elm_entry_select_none(entry);
604    EAIL_FILESELECTOR_ENTRY(text)->selection_start = 0;
605    EAIL_FILESELECTOR_ENTRY(text)->selection_end = 0;
606
607    return TRUE;
608 }
609
610 /**
611  * @brief Sets text selection for fileselector_entry
612  *
613  * This widget supports only one selection
614  * so selection_num should always be 0.
615  *
616  * @param text AtkText instance
617  * @param selection_num selection number
618  * @param start_pos start position of the selected region
619  * @param end_pos end position of the selected region
620  *
621  * @returns TRUE on success, FALSE otherwise
622  */
623 static gboolean
624 eail_fileselector_entry_set_selection(AtkText *text,
625                                       gint     selection_num,
626                                       gint     start_pos,
627                                       gint     end_pos)
628 {
629    if (0 != selection_num)
630      return FALSE;
631
632    return eail_fileselector_entry_add_selection(text, start_pos, end_pos);
633 }
634
635 /**
636  * @brief Gets text selection from fileselector_entry
637  *
638  * Use g_free() to free the returned string.
639  *
640  * This widget supports only one selection
641  * so selection_num should always be 0.
642  *
643  * @param text AtkText instance
644  * @param selection_num selection number
645  * @param start_offset start position of the selected region
646  * @param end_offset end position of the selected region
647  *
648  * @returns newly allocated string containing the selected text
649  */
650 static gchar *
651 eail_fileselector_entry_get_selection(AtkText *text,
652                                       gint     selection_num,
653                                       gint    *start_offset,
654                                       gint    *end_offset)
655 {
656    const char* selection;
657    Evas_Object *widget;
658    Evas_Object *entry;
659    Evas_Object *fileselector_entry_edje_layer = NULL;
660
661    if (0 != selection_num)
662      return g_strdup("");
663
664    widget = eail_widget_get_widget(EAIL_WIDGET(text));
665    if (!widget)
666      return g_strdup("");
667
668    fileselector_entry_edje_layer = elm_layout_edje_get(widget);
669    if (!fileselector_entry_edje_layer)
670      return g_strdup("");
671
672    entry = edje_object_part_swallow_get(fileselector_entry_edje_layer,
673                                         "elm.swallow.entry");
674    if (!widget)
675      return g_strdup("");
676
677    selection = elm_entry_selection_get(entry);
678    if (selection)
679    {
680      *start_offset = EAIL_FILESELECTOR_ENTRY(text)->selection_start;
681      *end_offset = EAIL_FILESELECTOR_ENTRY(text)->selection_end;
682      return g_strdup(selection);
683    }
684
685    return g_strdup("");
686 }
687
688
689 /**
690  * @brief Gets the number of selected text regions
691  *
692  * Only one selection is supported by this widget
693  * so the returned value is 0 or 1.
694  *
695  * @param text AtkText instance
696  * @returns integer representing the number of
697  * selected text regions
698  */
699 static gint
700 eail_fileselector_entry_get_n_selections(AtkText *text)
701 {
702    Evas_Object *widget;
703    Evas_Object *entry;
704    Evas_Object *fileselector_entry_edje_layer = NULL;
705
706    widget = eail_widget_get_widget(EAIL_WIDGET(text));
707    if (!widget)
708      return 0;
709
710    fileselector_entry_edje_layer = elm_layout_edje_get(widget);
711    if (!fileselector_entry_edje_layer)
712      return 0;
713
714    entry = edje_object_part_swallow_get(fileselector_entry_edje_layer,
715                                         "elm.swallow.entry");
716    if (!entry)
717      return 0;
718
719    if (elm_entry_selection_get(entry))
720      return 1;
721
722    return 0;
723 }
724
725 /**
726  * @brief Gets the caret offset
727  *
728  * @param text AtkText instance
729  * @return integer representing the caret offset
730  */
731 static gint
732 eail_fileselector_entry_get_caret_offset(AtkText *text)
733 {
734    Evas_Object *widget;
735    Evas_Object *entry = NULL;
736    Evas_Object *fileselector_entry_edje_layer = NULL;
737
738    widget = eail_widget_get_widget(EAIL_WIDGET(text));
739    if (!widget) return 0;
740
741    fileselector_entry_edje_layer = elm_layout_edje_get(widget);
742    if (!fileselector_entry_edje_layer) return 0;
743
744    entry = edje_object_part_swallow_get(fileselector_entry_edje_layer,
745                                         "elm.swallow.entry");
746    if (!entry) return 0;
747
748    return elm_entry_cursor_pos_get(entry);
749 }
750
751 /**
752  * @brief Sets the caret (cursor) position to the specified offset.
753  *
754  * Implementation of AtkTextIface->set_caret_offset callback.
755  *
756  * @param text AtkText instance
757  * @param offset starting position
758  *
759  * @returns TRUE on success, FALSE otherwise
760  */
761 static gboolean
762 eail_fileselector_entry_set_caret_offset (AtkText *text,
763                                           gint offset)
764 {
765    Evas_Object *widget;
766    Evas_Object *entry = NULL;
767    Evas_Object *fileselector_entry_edje_layer = NULL;
768
769    widget = eail_widget_get_widget(EAIL_WIDGET(text));
770    if (!widget) return FALSE;
771
772    fileselector_entry_edje_layer = elm_layout_edje_get(widget);
773    if (!fileselector_entry_edje_layer) return FALSE;
774
775    entry = edje_object_part_swallow_get(fileselector_entry_edje_layer,
776                                         "elm.swallow.entry");
777    if (!entry) return FALSE;
778
779    elm_entry_cursor_pos_set(entry, offset);
780
781    return TRUE;
782 }
783
784
785 /**
786  * @brief Creates an AtkAttributeSet which consists of the default values of
787  * attributes for the text
788  *
789  * The returned AtkAttributeSet should be freed by a call to
790  * atk_attribute_set_free().
791  *
792  * @param text AtkText instance
793  *
794  * @returns AtkAttributeSet which contains the default values of attributes
795  * at offset
796  */
797 static AtkAttributeSet *
798 eail_fileselector_entry_get_default_attributes(AtkText *text)
799 {
800    AtkAttributeSet *at_set = NULL;
801
802    at_set = eail_utils_text_add_attribute
803        (at_set, ATK_TEXT_ATTR_WRAP_MODE,
804         atk_text_attribute_get_value(ATK_TEXT_ATTR_WRAP_MODE, 0));
805
806    at_set = eail_utils_text_add_attribute
807        (at_set, ATK_TEXT_ATTR_EDITABLE,
808         atk_text_attribute_get_value
809          (ATK_TEXT_ATTR_EDITABLE, TRUE));
810
811    return at_set;
812 }
813
814 /**
815  * @brief Creates an AtkAttributeSet which consists of the attributes
816  * explicitly set at the position offset in the text
817  *
818  * start_offset and end_offset are set to the start and end of the range
819  * around offset where the attributes are invariant. Note that end_offset
820  * is the offset of the first character after the range.
821  *
822  * The returned AtkAttributeSet should be freed by a call to
823  * atk_attribute_set_free()
824  *
825  * @param text AtkText instance
826  * @param offset offset at which to get the attributes
827  * @param [out] start_offset start offset of the range
828  * @param [out] end_offset end offset of the range
829  *
830  * @returns AtkAttributeSet which contains the attributes explicitly set at
831  * offset
832  */
833 static AtkAttributeSet *
834 eail_fileselector_entry_get_run_attributes(AtkText *text,
835                                            gint offset,
836                                            gint *start_offset,
837                                            gint *end_offset)
838 {
839    AtkAttributeSet *at_set = NULL;
840    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
841    Evas_Object *entry;
842    Evas_Object *fileselector_entry_edje_layer = NULL;
843
844    if (!widget || offset >= eail_fileselector_entry_get_character_count(text))
845      {
846         *start_offset = -1;
847         *end_offset = -1;
848
849         return NULL;
850      }
851
852    fileselector_entry_edje_layer = elm_layout_edje_get(widget);
853    if (!fileselector_entry_edje_layer)
854      return NULL;
855
856    entry = edje_object_part_swallow_get(fileselector_entry_edje_layer,
857                                         "elm.swallow.entry");
858    if (!entry)
859      return NULL;
860
861    *start_offset = 0;
862    *end_offset = eail_fileselector_entry_get_character_count(text);
863
864    /* NOTE: Elm_Wrap_Type value is in 100% compatible with ATK wrap modes, so
865     * no additional conversion is needed*/
866    Elm_Wrap_Type wrap_type = elm_entry_line_wrap_get(entry);
867    at_set = eail_utils_text_add_attribute
868        (at_set, ATK_TEXT_ATTR_WRAP_MODE,
869         atk_text_attribute_get_value
870          (ATK_TEXT_ATTR_WRAP_MODE, wrap_type));
871
872    Eina_Bool editable = elm_entry_editable_get(entry);
873    at_set = eail_utils_text_add_attribute
874        (at_set, ATK_TEXT_ATTR_EDITABLE,
875         atk_text_attribute_get_value
876          (ATK_TEXT_ATTR_EDITABLE, editable));
877
878    return at_set;
879 }
880
881
882 /**
883  * @brief Gets the offset of the character located at coordinates
884  * x and y. x and y are interpreted as being relative to the
885  * screen or this widget's window depending on coords.
886  *
887  * @param text AtkText instance
888  * @param x screen x-position of character
889  * @param y screen y-position of character
890  * @param coords specify whether coordinates are relative to the
891  * screen or widget window
892  *
893  * @returns the offset to the character which is located at the
894  * specified x and y coordinates.
895  */
896 static gint
897 eail_fileselector_entry_get_offset_at_point(AtkText *text,
898                                             gint x,
899                                             gint y,
900                                             AtkCoordType coords)
901 {
902    Eina_Bool result = EINA_FALSE;
903    Evas_Object *textblock = NULL;
904    Evas_Textblock_Cursor *cur = NULL;
905    gint offset = -1;
906    Evas_Object *entry = NULL;
907    Evas_Object *fileselector_entry_edje_layer = NULL;
908
909    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
910
911    if (!widget) return offset;
912
913    fileselector_entry_edje_layer = elm_layout_edje_get(widget);
914    if (!fileselector_entry_edje_layer) return offset;
915
916    entry = edje_object_part_swallow_get(fileselector_entry_edje_layer,
917                                         "elm.swallow.entry");
918    if (!entry) return offset;
919
920    textblock = elm_entry_textblock_get(entry);
921    if (!textblock) return offset;
922
923    cur = evas_object_textblock_cursor_new(textblock);
924    if (!cur) return offset;
925
926    if (coords == ATK_XY_SCREEN)
927    {
928       int ee_x, ee_y;
929       Ecore_Evas *ee= ecore_evas_ecore_evas_get(evas_object_evas_get(widget));
930
931       ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
932       x -= ee_x;
933       y -= ee_y;
934     }
935
936    result = evas_textblock_cursor_char_coord_set(cur, x, y);
937
938    if (result == EINA_FALSE)
939    {
940       evas_textblock_cursor_free(cur);
941       return offset;
942    }
943
944    offset = evas_textblock_cursor_pos_get(cur);
945    evas_textblock_cursor_free(cur);
946
947    return offset;
948 }
949
950 /**
951  * @brief Initializer for AtkTextIface interface
952  *
953  * @param iface AtkTextIface instance
954  */
955 static void
956 atk_text_interface_init(AtkTextIface *iface)
957 {
958     iface->get_text = eail_fileselector_entry_get_text;
959     iface->get_character_at_offset = eail_fileselector_entry_get_character_at_offset;
960     iface->get_character_count = eail_fileselector_entry_get_character_count;
961     iface->get_text_after_offset = eail_fileselector_entry_get_text_after_offset;
962     iface->get_text_at_offset = eail_fileselector_entry_get_text_at_offset;
963     iface->get_text_before_offset = eail_fileselector_entry_get_text_before_offset;
964     iface->get_character_extents = eail_fileselector_entry_get_character_extents;
965     iface->get_selection = eail_fileselector_entry_get_selection;
966     iface->set_selection = eail_fileselector_entry_set_selection;
967     iface->get_n_selections = eail_fileselector_entry_get_n_selections;
968     iface->add_selection = eail_fileselector_entry_add_selection;
969     iface->remove_selection = eail_fileselector_entry_remove_selection;
970     iface->get_caret_offset = eail_fileselector_entry_get_caret_offset;
971     iface->set_caret_offset = eail_fileselector_entry_set_caret_offset;
972     iface->get_run_attributes = eail_fileselector_entry_get_run_attributes;
973     iface->get_default_attributes = eail_fileselector_entry_get_default_attributes;
974     iface->get_offset_at_point = eail_fileselector_entry_get_offset_at_point;
975 }
976
977 /*
978  * Implementation of the Actions
979  */
980
981 /**
982  * @brief Calls callback with given name
983  *
984  * @param action AtkAction instance
985  * @param action_name action name to be called
986  *
987  * @returns TRUE on success, FALSE otherwise
988  */
989 static gboolean
990 eail_fileselector_entry_do_action(AtkAction *action,
991                                   const char *action_name)
992 {
993    Evas_Object *button = NULL;
994
995    button = _eail_fileselector_entry_get_nested_button(ATK_OBJECT(action));
996    if (!button) return FALSE;
997
998    if (action_name == NULL) return FALSE;
999    /*emit signal*/
1000    evas_object_smart_callback_call(button, action_name, NULL);
1001    return TRUE;
1002 }
1003
1004 /**
1005  * @brief Handle for 'click' action
1006  *
1007  * @param action AtkAction instance
1008  * @param data additional action data (not used here)
1009  *
1010  * @return TRUE if action was triggered successfully, FALSE otherwise
1011  */
1012 static gboolean
1013 eail_action_click(AtkAction *action, void *data)
1014 {
1015    return eail_fileselector_entry_do_action(action, "clicked");
1016 }
1017
1018 /**
1019  * @brief Calls action with given name for actions based on x-y coordinates
1020  *
1021  * @param action AtkAction instance
1022  * @param name name string of the action to be called
1023  *
1024  * @returns TRUE on success, FALSE otherwise
1025  */
1026 static gboolean
1027 _eail_action_handle_coords_action(AtkAction *action, gchar *name)
1028 {
1029    Evas_Object *button = NULL;
1030    int x, y;
1031
1032    if (name == NULL) return FALSE;
1033
1034    button = _eail_fileselector_entry_get_nested_button(ATK_OBJECT(action));
1035    if (!button) return FALSE;
1036
1037    /* getting coordinates of center of the widget to make sure, that
1038     * click will be performed on active widget area */
1039    eail_get_coords_widget_center(button, &x, &y);
1040
1041    if (0 == g_strcmp0(name, EAIL_FSE_ACTION_PRESS))
1042         {
1043           DBG("Calling 'press' on button");
1044           eail_mouse_press_on_coords(button, x, y);
1045         }
1046    else if (0 == g_strcmp0(name, EAIL_FSE_ACTION_RELEASE))
1047       {
1048          DBG("Calling 'release' on button");
1049          eail_mouse_release_on_coords(button, x, y);
1050       }
1051    else
1052       {
1053          DBG("No action by given name %s", name);
1054          return FALSE;
1055       }
1056
1057    return TRUE;
1058 }
1059 /**
1060  * @brief Handle for 'longpress' action
1061  *
1062  * @param action AtkAction instance
1063  * @param data additional action data (not used here)
1064  *
1065  * @return TRUE if action was triggered successfully, FALSE otherwise
1066  */
1067 static gboolean
1068 eail_action_longpress(AtkAction *action, void *data)
1069 {
1070    return eail_fileselector_entry_do_action(action, "longpressed");
1071 }
1072
1073 /**
1074  * @brief Handle for 'press' action
1075  *
1076  * @param action AtkAction instance
1077  * @param data additional action data (not used here)
1078  *
1079  * @return TRUE if action was triggered successfully, FALSE otherwise
1080  */
1081 static gboolean
1082 eail_action_press(AtkAction *action, void *data)
1083 {
1084    /* this is being done to action press/release raise properly click event.
1085     * Without that for standard behavior of fileselector entry, nothing will
1086     * happen (that why not launching event but emulating mouse press)*/
1087    return _eail_action_handle_coords_action(action, EAIL_FSE_ACTION_PRESS);
1088 }
1089
1090 /**
1091  * @brief Handle for 'release' action
1092  *
1093  * @param action AtkAction instance
1094  * @param data additional action data (not used here)
1095  *
1096  * @return TRUE if action was triggered successfully, FALSE otherwise
1097  */
1098 static gboolean
1099 eail_action_release(AtkAction *action, void *data)
1100 {
1101    /* this is being done to action press/release raise properly click event.
1102     * Without that for standard behavior of fileselector entry, nothing will
1103     * happen (that why not launching event but emulating mouse release)*/
1104    return _eail_action_handle_coords_action(action, EAIL_FSE_ACTION_RELEASE);
1105 }
1106
1107 /**
1108  * @brief Adds fileselector actions to actions table
1109  *
1110  * @param action_widget widget that implements EailActionWidget interface
1111  */
1112 static void
1113 eail_fileselector_entry_actions_init(EailActionWidget *action_widget)
1114 {
1115    eail_action_widget_action_append(action_widget,
1116                                     EAIL_FSE_ACTION_CLICK, NULL,
1117                                     eail_action_click);
1118    eail_action_widget_action_append(action_widget,
1119                                     EAIL_FSE_ACTION_LONGPRESS, NULL,
1120                                     eail_action_longpress);
1121    eail_action_widget_action_append(action_widget,
1122                                     EAIL_FSE_ACTION_PRESS, NULL,
1123                                     eail_action_press);
1124    eail_action_widget_action_append(action_widget,
1125                                     EAIL_FSE_ACTION_RELEASE, NULL,
1126                                     eail_action_release);
1127 }