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