evolution-3.6.4/widgets/table/gal-a11y-e-cell.c

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 }