Function description fixes
[platform/core/uifw/eail.git] / eail / eail / eail_item.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_item.c
22  * @brief EailItem implementation
23  *
24  * In general - this object represents all kinds of objects that have form of
25  * a Elm_Obj_Item* and need ATK accessible representation. It stores
26  * Elm_Obj_Item* inside - unlike Evas_Object like those components that are
27  * extending EailWidget.
28 */
29
30 #include "eail_item.h"
31 #include "eail_item_parent.h"
32 #include "eail_factory.h"
33 #include "eail_utils.h"
34 #include "eail_priv.h"
35
36 static void atk_component_interface_init(AtkComponentIface *iface);
37 static void atk_action_interface_init(AtkActionIface *iface);
38 static void atk_text_interface_init(AtkTextIface *iface);
39
40 #define EAIL_ITEM_CLICK_NAME "click" /**< @brief 'click' action name*/
41 #define EAIL_ITEM_PRESS_NAME "press" /**< @brief 'press' action name*/
42 #define EAIL_ITEM_RELEASE_NAME "release" /**< @brief 'release' action name*/
43 #define EAIL_ITEM_PART_FIRST "start" /**< @brief 'start' action name*/
44 #define EAIL_ITEM_PART_SECOND "end" /**< @brief 'end' action name*/
45 #define EAIL_ITEM_PART_ICON "elm.swallow.icon" /**< @brief icon item part*/
46 #define EAIL_ITEM_PART_END "elm.swallow.end" /**< @brief end item part*/
47 #define EAIL_TXT_SEPARATOR " " /**< @brief separator for text content*/
48
49 /**
50  * @brief EailItem GObject definition
51  *
52  * It extends ATK_TYPE_OBJECT class and implements ATK_TYPE_COMPONENT,
53  * ATK_TYPE_TEXT and ATK_TYPE_ACTION interfaces
54  */
55 G_DEFINE_TYPE_WITH_CODE(EailItem,
56                         eail_item,
57                         ATK_TYPE_OBJECT,
58                         G_IMPLEMENT_INTERFACE(ATK_TYPE_COMPONENT,
59                                               atk_component_interface_init)
60                         G_IMPLEMENT_INTERFACE(ATK_TYPE_ACTION,
61                                               atk_action_interface_init)
62                         G_IMPLEMENT_INTERFACE(ATK_TYPE_TEXT,
63                                               atk_text_interface_init));
64
65 /**
66  * @brief Initializer for AtkObjectClass
67  *
68  * @param obj AtkObject instance
69  * @param data additional initialization data
70  */
71 static void
72 eail_item_initialize(AtkObject *obj, gpointer data)
73 {
74    EailItem *item = EAIL_ITEM(obj);
75
76    ATK_OBJECT_CLASS(eail_item_parent_class)->initialize(obj, data);
77
78    item->item = (Elm_Object_Item *)data;
79
80    /* NOTE: initializing role is being done only in eail_item_new(..) */
81 }
82
83 /**
84  *
85  * @param item EailItem to take nested Elm_Object_Item from
86  *
87  * @returns Elm_Object_Item * representing nested item or NULL if an error occured
88  */
89 Elm_Object_Item *
90 eail_item_get_item(EailItem *item)
91 {
92    g_return_val_if_fail(EAIL_IS_ITEM(item), NULL);
93
94    return item->item;
95 }
96
97 /*
98  * Implementation of the *AtkObject* interface
99  */
100
101 /**
102  * @brief Gets the accessible name of the accessible.
103  *
104  * Implementation of AtkObject->get_name callback.
105  *
106  * @param obj AtkObject for EailItem
107  * @returns string representing the accessible description of
108  * the accessible.
109  */
110 static const gchar *
111 eail_item_get_name(AtkObject *obj)
112 {
113    const gchar *atk_name_default = NULL;
114    AtkObject *parent = atk_object_get_parent(obj);
115
116    if (!parent) return NULL;
117
118    /* returning name from default atk implementation when it available (it
119     * means that it was set by user)*/
120    atk_name_default = ATK_OBJECT_CLASS(eail_item_parent_class)->get_name(obj);
121    if (atk_name_default) return atk_name_default;
122
123    return eail_item_parent_get_item_name(EAIL_ITEM_PARENT(parent),
124                                          EAIL_ITEM(obj));
125 }
126
127 /**
128  * @brief Gets the role of the accessible
129  *
130  * Implementation of AtkObject->get_role callback.
131  *
132  * @param obj AtkObject for EailItem
133  * @returns AtkRole representing the parameter's role
134  */
135 static AtkRole
136 eail_item_get_role(AtkObject *obj)
137 {
138    AtkObject *parent = atk_object_get_parent(obj);
139
140    if (!parent) return ATK_ROLE_INVALID;
141
142    return eail_item_parent_get_item_role(EAIL_ITEM_PARENT(parent),
143                                          EAIL_ITEM(obj));
144 }
145
146 /**
147  * @brief Gets the 0-based index of this accessible in its parent.
148  *
149  * Implementation of AtkObject->get_index_in_parent callback.
150  *
151  * @param obj AtkObject for EailItem
152  * @returns integer representing the index of the accessible in its parent or -1 if the accessible does not have an accessible parent
153  */
154 static gint
155 eail_item_get_index_in_parent(AtkObject *obj)
156 {
157    AtkObject *parent = atk_object_get_parent(obj);
158
159    if (!parent) return -1;
160
161    return eail_item_parent_get_item_index_in_parent(EAIL_ITEM_PARENT(parent),
162                                                     EAIL_ITEM(obj));
163 }
164
165 /**
166  * @brief Gets a reference to the state set of the accessible.
167  *
168  * The caller must unreference it when it is no longer needed.
169  *
170  * Implementation of AtkObject->ref_state_set callback.
171  *
172  * @param obj AtkObject for EailItem
173  * @returns AtkStateSet containing a reference to the state set of the
174  * accessible
175  */
176 static AtkStateSet *
177 eail_item_ref_state_set(AtkObject *obj)
178 {
179    AtkStateSet *state_set;
180    AtkObject *parent = atk_object_get_parent(obj);
181    EailItem *item = EAIL_ITEM(obj);
182    Elm_Object_Item *it = eail_item_get_item(item);
183
184    state_set = ATK_OBJECT_CLASS(eail_item_parent_class)->ref_state_set(obj);
185
186    if (!parent || !it)
187      {
188         atk_state_set_add_state(state_set, ATK_STATE_DEFUNCT);
189         return state_set;
190      }
191
192    if (!elm_object_item_disabled_get(it))
193      {
194         atk_state_set_add_state(state_set, ATK_STATE_SENSITIVE);
195         atk_state_set_add_state(state_set, ATK_STATE_ENABLED);
196      }
197
198    return eail_item_parent_ref_item_state_set(EAIL_ITEM_PARENT(parent),
199                                               item, state_set);
200 }
201
202
203 /**
204  * @brief Initializer for GObject class
205  * @param item EailItem instance
206  */
207 static void
208 eail_item_init(EailItem *item)
209 {
210 }
211
212 /**
213  * @brief Finalizes implementation for GObject class
214  * @param obj AtkObject for EailItem instance that needs to be finalized
215  */
216 static void
217 eail_item_class_finalize(GObject *obj)
218 {
219    EailItem *eail_item = EAIL_ITEM(obj);
220    Elm_Object_Item *obj_item = eail_item_get_item(eail_item);
221
222    if (obj_item)
223      eail_factory_unregister_item_from_cache(obj_item);
224
225    G_OBJECT_CLASS(eail_item_parent_class)->finalize(obj);
226 }
227
228 /**
229  * @brief Helper function used for adding Evas_Object* content to the item's list
230  * if the content is available.
231  *
232  * @param eail_obj_item item used for browsing for given content part
233  * @param items list of items that will be extended by the content part
234  * @param part_str name of content part to be found
235  *
236  * @returns Eina_List filled with Evas_Object* objects
237  */
238 static Eina_List *
239 _eail_item_append_part_if_exist(Elm_Object_Item *eail_obj_item,
240                                 Eina_List *items,
241                                 gchar *part_str)
242 {
243    Evas_Object *content = NULL;
244
245    content = elm_object_item_part_content_get
246                                          (eail_obj_item, part_str);
247    if (content)
248      items = eina_list_append(items, content);
249
250    return items;
251 }
252
253 /**
254  * @brief Checks if content_get is supported by the given EailItem object
255  *
256  * @param atk_object AtkObject instance
257  *
258  * @returns TRUE if content_get is supported, FALSE otherwise
259  */
260 static gboolean
261 _eail_item_is_content_get_supported(AtkObject *atk_object)
262 {
263    AtkObject *parent = NULL;
264
265
266    parent = atk_object_get_parent(atk_object);
267    g_return_val_if_fail(parent, FALSE);
268
269    return eail_item_parent_is_is_content_get_supported
270                               (EAIL_ITEM_PARENT(parent),EAIL_ITEM(atk_object));
271 }
272
273 /**
274  * @brief Gets list of item's content parts with well documented content strings
275  *
276  * @param eail_item item to get content from
277  *
278  * @returns Eina_List filled with the content parts that have been found
279  */
280 static Eina_List *
281 _eail_item_get_basic_parts(EailItem *eail_item)
282 {
283    Eina_List *items = NULL;
284    Elm_Object_Item *obj_item = NULL;
285
286    /* if content_get is not supported then content from basic parts will be
287     * always empty. This checking is being done, because elementary library
288     * don't want to ask for some widget usign content_get API */
289    if (!_eail_item_is_content_get_supported(ATK_OBJECT(eail_item)))
290      return items;
291
292    obj_item = eail_item_get_item(EAIL_ITEM(eail_item));
293    items = _eail_item_append_part_if_exist
294                                        (obj_item, items, EAIL_ITEM_PART_FIRST);
295    items = _eail_item_append_part_if_exist
296                                        (obj_item, items, EAIL_ITEM_PART_SECOND);
297    items = _eail_item_append_part_if_exist
298                                        (obj_item, items, EAIL_ITEM_PART_ICON);
299    items = _eail_item_append_part_if_exist
300                                        (obj_item, items, EAIL_ITEM_PART_END);
301
302    return items;
303 }
304
305 /**
306  * @brief Helper function for adding unique entries from one list to another
307  *
308  * @param item_list list which unique items will be appended to
309  * @param additional_items source list with items to be added to item_list
310  *
311  * @returns Eina_List filled with unique entries from both lists
312  */
313 static Eina_List *
314 _eail_add_unique_listsparts(Eina_List *item_list,
315                             Eina_List *additional_items)
316 {
317    Eina_List *l = NULL;
318    Elm_Object_Item *item_edj;
319
320    EINA_LIST_FOREACH(additional_items, l, item_edj)
321     {
322       if (!eina_list_data_find(item_list, item_edj))
323         item_list = eina_list_append(item_list, item_edj);
324     }
325
326    return item_list;
327 }
328
329 /**
330  * @brief Gets content part items from the given EailItem object
331  *
332  * List should be freed when results will be processed.
333  *
334  * @param eail_item EailItem object used to get content from
335  *
336  * @returns Eina_List containing content parts for the given item.
337  */
338 static Eina_List *
339 _eail_item_get_part_items(EailItem *eail_item)
340 {
341    Eina_List *items = NULL, *edje_items = NULL;
342    Elm_Object_Item *obj_item = NULL;
343
344    obj_item = eail_item_get_item(eail_item);
345    g_return_val_if_fail(obj_item, NULL);
346
347    /* parts from well documented default content parts - there are being used
348     * mostly by desktop applications. Some of these parts are not listed in
349     * edje objects (used below), so results from both list need to be merged
350     * to list full item content */
351    items = _eail_item_get_basic_parts(eail_item);
352
353    /* content parts from taken from edje object*/
354    edje_items = eail_get_edje_parts_for_item(obj_item);
355
356    /* adding unique edje items to content list*/
357    items = _eail_add_unique_listsparts(items, edje_items);
358
359    eina_list_free(edje_items);
360
361    return items;
362 }
363
364 /**
365  * @brief Gets the number of accessible children of the accessible.
366  *
367  * Implementation AtkObject->get_n_children callback.
368  *
369  * @param obj AtkObject (EailItem) instance
370  *
371  * @returns integer representing the number of accessible children of
372  * the accessible
373  */
374 static gint
375 eail_item_get_n_children(AtkObject *obj)
376 {
377    gint n_items, parent_n_items;
378    Eina_List *items;
379    AtkObject *parent = atk_object_get_parent(obj);
380
381    if (!parent) return 0;
382    parent_n_items = eail_item_parent_get_n_children(EAIL_ITEM_PARENT(parent),
383                                                     EAIL_ITEM(obj));
384    /* if there is item parent impl, then returning item count
385     * from it*/
386    if (parent_n_items != -1) return parent_n_items;
387
388    items = _eail_item_get_part_items(EAIL_ITEM(obj));
389    n_items = eina_list_count(items);
390
391    eina_list_free(items);
392
393    return n_items;
394 }
395
396 /**
397  * @brief Gets a reference to the specified accessible child of the object.
398  *
399  * The accessible children are 0-based so the first accessible child is at index 0,
400  * the second at index 1 and so on.
401  *
402  * Implementation of AtkObject->ref_child callback.
403  *
404  * @param obj AtkObject for EailItem instance
405  * @param i index of item to reference
406  *
407  * @returns AtkObject representing the specified accessible child of the
408  * accessible
409  */
410 static AtkObject *
411 eail_item_ref_child(AtkObject *obj, gint i)
412 {
413    Eina_List *items;
414    AtkObject *child = NULL;
415    AtkObject *parent = atk_object_get_parent(obj);
416    AtkObject *ref_child_from_parent = NULL;
417
418    if (!parent) return NULL;
419
420    ref_child_from_parent = eail_item_parent_ref_n_child
421                               (EAIL_ITEM_PARENT(parent), EAIL_ITEM(obj), i);
422
423    /* if there is item parent implementation for ref child, then returning
424     * object using that parent implementation*/
425    if (ref_child_from_parent)
426       {
427         g_object_ref(ref_child_from_parent);
428         return ref_child_from_parent;
429       }
430
431    items = _eail_item_get_part_items(EAIL_ITEM(obj));
432    if (eina_list_count(items) > i)
433      child = eail_factory_get_accessible(eina_list_nth(items, i));
434    else
435       ERR("Tried to ref child with index %d out of bounds!", i);
436
437    eina_list_free(items);
438
439    if (child)
440      g_object_ref(child);
441    else
442      DBG("Child could not created in factory");
443
444    return child;
445 }
446
447 /**
448  * @brief Initializer for GObject class
449  *
450  * Defines callbacks for base AtkObject.
451  *
452  * @param klass EailItemClass instance
453  */
454 static void
455 eail_item_class_init(EailItemClass *klass)
456 {
457    AtkObjectClass *class = ATK_OBJECT_CLASS(klass);
458    GObjectClass *g_object_class = G_OBJECT_CLASS(klass);
459
460    class->initialize = eail_item_initialize;
461    class->get_name = eail_item_get_name;
462    class->get_role = eail_item_get_role;
463    class->get_index_in_parent = eail_item_get_index_in_parent;
464    class->ref_state_set = eail_item_ref_state_set;
465    class->get_n_children = eail_item_get_n_children;
466    class->ref_child = eail_item_ref_child;
467
468    g_object_class->finalize = eail_item_class_finalize;
469 }
470
471 /*
472  * Implementation of the *AtkComponent* interface
473  */
474
475 /**
476  * @brief Grabs focus for this component.
477  *
478  * Implementation of AtkComponent->grab_focus callback.
479  *
480  * @param component AtkComponent (EailItem) instance
481  * @returns TRUE on success, FALSE otherwise.
482  */
483 static gboolean
484 eail_item_grab_focus(AtkComponent *component)
485 {
486    AtkObject *obj = ATK_OBJECT(component);
487    AtkObject *parent = atk_object_get_parent(obj);
488
489    if (!parent) return FALSE;
490
491    return eail_item_parent_grab_item_focus(EAIL_ITEM_PARENT(parent),
492                                            EAIL_ITEM(obj));
493 }
494
495 /**
496  * @brief Gets the rectangle which gives the extent of the component.
497  *
498  * Implementation of AtkComponent->get_extents callback.
499  *
500  * @param component AtkComponent instance
501  * @param [out] x rectangle upper left x coordinate
502  * @param [out] y rectangle upper left y coordinate
503  * @param [out] width width of the rectangle
504  * @param [out] height height of the rectangle
505  * @param coord_type specifies whether the coordinates are relative to the
506  * screen or to the components top level window
507  */
508 static void
509 eail_item_get_extents(AtkComponent    *component,
510                       gint            *x,
511                       gint            *y,
512                       gint            *width,
513                       gint            *height,
514                       AtkCoordType     coord_type)
515 {
516    AtkObject *obj = ATK_OBJECT(component);
517    AtkObject *parent = atk_object_get_parent(obj);
518
519    *x = *y = G_MININT;
520    *width = *height = -1;
521
522    if (!parent) return;
523
524    eail_item_parent_get_item_extents(EAIL_ITEM_PARENT(parent),
525                                      EAIL_ITEM(obj),
526                                      x, y, width, height, coord_type);
527 }
528
529 /**
530  * @brief AtkComponent interface initialization
531  *
532  * @param iface EailNaviframPage instance
533  */
534 static void
535 atk_component_interface_init(AtkComponentIface *iface)
536 {
537    iface->grab_focus  = eail_item_grab_focus;
538    iface->get_extents = eail_item_get_extents;
539 }
540
541 /*
542  * AtkAction interface init
543  */
544
545 /**
546  * @brief Gets actions supported by given EailItem object
547  *
548  * @param action AtkAction instance
549  *
550  * @returns EailActionSupported enum entry that shows what kind of actions are
551  * supported
552  */
553 static gint
554 _eail_item_get_actions_supported(AtkAction *action)
555 {
556    AtkObject *parent = NULL;
557
558    parent = atk_object_get_parent(ATK_OBJECT(action));
559    g_return_val_if_fail(parent, FALSE);
560
561    return eail_item_parent_get_actions_supported
562                                  (EAIL_ITEM_PARENT(parent),EAIL_ITEM(action));
563
564 }
565
566 /**
567  * @brief Returns the number of implemented ATK actions.
568  *
569  * Implementation of AtkActionIface get_n_actions callback.
570  *
571  * @param action object that implements AtkAction interface
572  * @returns integer representing number of implemented actions
573  */
574 static int
575 eail_item_n_actions_get(AtkAction *action)
576 {
577    int actions_num = 0;
578    /* if parent item does not support click action, then return no action */
579    if (_eail_item_get_actions_supported(action) == EAIL_ACTION_SUPPORTED_NONE)
580      return 0;
581
582    if (_eail_item_get_actions_supported(action) & EAIL_ACTION_SUPPORTED_CLICK)
583      actions_num++;
584
585    if (_eail_item_get_actions_supported(action) & EAIL_ACTION_SUPPORTED_PRESS)
586      actions_num++;
587
588    if (_eail_item_get_actions_supported(action) & EAIL_ACTION_SUPPORTED_RELEASE)
589      actions_num++;
590
591    return actions_num;
592 }
593
594 /**
595  * @brief Returns the accessible name of the specified action
596  *
597  * @param action object that implements AtkAction interface
598  * @param i index (number) of action
599  * @returns string containing the accessible name of the specified action
600  */
601 static const char*
602 eail_item_action_name_get(AtkAction *action, int i)
603 {
604    const char* action_name;
605
606    /* if parent item does not support click action, then return no action */
607    if (_eail_item_get_actions_supported(action) == EAIL_ACTION_SUPPORTED_NONE)
608      return NULL;
609
610    switch (i)
611      {
612       case 0:
613          /*"click": the user clicked the item*/
614          action_name = EAIL_ITEM_CLICK_NAME;
615          break;
616       case 1:
617          /*"press": the user pressed the item*/
618          action_name = EAIL_ITEM_PRESS_NAME;
619          break;
620       case 2:
621          /*"release": the user pressed the item*/
622          action_name = EAIL_ITEM_RELEASE_NAME;
623          break;
624       default:
625          action_name = NULL;
626          break;
627      }
628
629    return action_name;
630 }
631
632 /**
633  * @brief Gets the clickable Evas_Object for the given EailItem
634  *
635  * @param atk_item EailItem instance
636  *
637  * @returns clickable Evas_Object or NULL of no clickable content was found
638  */
639 static Evas_Object *
640 _eail_item_get_clickable_evas_obj(AtkObject *atk_item)
641 {
642    AtkObject *parent = NULL;
643    Evas_Object *widget = NULL;
644    Eina_List *parts = NULL;
645
646    parent = atk_object_get_parent(atk_item);
647    g_return_val_if_fail(parent, FALSE);
648
649    widget = eail_item_parent_get_evas_obj
650                            (EAIL_ITEM_PARENT(parent), EAIL_ITEM(atk_item));
651    if (widget) return widget;
652
653    /* if not supported from parent, then trying to get content widget nested
654     * in item */
655    parts = _eail_item_get_part_items(EAIL_ITEM(atk_item));
656    if (parts && eina_list_count(parts) > 0)
657      {
658         /* getting first widget from content */
659         widget = eina_list_nth(parts, 0);
660      }
661    eina_list_free(parts);
662    if (widget) return widget;
663
664    /* if no nested widget, then getting evas clickable area */
665    parts = eail_get_raw_evas_obj_list_from_item
666                                     (eail_item_get_item(EAIL_ITEM(atk_item)));
667
668    if (parts && eina_list_count(parts) > 0)
669      {
670         /* getting first widget from content */
671         widget = eina_list_nth(parts, 0);
672      }
673
674    return widget;
675 }
676
677
678 /**
679  * @brief Performs an action with the given name on given item
680  *
681  * @param atk_item item object to perform the action on
682  * @param action_name name of the action (eg. 'click', 'press'...)
683  *
684  * @returns TRUE if operation was successful, FALSE otherwise
685  */
686 static gboolean
687 _eail_item_perform_action(AtkObject *atk_item, const gchar *action_name)
688 {
689    AtkObject *parent = NULL;
690    Evas_Object *widget = NULL;
691    int x, y;
692
693    parent = atk_object_get_parent(atk_item);
694    g_return_val_if_fail(parent, FALSE);
695
696    widget =_eail_item_get_clickable_evas_obj(atk_item);
697
698    if (!widget)
699      {
700         ERR("No widget for click found");
701         return FALSE;
702      }
703
704    /* getting coordinates of center of the widget to make sure, that
705     * click will be performed on active widget area */
706    eail_get_coords_widget_center(widget, &x, &y);
707
708    if (0 == g_strcmp0(action_name, EAIL_ITEM_CLICK_NAME))
709      {
710        DBG("Calling 'click' on item");
711        eail_mouse_click_on_coords(widget, x, y);
712      }
713    else if (0 == g_strcmp0(action_name, EAIL_ITEM_PRESS_NAME))
714      {
715         DBG("Calling 'press' on item");
716         eail_mouse_press_on_coords(widget, x, y);
717      }
718    else if (0 == g_strcmp0(action_name, EAIL_ITEM_RELEASE_NAME))
719      {
720         DBG("Calling 'release' on item");
721         eail_mouse_release_on_coords(widget, x, y);
722      }
723    else
724      {
725         DBG("Action name not found: %s", action_name);
726         return FALSE;
727      }
728
729    return TRUE;
730 }
731
732 /**
733  * \brief Launches action with given index
734  *
735  * @param action AtkAction instance
736  * @param i index (number) of the action
737  *
738  * @returns TRUE if action was successfully launched, FALSE otherwise
739  */
740 static gboolean
741 eail_item_do_action(AtkAction *action, int i)
742 {
743    const char *action_name = atk_action_get_name(action, i);
744
745    /* if parent item does not support click action, then return immediately */
746    if (_eail_item_get_actions_supported(action) == EAIL_ACTION_SUPPORTED_NONE)
747      return FALSE;
748
749    if (action_name == NULL) return FALSE;
750
751    return _eail_item_perform_action(ATK_OBJECT(action), action_name);;
752 }
753
754 /**
755  * @brief Initializer for AtkActionIface
756  * @param iface AtkActionIface instance to fill
757  */
758 static void
759 atk_action_interface_init(AtkActionIface *iface)
760 {
761    g_return_if_fail(iface != NULL);
762
763    iface->do_action     = eail_item_do_action;
764    iface->get_n_actions = eail_item_n_actions_get;
765    iface->get_name      = eail_item_action_name_get;
766 }
767
768 /**
769  * @brief Gets text content from item
770  *
771  * Implementation of AtkTextIface->get_text callback.
772  *
773  * Use g_free() to free the returned.
774  *
775  * @param text AtkText instance
776  * @param start_offset start position
777  * @param end_offset end position, or -1 for the end of the string.
778  *
779  * @returns a newly allocated string containing the text from start_offset
780  * up to, but not including end_offset.
781  * string.
782  */
783 static gchar*
784 eail_item_get_text(AtkText   *text,
785                    gint       start_offset,
786                    gint       end_offset)
787 {
788    Eina_Strbuf *buf = NULL;
789    Elm_Object_Item *obj_item = NULL;
790    Eina_List *string_parts = NULL, *l = NULL;
791    gchar *string_part = NULL;
792    gchar *ret_str = NULL;
793    gboolean first_part = TRUE;
794
795    obj_item = eail_item_get_item(EAIL_ITEM(text));
796    g_return_val_if_fail(obj_item, NULL);
797
798    string_parts = eail_item_get_content_strings(obj_item);
799    if (!string_parts) return NULL;
800
801    buf = eina_strbuf_new();
802    EINA_LIST_FOREACH(string_parts, l, string_part)
803     {
804       if (!first_part)
805         eina_strbuf_append(buf, EAIL_TXT_SEPARATOR);
806
807       eina_strbuf_append(buf, string_part);
808       first_part = FALSE;
809     }
810
811    /* ret_str is newly allocated */
812    ret_str = eail_get_substring
813                      (eina_strbuf_string_get(buf), start_offset, end_offset);
814
815    eina_list_free(string_parts);
816    eina_strbuf_free(buf);
817
818    return ret_str;
819 }
820
821 /**
822  * @brief Gets character from an item at the given offset
823  *
824  * Implementation of AtkTextIface->get_character_at_offset callback.
825  *
826  * @param text AtkText instance
827  * @param offset offset to get the character from
828  *
829  * @returns char located at offset
830  */
831 static gunichar
832 eail_item_get_character_at_offset(AtkText *text, gint offset)
833 {
834    gunichar character = '\0';
835    gchar* time_str = NULL;
836
837    time_str = eail_item_get_text(text, 0, -1);
838
839    if (time_str)
840      {
841          character = g_utf8_get_char
842                               (g_utf8_offset_to_pointer(time_str, offset));
843          g_free(time_str);
844      }
845
846    return character;
847 }
848
849 /**
850  * @brief Gets the character count from text content in item
851  *
852  * Implementation of AtkTextIface->get_character_count callback.
853  *
854  * @param text AtkText instance
855  *
856  * @returns integer representing the character count
857  */
858 static gint
859 eail_item_get_character_count(AtkText *text)
860 {
861    gint count = 0;
862    gchar* str = NULL;
863
864    str = eail_item_get_text(text, 0, -1);
865
866    if (str)
867       {
868          count = g_utf8_strlen(str, -1);
869          g_free(str);
870       }
871
872    return count;
873 }
874
875 /**
876  * @brief Initializer for AtkTextinterface
877  * @param iface AtkTextIface instance to fill
878  */
879 static void
880 atk_text_interface_init(AtkTextIface *iface)
881 {
882    iface->get_text = eail_item_get_text;
883    iface->get_character_at_offset = eail_item_get_character_at_offset;
884    iface->get_character_count = eail_item_get_character_count;
885 }