Function description fixes
[platform/core/uifw/eail.git] / eail / eail / eail_multibuttonentry.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_multibuttonentry.c
22  * @brief EailMultibuttonentry implementation
23  */
24
25 #include <Elementary.h>
26
27 #include "eail_multibuttonentry.h"
28 #include "eail_factory.h"
29 #include "eail_item_parent.h"
30 #include "eail_priv.h"
31 #include "eail_utils.h"
32 #include "eail_clipboard.h"
33
34 static void eail_item_parent_interface_init(EailItemParentIface *iface);
35 static void atk_editable_text_interface_init(AtkEditableTextIface *iface);
36 static void atk_text_interface_init(AtkTextIface *iface);
37
38 /**
39  * @brief EailMultibuttonentry type definition
40  */
41 G_DEFINE_TYPE_WITH_CODE(EailMultibuttonentry,
42                         eail_multibuttonentry,
43                         EAIL_TYPE_ACTION_WIDGET,
44                         G_IMPLEMENT_INTERFACE(ATK_TYPE_TEXT,
45                                               atk_text_interface_init)
46                         G_IMPLEMENT_INTERFACE(ATK_TYPE_EDITABLE_TEXT,
47                                               atk_editable_text_interface_init)
48                         G_IMPLEMENT_INTERFACE(EAIL_TYPE_ITEM_PARENT,
49                                               eail_item_parent_interface_init));
50
51 /**
52  * @brief Checks if content get is supported
53  *
54  * Implementation of EailItemParent->is_content_get_supported callback.
55  *
56  * @param parent EailItemParent instance
57  * @param item EailItem instance
58  * @returns always FALSE
59  */
60 gboolean
61 eail_multibuttonentry_content_get_support(EailItemParent   *parent,
62                                           EailItem         *item)
63 {
64    return FALSE;
65 }
66
67 /**
68  * @brief Gets the name of a multibuttonentry's child
69  *
70  * Implementation of get_item_name callback of EailItemParent interface.
71  *
72  * @param parent EailItemParent instance representing a multibuttonentry
73  * @param item Multibuttonentry EailItem instance representing a child
74  *
75  * @returns string representing the name of the child
76  */
77 static const gchar *
78 eail_multibuttonentry_item_name_get(EailItemParent *parent, EailItem *item)
79 {
80    Elm_Object_Item *it = eail_item_get_item(item);
81    /*that will work only for default theme*/
82    if (!it) return NULL;
83
84    return elm_object_item_part_text_get(it, NULL);
85 }
86
87 /**
88  * @brief EailItemParent interface initializer
89  *
90  * Initialization of callbacks used by EailItemParent interface.
91  *
92  * @param iface EailItemParentIface instance
93  */
94 static void
95 eail_item_parent_interface_init(EailItemParentIface *iface)
96 {
97    iface->is_content_get_supported = eail_multibuttonentry_content_get_support;
98    iface->get_item_name = eail_multibuttonentry_item_name_get;
99 }
100
101 /**
102  * @brief Helper function for getting multibuttonentry text
103  *
104  * @param text an AtkText (EailMultibutton object)
105  *
106  * @return string representation of multibutton entry text
107  */
108 static const gchar*
109 _eail_multibuttonentry_get_entry_string(AtkText *text)
110 {
111    const gchar *string = NULL;
112    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(text));
113    Evas_Object *entry = elm_multibuttonentry_entry_get(widget);
114
115    if (entry)
116      string = elm_entry_entry_get(entry);
117
118    /* if entry string is empty then trying to return "guide" part*/
119    if (!string || 0 == g_strcmp0(string, ""))
120      {
121         /* If there are some children of widget, then it means that guide
122          * is not visible. So returning guide as text only if no children
123          * exist */
124         if (!elm_multibuttonentry_items_get(widget))
125           string = elm_object_part_text_get(widget, "guide");
126      }
127
128    return string;
129 }
130
131 /**
132  * @brief Gets text bounded by start_offset and end_offset
133  *
134  * Use g_free() to free the returned string.
135  *
136  * @param text AtkText instance
137  * @param start_offset start position
138  * @param end_offset end position or -1 for the end of the string
139  * @return string containing text from start_offset up to, but not including
140  * end_offset
141  */
142 static gchar*
143 eail_multibuttonentry_get_text(AtkText   *text,
144                    gint       start_offset,
145                    gint       end_offset)
146 {
147    const gchar *string = NULL;
148
149    string = _eail_multibuttonentry_get_entry_string(text);
150
151    return eail_get_substring(string, start_offset, end_offset);
152 }
153
154 /**
155  * @brief Gets the character at offset
156  *
157  * @param text AtkText instance
158  * @param offset offset to obtain the character from
159  * @return char representing the character at given offset
160  */
161 static gunichar
162 eail_multibuttonentry_get_character_at_offset(AtkText    *text,
163                                               gint        offset)
164 {
165    gunichar character = '\0';
166
167    character = g_utf8_get_char(
168          g_utf8_offset_to_pointer
169                      (_eail_multibuttonentry_get_entry_string(text), offset));
170
171    return character;
172 }
173
174 /**
175  * @brief Gets the length of text
176  *
177  * @param text AtkText instance
178  * @return integer representing text's length
179  */
180 static gint
181 eail_multibuttonentry_get_character_count(AtkText *text)
182 {
183    gint count = 0;
184    const gchar *string_text = NULL;
185
186    string_text = _eail_multibuttonentry_get_entry_string(text);
187    if (!string_text) return count;
188
189    count = g_utf8_strlen(string_text, -1);
190
191    return count;
192 }
193
194 /**
195  * @brief AktText initialization function
196  *
197  * @param iface AtkTextIface instance
198  */
199 static void
200 atk_text_interface_init(AtkTextIface *iface)
201 {
202    iface->get_text = eail_multibuttonentry_get_text;
203    iface->get_character_at_offset = eail_multibuttonentry_get_character_at_offset;
204    iface->get_character_count = eail_multibuttonentry_get_character_count;
205 }
206
207 /**
208  * @brief Sets text contents of text
209  *
210  * @param text AtkEditableText instance
211  * @param string new text to be set
212  */
213 static void
214 eail_multibuttonentry_set_text_contents(AtkEditableText *text,
215                                         const gchar *string)
216 {
217    Evas_Object *entry;
218    Evas_Object *widget;
219
220    widget = eail_widget_get_widget(EAIL_WIDGET(text));
221    if (!widget) return;
222
223    entry = elm_multibuttonentry_entry_get(widget);
224    if (!entry) return;
225
226    if (elm_multibuttonentry_editable_get(widget))
227      elm_entry_entry_set(entry, string);
228 }
229
230 /**
231  * @brief Copies text content from entry to clipboard
232  *
233  * @param text AtkEditableText instance
234  * @param start_pos index of copied text's first character
235  * @param end_pos index of last copied text's last character
236  */
237 static void
238 eail_multibuttonentry_copy_text(AtkEditableText *text,
239                      gint             start_pos,
240                      gint             end_pos)
241 {
242    Evas_Object *widget;
243    Evas_Object *entry;
244    const char *entry_text;
245    char *tmp;
246
247
248    widget = eail_widget_get_widget(EAIL_WIDGET(text));
249    if (!widget) return;
250
251    entry = elm_multibuttonentry_entry_get(widget);
252    entry_text = elm_entry_entry_get(entry);
253    tmp = eail_get_substring(entry_text, start_pos, end_pos);
254    eail_clipboard_set_text(tmp);
255    g_free(tmp);
256 }
257
258 /**
259  * @brief Cuts text content from entry to clipboard
260  *
261  * @param text AtkEditableText instance
262  * @param start_pos index of cut text's first character
263  * @param end_pos index of cut text's last character
264  */
265 static void
266 eail_multibuttonentry_cut_text(AtkEditableText *text,
267                     gint             start_pos,
268                     gint             end_pos)
269 {
270    Evas_Object *widget;
271    Evas_Object *entry;
272    const char *entry_text;
273    char *tmp;
274    GString *s;
275
276
277    widget = eail_widget_get_widget(EAIL_WIDGET(text));
278    if (!widget || !elm_multibuttonentry_editable_get(widget)) return;
279
280    entry = elm_multibuttonentry_entry_get(widget);
281    entry_text = elm_entry_entry_get(entry);
282    tmp = eail_get_substring(entry_text, start_pos, end_pos);
283    eail_clipboard_set_text(tmp);
284    g_free(tmp);
285
286    s = g_string_new(entry_text);
287    s = g_string_erase(s, start_pos, end_pos - start_pos);
288
289    elm_entry_entry_set(entry, s->str);
290    g_string_free(s, TRUE);
291 }
292
293 /**
294  * @brief Pastes text content from clipboard into entry
295  *
296  * @param text AtkEditableText instance
297  * @param position index of pasted text's first character
298  */
299 static void
300 eail_multibuttonentry_paste_text(AtkEditableText *text,
301                                  gint position)
302 {
303    Evas_Object *widget;
304    Evas_Object *entry = NULL;
305    GString *s;
306    const char *tmp;
307
308    widget = eail_widget_get_widget(EAIL_WIDGET(text));
309    if (!widget || !elm_multibuttonentry_editable_get(entry))
310      return;
311
312    entry = elm_multibuttonentry_entry_get(widget);
313    s = g_string_new(elm_entry_entry_get(entry));
314    tmp = eail_clipboard_get_text();
315    s = g_string_insert(s, position, tmp);
316    elm_entry_entry_set(entry, s->str);
317    g_string_free(s, TRUE);
318 }
319
320 /**
321  * @brief Deletes text between start_pos and end_pos but not
322  * including end_pos
323  *
324  * @param text AtkEditableText instance
325  * @param start_pos start position
326  * @param end_pos end position
327  */
328 static void
329 eail_multibuttonentry_delete_text(AtkEditableText *text,
330                        gint start_pos,
331                        gint end_pos)
332 {
333    Evas_Object *widget;
334    Evas_Object *entry;
335    GString *s;
336
337    widget = eail_widget_get_widget(EAIL_WIDGET(text));
338    if (!widget || !elm_multibuttonentry_editable_get(widget)) return;
339
340    entry = elm_multibuttonentry_entry_get(widget);
341    s = g_string_new(elm_entry_entry_get(entry));
342    s = g_string_erase(s, start_pos, end_pos-start_pos);
343    elm_entry_entry_set(entry, s->str);
344    g_string_free(s, TRUE);
345 }
346
347 /**
348  * @brief Inserts text at the given position
349  *
350  * After the call it points at the position after the newly inserted text.
351  *
352  * @param text AtkEditableText instance
353  * @param string string to insert
354  * @param length string length
355  * @param [out] position position to insert the text
356  *
357  */
358 static void
359 eail_multibuttonentry_insert_text(AtkEditableText *text,
360                        const gchar *string,
361                        gint length,
362                        gint *position)
363 {
364    Evas_Object *widget;
365    Evas_Object *entry;
366    GString *s;
367
368    widget = eail_widget_get_widget(EAIL_WIDGET(text));
369    if (!widget || !elm_multibuttonentry_editable_get(widget))
370      return;
371
372    entry = elm_multibuttonentry_entry_get(widget);
373    s = g_string_new(elm_entry_entry_get(entry));
374    s = g_string_insert_len(s, *position, string, length);
375    elm_entry_entry_set(entry, s->str);
376    g_string_free(s, TRUE);
377    *position += length;
378 }
379
380 /**
381  * @brief Initialization for AtkEditableTextIface interface
382  *
383  * Function called upon instance creation.
384  *
385  * It initializes AtkText interface
386  * implementation i.e hooks method pointers in the interface structure
387  * to the implementing class's implementation.
388  *
389  * @param iface AtkEditableTextIface instance
390  */
391 static void
392 atk_editable_text_interface_init(AtkEditableTextIface *iface)
393 {
394    iface->set_text_contents = eail_multibuttonentry_set_text_contents;
395    iface->copy_text = eail_multibuttonentry_copy_text;
396    iface->cut_text = eail_multibuttonentry_cut_text;
397    iface->paste_text = eail_multibuttonentry_paste_text;
398    iface->delete_text = eail_multibuttonentry_delete_text;
399    iface->insert_text = eail_multibuttonentry_insert_text;
400 }
401
402 /**
403  * @brief 'expand' action callback
404  *
405  * @param action AtkAction instance
406  * @param data user data passed to callback
407  *
408  * @returns TRUE on action success, FALSE otherwise
409  */
410 static gboolean
411 eail_multibuttonentry_action_expand_cb(AtkAction *action, void *data)
412 {
413    Evas_Object *widget;
414
415    widget = eail_widget_get_widget(EAIL_WIDGET(action));
416    if (!widget) return FALSE;
417
418    if ((elm_object_disabled_get(widget)) || (!evas_object_visible_get(widget)))
419      return FALSE;
420
421    if (elm_multibuttonentry_expanded_get(widget)) return FALSE;
422
423    elm_multibuttonentry_expanded_set(widget, EINA_TRUE);
424    atk_object_notify_state_change(ATK_OBJECT(action), ATK_STATE_EXPANDED, TRUE);
425
426    return TRUE;
427 }
428
429 /**
430  * @brief 'shrink' action callback
431  *
432  * @param action AtkAction instance
433  * @param data user data passed to callback
434  *
435  * @returns TRUE on action success, FALSE otherwise
436  */
437 static gboolean
438 eail_multibuttonentry_action_shrink_cb(AtkAction *action, void *data)
439 {
440    Evas_Object *widget;
441
442    widget = eail_widget_get_widget(EAIL_WIDGET(action));
443    if (!widget) return FALSE;
444
445    if ((elm_object_disabled_get(widget)) || (!evas_object_visible_get(widget)))
446      return FALSE;
447
448    if (!elm_multibuttonentry_expanded_get(widget)) return FALSE;
449
450    elm_multibuttonentry_expanded_set(widget, EINA_FALSE);
451    atk_object_notify_state_change(ATK_OBJECT(action), ATK_STATE_EXPANDED, FALSE);
452
453    return TRUE;
454 }
455
456 /**
457  * @brief Registers multibuttonentry's actions
458  *
459  * @param action_widget EailActionWidget instance
460  */
461 static void eail_multibuttonentry_actions_init(EailActionWidget *action_widget)
462 {
463    eail_action_widget_action_append(action_widget, "expand", NULL,
464                                     eail_multibuttonentry_action_expand_cb);
465    eail_action_widget_action_append(action_widget, "shrink", NULL,
466                                     eail_multibuttonentry_action_shrink_cb);
467 }
468
469 /**
470  * @brief Handler for "item,added" event, used to notify about multibuttonentry
471  * content changes
472  *
473  * @param data passed to callback
474  * @param obj object that raised event
475  * @param event_info additional event info (item is passed here)
476  */
477 static void
478 eail_multibuttonentry_item_handle_added_event(void *data,
479                                               Evas_Object *obj,
480                                               void *event_info)
481 {
482    Elm_Object_Item *item = (Elm_Object_Item *) event_info;
483    AtkObject *atk_item = NULL, *atk_parent = NULL;
484
485    atk_parent = ATK_OBJECT(data);
486    if (!atk_parent) return;
487
488    atk_item = eail_factory_get_item_atk_obj
489                                          (item, ATK_ROLE_LABEL, atk_parent);
490
491    if (!atk_item) return;
492
493    eail_emit_children_changed_obj(TRUE, atk_parent, atk_item);
494 }
495
496 /**
497  * @brief Handler for "item,deleted" event, used to notify about
498  * multibuttonentry content changes
499  *
500  * @param data passed to callback
501  * @param obj object that raised event
502  * @param event_info additional event info (item is passed here)
503  */
504 static void
505 eail_multibuttonentry_item_handle_removed_event(void *data,
506                                                 Evas_Object *obj,
507                                                 void *event_info)
508 {
509    Elm_Object_Item *item = (Elm_Object_Item *) event_info;
510    AtkObject *atk_item = NULL, *atk_parent = NULL;
511
512    atk_parent = ATK_OBJECT(data);
513    if (!atk_parent) return;
514
515    atk_item = eail_factory_get_item_atk_obj
516                                          (item, ATK_ROLE_LABEL, atk_parent);
517
518    if (!atk_item) return;
519
520    eail_emit_children_changed_obj(FALSE, atk_parent, atk_item);
521    atk_object_notify_state_change(atk_item, ATK_STATE_DEFUNCT, TRUE);
522
523    DBG("Unregistering item from cache...");
524    eail_factory_unregister_item_from_cache(item);
525 }
526
527 /**
528  * @brief EailMultibuttonentry type initializer
529  * @param obj AtkObject instance
530  * @param data initialization data
531  */
532 void
533 eail_multibuttonentry_initialize(AtkObject *obj, gpointer data)
534 {
535    Evas_Object *nested_widget = NULL;
536    ATK_OBJECT_CLASS(eail_multibuttonentry_parent_class)->initialize(obj, data);
537    obj->role = ATK_ROLE_ENTRY;
538
539    eail_multibuttonentry_actions_init(EAIL_ACTION_WIDGET(obj));
540
541    nested_widget = eail_widget_get_widget(EAIL_WIDGET(obj));
542    if (!nested_widget)
543      {
544         ERR("No evas object inside EailWidget was found");
545         return;
546      }
547
548    evas_object_smart_callback_add(nested_widget, "item,added",
549                           eail_multibuttonentry_item_handle_added_event, obj);
550    evas_object_smart_callback_add(nested_widget, "item,deleted",
551                           eail_multibuttonentry_item_handle_removed_event, obj);
552 }
553
554 /**
555  * @brief EailMultibuttonentry instance initializer
556  *
557  * @param multibuttonentry EailMultibuttonentry instance
558  */
559 static void
560 eail_multibuttonentry_init(EailMultibuttonentry *multibuttonentry)
561 {
562 }
563
564 /**
565  * @brief Gets obj's state set
566  *
567  * The caller must unreference it when it is no longer needed.
568  *
569  * @param obj AtkObject instance
570  * @return AtkStateSet containing object's state set
571  */
572 static AtkStateSet *
573 eail_multibuttonentry_ref_state_set(AtkObject *obj)
574 {
575    AtkStateSet *state_set;
576    Evas_Object *widget;
577
578    g_return_val_if_fail(EAIL_MULTIBUTTONENTRY(obj), NULL);
579
580    widget = eail_widget_get_widget(EAIL_WIDGET(obj));
581    state_set = ATK_OBJECT_CLASS(eail_multibuttonentry_parent_class)->ref_state_set(obj);
582
583    if (!widget) return state_set;
584
585    if (elm_multibuttonentry_expanded_get(widget))
586      {
587         atk_state_set_add_state(state_set, ATK_STATE_EXPANDED);
588
589         if (elm_multibuttonentry_editable_get(widget))
590             atk_state_set_add_state(state_set, ATK_STATE_EDITABLE);
591      }
592    else
593      {
594         atk_state_set_add_state(state_set, ATK_STATE_DEFAULT);
595      }
596
597    return state_set;
598 }
599
600 /**
601  * @brief Gets the list of multibuttonentry's items
602  *
603  * @param multibuttonentry EailMultibuttonentry instance
604  * @return Eina_List containing multibuttonentry's items
605  * */
606 static const Eina_List *
607 eail_multibuttonentry_get_items(EailMultibuttonentry *multibuttonentry)
608 {
609    Evas_Object *widget = eail_widget_get_widget(EAIL_WIDGET(multibuttonentry));
610    if (!widget) return NULL;
611
612    return elm_multibuttonentry_items_get(widget);
613 }
614
615 /**
616  * @brief Gets the number of accessible children of the accessible
617  *
618  * @param obj AtkObject instance
619  * @return integer representing the number of accessible children of the accessible
620  */
621 static gint
622 eail_multibuttonentry_get_n_children(AtkObject *obj)
623 {
624    gint n_items;
625    const Eina_List *items;
626
627    items = eail_multibuttonentry_get_items(EAIL_MULTIBUTTONENTRY(obj));
628    n_items = eina_list_count(items);
629
630    return n_items;
631 }
632
633 /**
634  * @brief Gets a reference to the specified child of obj
635  *
636  * The caller must unreference it when it is no longer needed.
637  *
638  * @param obj AtkObject instance
639  * @param i child index
640  * @return AtkObject containing reference to the specified child of obj
641  */
642 static AtkObject *
643 eail_multibuttonentry_ref_child(AtkObject *obj, gint i)
644 {
645    const Eina_List *items;
646    AtkObject *child = NULL;
647
648    items = eail_multibuttonentry_get_items(EAIL_MULTIBUTTONENTRY(obj));
649    if (eina_list_count(items) > i)
650      {
651         child = eail_factory_get_item_atk_obj
652             (eina_list_nth(items, i), ATK_ROLE_LABEL, obj);
653
654         g_object_ref(child);
655      }
656    else
657      ERR("Tried to ref child with index %d out of bounds!", i);
658
659    return child;
660 }
661
662 /**
663  * @brief EailMultibuttonentry class initializer
664  *
665  * @param klass EailMultibuttonentryClass instance
666  */
667 static void
668 eail_multibuttonentry_class_init(EailMultibuttonentryClass *klass)
669 {
670    AtkObjectClass *class = ATK_OBJECT_CLASS(klass);
671
672    class->initialize = eail_multibuttonentry_initialize;
673    class->get_n_children = eail_multibuttonentry_get_n_children;
674    class->ref_child = eail_multibuttonentry_ref_child;
675    class->ref_state_set = eail_multibuttonentry_ref_state_set;
676 }