Merge "custom eail widget implementation" into tizen
[platform/core/uifw/eail.git] / 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 Callback used for tracking show-changes for items
69  *
70  * @param data data passed to callback
71  * @param e Evas instance that has been shown
72  * @param obj Evas_Object instance that has been shown
73  * @param event_info additional event info
74  */
75 static void
76 eail_item_on_show(void *data, Evas *e, Evas_Object *obj, void *event_info)
77 {
78    g_return_if_fail(ATK_IS_OBJECT(data));
79
80    atk_object_notify_state_change(ATK_OBJECT(data), ATK_STATE_SHOWING, TRUE);
81    atk_object_notify_state_change(ATK_OBJECT(data), ATK_STATE_VISIBLE, TRUE);
82 }
83
84 /**
85  * @brief Callback used for tracking hide-changes for items
86  *
87  * @param data data passed to callback
88  * @param e Evas instance that has been shown
89  * @param obj Evas_Object instance that has been shown
90  * @param event_info additional event info
91  */
92 static void
93 eail_item_on_hide(void *data, Evas *e, Evas_Object *obj, void *event_info)
94 {
95    g_return_if_fail(ATK_IS_OBJECT(data));
96
97    atk_object_notify_state_change(ATK_OBJECT(data), ATK_STATE_SHOWING, FALSE);
98    atk_object_notify_state_change(ATK_OBJECT(data), ATK_STATE_VISIBLE, FALSE);
99 }
100 /**
101  * @brief Initializer for AtkObjectClass
102  *
103  * @param obj AtkObject instance
104  * @param data additional initialization data
105  */
106 static void
107 eail_item_initialize(AtkObject *obj, gpointer data)
108 {
109    EailItem *item = EAIL_ITEM(obj);
110
111    ATK_OBJECT_CLASS(eail_item_parent_class)->initialize(obj, data);
112
113    item->item = (Elm_Object_Item *)data;
114
115    Evas_Object *widget = elm_object_item_widget_get(item->item);
116
117    evas_object_event_callback_add(widget, EVAS_CALLBACK_SHOW,
118                                   eail_item_on_show, item);
119    evas_object_event_callback_add(widget, EVAS_CALLBACK_HIDE,
120                                   eail_item_on_hide, item);
121    /* NOTE: initializing role is being done only in eail_item_new(..) */
122 }
123
124 /**
125  *
126  * @param item EailItem to take nested Elm_Object_Item from
127  *
128  * @returns Elm_Object_Item * representing nested item or NULL if an error occured
129  */
130 Elm_Object_Item *
131 eail_item_get_item(EailItem *item)
132 {
133    g_return_val_if_fail(EAIL_IS_ITEM(item), NULL);
134
135    return item->item;
136 }
137
138 /*
139  * Implementation of the *AtkObject* interface
140  */
141
142 /**
143  * @brief Gets the accessible name of the accessible.
144  *
145  * Implementation of AtkObject->get_name callback.
146  *
147  * @param obj AtkObject for EailItem
148  * @returns string representing the accessible description of
149  * the accessible.
150  */
151 static const gchar *
152 eail_item_get_name(AtkObject *obj)
153 {
154    const gchar *atk_name_default = NULL;
155    AtkObject *parent = atk_object_get_parent(obj);
156
157    if (!parent) return NULL;
158
159    /* returning name from default atk implementation when it available (it
160     * means that it was set by user)*/
161    atk_name_default = ATK_OBJECT_CLASS(eail_item_parent_class)->get_name(obj);
162    if (atk_name_default) return atk_name_default;
163
164    return eail_item_parent_get_item_name(EAIL_ITEM_PARENT(parent),
165                                          EAIL_ITEM(obj));
166 }
167
168 /**
169  * @brief Gets the role of the accessible
170  *
171  * Implementation of AtkObject->get_role callback.
172  *
173  * @param obj AtkObject for EailItem
174  * @returns AtkRole representing the parameter's role
175  */
176 static AtkRole
177 eail_item_get_role(AtkObject *obj)
178 {
179    AtkObject *parent = atk_object_get_parent(obj);
180
181    if (!parent) return ATK_ROLE_INVALID;
182
183    return eail_item_parent_get_item_role(EAIL_ITEM_PARENT(parent),
184                                          EAIL_ITEM(obj));
185 }
186
187 /**
188  * @brief Gets the 0-based index of this accessible in its parent.
189  *
190  * Implementation of AtkObject->get_index_in_parent callback.
191  *
192  * @param obj AtkObject for EailItem
193  * @returns integer representing the index of the accessible in its parent or -1 if the accessible does not have an accessible parent
194  */
195 static gint
196 eail_item_get_index_in_parent(AtkObject *obj)
197 {
198    AtkObject *parent = atk_object_get_parent(obj);
199
200    if (!parent) return -1;
201
202    return eail_item_parent_get_item_index_in_parent(EAIL_ITEM_PARENT(parent),
203                                                     EAIL_ITEM(obj));
204 }
205
206 /**
207  * @brief Gets a reference to the state set of the accessible.
208  *
209  * The caller must unreference it when it is no longer needed.
210  *
211  * Implementation of AtkObject->ref_state_set callback.
212  *
213  * @param obj AtkObject for EailItem
214  * @returns AtkStateSet containing a reference to the state set of the
215  * accessible
216  */
217 static AtkStateSet *
218 eail_item_ref_state_set(AtkObject *obj)
219 {
220    AtkStateSet *state_set;
221    AtkObject *parent = atk_object_get_parent(obj);
222    EailItem *item = EAIL_ITEM(obj);
223    Elm_Object_Item *it = eail_item_get_item(item);
224
225    state_set = ATK_OBJECT_CLASS(eail_item_parent_class)->ref_state_set(obj);
226
227    if (!parent || !it)
228      {
229         atk_state_set_add_state(state_set, ATK_STATE_DEFUNCT);
230         return state_set;
231      }
232
233    if (!elm_object_item_disabled_get(it))
234      {
235         atk_state_set_add_state(state_set, ATK_STATE_SENSITIVE);
236         atk_state_set_add_state(state_set, ATK_STATE_ENABLED);
237      }
238
239    return eail_item_parent_ref_item_state_set(EAIL_ITEM_PARENT(parent),
240                                               item, state_set);
241 }
242
243
244 /**
245  * @brief Initializer for GObject class
246  * @param item EailItem instance
247  */
248 static void
249 eail_item_init(EailItem *item)
250 {
251    item->click_description = NULL;
252    item->press_description = NULL;
253    item->release_description = NULL;
254    item->expand_description = NULL;
255    item->shrink_description = NULL;
256 }
257
258 /**
259  * @brief Finalizes implementation for GObject class
260  * @param obj AtkObject for EailItem instance that needs to be finalized
261  */
262 static void
263 eail_item_class_finalize(GObject *obj)
264 {
265    EailItem *eail_item = EAIL_ITEM(obj);
266    Elm_Object_Item *obj_item = eail_item_get_item(eail_item);
267
268    if (obj_item)
269      eail_factory_unregister_item_from_cache(obj_item);
270
271    if (eail_item->click_description) free(eail_item->click_description);
272    if (eail_item->press_description) free(eail_item->press_description);
273    if (eail_item->release_description) free(eail_item->release_description);
274    if (eail_item->expand_description) free(eail_item->expand_description);
275    if (eail_item->shrink_description) free(eail_item->shrink_description);
276
277    G_OBJECT_CLASS(eail_item_parent_class)->finalize(obj);
278 }
279
280 /**
281  * @brief Helper function used for adding Evas_Object* content to the item's list
282  * if the content is available.
283  *
284  * @param eail_obj_item item used for browsing for given content part
285  * @param items list of items that will be extended by the content part
286  * @param part_str name of content part to be found
287  *
288  * @returns Eina_List filled with Evas_Object* objects
289  */
290 static Eina_List *
291 _eail_item_append_part_if_exist(Elm_Object_Item *eail_obj_item,
292                                 Eina_List *items,
293                                 gchar *part_str)
294 {
295    Evas_Object *content = NULL;
296
297    content = elm_object_item_part_content_get
298                                          (eail_obj_item, part_str);
299    if (content)
300      items = eina_list_append(items, content);
301
302    return items;
303 }
304
305 /**
306  * @brief Checks if content_get is supported by the given EailItem object
307  *
308  * @param atk_object AtkObject instance
309  *
310  * @returns TRUE if content_get is supported, FALSE otherwise
311  */
312 static gboolean
313 _eail_item_is_content_get_supported(AtkObject *atk_object)
314 {
315    AtkObject *parent = NULL;
316
317
318    parent = atk_object_get_parent(atk_object);
319    g_return_val_if_fail(parent, FALSE);
320
321    return eail_item_parent_is_is_content_get_supported
322                               (EAIL_ITEM_PARENT(parent),EAIL_ITEM(atk_object));
323 }
324
325 /**
326  * @brief Gets list of item's content parts with well documented content strings
327  *
328  * @param eail_item item to get content from
329  *
330  * @returns Eina_List filled with the content parts that have been found
331  */
332 static Eina_List *
333 _eail_item_get_basic_parts(EailItem *eail_item)
334 {
335    Eina_List *items = NULL;
336    Elm_Object_Item *obj_item = NULL;
337
338    /* if content_get is not supported then content from basic parts will be
339     * always empty. This checking is being done, because elementary library
340     * don't want to ask for some widget usign content_get API */
341    if (!_eail_item_is_content_get_supported(ATK_OBJECT(eail_item)))
342      return items;
343
344    obj_item = eail_item_get_item(EAIL_ITEM(eail_item));
345    items = _eail_item_append_part_if_exist
346                                        (obj_item, items, EAIL_ITEM_PART_FIRST);
347    items = _eail_item_append_part_if_exist
348                                        (obj_item, items, EAIL_ITEM_PART_SECOND);
349    items = _eail_item_append_part_if_exist
350                                        (obj_item, items, EAIL_ITEM_PART_ICON);
351    items = _eail_item_append_part_if_exist
352                                        (obj_item, items, EAIL_ITEM_PART_END);
353
354    return items;
355 }
356
357 /**
358  * @brief Helper function for adding unique entries from one list to another
359  *
360  * @param item_list list which unique items will be appended to
361  * @param additional_items source list with items to be added to item_list
362  *
363  * @returns Eina_List filled with unique entries from both lists
364  */
365 static Eina_List *
366 _eail_add_unique_listsparts(Eina_List *item_list,
367                             Eina_List *additional_items)
368 {
369    Eina_List *l = NULL;
370    Elm_Object_Item *item_edj;
371
372    EINA_LIST_FOREACH(additional_items, l, item_edj)
373     {
374       if (!eina_list_data_find(item_list, item_edj))
375         item_list = eina_list_append(item_list, item_edj);
376     }
377
378    return item_list;
379 }
380
381 /**
382  * @brief Gets content part items from the given EailItem object
383  *
384  * List should be freed when results will be processed.
385  *
386  * @param eail_item EailItem object used to get content from
387  *
388  * @returns Eina_List containing content parts for the given item.
389  */
390 static Eina_List *
391 _eail_item_get_part_items(EailItem *eail_item)
392 {
393    Eina_List *items = NULL, *edje_items = NULL;
394    Elm_Object_Item *obj_item = NULL;
395
396    obj_item = eail_item_get_item(eail_item);
397    g_return_val_if_fail(obj_item, NULL);
398
399    /* parts from well documented default content parts - there are being used
400     * mostly by desktop applications. Some of these parts are not listed in
401     * edje objects (used below), so results from both list need to be merged
402     * to list full item content */
403    items = _eail_item_get_basic_parts(eail_item);
404
405    /* content parts from taken from edje object*/
406    edje_items = eail_get_edje_parts_for_item(obj_item);
407
408    /* adding unique edje items to content list*/
409    items = _eail_add_unique_listsparts(items, edje_items);
410
411    eina_list_free(edje_items);
412
413    return items;
414 }
415
416 /**
417  * @brief Gets the number of accessible children of the accessible.
418  *
419  * Implementation AtkObject->get_n_children callback.
420  *
421  * @param obj AtkObject (EailItem) instance
422  *
423  * @returns integer representing the number of accessible children of
424  * the accessible
425  */
426 static gint
427 eail_item_get_n_children(AtkObject *obj)
428 {
429    gint n_items, parent_n_items;
430    Eina_List *items;
431    AtkObject *parent = atk_object_get_parent(obj);
432
433    if (!parent) return 0;
434    parent_n_items = eail_item_parent_get_n_children(EAIL_ITEM_PARENT(parent),
435                                                     EAIL_ITEM(obj));
436    /* if there is item parent impl, then returning item count
437     * from it*/
438    if (parent_n_items != -1) return parent_n_items;
439
440    items = _eail_item_get_part_items(EAIL_ITEM(obj));
441    n_items = eina_list_count(items);
442
443    eina_list_free(items);
444
445    return n_items;
446 }
447
448 /**
449  * @brief Gets a reference to the specified accessible child of the object.
450  *
451  * The accessible children are 0-based so the first accessible child is at index 0,
452  * the second at index 1 and so on.
453  *
454  * Implementation of AtkObject->ref_child callback.
455  *
456  * @param obj AtkObject for EailItem instance
457  * @param i index of item to reference
458  *
459  * @returns AtkObject representing the specified accessible child of the
460  * accessible
461  */
462 static AtkObject *
463 eail_item_ref_child(AtkObject *obj, gint i)
464 {
465    Eina_List *items;
466    AtkObject *child = NULL;
467    AtkObject *parent = atk_object_get_parent(obj);
468    AtkObject *ref_child_from_parent = NULL;
469
470    if (!parent) return NULL;
471
472    ref_child_from_parent = eail_item_parent_ref_n_child
473                               (EAIL_ITEM_PARENT(parent), EAIL_ITEM(obj), i);
474
475    /* if there is item parent implementation for ref child, then returning
476     * object using that parent implementation*/
477    if (ref_child_from_parent)
478       {
479         g_object_ref(ref_child_from_parent);
480         return ref_child_from_parent;
481       }
482
483    items = _eail_item_get_part_items(EAIL_ITEM(obj));
484    if (eina_list_count(items) > i)
485      child = eail_factory_get_accessible(eina_list_nth(items, i));
486    else
487       ERR("Tried to ref child with index %d out of bounds!", i);
488
489    eina_list_free(items);
490
491    if (child)
492      g_object_ref(child);
493    else
494      DBG("Child could not created in factory");
495
496    return child;
497 }
498
499 /**
500  * @brief Gets obj's attributes set
501  *
502  * The caller must free attribute set when it is no longer needed.
503  *
504  * @param obj AtkObject instance
505  * @return AtkAttributeSet containing obj's attributes
506  */
507 static AtkAttributeSet *
508 eail_item_get_attributes(AtkObject *obj)
509 {
510    AtkAttribute *attr;
511    AtkAttributeSet *attributes;
512    Elm_Object_Item *obj_item = NULL;
513
514    obj_item = eail_item_get_item(EAIL_ITEM(obj));
515    if (!obj_item) {
516       return NULL;
517    }
518
519    Evas_Object *widget = elm_object_item_widget_get(obj_item);
520
521    if (!widget) {
522       return NULL;
523    }
524
525    attr = g_new(AtkAttribute, 1);
526    attr->name = g_strdup("parent-type");
527    attr->value = g_strdup(elm_object_widget_type_get(widget));
528
529    attributes = g_slist_append(NULL, attr);
530
531    return attributes;
532 }
533 /**
534  * @brief Initializer for GObject class
535  *
536  * Defines callbacks for base AtkObject.
537  *
538  * @param klass EailItemClass instance
539  */
540 static void
541 eail_item_class_init(EailItemClass *klass)
542 {
543    AtkObjectClass *class = ATK_OBJECT_CLASS(klass);
544    GObjectClass *g_object_class = G_OBJECT_CLASS(klass);
545
546    class->initialize = eail_item_initialize;
547    class->get_name = eail_item_get_name;
548    class->get_role = eail_item_get_role;
549    class->get_index_in_parent = eail_item_get_index_in_parent;
550    class->ref_state_set = eail_item_ref_state_set;
551    class->get_n_children = eail_item_get_n_children;
552    class->ref_child = eail_item_ref_child;
553    class->get_attributes = eail_item_get_attributes;
554
555    g_object_class->finalize = eail_item_class_finalize;
556 }
557
558 /*
559  * Implementation of the *AtkComponent* interface
560  */
561
562 /**
563  * @brief Grabs focus for this component.
564  *
565  * Implementation of AtkComponent->grab_focus callback.
566  *
567  * @param component AtkComponent (EailItem) instance
568  * @returns TRUE on success, FALSE otherwise.
569  */
570 static gboolean
571 eail_item_grab_focus(AtkComponent *component)
572 {
573    AtkObject *obj = ATK_OBJECT(component);
574    AtkObject *parent = atk_object_get_parent(obj);
575
576    if (!parent) return FALSE;
577
578    return eail_item_parent_grab_item_focus(EAIL_ITEM_PARENT(parent),
579                                            EAIL_ITEM(obj));
580 }
581
582 /**
583  * @brief Gets the rectangle which gives the extent of the component.
584  *
585  * Implementation of AtkComponent->get_extents callback.
586  *
587  * @param component AtkComponent instance
588  * @param [out] x rectangle upper left x coordinate
589  * @param [out] y rectangle upper left y coordinate
590  * @param [out] width width of the rectangle
591  * @param [out] height height of the rectangle
592  * @param coord_type specifies whether the coordinates are relative to the
593  * screen or to the components top level window
594  */
595 static void
596 eail_item_get_extents(AtkComponent    *component,
597                       gint            *x,
598                       gint            *y,
599                       gint            *width,
600                       gint            *height,
601                       AtkCoordType     coord_type)
602 {
603    AtkObject *obj = ATK_OBJECT(component);
604    AtkObject *parent = atk_object_get_parent(obj);
605
606    *x = *y = G_MININT;
607    *width = *height = -1;
608
609    if (!parent) return;
610
611    eail_item_parent_get_item_extents(EAIL_ITEM_PARENT(parent),
612                                      EAIL_ITEM(obj),
613                                      x, y, width, height, coord_type);
614 }
615
616 /**
617  * @brief AtkComponent interface initialization
618  *
619  * @param iface EailNaviframPage instance
620  */
621 static void
622 atk_component_interface_init(AtkComponentIface *iface)
623 {
624    iface->grab_focus  = eail_item_grab_focus;
625    iface->get_extents = eail_item_get_extents;
626 }
627
628 /*
629  * AtkAction interface init
630  */
631
632 /**
633  * @brief Gets actions supported by given EailItem object
634  *
635  * @param action AtkAction instance
636  *
637  * @returns EailActionSupported enum entry that shows what kind of actions are
638  * supported
639  */
640 static gint
641 _eail_item_get_actions_supported(AtkAction *action)
642 {
643    AtkObject *parent = NULL;
644
645    parent = atk_object_get_parent(ATK_OBJECT(action));
646    g_return_val_if_fail(parent, FALSE);
647
648    return eail_item_parent_get_actions_supported
649                                  (EAIL_ITEM_PARENT(parent),EAIL_ITEM(action));
650
651 }
652
653 /**
654  * @brief Returns the number of implemented ATK actions.
655  *
656  * Implementation of AtkActionIface get_n_actions callback.
657  *
658  * @param action object that implements AtkAction interface
659  * @returns integer representing number of implemented actions
660  */
661 static int
662 eail_item_n_actions_get(AtkAction *action)
663 {
664    int actions_num = 0;
665    /* if parent item does not support click action, then return no action */
666    if (_eail_item_get_actions_supported(action) == EAIL_ACTION_SUPPORTED_NONE)
667      return 0;
668
669    if (_eail_item_get_actions_supported(action) & EAIL_ACTION_SUPPORTED_CLICK)
670      actions_num++;
671
672    if (_eail_item_get_actions_supported(action) & EAIL_ACTION_SUPPORTED_PRESS)
673      actions_num++;
674
675    if (_eail_item_get_actions_supported(action) & EAIL_ACTION_SUPPORTED_RELEASE)
676      actions_num++;
677
678    if (_eail_item_get_actions_supported(action) & EAIL_ACTION_SUPPORTED_EXPAND)
679      actions_num++;
680
681    if (_eail_item_get_actions_supported(action) & EAIL_ACTION_SUPPORTED_SHRINK)
682      actions_num++;
683
684    return actions_num;
685 }
686
687 /**
688  * @brief Returns the accessible name of the specified action
689  *
690  * @param action object that implements AtkAction interface
691  * @param i index (number) of action
692  * @returns string containing the accessible name of the specified action
693  */
694 static const char*
695 eail_item_action_name_get(AtkAction *action, int i)
696 {
697    const char* action_name;
698    gint actions_num;
699
700    /* if parent item does not support click action, then return no action */
701    if (_eail_item_get_actions_supported(action) == EAIL_ACTION_SUPPORTED_NONE)
702      return NULL;
703
704    actions_num = atk_action_get_n_actions(action);
705    if (i >= actions_num) return NULL;
706
707    switch (i)
708      {
709       case 0:
710          /*"click": the user clicked the item*/
711          action_name = EAIL_ITEM_CLICK_NAME;
712          break;
713       case 1:
714          /*"press": the user pressed the item*/
715          action_name = EAIL_ITEM_PRESS_NAME;
716          break;
717       case 2:
718          /*"release": the user pressed the item*/
719          action_name = EAIL_ITEM_RELEASE_NAME;
720          break;
721       case 3:
722          /*"expand": the user expand the item*/
723          action_name = EAIL_ITEM_EXPAND_NAME;
724          break;
725       case 4:
726          /*"shrink": the user shrink the item*/
727          action_name = EAIL_ITEM_SHRINK_NAME;
728          break;
729       default:
730          action_name = NULL;
731          break;
732      }
733
734    return action_name;
735 }
736
737 /**
738  * @brief Gets the clickable Evas_Object for the given EailItem
739  *
740  * @param atk_item EailItem instance
741  *
742  * @returns clickable Evas_Object or NULL of no clickable content was found
743  */
744 static Evas_Object *
745 _eail_item_get_clickable_evas_obj(AtkObject *atk_item)
746 {
747    AtkObject *parent = NULL;
748    Evas_Object *widget = NULL;
749    Eina_List *parts = NULL;
750
751    parent = atk_object_get_parent(atk_item);
752    g_return_val_if_fail(parent, FALSE);
753
754    widget = eail_item_parent_get_evas_obj
755                            (EAIL_ITEM_PARENT(parent), EAIL_ITEM(atk_item));
756    if (widget) return widget;
757
758    /* if not supported from parent, then trying to get content widget nested
759     * in item */
760    parts = _eail_item_get_part_items(EAIL_ITEM(atk_item));
761    if (parts && eina_list_count(parts) > 0)
762      {
763         /* getting first widget from content */
764         widget = eina_list_nth(parts, 0);
765      }
766    eina_list_free(parts);
767    if (widget) return widget;
768
769    /* if no nested widget, then getting evas clickable area */
770    return eail_get_edje_obj_from_item
771                            (eail_item_get_item(EAIL_ITEM(atk_item)));
772 }
773
774 /**
775  * @brief Expand or shrink the item
776  *
777  * @param atk_item item object to expand
778  * @param expand info if item should be expanded or shrinked
779  *
780  * @returns TRUE if operation was successful, FALSE otherwise
781  */
782 static gboolean _eail_item_expand(AtkObject *atk_item, Eina_Bool expand)
783 {
784    Elm_Object_Item *item = eail_item_get_item(EAIL_ITEM(atk_item));
785
786    if(elm_genlist_item_type_get(item) != ELM_GENLIST_ITEM_TREE ||
787         elm_genlist_item_expanded_get(item) == expand)
788      {
789         return FALSE;
790      }
791    elm_genlist_item_expanded_set(item, expand);
792    return FALSE;
793 }
794
795 /**
796  * @brief Performs an action with the given name on given item
797  *
798  * @param atk_item item object to perform the action on
799  * @param action_name name of the action (eg. 'click', 'press'...)
800  *
801  * @returns TRUE if operation was successful, FALSE otherwise
802  */
803 static gboolean
804 _eail_item_perform_action(AtkObject *atk_item, const gchar *action_name)
805 {
806    AtkObject *parent = NULL;
807    Evas_Object *widget = NULL;
808    int x, y;
809
810    parent = atk_object_get_parent(atk_item);
811    g_return_val_if_fail(parent, FALSE);
812
813    widget =_eail_item_get_clickable_evas_obj(atk_item);
814
815    if (!widget)
816      {
817         ERR("No widget for click found");
818         return FALSE;
819      }
820
821    if (0 == g_strcmp0(action_name, EAIL_ITEM_CLICK_NAME))
822      {
823         DBG("Calling 'click' on item");
824         eail_get_coords_widget_center(widget, &x, &y);
825         eail_mouse_click_on_coords(widget, x, y);
826      }
827    else if (0 == g_strcmp0(action_name, EAIL_ITEM_PRESS_NAME))
828      {
829         DBG("Calling 'press' on item");
830         eail_get_coords_widget_center(widget, &x, &y);
831         eail_mouse_press_on_coords(widget, x, y);
832      }
833    else if (0 == g_strcmp0(action_name, EAIL_ITEM_RELEASE_NAME))
834      {
835         DBG("Calling 'release' on item");
836         eail_get_coords_widget_center(widget, &x, &y);
837         eail_mouse_release_on_coords(widget, x, y);
838      }
839    else if (0 == g_strcmp0(action_name, EAIL_ITEM_EXPAND_NAME))
840      {
841         DBG("Calling 'expand' on item");
842         return _eail_item_expand(atk_item, EINA_TRUE);
843      }
844    else if (0 == g_strcmp0(action_name, EAIL_ITEM_SHRINK_NAME))
845      {
846         DBG("Calling 'shrink' on item");
847         return _eail_item_expand(atk_item, EINA_FALSE);
848      }
849    else
850      {
851         DBG("Action name not found: %s", action_name);
852         return FALSE;
853      }
854
855    return TRUE;
856 }
857
858 /**
859  * \brief Launches action with given index
860  *
861  * @param action AtkAction instance
862  * @param i index (number) of the action
863  *
864  * @returns TRUE if action was successfully launched, FALSE otherwise
865  */
866 static gboolean
867 eail_item_do_action(AtkAction *action, int i)
868 {
869    const char *action_name = atk_action_get_name(action, i);
870
871    /* if parent item does not support click action, then return immediately */
872    if (_eail_item_get_actions_supported(action) == EAIL_ACTION_SUPPORTED_NONE)
873      return FALSE;
874
875    if (action_name == NULL) return FALSE;
876
877    return _eail_item_perform_action(ATK_OBJECT(action), action_name);;
878 }
879
880 /**
881  * @brief Gets the description string of the specified action
882  *
883  * Implementation of get_description from AtkAction interface.
884  *
885  * @param action EailBubble instance
886  * @param i action index
887  *
888  * @return string representing the specified action's description
889  */
890 static const char*
891 eail_item_description_get(AtkAction *action,
892                           gint i)
893 {
894    EailItem *item = EAIL_ITEM(action);
895    const char *action_description;
896    gint actions_num;
897
898    if (!item) return NULL;
899
900    actions_num = atk_action_get_n_actions(action);
901    if (i >= actions_num) return NULL;
902
903    switch (i)
904      {
905       case 0:
906          /*"click": the user clicked the item*/
907          action_description = item->click_description;
908          break;
909       case 1:
910          /*"press": the user pressed the item*/
911          action_description = item->press_description;
912          break;
913       case 2:
914          /*"release": the user released the item*/
915          action_description = item->release_description;
916          break;
917       case 3:
918          /*"expand": the user expand the item*/
919          action_description = item->expand_description;
920          break;
921       case 4:
922          /*"shrink": the user shrink the item*/
923          action_description = item->shrink_description;
924          break;
925       default:
926          action_description = NULL;
927          break;
928      }
929
930    return action_description;
931 }
932
933 /**
934  * @brief Sets a description of the specified action of the object
935  *
936  * Implementation of set_description from AtkAction interface.
937  *
938  * @param action AtkAction instance
939  * @param i action index
940  * @param description action description
941  *
942  * @return TRUE on success, FALSE otherwise
943  */
944 static gboolean
945 eail_item_description_set(AtkAction *action,
946                           gint i,
947                           const char *description)
948 {
949    EailItem *item = EAIL_ITEM(action);
950    char **value;
951    gint actions_num;
952
953    if (!item) return FALSE;
954
955    actions_num = atk_action_get_n_actions(action);
956    if (i >= actions_num) return FALSE;
957
958    switch (i)
959      {
960       case 0:
961          /*"click": the user clicked the item*/
962          value = &item->click_description;
963          break;
964       case 1:
965          /*"press": the user pressed the item*/
966          value = &item->press_description;
967          break;
968       case 2:
969          /*"release": the user released the item*/
970          value = &item->release_description;
971          break;
972       case 3:
973          /*"expand": the user expand the item*/
974          value = &item->expand_description;
975          break;
976       case 4:
977          /*"shrink": the user shrink the item*/
978          value = &item->shrink_description;
979          break;
980       default:
981          value = NULL;
982          break;
983      }
984
985    if (value)
986      {
987         free(*value);
988         *value = g_strdup(description);
989         return TRUE;
990      }
991
992    return FALSE;
993 }
994
995 /**
996  * @brief Initializer for AtkActionIface
997  * @param iface AtkActionIface instance to fill
998  */
999 static void
1000 atk_action_interface_init(AtkActionIface *iface)
1001 {
1002    g_return_if_fail(iface != NULL);
1003
1004    iface->do_action     = eail_item_do_action;
1005    iface->get_n_actions = eail_item_n_actions_get;
1006    iface->get_name      = eail_item_action_name_get;
1007    iface->get_description = eail_item_description_get;
1008    iface->set_description = eail_item_description_set;
1009 }
1010
1011 /**
1012  * @brief Gets text content from item
1013  *
1014  * Implementation of AtkTextIface->get_text callback.
1015  *
1016  * Use g_free() to free the returned.
1017  *
1018  * @param text AtkText instance
1019  * @param start_offset start position
1020  * @param end_offset end position, or -1 for the end of the string.
1021  *
1022  * @returns a newly allocated string containing the text from start_offset
1023  * up to, but not including end_offset.
1024  * string.
1025  */
1026 static gchar*
1027 eail_item_get_text(AtkText   *text,
1028                    gint       start_offset,
1029                    gint       end_offset)
1030 {
1031    Eina_Strbuf *buf = NULL;
1032    Elm_Object_Item *obj_item = NULL;
1033    Eina_List *string_parts = NULL, *l = NULL;
1034    gchar *string_part = NULL;
1035    gchar *ret_str = NULL;
1036    gboolean first_part = TRUE;
1037
1038    obj_item = eail_item_get_item(EAIL_ITEM(text));
1039    g_return_val_if_fail(obj_item, NULL);
1040
1041    string_parts = eail_item_get_content_strings(obj_item);
1042    if (!string_parts) return NULL;
1043
1044    buf = eina_strbuf_new();
1045    EINA_LIST_FOREACH(string_parts, l, string_part)
1046     {
1047       if (!first_part)
1048         eina_strbuf_append(buf, EAIL_TXT_SEPARATOR);
1049
1050       eina_strbuf_append(buf, string_part);
1051       first_part = FALSE;
1052     }
1053
1054    /* ret_str is newly allocated */
1055    ret_str = eail_get_substring
1056                      (eina_strbuf_string_get(buf), start_offset, end_offset);
1057
1058    eina_list_free(string_parts);
1059    eina_strbuf_free(buf);
1060
1061    return ret_str;
1062 }
1063
1064 /**
1065  * @brief Gets character from an item at the given offset
1066  *
1067  * Implementation of AtkTextIface->get_character_at_offset callback.
1068  *
1069  * @param text AtkText instance
1070  * @param offset offset to get the character from
1071  *
1072  * @returns char located at offset
1073  */
1074 static gunichar
1075 eail_item_get_character_at_offset(AtkText *text, gint offset)
1076 {
1077    gunichar character = '\0';
1078    gchar* time_str = NULL;
1079
1080    time_str = eail_item_get_text(text, 0, -1);
1081
1082    if (time_str)
1083      {
1084          character = g_utf8_get_char
1085                               (g_utf8_offset_to_pointer(time_str, offset));
1086          g_free(time_str);
1087      }
1088
1089    return character;
1090 }
1091
1092 /**
1093  * @brief Gets the character count from text content in item
1094  *
1095  * Implementation of AtkTextIface->get_character_count callback.
1096  *
1097  * @param text AtkText instance
1098  *
1099  * @returns integer representing the character count
1100  */
1101 static gint
1102 eail_item_get_character_count(AtkText *text)
1103 {
1104    gint count = 0;
1105    gchar* str = NULL;
1106
1107    str = eail_item_get_text(text, 0, -1);
1108
1109    if (str)
1110       {
1111          count = g_utf8_strlen(str, -1);
1112          g_free(str);
1113       }
1114
1115    return count;
1116 }
1117
1118 /*
1119  * @brief Creates an AtkAttributeSet which consists of the attributes
1120  * explicitly set at the position offset in the text.
1121  *
1122  * start_offset and end_offset are set to the start and end of the range around offset
1123  * where the attributes are invariant.
1124  *
1125  * Note that end_offset is the offset of the first character after the range.
1126  *
1127  * This AtkAttributeSet should be freed by a call to
1128  * atk_attribute_set_free()
1129  *
1130  * @param text AtkText instance
1131  * @param offset the offset at which to get the attributes
1132  * @param [out] start_offset start offset of the range
1133  * @param [out] end_offset end offset of the range
1134  *
1135  * @returns an AtkAttributeSet which contains the attributes explicitly set at
1136  * offset.
1137  */
1138 static AtkAttributeSet *
1139 eail_item_get_run_attributes(AtkText *text,
1140                              gint offset,
1141                              gint *start_offset,
1142                              gint *end_offset)
1143 {
1144    AtkAttributeSet *at_set = NULL;
1145    Elm_Object_Item *obj_item = NULL;
1146    obj_item = eail_item_get_item(EAIL_ITEM(text));
1147    gint len = eail_item_get_character_count(text);
1148
1149    if (!obj_item || offset >= len)
1150      {
1151         *start_offset = -1;
1152         *end_offset = -1;
1153
1154         return NULL;
1155      }
1156
1157    *start_offset = 0;
1158    *end_offset = len;
1159
1160    /* NOTE: Elm_Wrap_Type value is in 100% compatible with ATK wrap modes, so
1161     * no additional conversion is needed*/
1162    Elm_Wrap_Type wrap_type = ELM_WRAP_NONE;
1163    at_set = eail_utils_text_add_attribute
1164        (at_set, ATK_TEXT_ATTR_WRAP_MODE,
1165         atk_text_attribute_get_value
1166          (ATK_TEXT_ATTR_WRAP_MODE, wrap_type));
1167
1168    at_set = eail_utils_text_add_attribute
1169        (at_set, ATK_TEXT_ATTR_EDITABLE,
1170         atk_text_attribute_get_value
1171          (ATK_TEXT_ATTR_EDITABLE, FALSE));
1172
1173    return at_set;
1174 }
1175
1176 /**
1177  * @brief Creates an AtkAttributeSet which consists of the default values of
1178  * attributes for the text.
1179  *
1180  * This AtkAttributeSet should be freed by a call to
1181  * atk_attribute_set_free()
1182  *
1183  * @param text AtkText instance
1184  *
1185  * @returns AtkAttributeSet containing default values of attributes
1186  * at offset.
1187  */
1188 static AtkAttributeSet *
1189 eail_item_get_default_attributes(AtkText *text)
1190 {
1191    AtkAttributeSet *at_set = NULL;
1192
1193    at_set = eail_utils_text_add_attribute
1194        (at_set, ATK_TEXT_ATTR_WRAP_MODE,
1195         atk_text_attribute_get_value(ATK_TEXT_ATTR_WRAP_MODE, 0));
1196
1197    at_set = eail_utils_text_add_attribute
1198        (at_set, ATK_TEXT_ATTR_EDITABLE,
1199         atk_text_attribute_get_value
1200          (ATK_TEXT_ATTR_EDITABLE, FALSE));
1201
1202    return at_set;
1203 }
1204
1205 /**
1206  * @brief Initializer for AtkTextinterface
1207  * @param iface AtkTextIface instance to fill
1208  */
1209 static void
1210 atk_text_interface_init(AtkTextIface *iface)
1211 {
1212    iface->get_text = eail_item_get_text;
1213    iface->get_character_at_offset = eail_item_get_character_at_offset;
1214    iface->get_character_count = eail_item_get_character_count;
1215    iface->get_run_attributes = eail_item_get_run_attributes;
1216    iface->get_default_attributes = eail_item_get_default_attributes;
1217 }