No issues found
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) version 3.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with the program; if not, see <http://www.gnu.org/licenses/>
14 *
15 *
16 * Authors:
17 * Christopher James Lahey <clahey@ximian.com>
18 *
19 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
20 *
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <string.h>
28
29 #include <gtk/gtk.h>
30
31 #include "a11y/gal-a11y-util.h"
32 #include "table/e-table.h"
33 #include "table/e-tree.h"
34 #include <glib/gi18n.h>
35
36 #include "gal-a11y-e-cell.h"
37 #include "gal-a11y-e-cell-vbox.h"
38 #include "gal-a11y-e-table-item.h"
39
40 static GObjectClass *parent_class;
41 #define PARENT_TYPE (atk_object_get_type ())
42
43 #if 0
44 static void
45 unref_item (gpointer user_data,
46 GObject *obj_loc)
47 {
48 GalA11yECell *a11y = GAL_A11Y_E_CELL (user_data);
49 a11y->item = NULL;
50 g_object_unref (a11y);
51 }
52
53 static void
54 unref_cell (gpointer user_data,
55 GObject *obj_loc)
56 {
57 GalA11yECell *a11y = GAL_A11Y_E_CELL (user_data);
58 a11y->cell_view = NULL;
59 g_object_unref (a11y);
60 }
61 #endif
62
63 static gboolean
64 is_valid (AtkObject *cell)
65 {
66 GalA11yECell *a11y = GAL_A11Y_E_CELL (cell);
67 GalA11yETableItem *a11yItem = GAL_A11Y_E_TABLE_ITEM (a11y->parent);
68 AtkStateSet *item_ss;
69 gboolean ret = TRUE;
70
71 item_ss = atk_object_ref_state_set (ATK_OBJECT (a11yItem));
72 if (atk_state_set_contains_state (item_ss, ATK_STATE_DEFUNCT))
73 ret = FALSE;
74
75 g_object_unref (item_ss);
76
77 if (ret && atk_state_set_contains_state (a11y->state_set, ATK_STATE_DEFUNCT))
78 ret = FALSE;
79
80 return ret;
81 }
82
83 static void
84 gal_a11y_e_cell_dispose (GObject *object)
85 {
86 GalA11yECell *a11y = GAL_A11Y_E_CELL (object);
87
88 #if 0
89 if (a11y->item)
90 g_object_unref (a11y->item); /*, unref_item, a11y); */
91 if (a11y->cell_view)
92 g_object_unref (a11y->cell_view); /*, unref_cell, a11y); */
93 if (a11y->parent)
94 g_object_unref (a11y->parent);
95 #endif
96
97 if (a11y->state_set) {
98 g_object_unref (a11y->state_set);
99 a11y->state_set = NULL;
100 }
101
102 if (parent_class->dispose)
103 parent_class->dispose (object);
104
105 }
106
107 /* Static functions */
108 static const gchar *
109 gal_a11y_e_cell_get_name (AtkObject *a11y)
110 {
111 GalA11yECell *cell = GAL_A11Y_E_CELL (a11y);
112 ETableCol *ecol;
113
114 if (a11y->name != NULL && strcmp (a11y->name, ""))
115 return a11y->name;
116
117 if (cell->item != NULL) {
118 ecol = e_table_header_get_column (cell->item->header, cell->view_col);
119 if (ecol != NULL)
120 return ecol->text;
121 }
122
123 return _("Table Cell");
124 }
125
126 static AtkStateSet *
127 gal_a11y_e_cell_ref_state_set (AtkObject *accessible)
128 {
129 GalA11yECell *cell = GAL_A11Y_E_CELL (accessible);
130
131 g_return_val_if_fail (cell->state_set, NULL);
132
133 g_object_ref (cell->state_set);
134
135 return cell->state_set;
136 }
137
138 static AtkObject *
139 gal_a11y_e_cell_get_parent (AtkObject *accessible)
140 {
141 GalA11yECell *a11y = GAL_A11Y_E_CELL (accessible);
142 return a11y->parent;
143 }
144
145 static gint
146 gal_a11y_e_cell_get_index_in_parent (AtkObject *accessible)
147 {
148 GalA11yECell *a11y = GAL_A11Y_E_CELL (accessible);
149
150 if (!is_valid (accessible))
151 return -1;
152
153 return (a11y->row + 1) * a11y->item->cols + a11y->view_col;
154 }
155
156 /* Component IFace */
157 static void
158 gal_a11y_e_cell_get_extents (AtkComponent *component,
159 gint *x,
160 gint *y,
161 gint *width,
162 gint *height,
163 AtkCoordType coord_type)
164 {
165 GalA11yECell *a11y = GAL_A11Y_E_CELL (component);
166 GtkWidget *tableOrTree;
167 gint row;
168 gint col;
169 gint xval;
170 gint yval;
171
172 row = a11y->row;
173 col = a11y->view_col;
174
175 tableOrTree = gtk_widget_get_parent (GTK_WIDGET (a11y->item->parent.canvas));
176 if (E_IS_TREE (tableOrTree)) {
177 e_tree_get_cell_geometry (
178 E_TREE (tableOrTree),
179 row, col, &xval, &yval,
180 width, height);
181 } else {
182 e_table_get_cell_geometry (
183 E_TABLE (tableOrTree),
184 row, col, &xval, &yval,
185 width, height);
186 }
187
188 atk_component_get_position (
189 ATK_COMPONENT (a11y->parent),
190 x, y, coord_type);
191 if (x && *x != G_MININT)
192 *x += xval;
193 if (y && *y != G_MININT)
194 *y += yval;
195 }
196
197 static gboolean
198 gal_a11y_e_cell_grab_focus (AtkComponent *component)
199 {
200 GalA11yECell *a11y;
201 gint index;
202 GtkWidget *toplevel;
203 GalA11yETableItem *a11yTableItem;
204
205 a11y = GAL_A11Y_E_CELL (component);
206
207 /* for e_cell_vbox's children, we just grab the e_cell_vbox */
208 if (GAL_A11Y_IS_E_CELL_VBOX (a11y->parent)) {
209 return atk_component_grab_focus (ATK_COMPONENT (a11y->parent));
210 }
211
212 a11yTableItem = GAL_A11Y_E_TABLE_ITEM (a11y->parent);
213 index = atk_object_get_index_in_parent (ATK_OBJECT (a11y));
214
215 atk_selection_clear_selection (ATK_SELECTION (a11yTableItem));
216 atk_selection_add_selection (ATK_SELECTION (a11yTableItem), index);
217
218 gtk_widget_grab_focus (
219 GTK_WIDGET (GNOME_CANVAS_ITEM (a11y->item)->canvas));
220 toplevel = gtk_widget_get_toplevel (
221 GTK_WIDGET (GNOME_CANVAS_ITEM (a11y->item)->canvas));
222 if (toplevel && gtk_widget_is_toplevel (toplevel))
223 gtk_window_present (GTK_WINDOW (toplevel));
224
225 return TRUE;
226 }
227
228 /* Table IFace */
229
230 static void
231 gal_a11y_e_cell_atk_component_iface_init (AtkComponentIface *iface)
232 {
233 iface->get_extents = gal_a11y_e_cell_get_extents;
234 iface->grab_focus = gal_a11y_e_cell_grab_focus;
235 }
236
237 static void
238 gal_a11y_e_cell_class_init (GalA11yECellClass *class)
239 {
240 AtkObjectClass *atk_object_class = ATK_OBJECT_CLASS (class);
241 GObjectClass *object_class = G_OBJECT_CLASS (class);
242
243 parent_class = g_type_class_ref (PARENT_TYPE);
244
245 object_class->dispose = gal_a11y_e_cell_dispose;
246
247 atk_object_class->get_parent = gal_a11y_e_cell_get_parent;
248 atk_object_class->get_index_in_parent = gal_a11y_e_cell_get_index_in_parent;
249 atk_object_class->ref_state_set = gal_a11y_e_cell_ref_state_set;
250 atk_object_class->get_name = gal_a11y_e_cell_get_name;
251 }
252
253 static void
254 gal_a11y_e_cell_init (GalA11yECell *a11y)
255 {
256 a11y->item = NULL;
257 a11y->cell_view = NULL;
258 a11y->parent = NULL;
259 a11y->model_col = -1;
260 a11y->view_col = -1;
261 a11y->row = -1;
262
263 a11y->state_set = atk_state_set_new ();
264 atk_state_set_add_state (a11y->state_set, ATK_STATE_TRANSIENT);
265 atk_state_set_add_state (a11y->state_set, ATK_STATE_ENABLED);
266 atk_state_set_add_state (a11y->state_set, ATK_STATE_SENSITIVE);
267 atk_state_set_add_state (a11y->state_set, ATK_STATE_SELECTABLE);
268 atk_state_set_add_state (a11y->state_set, ATK_STATE_SHOWING);
269 atk_state_set_add_state (a11y->state_set, ATK_STATE_FOCUSABLE);
270 atk_state_set_add_state (a11y->state_set, ATK_STATE_VISIBLE);
271 }
272
273 static ActionInfo *
274 _gal_a11y_e_cell_get_action_info (GalA11yECell *cell,
275 gint index)
276 {
277 GList *list_node;
278
279 g_return_val_if_fail (GAL_A11Y_IS_E_CELL (cell), NULL);
280 if (cell->action_list == NULL)
281 return NULL;
282 list_node = g_list_nth (cell->action_list, index);
283 if (!list_node)
284 return NULL;
285 return (ActionInfo *) (list_node->data);
286 }
287
288 static void
289 _gal_a11y_e_cell_destroy_action_info (gpointer action_info,
290 gpointer user_data)
291 {
292 ActionInfo *info = (ActionInfo *) action_info;
293
294 g_return_if_fail (info != NULL);
295 g_free (info->name);
296 g_free (info->description);
297 g_free (info->keybinding);
298 g_free (info);
299 }
300
301 gboolean
302 gal_a11y_e_cell_add_action (GalA11yECell *cell,
303 const gchar *action_name,
304 const gchar *action_description,
305 const gchar *action_keybinding,
306 ACTION_FUNC action_func)
307 {
308 ActionInfo *info;
309 g_return_val_if_fail (GAL_A11Y_IS_E_CELL (cell), FALSE);
310 info = g_new (ActionInfo, 1);
311
312 if (action_name != NULL)
313 info->name = g_strdup (action_name);
314 else
315 info->name = NULL;
316
317 if (action_description != NULL)
318 info->description = g_strdup (action_description);
319 else
320 info->description = NULL;
321 if (action_keybinding != NULL)
322 info->keybinding = g_strdup (action_keybinding);
323 else
324 info->keybinding = NULL;
325 info->do_action_func = action_func;
326
327 cell->action_list = g_list_append (cell->action_list, (gpointer) info);
328 return TRUE;
329 }
330
331 gboolean
332 gal_a11y_e_cell_remove_action (GalA11yECell *cell,
333 gint action_index)
334 {
335 GList *list_node;
336
337 g_return_val_if_fail (GAL_A11Y_IS_E_CELL (cell), FALSE);
338 list_node = g_list_nth (cell->action_list, action_index);
339 if (!list_node)
340 return FALSE;
341 g_return_val_if_fail (list_node->data != NULL, FALSE);
342 _gal_a11y_e_cell_destroy_action_info (list_node->data, NULL);
343 cell->action_list = g_list_remove_link (cell->action_list, list_node);
344
345 return TRUE;
346 }
347
348 gboolean
349 gal_a11y_e_cell_remove_action_by_name (GalA11yECell *cell,
350 const gchar *action_name)
351 {
352 GList *list_node;
353 gboolean action_found= FALSE;
354
355 g_return_val_if_fail (GAL_A11Y_IS_E_CELL (cell), FALSE);
356 for (list_node = cell->action_list; list_node && !action_found;
357 list_node = list_node->next) {
358 if (!g_ascii_strcasecmp (
359 ((ActionInfo *)(list_node->data))->name,
360 action_name)) {
361 action_found = TRUE;
362 break;
363 }
364 }
365
366 g_return_val_if_fail (action_found, FALSE);
367 _gal_a11y_e_cell_destroy_action_info (list_node->data, NULL);
368 cell->action_list = g_list_remove_link (cell->action_list, list_node);
369
370 return TRUE;
371 }
372
373 static gint
374 gal_a11y_e_cell_action_get_n_actions (AtkAction *action)
375 {
376 GalA11yECell *cell = GAL_A11Y_E_CELL (action);
377 if (cell->action_list != NULL)
378 return g_list_length (cell->action_list);
379 else
380 return 0;
381 }
382
383 static const gchar *
384 gal_a11y_e_cell_action_get_name (AtkAction *action,
385 gint index)
386 {
387 GalA11yECell *cell = GAL_A11Y_E_CELL (action);
388 ActionInfo *info = _gal_a11y_e_cell_get_action_info (cell, index);
389
390 if (info == NULL)
391 return NULL;
392 return info->name;
393 }
394
395 static const gchar *
396 gal_a11y_e_cell_action_get_description (AtkAction *action,
397 gint index)
398 {
399 GalA11yECell *cell = GAL_A11Y_E_CELL (action);
400 ActionInfo *info = _gal_a11y_e_cell_get_action_info (cell, index);
401
402 if (info == NULL)
403 return NULL;
404 return info->description;
405 }
406
407 static gboolean
408 gal_a11y_e_cell_action_set_description (AtkAction *action,
409 gint index,
410 const gchar *desc)
411 {
412 GalA11yECell *cell = GAL_A11Y_E_CELL (action);
413 ActionInfo *info = _gal_a11y_e_cell_get_action_info (cell, index);
414
415 if (info == NULL)
416 return FALSE;
417 g_free (info->description);
418 info->description = g_strdup (desc);
419 return TRUE;
420 }
421
422 static const gchar *
423 gal_a11y_e_cell_action_get_keybinding (AtkAction *action,
424 gint index)
425 {
426 GalA11yECell *cell = GAL_A11Y_E_CELL (action);
427 ActionInfo *info = _gal_a11y_e_cell_get_action_info (cell, index);
428 if (info == NULL)
429 return NULL;
430
431 return info->keybinding;
432 }
433
434 static gboolean
435 idle_do_action (gpointer data)
436 {
437 GalA11yECell *cell;
438
439 cell = GAL_A11Y_E_CELL (data);
440
441 if (!is_valid (ATK_OBJECT (cell)))
442 return FALSE;
443
444 cell->action_idle_handler = 0;
445 cell->action_func (cell);
446 g_object_unref (cell);
447
448 return FALSE;
449 }
450
451 static gboolean
452 gal_a11y_e_cell_action_do_action (AtkAction *action,
453 gint index)
454 {
455 GalA11yECell *cell = GAL_A11Y_E_CELL (action);
456 ActionInfo *info = _gal_a11y_e_cell_get_action_info (cell, index);
457
458 if (!is_valid (ATK_OBJECT (action)))
459 return FALSE;
460
461 if (info == NULL)
462 return FALSE;
463 g_return_val_if_fail (info->do_action_func, FALSE);
464 if (cell->action_idle_handler)
465 return FALSE;
466 cell->action_func = info->do_action_func;
467 g_object_ref (cell);
468 cell->action_idle_handler = g_idle_add (idle_do_action, cell);
469
470 return TRUE;
471 }
472
473 static void
474 gal_a11y_e_cell_atk_action_interface_init (AtkActionIface *iface)
475 {
476 g_return_if_fail (iface != NULL);
477
478 iface->get_n_actions = gal_a11y_e_cell_action_get_n_actions;
479 iface->do_action = gal_a11y_e_cell_action_do_action;
480 iface->get_name = gal_a11y_e_cell_action_get_name;
481 iface->get_description = gal_a11y_e_cell_action_get_description;
482 iface->set_description = gal_a11y_e_cell_action_set_description;
483 iface->get_keybinding = gal_a11y_e_cell_action_get_keybinding;
484 }
485
486 void
487 gal_a11y_e_cell_type_add_action_interface (GType type)
488 {
489 static const GInterfaceInfo atk_action_info =
490 {
491 (GInterfaceInitFunc) gal_a11y_e_cell_atk_action_interface_init,
492 (GInterfaceFinalizeFunc) NULL,
493 NULL
494 };
495
496 g_type_add_interface_static (
497 type, ATK_TYPE_ACTION,
498 &atk_action_info);
499 }
500
501 gboolean
502 gal_a11y_e_cell_add_state (GalA11yECell *cell,
503 AtkStateType state_type,
504 gboolean emit_signal)
505 {
506 if (!atk_state_set_contains_state (cell->state_set, state_type)) {
507 gboolean rc;
508
509 rc = atk_state_set_add_state (cell->state_set, state_type);
510 /*
511 * The signal should only be generated if the value changed,
512 * not when the cell is set up. So states that are set
513 * initially should pass FALSE as the emit_signal argument.
514 */
515
516 if (emit_signal) {
517 atk_object_notify_state_change (ATK_OBJECT (cell), state_type, TRUE);
518 /* If state_type is ATK_STATE_VISIBLE, additional
519 * notification */
520 if (state_type == ATK_STATE_VISIBLE)
521 g_signal_emit_by_name (cell, "visible_data_changed");
522 }
523
524 return rc;
525 }
526 else
527 return FALSE;
528 }
529
530 gboolean
531 gal_a11y_e_cell_remove_state (GalA11yECell *cell,
532 AtkStateType state_type,
533 gboolean emit_signal)
534 {
535 if (atk_state_set_contains_state (cell->state_set, state_type)) {
536 gboolean rc;
537
538 rc = atk_state_set_remove_state (cell->state_set, state_type);
539 /*
540 * The signal should only be generated if the value changed,
541 * not when the cell is set up. So states that are set
542 * initially should pass FALSE as the emit_signal argument.
543 */
544
545 if (emit_signal) {
546 atk_object_notify_state_change (ATK_OBJECT (cell), state_type, FALSE);
547 /* If state_type is ATK_STATE_VISIBLE, additional notification */
548 if (state_type == ATK_STATE_VISIBLE)
549 g_signal_emit_by_name (cell, "visible_data_changed");
550 }
551
552 return rc;
553 }
554 else
555 return FALSE;
556 }
557
558 /**
559 * gal_a11y_e_cell_get_type:
560 * @void:
561 *
562 * Registers the &GalA11yECell class if necessary, and returns the type ID
563 * associated to it.
564 *
565 * Return value: The type ID of the &GalA11yECell class.
566 **/
567 GType
568 gal_a11y_e_cell_get_type (void)
569 {
570 static GType type = 0;
571
572 if (!type) {
573 GTypeInfo info = {
574 sizeof (GalA11yECellClass),
575 (GBaseInitFunc) NULL,
576 (GBaseFinalizeFunc) NULL,
577 (GClassInitFunc) gal_a11y_e_cell_class_init,
578 (GClassFinalizeFunc) NULL,
579 NULL, /* class_data */
580 sizeof (GalA11yECell),
581 0,
582 (GInstanceInitFunc) gal_a11y_e_cell_init,
583 NULL /* value_cell */
584 };
585
586 static const GInterfaceInfo atk_component_info = {
587 (GInterfaceInitFunc) gal_a11y_e_cell_atk_component_iface_init,
588 (GInterfaceFinalizeFunc) NULL,
589 NULL
590 };
591
592 type = g_type_register_static (PARENT_TYPE, "GalA11yECell", &info, 0);
593 g_type_add_interface_static (type, ATK_TYPE_COMPONENT, &atk_component_info);
594 }
595
596 return type;
597 }
598
599 AtkObject *
600 gal_a11y_e_cell_new (ETableItem *item,
601 ECellView *cell_view,
602 AtkObject *parent,
603 gint model_col,
604 gint view_col,
605 gint row)
606 {
607 AtkObject *a11y;
608
609 a11y = g_object_new (gal_a11y_e_cell_get_type (), NULL);
610
611 gal_a11y_e_cell_construct (
612 a11y,
613 item,
614 cell_view,
615 parent,
616 model_col,
617 view_col,
618 row);
619 return a11y;
620 }
621
622 void
623 gal_a11y_e_cell_construct (AtkObject *object,
624 ETableItem *item,
625 ECellView *cell_view,
626 AtkObject *parent,
627 gint model_col,
628 gint view_col,
629 gint row)
630 {
631 GalA11yECell *a11y = GAL_A11Y_E_CELL (object);
632 a11y->item = item;
633 a11y->cell_view = cell_view;
634 a11y->parent = parent;
635 a11y->model_col = model_col;
636 a11y->view_col = view_col;
637 a11y->row = row;
638 ATK_OBJECT (a11y) ->role = ATK_ROLE_TABLE_CELL;
639
640 if (item)
641 g_object_ref (item);
642
643 #if 0
644 if (parent)
645 g_object_ref (parent);
646
647 if (cell_view)
648 g_object_ref (cell_view);
649
650 #endif
651 }