Merge "custom eail widget implementation" into tizen
[platform/core/uifw/eail.git] / eail / eail_gengrid.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_gengrid.c
22  * @brief EailGengrid implementation
23  */
24
25 #include <Elementary.h>
26
27 #include "eail_gengrid.h"
28 #include "eail_item_parent.h"
29 #include "eail_factory.h"
30 #include "eail_utils.h"
31 #include "eail_priv.h"
32
33 static void eail_item_parent_interface_init(EailItemParentIface *iface);
34 static void atk_table_interface_init(AtkTableIface *iface);
35 static void atk_selection_interface_init(AtkSelectionIface *iface);
36
37 /** @brief GObject definition for EailGengrid implementation*/
38 G_DEFINE_TYPE_WITH_CODE(EailGengrid,
39                         eail_gengrid,
40                         EAIL_TYPE_WIDGET,
41                         G_IMPLEMENT_INTERFACE(EAIL_TYPE_ITEM_PARENT,
42                                               eail_item_parent_interface_init)
43                         G_IMPLEMENT_INTERFACE(ATK_TYPE_TABLE,
44                                               atk_table_interface_init)
45                         G_IMPLEMENT_INTERFACE(ATK_TYPE_SELECTION,
46                                               atk_selection_interface_init));
47
48 /*
49  * Implementation of the *AtkObject* interface
50  */
51
52 /**
53  * @brief Handler for realized event, used to notify about gengrid content
54  * changes
55  *
56  * @param data passed to callback
57  * @param obj object that raised event
58  * @param event_info additional event info (item is passed here)
59  */
60 void
61 eail_gengrid_item_handle_realized_event(void *data,
62                                         Evas_Object *obj,
63                                         void *event_info)
64 {
65    Elm_Object_Item *item = (Elm_Object_Item *) event_info;
66    AtkObject *atk_item = NULL, *atk_parent = NULL;
67
68    atk_parent = ATK_OBJECT(data);
69    if (!atk_parent) return;
70
71    atk_item = eail_factory_get_item_atk_obj
72                                          (item, ATK_ROLE_LIST_ITEM, atk_parent);
73
74    if (!atk_item) return;
75
76    eail_emit_children_changed_obj(TRUE, atk_parent, atk_item);
77 }
78
79 /**
80  * @brief Handler for unrealized event, used to notify about gengrid content
81  * changes
82  *
83  * @param data passed to callback
84  * @param obj object that raised event
85  * @param event_info additional event info (item is passed here)
86  */
87 void
88 eail_gengrid_item_handle_unrealized_event(void *data,
89                                           Evas_Object *obj,
90                                           void *event_info)
91 {
92    Elm_Object_Item *item = (Elm_Object_Item *) event_info;
93    AtkObject *atk_item = NULL, *atk_parent = NULL;
94
95    atk_parent = ATK_OBJECT(data);
96    if (!atk_parent) return;
97
98    atk_item = eail_factory_get_item_atk_obj
99                                          (item, ATK_ROLE_LIST_ITEM, atk_parent);
100
101    if (!atk_item) return;
102
103    eail_emit_children_changed_obj(FALSE, atk_parent, atk_item);
104    atk_object_notify_state_change(atk_item, ATK_STATE_DEFUNCT, TRUE);
105
106    DBG("Unregistering item from cache...");
107    eail_factory_unregister_item_from_cache(item);
108 }
109
110 /**
111  * @brief Initializes EailGengrid object
112  *
113  * @param obj EailGengrid instance
114  * @param data user data passed for initialization
115  */
116 static void
117 eail_gengrid_initialize(AtkObject *obj, gpointer data)
118 {
119    Evas_Object *nested_widget = NULL;
120    ATK_OBJECT_CLASS(eail_gengrid_parent_class)->initialize(obj, data);
121    obj->role = ATK_ROLE_TABLE;
122
123    nested_widget = eail_widget_get_widget(EAIL_WIDGET(obj));
124    if (!nested_widget)
125      {
126         ERR("No evas object inside EailWidget was found");
127         return;
128      }
129
130    evas_object_smart_callback_add(nested_widget, "selected",
131                                 eail_list_item_handle_selected_event, obj);
132    evas_object_smart_callback_add(nested_widget, "unselected",
133                                 eail_list_item_handle_unselected_event, obj);
134    evas_object_smart_callback_add(nested_widget, "realized",
135                                 eail_gengrid_item_handle_realized_event, obj);
136    evas_object_smart_callback_add(nested_widget, "unrealized",
137                                 eail_gengrid_item_handle_unrealized_event, obj);
138 }
139
140 /**
141  * @brief Gets the list of created widgets
142  *
143  * @param gengrid EailGengrid instance
144  *
145  * @returns Eina_List representing the list of widgets elm_gengrid holds
146  */
147 static Eina_List *
148 eail_gengrid_items_get(EailGengrid *gengrid)
149 {
150    g_return_val_if_fail(EAIL_IS_WIDGET(gengrid), NULL);
151
152    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(gengrid));
153
154    return elm_gengrid_realized_items_get(widget);
155 }
156
157 /**
158  * @brief Gets the number of created widgets
159  *
160  * @param obj AtkObject instance
161  *
162  * @returns integer representing the number of created widgets
163  */
164 static gint
165 eail_gengrid_n_items_get(AtkObject *obj)
166 {
167    gint n_items;
168    Eina_List *items = eail_gengrid_items_get(EAIL_GENGRID(obj));
169    n_items  = eina_list_count(items);
170    eina_list_free(items);
171
172    return n_items;
173 }
174
175 /**
176  * @brief Gets the reference to the specified elm_gengrid's child
177  *
178  * @param obj AtkObject instance
179  * @param i child index
180  *
181  * @returns AtkObject representing the elm_gengrid's child
182  */
183 static AtkObject *
184 eail_gengrid_ref_child(AtkObject *obj, gint i)
185 {
186    g_return_val_if_fail(EAIL_IS_GENGRID(obj), NULL);
187
188    AtkObject *child = NULL;
189
190    Eina_List *list = eail_gengrid_items_get(EAIL_GENGRID(obj));
191    if (eina_list_count(list) > i)
192      {
193         child = eail_factory_get_item_atk_obj
194                              (eina_list_nth(list, i), ATK_ROLE_LIST_ITEM, obj);
195
196         g_object_ref(child);
197      }
198
199    return child;
200 }
201
202 /**
203  * @brief Gets a reference to the state set of the accessible
204  *
205  * The caller must unreference it when it is no longer needed.
206  *
207  * Implementation of ref_state_set from AtkObject.
208  *
209  * @param obj AtkObject instance
210  *
211  * @returns AtkStateSet representing the state set of the accessible
212  */
213 static AtkStateSet *
214 eail_gengrid_ref_state_set(AtkObject *obj)
215 {
216    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(obj));
217    AtkStateSet *state_set =
218       ATK_OBJECT_CLASS(eail_gengrid_parent_class)->ref_state_set(obj);
219
220    if (!widget) return state_set;
221
222    if (elm_gengrid_multi_select_get(widget))
223      atk_state_set_add_state(state_set, ATK_STATE_MULTISELECTABLE);
224
225    return state_set;
226 }
227
228 /**
229  * @brief Initializes EailGengrid object
230  *
231  * @param gengrid EailGengrid instance
232  */
233 static void
234 eail_gengrid_init(EailGengrid *gengrid)
235 {
236 }
237
238 /**
239  * @brief Initializes EailGengrid class
240  *
241  * @param klass EailGengridClass instance
242  */
243 static void
244 eail_gengrid_class_init(EailGengridClass *klass)
245 {
246    AtkObjectClass *atk_class = ATK_OBJECT_CLASS(klass);
247
248    atk_class->initialize = eail_gengrid_initialize;
249    atk_class->get_n_children = eail_gengrid_n_items_get;
250    atk_class->ref_child = eail_gengrid_ref_child;
251    atk_class->ref_state_set = eail_gengrid_ref_state_set;
252 }
253
254 /**
255  * @brief Gets the name of elm_gengrid child
256  *
257  * @param parent EailItemParent instance
258  * @param item EailItem child instance
259  *
260  * @returns string representing the item's name
261  */
262 static const gchar *
263 eail_gengrid_item_name_get(EailItemParent *parent, EailItem *item)
264 {
265    Elm_Object_Item *it = eail_item_get_item(item);
266    /*that will work only for default theme*/
267    if (!it) return NULL;
268
269    return elm_object_item_part_text_get(it, "elm.text");
270 }
271
272 /**
273  * @brief Gets the item's index in parent object
274  *
275  * @param parent EailItemParent instance
276  * @param item EailItem child instance
277  *
278  * @returns integer representing the child's index in parent
279  */
280 static int
281 eail_gengrid_item_index_in_parent_get(EailItemParent *parent, EailItem *item)
282 {
283    Elm_Object_Item *it = eail_item_get_item(item);
284
285    if (!it) return -1;
286
287    return elm_gengrid_item_index_get(it)-1;
288 }
289
290 /**
291  * @brief Gets the state set of EailGengrid item
292  *
293  * @param parent EailItemParent instance
294  * @param item EailItem child instance
295  * @param state_set AtkStateSet to fill
296  *
297  * @returns AtkStateSet representing the state set of the child
298  */
299 static AtkStateSet *
300 eail_gengrid_ref_item_state_set(EailItemParent *parent,
301                                 EailItem *item,
302                                 AtkStateSet *state_set)
303 {
304    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(parent));
305    Elm_Object_Item *it = eail_item_get_item(item);
306
307    if (!widget || !it) return state_set;
308
309    Evas_Object *cell = elm_object_item_widget_get(it);
310
311    if ((elm_gengrid_select_mode_get(widget) != ELM_OBJECT_SELECT_MODE_NONE) &&
312        (elm_gengrid_item_select_mode_get(it) != ELM_OBJECT_SELECT_MODE_NONE))
313      {
314         atk_state_set_add_state(state_set, ATK_STATE_SELECTABLE);
315         if (elm_gengrid_selected_item_get(cell))
316           atk_state_set_add_state(state_set, ATK_STATE_SELECTED);
317      }
318
319    if (evas_object_visible_get(cell))
320      atk_state_set_add_state(state_set, ATK_STATE_VISIBLE);
321
322    atk_state_set_add_state(state_set, ATK_STATE_SHOWING);
323
324    return state_set;
325 }
326
327 /**
328  * @brief Grabs focus of EailGengrid item
329  *
330  * @param parent EailGengrid instance
331  * @param item EailGengrid child instance
332  *
333  * @returns TRUE on success, FALSE otherwise
334  */
335 static gboolean
336 eail_gengrid_grab_item_focus(EailItemParent *parent,
337                              EailItem *item)
338 {
339    Elm_Object_Item *it = eail_item_get_item(item);
340    if (!it) return FALSE;
341
342    Evas_Object *obj = elm_object_item_widget_get(it);
343    if (!elm_object_focus_allow_get(obj)) return FALSE;
344
345    elm_object_focus_set(obj, EINA_TRUE);
346
347    return TRUE;
348 }
349
350 /**
351  * @brief Gets the rectangle which gives the extent of the component
352  *
353  * Implementation of get_extents from AtkComponent for EailGengrid child.
354  *
355  * @param parent EailGengrid instance
356  * @param item EailGengrid child instance
357  * @param [out] x x coordinate
358  * @param [out] y coordinate
359  * @param [out] width width of the rectangle
360  * @param [out] height height of the rectangle
361  * @param coord_type specifies whether the coordinates are relative to the screen or to the components top level window
362  */
363 static void
364 eail_gengrid_item_extents_get(EailItemParent *parent,
365                               EailItem *item,
366                               gint *x,
367                               gint *y,
368                               gint *width,
369                               gint *height,
370                               AtkCoordType coord_type)
371 {
372    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(parent));
373    Elm_Object_Item *it = eail_item_get_item(item);
374
375    if ((!widget) || (!it)) return;
376
377    Evas_Object *it_widget = elm_object_item_widget_get(it);
378    evas_object_geometry_get(it_widget, x, y, width, height);
379
380    if (coord_type == ATK_XY_SCREEN) {
381         int ee_x, ee_y;
382         Ecore_Evas *ee =
383            ecore_evas_ecore_evas_get(evas_object_evas_get(it_widget));
384
385         ecore_evas_geometry_get(ee, &ee_x, &ee_y, NULL, NULL);
386         *x += ee_x;
387         *y += ee_y;
388    }
389 }
390
391 /**
392  * @brief Gets supported actions
393  *
394  * Implementation of EailItemParent->get_actions_supported callback.
395  *
396  * @param parent EailItemParent instance
397  * @param item EailItem instance
398  * @returns implementation representing supported actions
399  */
400 static gint
401 eail_gengrid_get_actions_supported(EailItemParent   *parent,
402                                    EailItem         *item)
403 {
404    return EAIL_ACTION_SUPPORTED_CLICK | EAIL_ACTION_SUPPORTED_PRESS |
405             EAIL_ACTION_SUPPORTED_RELEASE;
406 }
407
408 /**
409  * @brief Gets index in parent
410  *
411  * @param parent EailItemParent instance
412  * @param item EailItem child instance
413  *
414  * @returns int representing the index in parent
415  */
416 static gint
417 eail_gengrid_get_item_index_in_parent(EailItemParent *parent, EailItem *item)
418 {
419    Elm_Object_Item *it = eail_item_get_item(item);
420
421    if (!it) return -1;
422
423    return elm_gengrid_item_index_get(it)-1;
424 }
425
426 /**
427  * @brief EailItemParent interface initialization
428  *
429  * @param iface EailItemParentIface instance
430  */
431 static void
432 eail_item_parent_interface_init(EailItemParentIface *iface)
433 {
434    if (!iface) return;
435
436    iface->get_item_name            = eail_gengrid_item_name_get;
437    iface->get_item_index_in_parent = eail_gengrid_item_index_in_parent_get;
438    iface->ref_item_state_set       = eail_gengrid_ref_item_state_set;
439    iface->grab_item_focus          = eail_gengrid_grab_item_focus;
440    iface->get_item_extents         = eail_gengrid_item_extents_get;
441    iface->get_actions_supported    = eail_gengrid_get_actions_supported;
442    iface->get_item_index_in_parent = eail_gengrid_get_item_index_in_parent;
443 }
444
445 /**
446  * @brief Helper function for getting rows and columns count
447  *
448  * @param object elm_gengrid instance
449  * @param [out] rows rows count
450  * @param [out] columns columns count
451  */
452 static void
453 _get_n_rows_columns(const Evas_Object *object,
454                     int *rows, int *columns)
455 {
456    Elm_Object_Item *it;
457    Eina_List *l, *list = elm_gengrid_realized_items_get(object);
458    int row, column;
459
460    if (list == NULL)
461      {
462         *rows = 0;
463         *columns = 0;
464         return;
465      }
466
467    row = column = 0;
468    EINA_LIST_FOREACH(list, l, it)
469      {
470         unsigned int item_row, item_col;
471         elm_gengrid_item_pos_get(it, &item_col, &item_row);
472         if (item_row > row) row++;
473         if (item_col > column) column++;
474      }
475
476    eina_list_free(list);
477    *rows = row + 1;
478    *columns = column + 1;
479 }
480
481
482 /**
483  * @brief Gets the number of rows in the table
484  *
485  * Implementation of get_n_rows from AtkTable.
486  *
487  * @param table AtkTable instance
488  *
489  * @returns integer representing the number of rows
490  */
491 static gint
492 eail_gengrid_n_rows_get(AtkTable *table)
493 {
494    Evas_Object *widget;
495    int rows, columns;
496
497    g_return_val_if_fail(EAIL_IS_GENGRID(table), -1);
498
499    widget = eail_widget_get_widget(EAIL_WIDGET(table));
500    if (!widget) return -1;
501
502    _get_n_rows_columns(widget, &rows, &columns);
503    return rows;
504 }
505
506 /**
507  * @brief Gets the number of columns in the table
508  *
509  * Implementation of get_n_columns from AtkTable.
510  *
511  * @param table AtkTable instance
512  *
513  * @returns integer representing the number of columns
514  */
515 static gint
516 eail_gengrid_n_columns_get(AtkTable *table)
517 {
518    Evas_Object *widget;
519    int rows, columns;
520
521    g_return_val_if_fail(EAIL_IS_GENGRID(table), -1);
522
523    widget = eail_widget_get_widget(EAIL_WIDGET(table));
524
525    _get_n_rows_columns(widget, &rows, &columns);
526
527    return columns;
528 }
529
530 /**
531  * @brief Gets a gint representing the index at the specified row and column
532  *
533  * Implementation of get_index_at from AtkTable.
534  *
535  * @param table AtkTable instance
536  * @param row number of row in table
537  * @param column number of column in table
538  *
539  * @returns integer representing the index of the specified position
540  */
541 static gint
542 eail_gengrid_index_at_get(AtkTable *table, gint row, gint column)
543 {
544    Evas_Object *widget;
545    gint n_rows, n_columns;
546    gint ret_val = -1;
547
548    g_return_val_if_fail(EAIL_IS_GENGRID(table), -1);
549    widget = eail_widget_get_widget(EAIL_WIDGET(table));
550    if (!widget) return -1;
551
552    _get_n_rows_columns(widget, &n_rows, &n_columns);
553
554    if ((row >= n_rows) || (column >= n_columns)) return -1;
555
556    if (elm_gengrid_horizontal_get(widget))
557      ret_val = ((n_columns) * column) + row;
558    else
559      ret_val = ((n_columns) * row) + column;
560
561    /* testing if result is within bounds */
562    if (ret_val >= eail_gengrid_n_items_get(ATK_OBJECT(table)))
563      return -1;
564
565    return ret_val;
566 }
567
568 /**
569  * @brief Get a reference to the table cell at row, column
570  *
571  * Implementation of ref_at from AtkTable.
572  *
573  * @param table AtkTable instance
574  * @param row number of row in table
575  * @param column number of column in table
576  *
577  * @returns AtkObject representing the child object
578  */
579 static AtkObject *
580 eail_gengrid_ref_at(AtkTable *table, gint row, gint column)
581 {
582    gint index;
583
584    g_return_val_if_fail(EAIL_IS_GENGRID(table), NULL);
585
586    index = eail_gengrid_index_at_get(table, row, column);
587    if (index == -1) return NULL;
588
589    return eail_gengrid_ref_child(ATK_OBJECT(table), index);
590 }
591
592 /**
593  * @brief Helper function for getting object's position in table at given index
594  *
595  * @param widget Evas_Object instance
596  * @param [out] row row number
597  * @param [out] column column number
598  * @param index index of child item
599  */
600 static void
601 _get_item_pos(const Evas_Object *widget, gint *row, gint *column, gint index)
602 {
603    Elm_Object_Item *it;
604    Eina_List *list;
605
606    if (!widget)
607      {
608         *row = -1;
609         *column = -1;
610         return;
611      }
612
613    list = elm_gengrid_realized_items_get(widget);
614    it = eina_list_nth(list, index);
615    elm_gengrid_item_pos_get(it, (unsigned int *)column, (unsigned int *)row);
616
617    eina_list_free(list);
618 }
619
620 /**
621  * @brief Gets an integer representing the column at the specified index
622  *
623  * Implementation of get_column_at_index from AtkTable.
624  *
625  * @param table AtkTable instance
626  * @param index child index
627  *
628  * @returns integer representing the column number in table
629  */
630 static gint
631 eail_gengrid_column_at_index_get(AtkTable *table, gint index)
632 {
633    Evas_Object *widget;
634    int row, column;
635
636    g_return_val_if_fail(EAIL_IS_GENGRID(table), -1);
637    if (index >= eail_gengrid_n_items_get(ATK_OBJECT(table)))
638      return -1;
639
640    widget = eail_widget_get_widget(EAIL_WIDGET(table));
641    _get_item_pos(widget, &row, &column, index);
642
643    return column;
644 }
645
646 /**
647  * @brief Gets a gint representing the row at the specified index
648  *
649  * Implementation of get_row_at_index from AtkTable.
650  *
651  * @param table AtkTable instance
652  * @param index child index
653  *
654  * @returns integer representing the row number in table
655  */
656 static gint
657 eail_gengrid_row_at_index_get(AtkTable *table, gint index)
658 {
659    Evas_Object *widget;
660    int row, column;
661
662    g_return_val_if_fail(EAIL_IS_GENGRID(table), -1);
663    if (index >= eail_gengrid_n_items_get(ATK_OBJECT(table)))
664      return -1;
665
666    widget = eail_widget_get_widget(EAIL_WIDGET(table));
667    _get_item_pos(widget, &row, &column, index);
668
669    return row;
670 }
671
672 /**
673  * @brief Gets a boolean value indicating whether the accessible object
674  * at the specified row and column is selected
675  *
676  * Implementation of is_selected from AtkTable.
677  *
678  * @param table AtkTable instance
679  * @param row row's number
680  * @param column column's number
681  *
682  * @returns TRUE if selected, FALSE otherwise
683  */
684 static gboolean
685 eail_gengrid_is_selected(AtkTable *table, gint row, gint column)
686 {
687    Evas_Object *widget;
688    Elm_Object_Item *it;
689    int index;
690    Eina_List *list;
691    gboolean result;
692
693    g_return_val_if_fail(EAIL_IS_GENGRID(table), FALSE);
694    widget = eail_widget_get_widget(EAIL_WIDGET(table));
695    index = eail_gengrid_index_at_get(table, row, column);
696    if (index == -1) return FALSE;
697
698    list = elm_gengrid_realized_items_get(widget);
699    it = eina_list_nth(list, index);
700    result = elm_gengrid_item_selected_get(it);
701
702    eina_list_free(list);
703    return result;
704 }
705
706 /**
707  * @brief Gets a boolean value indicating whether the specified row is selected
708  *
709  * Implementation of is_row_selected from AtkTable interface.
710  *
711  * @param table AtkTable instance
712  * @param row number of row in table
713  *
714  * @returns TRUE if selected, FALSE otherwise
715  */
716 static gboolean
717 eail_gengrid_is_row_selected(AtkTable *table, gint row)
718 {
719    Evas_Object *widget;
720    Eina_List *list;
721    const Eina_List *selected;
722    gboolean result;
723    int list_count, n_rows;
724
725    g_return_val_if_fail(EAIL_IS_GENGRID(table), FALSE);
726    widget = eail_widget_get_widget(EAIL_WIDGET(table));
727    /*it is possible to select row only in multiselct mode*/
728    if (!elm_gengrid_multi_select_get(widget))
729      return FALSE;
730
731    selected = elm_gengrid_selected_items_get(widget);
732    if (!selected) return FALSE;
733
734    n_rows = eail_gengrid_n_rows_get(table);
735    if (row > n_rows) return FALSE;
736
737    list = elm_gengrid_realized_items_get(widget);
738    list_count = eina_list_count(list);
739
740    result = TRUE;
741    for (int i = 0; i < list_count; i++)
742      {
743         Elm_Object_Item *it = eina_list_nth(list, i);
744         unsigned int x, y;
745         elm_gengrid_item_pos_get(it, &x, &y);
746         if((row == x) && (!elm_gengrid_item_selected_get(it)))
747           {
748              /*row is considered selected if all items in row are selected*/
749              result = FALSE;
750              break;
751           }
752      }
753    eina_list_free(list);
754    return result;
755 }
756
757 /**
758  * @brief Gets the selected rows of the table by initializing selected
759  * with the selected row numbers
760  *
761  * This array should be freed by the caller.
762  *
763  * Implementation of get_selected_rows from AtkTable interface.
764  *
765  * @param table AtkTable instance
766  * @param [out] selected selected rows number
767  *
768  * @returns integer representing the selected rows count
769  */
770 static gint
771 eail_gengrid_selected_rows_get(AtkTable *table, gint **selected)
772 {
773    GArray *array;
774    Evas_Object *widget;
775    gint row;
776    int n_rows, n_selected, i;
777
778    g_return_val_if_fail(EAIL_IS_GENGRID(table), 0);
779    widget = eail_widget_get_widget(EAIL_WIDGET(table));
780
781    if (!widget)
782      return 0;
783    if (!elm_gengrid_multi_select_get(widget)  && eail_gengrid_n_columns_get(table) > 1)
784      return 0;
785
786    n_rows = eail_gengrid_n_rows_get(table);
787
788    array = g_array_new(FALSE, FALSE, sizeof(gint));
789    for (i = 0; i < n_rows; i++)
790      {
791         if (eail_gengrid_is_row_selected(table, i))
792           g_array_append_val(array, i);
793      }
794
795    n_selected = array->len;
796
797    if (n_selected)
798    {
799      *selected = (gint *) g_malloc (n_selected * sizeof(gint));
800
801      for (i=0; i<n_selected;i++)
802      {
803        row = g_array_index(array,gint,i);
804        (*selected)[i] = row;
805      }
806
807      g_array_free(array, FALSE);
808
809    }
810
811    return n_selected;
812 }
813
814 /**
815  * @brief Helper function for setting row selection
816  *
817  * @param table AtkTable instance
818  * @param row row number
819  * @param selection EINA_TRUE for selection, EINA_FALSE for removing selection
820  */
821 static void
822 _set_row_selection(AtkTable *table, int row, Eina_Bool selection)
823 {
824    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(table));
825    Eina_List *list = elm_gengrid_realized_items_get(widget);
826    int list_count = eina_list_count(list);
827
828    for (int i = 0; i < list_count; i++)
829      {
830         unsigned int x, y;
831         Elm_Object_Item *it = eina_list_nth(list, i);
832         elm_gengrid_item_pos_get(it, &x, &y);
833         if (x == row)
834           {
835              elm_gengrid_item_selected_set(it, selection);
836           }
837      }
838
839    eina_list_free(list);
840 }
841
842 /**
843  * @brief Adds the specified row to the selection
844  *
845  * Implementation of add_row_selection from AtkTable.
846  *
847  * @param table AtkTable instance
848  * @param row row number in table
849  *
850  * @returns TRUE on success, FALSE otherwise
851  */
852 static gboolean
853 eail_gengrid_add_row_selection(AtkTable *table, gint row)
854 {
855    Evas_Object *widget;
856    int n_rows;
857
858    g_return_val_if_fail(EAIL_IS_GENGRID(table), FALSE);
859    widget = eail_widget_get_widget(EAIL_WIDGET(table));
860
861    if (!widget) return FALSE;
862    if (!elm_gengrid_multi_select_get(widget)) return FALSE;
863    n_rows = eail_gengrid_n_rows_get(table);
864    if (row > n_rows) return FALSE;
865
866    _set_row_selection(table, row, EINA_TRUE);
867    return TRUE;
868 }
869
870 /**
871  * @brief Removes the specified row from the selection
872  *
873  * Implementation of remove_row_selection from AtkTable interface.
874  *
875  * @param table AtkTable instance
876  * @param row number of row in table
877  *
878  * @returns TRUE on success, FALSE otherwise
879  */
880 static gboolean
881 eail_gengrid_remove_row_selection(AtkTable *table, gint row)
882 {
883    Evas_Object *widget;
884    int n_rows;
885
886    g_return_val_if_fail(EAIL_IS_GENGRID(table), FALSE);
887
888    widget = eail_widget_get_widget(EAIL_WIDGET(table));
889    if (!widget) return FALSE;
890    if (!elm_gengrid_multi_select_get(widget)) return FALSE;
891    n_rows = eail_gengrid_n_rows_get(table);
892    if (row > n_rows) return FALSE;
893
894    _set_row_selection(table, row, EINA_FALSE);
895    return TRUE;
896
897 }
898
899 /**
900  * @brief Gets a boolean value indicating whether the specified column is selected
901  *
902  * Implementation of is_column_selected from AtkTable interface.
903  *
904  * @param table AtkTable implementation
905  * @param column number of column in table
906  *
907  * @returns TRUE on selection, FALSE otherwise
908  */
909 static gboolean
910 eail_gengrid_is_column_selected(AtkTable *table, gint column)
911 {
912    Evas_Object *widget;
913    Eina_List *list;
914    const Eina_List *selected;
915    int n_columns, list_count;
916    gboolean result;
917
918    g_return_val_if_fail(EAIL_IS_GENGRID(table), FALSE);
919    widget = eail_widget_get_widget(EAIL_WIDGET(table));
920    if (!elm_gengrid_multi_select_get(widget)) return FALSE;
921    n_columns = eail_gengrid_n_columns_get(table);
922    if (column > n_columns) return FALSE;
923    selected = elm_gengrid_selected_items_get(widget);
924    if (!selected) return FALSE;
925
926    list = elm_gengrid_realized_items_get(widget);
927    list_count = eina_list_count(list);
928    result = TRUE;
929    for (int i = 0; i < list_count; i++)
930      {
931         Elm_Object_Item *it = eina_list_nth(list, i);
932         unsigned int x, y;
933         elm_gengrid_item_pos_get(it, &x, &y);
934         if ((y == column) && (!elm_gengrid_item_selected_get(it)))
935           {
936              result = FALSE;
937              break;
938           }
939      }
940
941    eina_list_free(list);
942    return result;
943 }
944
945 /**
946  * @brief Helper function for setting column selection in elm_gengrid
947  *
948  * @param table AtkTable instance
949  * @param column number of column in table
950  * @param selection EINA_TRUE for selection, EINA_FALSE otherwise
951  */
952 static void
953 _set_column_selection(AtkTable *table, int column, Eina_Bool selection)
954 {
955    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(table));
956    Eina_List *list = elm_gengrid_realized_items_get(widget);
957    int list_count = eina_list_count(list);
958
959    for (int i = 0; i < list_count; i++)
960      {
961         unsigned int x, y;
962         Elm_Object_Item *it = eina_list_nth(list, i);
963         elm_gengrid_item_pos_get(it, &x, &y);
964         if (y == column)
965           {
966              elm_gengrid_item_selected_set(it, selection);
967           }
968      }
969
970    eina_list_free(list);
971 }
972
973 /**
974  * @brief Gets the selected columns of the table by initializing selected
975  * with the selected columns numbers
976  *
977  * This array should be freed by the caller.
978  *
979  * Implementation of get_selected_columns from AtkTable interface.
980  *
981  * @param table AtkTable instance
982  * @param [out] selected selected columns number
983  *
984  * @returns integer representing the selected columns count
985  */
986 static gint
987 eail_gengrid_selected_columns_get(AtkTable *table, gint **selected)
988 {
989    GArray *array;
990    Evas_Object *widget;
991    gint col;
992    int n_cols, n_selected, i;
993
994    g_return_val_if_fail(EAIL_IS_GENGRID(table), 0);
995    widget = eail_widget_get_widget(EAIL_WIDGET(table));
996
997    if (!widget)
998      return 0;
999    if (!elm_gengrid_multi_select_get(widget)  && eail_gengrid_n_rows_get(table) > 1)
1000      return 0;
1001
1002    n_cols = eail_gengrid_n_columns_get(table);
1003
1004    array = g_array_new(FALSE, FALSE, sizeof(gint));
1005    for (i = 0; i < n_cols; i++)
1006      {
1007         if (eail_gengrid_is_column_selected(table, i))
1008           g_array_append_val(array, i);
1009      }
1010
1011    n_selected = array->len;
1012
1013    if (n_selected)
1014    {
1015      *selected = (gint *) g_malloc (n_selected * sizeof(gint));
1016
1017      for (i=0; i<n_selected;i++)
1018      {
1019        col = g_array_index(array,gint,i);
1020        (*selected)[i] = col;
1021      }
1022
1023      g_array_free(array, FALSE);
1024
1025    }
1026
1027    return n_selected;
1028 }
1029
1030 /**
1031  * @brief Adds the specified column to the selection
1032  *
1033  * Implementation of add_column_selection from AtkTable interface.
1034  *
1035  * @param table AtkTable instance
1036  * @param column number of column in table
1037  *
1038  * @returns TRUE on success, FALSE otherwise
1039  */
1040 static gboolean
1041 eail_gengrid_add_column_selection(AtkTable *table, gint column)
1042 {
1043    Evas_Object *widget;
1044    int n_columns;
1045
1046    g_return_val_if_fail(EAIL_IS_GENGRID(table), FALSE);
1047    widget = eail_widget_get_widget(EAIL_WIDGET(table));
1048    if (!widget) return FALSE;
1049    if (!elm_gengrid_multi_select_get(widget)) return FALSE;
1050    n_columns = eail_gengrid_n_columns_get(table);
1051    if (column > n_columns) return FALSE;
1052
1053    _set_column_selection(table, column, EINA_TRUE);
1054    return TRUE;
1055 }
1056
1057 /**
1058  * @brief Removes the specified column from the selection
1059  *
1060  * Implementation of remove_column_selection from AtkTable.
1061  *
1062  * @param table AtkTable instance
1063  * @param column column number in table
1064  *
1065  * @returns TRUE on success, FALSE otherwise
1066  */
1067 static gboolean
1068 eail_gengrid_remove_column_selection(AtkTable *table, gint column)
1069 {
1070    Evas_Object *widget;
1071    int n_columns;
1072
1073    g_return_val_if_fail(EAIL_IS_GENGRID(table), FALSE);
1074    widget = eail_widget_get_widget(EAIL_WIDGET(table));
1075    if (!widget) return FALSE;
1076    if (!elm_gengrid_multi_select_get(widget)) return FALSE;
1077    n_columns = eail_gengrid_n_columns_get(table);
1078    if (column > n_columns) return FALSE;
1079
1080    _set_column_selection(table, column, EINA_FALSE);
1081    return TRUE;
1082
1083 }
1084
1085 /**
1086  * @brief AtkTable interface initialization
1087  *
1088  * @param iface AtkTableIface instance
1089  */
1090 static void
1091 atk_table_interface_init(AtkTableIface *iface)
1092 {
1093    if (!iface) return;
1094
1095    iface->ref_at = eail_gengrid_ref_at;
1096    iface->get_n_rows = eail_gengrid_n_rows_get;
1097    iface->get_n_columns = eail_gengrid_n_columns_get;
1098    iface->get_index_at = eail_gengrid_index_at_get;
1099    iface->get_column_at_index = eail_gengrid_column_at_index_get;
1100    iface->get_row_at_index = eail_gengrid_row_at_index_get;
1101    iface->is_row_selected = eail_gengrid_is_row_selected;
1102    iface->is_selected = eail_gengrid_is_selected;
1103    iface->get_selected_rows = eail_gengrid_selected_rows_get;
1104    iface->add_row_selection = eail_gengrid_add_row_selection;
1105    iface->remove_row_selection = eail_gengrid_remove_row_selection;
1106    iface->is_column_selected = eail_gengrid_is_column_selected;
1107    iface->get_selected_columns = eail_gengrid_selected_columns_get;
1108    iface->add_column_selection = eail_gengrid_add_column_selection;
1109    iface->remove_column_selection = eail_gengrid_remove_column_selection;
1110
1111    /*unsupported*/
1112    iface->get_column_extent_at = NULL;
1113    iface->get_row_extent_at = NULL;
1114    iface->get_column_header = NULL;
1115    iface->get_column_description = NULL;
1116 }
1117
1118 /**
1119  * @brief Adds the specified accessible child of the object to the object's selection
1120  *
1121  * Implementation of add_selection from AtkSelection interface.
1122  *
1123  * @param selection AtkSelection instance
1124  * @param i index of child to select
1125  *
1126  * @returns TRUE on success, FALSE otherwise
1127  */
1128 static gboolean
1129 eail_gengrid_selection_add(AtkSelection *selection, gint i)
1130 {
1131    Evas_Object *widget;
1132    Elm_Object_Item *it;
1133    Eina_List *list;
1134    gboolean result;
1135
1136    g_return_val_if_fail(EAIL_IS_GENGRID(selection), FALSE);
1137    widget = eail_widget_get_widget(EAIL_WIDGET(selection));
1138    list = elm_gengrid_realized_items_get(widget);
1139
1140    if (i > eina_list_count(list)) return FALSE;
1141    it = eina_list_nth(list, i);
1142
1143    if (elm_gengrid_item_selected_get(it))
1144      result = FALSE;
1145    else
1146      {
1147         elm_gengrid_item_selected_set(it, EINA_TRUE);
1148         result = TRUE;
1149      }
1150
1151    eina_list_free(list);
1152    return result;
1153 }
1154
1155 /**
1156  * @brief Clears the selection in the object so that no children in the object are selected
1157  *
1158  * Implementation of clear_selection from AtkSelection.
1159  *
1160  * @param selection AtkSelection instance
1161  *
1162  * @returns TRUE on success, FALSE otherwise
1163  */
1164 static gboolean
1165 eail_gengrid_selection_clear(AtkSelection *selection)
1166 {
1167    const Eina_List *l, *list;
1168    Evas_Object *widget;
1169    Elm_Object_Item *it;
1170
1171    g_return_val_if_fail(EAIL_IS_GENGRID(selection), FALSE);
1172    widget = eail_widget_get_widget(EAIL_WIDGET(selection));
1173
1174    if (elm_gengrid_multi_select_get(widget))
1175      {
1176         list = elm_gengrid_selected_items_get(widget);
1177         EINA_LIST_FOREACH(list, l, it)
1178           {
1179              elm_gengrid_item_selected_set(it, EINA_FALSE);
1180           }
1181      }
1182    else
1183      {
1184         it = elm_gengrid_selected_item_get(widget);
1185         elm_gengrid_item_selected_set(it, EINA_FALSE);
1186      }
1187
1188    return TRUE;
1189 }
1190
1191
1192 /**
1193  * @brief Gets a reference to the accessible object representing the specified
1194  * selected child of the object
1195  *
1196  * Note: callers should not rely on NULL
1197  * or on a zero value for indication of whether AtkSelectionIface is
1198  * implemented, they should use type checking/interface checking macros
1199  * or the atk_get_accessible_value() convenience method.
1200  *
1201  * Implementation of ref_selection from AtkSelection interface.
1202  *
1203  * @param selection AtkSelection instance
1204  * @param i index of selected child
1205  *
1206  * @returns AtkObject representing the selected object
1207  */
1208 static AtkObject *
1209 eail_gengrid_selection_ref(AtkSelection *selection, gint i)
1210 {
1211    Evas_Object *widget;
1212    Elm_Object_Item *it;
1213    const Eina_List *list;
1214    Eina_Bool multiselect;
1215    AtkObject *child;
1216
1217    g_return_val_if_fail(EAIL_IS_GENGRID(selection), NULL);
1218    widget = eail_widget_get_widget(EAIL_WIDGET(selection));
1219    multiselect = elm_gengrid_multi_select_get(widget);
1220
1221    if ((!multiselect) && (i != 0)) return FALSE;
1222
1223    if (multiselect)
1224      {
1225         list = elm_gengrid_selected_items_get(widget);
1226         if (i > eina_list_count(list)) return NULL;
1227         it = eina_list_nth(list, i);
1228      }
1229    else
1230      {
1231         it = elm_gengrid_selected_item_get(widget);
1232      }
1233
1234    if (!it) return NULL;
1235
1236    child = eail_factory_get_item_atk_obj
1237                               (it, ATK_ROLE_LIST_ITEM, ATK_OBJECT(selection));
1238
1239    g_object_ref(child);
1240
1241    return child;
1242 }
1243
1244 /**
1245  * @brief Gets the number of accessible children currently selected.
1246  *
1247  * Note: callers should not rely on NULL or on a zero value
1248  * for indication of whether AtkSelectionIface is implemented,
1249  * they should use type checking/interface checking macros or
1250  * the atk_get_accessible_value() convenience method.
1251  *
1252  * Implementation of get_selection_count from AtkSelection interface.
1253  *
1254  * @param selection AtkSelection instance
1255  *
1256  * @returns integer representing the number of selected items
1257  */
1258 static gint
1259 eail_gengrid_selection_count_get(AtkSelection *selection)
1260 {
1261    Evas_Object *widget;
1262    Elm_Object_Item *it;
1263    const Eina_List *list;
1264    int n_selections;
1265
1266    g_return_val_if_fail(EAIL_IS_GENGRID(selection), -1);
1267    widget = eail_widget_get_widget(EAIL_WIDGET(selection));
1268    if (!elm_gengrid_multi_select_get(widget))
1269      {
1270         it = elm_gengrid_selected_item_get(widget);
1271         n_selections = (it ? 1 : 0);
1272      }
1273    else
1274      {
1275         list = elm_gengrid_selected_items_get(widget);
1276         n_selections = eina_list_count(list);
1277      }
1278
1279    return n_selections;
1280 }
1281
1282 /**
1283  * @brief Determines if the current child of this object is selected.
1284  *
1285  * Note: callers should not rely on NULL or on a zero value for
1286  * indication of whether AtkSelectionIface is implemented, they
1287  * should use type checking/interface checking macros or
1288  * the atk_get_accessible_value() convenience method.
1289  *
1290  * Implementation of is_child_selected from AtkSelection interface.
1291  *
1292  * @param selection AtkSelection instance
1293  * @param i index of child
1294  *
1295  * @returns TRUE on selection, FALSE otherwise
1296  */
1297 static gboolean
1298 eail_gengrid_selection_is_child_selected(AtkSelection *selection, int i)
1299 {
1300    Evas_Object *widget;
1301    Elm_Object_Item *it;
1302    Eina_List *list;
1303    gboolean selected;
1304
1305    g_return_val_if_fail(EAIL_IS_GENGRID(selection), FALSE);
1306    widget = eail_widget_get_widget(EAIL_WIDGET(selection));
1307    list = elm_gengrid_realized_items_get(widget);
1308
1309    if (i > eina_list_count(list))
1310      {
1311         eina_list_free(list);
1312         return FALSE;
1313      }
1314
1315    it = eina_list_nth(list, i);
1316    selected = (elm_gengrid_item_selected_get(it) ? TRUE : FALSE);
1317    eina_list_free(list);
1318
1319    return selected;
1320 }
1321
1322 /**
1323  * @brief Removes the specified child of the object from the object's selection
1324  *
1325  * Implementation of remove_selection from AtkSelection.
1326  *
1327  * @param selection AtkSelection instance
1328  * @param i index of selected child
1329  *
1330  * @returns TRUE on success, FALSE otherwise
1331  */
1332 static gboolean
1333 eail_gengrid_selection_remove(AtkSelection *selection, gint i)
1334 {
1335    Evas_Object *widget;
1336    Elm_Object_Item *it;
1337    const Eina_List *list;
1338    Eina_Bool multiselect;
1339
1340    g_return_val_if_fail(EAIL_IS_GENGRID(selection), FALSE);
1341    widget = eail_widget_get_widget(EAIL_WIDGET(selection));
1342    multiselect = elm_gengrid_multi_select_get(widget);
1343    if ((!multiselect) && (i != 0)) return FALSE;
1344
1345    if (!multiselect)
1346      {
1347         it = elm_gengrid_selected_item_get(widget);
1348         elm_gengrid_item_selected_set(it, FALSE);
1349      }
1350    else
1351      {
1352         list = elm_gengrid_selected_items_get(widget);
1353         if (i > eina_list_count(list)) return FALSE;
1354
1355         it = eina_list_nth(list, i);
1356         elm_gengrid_item_selected_set(it, EINA_FALSE);
1357     }
1358
1359    return TRUE;
1360 }
1361
1362 /**
1363  * @brief Causes every child of the object to be selected if the object supports multiple selections
1364  *
1365  * Implementation of select_all from AtkSelection interface.
1366  *
1367  * @param selection AtkSelection instance
1368  *
1369  * @return TRUE on success, FALSE otherwise
1370  */
1371 static gboolean
1372 eail_gengrid_selection_select_all(AtkSelection *selection)
1373 {
1374    Evas_Object *widget;
1375    Elm_Object_Item *it;
1376    Eina_List *l, *list;
1377
1378    g_return_val_if_fail(EAIL_IS_GENGRID(selection), FALSE);
1379    widget = eail_widget_get_widget(EAIL_WIDGET(selection));
1380    if (!elm_gengrid_multi_select_get(widget)) return FALSE;
1381
1382    list = elm_gengrid_realized_items_get(widget);
1383    EINA_LIST_FOREACH(list, l, it)
1384      {
1385         elm_gengrid_item_selected_set(it, EINA_TRUE);
1386      }
1387    return TRUE;
1388 }
1389
1390 /**
1391  * @brief AtkSelection interface initialization
1392  *
1393  * @param iface AtkSelectionIface instance
1394  */
1395 static void
1396 atk_selection_interface_init(AtkSelectionIface *iface)
1397 {
1398    g_return_if_fail(iface != NULL);
1399
1400    iface->add_selection = eail_gengrid_selection_add;
1401    iface->clear_selection = eail_gengrid_selection_clear;
1402    iface->ref_selection = eail_gengrid_selection_ref;
1403    iface->get_selection_count = eail_gengrid_selection_count_get;
1404    iface->is_child_selected = eail_gengrid_selection_is_child_selected;
1405    iface->remove_selection = eail_gengrid_selection_remove;
1406    iface->select_all_selection = eail_gengrid_selection_select_all;
1407 }