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