evolution-3.6.4/widgets/misc/ea-calendar-item.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  *		Bolian Yin <bolian.yin@sun.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 <stdio.h>
  28 #include <time.h>
  29 #include <string.h>
  30 #include <libgnomecanvas/gnome-canvas.h>
  31 #include <e-util/e-util.h>
  32 #include <glib/gi18n.h>
  33 
  34 #include <libedataserver/libedataserver.h>
  35 
  36 #include "ea-calendar-item.h"
  37 #include "ea-calendar-cell.h"
  38 #include "ea-cell-table.h"
  39 
  40 #define EA_CALENDAR_COLUMN_NUM E_CALENDAR_COLS_PER_MONTH
  41 
  42 /* EaCalendarItem */
  43 static void ea_calendar_item_class_init (EaCalendarItemClass *class);
  44 static void ea_calendar_item_finalize (GObject *object);
  45 
  46 static const gchar * ea_calendar_item_get_name (AtkObject *accessible);
  47 static const gchar * ea_calendar_item_get_description (AtkObject *accessible);
  48 static gint ea_calendar_item_get_n_children (AtkObject *accessible);
  49 static AtkObject *ea_calendar_item_ref_child (AtkObject *accessible, gint index);
  50 static AtkStateSet * ea_calendar_item_ref_state_set (AtkObject *accessible);
  51 
  52 /* atk table interface */
  53 static void atk_table_interface_init (AtkTableIface *iface);
  54 static gint table_interface_get_index_at (AtkTable *table,
  55 					  gint     row,
  56 					  gint     column);
  57 static gint table_interface_get_column_at_index (AtkTable *table,
  58 						 gint     index);
  59 static gint table_interface_get_row_at_index (AtkTable *table,
  60 					      gint     index);
  61 static AtkObject * table_interface_ref_at (AtkTable *table,
  62 					  gint     row,
  63 					  gint     column);
  64 static gint table_interface_get_n_rows (AtkTable *table);
  65 static gint table_interface_get_n_columns (AtkTable *table);
  66 static gint table_interface_get_column_extent_at (AtkTable      *table,
  67 						  gint          row,
  68 						  gint          column);
  69 static gint table_interface_get_row_extent_at (AtkTable      *table,
  70 					       gint          row,
  71 					       gint          column);
  72 
  73 static gboolean table_interface_is_row_selected (AtkTable *table,
  74 						 gint     row);
  75 static gboolean table_interface_is_column_selected (AtkTable *table,
  76 						    gint     row);
  77 static gboolean table_interface_is_selected (AtkTable *table,
  78 					     gint     row,
  79 					     gint     column);
  80 static gint table_interface_get_selected_rows (AtkTable *table,
  81 					       gint **rows_selected);
  82 static gint table_interface_get_selected_columns (AtkTable *table,
  83 						  gint     **columns_selected);
  84 static gboolean table_interface_add_row_selection (AtkTable *table, gint row);
  85 static gboolean table_interface_remove_row_selection (AtkTable *table,
  86 						      gint row);
  87 static gboolean table_interface_add_column_selection (AtkTable *table,
  88 						      gint column);
  89 static gboolean table_interface_remove_column_selection (AtkTable *table,
  90 							 gint column);
  91 static AtkObject * table_interface_get_row_header (AtkTable *table, gint row);
  92 static AtkObject * table_interface_get_column_header (AtkTable *table,
  93 						     gint in_col);
  94 static AtkObject * table_interface_get_caption (AtkTable *table);
  95 
  96 static const gchar *
  97 table_interface_get_column_description (AtkTable *table,
  98                                         gint in_col);
  99 
 100 static const gchar *
 101 table_interface_get_row_description (AtkTable *table,
 102                                      gint row);
 103 
 104 static AtkObject *table_interface_get_summary (AtkTable *table);
 105 
 106 /* atk selection interface */
 107 static void atk_selection_interface_init (AtkSelectionIface *iface);
 108 static gboolean selection_interface_add_selection (AtkSelection *selection,
 109                                                    gint i);
 110 static gboolean selection_interface_clear_selection (AtkSelection *selection);
 111 static AtkObject *selection_interface_ref_selection (AtkSelection *selection,
 112                                                      gint i);
 113 static gint selection_interface_get_selection_count (AtkSelection *selection);
 114 static gboolean selection_interface_is_child_selected (AtkSelection *selection,
 115                                                        gint i);
 116 
 117 /* callbacks */
 118 static void selection_preview_change_cb (ECalendarItem *calitem);
 119 static void date_range_changed_cb (ECalendarItem *calitem);
 120 
 121 /* helpers */
 122 static EaCellTable *ea_calendar_item_get_cell_data (EaCalendarItem *ea_calitem);
 123 static void ea_calendar_item_destory_cell_data (EaCalendarItem *ea_calitem);
 124 static gboolean ea_calendar_item_get_column_label (EaCalendarItem *ea_calitem,
 125                                                    gint column,
 126                                                    gchar *buffer,
 127                                                    gint buffer_size);
 128 static gboolean ea_calendar_item_get_row_label (EaCalendarItem *ea_calitem,
 129                                                 gint row,
 130                                                 gchar *buffer,
 131                                                 gint buffer_size);
 132 static gboolean e_calendar_item_get_offset_for_date (ECalendarItem *calitem,
 133                                                      gint year,
 134                                                      gint month,
 135                                                      gint day,
 136                                                      gint *offset);
 137 static void ea_calendar_set_focus_object (EaCalendarItem *ea_calitem,
 138                                           AtkObject *item_cell);
 139 
 140 #ifdef ACC_DEBUG
 141 static gint n_ea_calendar_item_created = 0;
 142 static gint n_ea_calendar_item_destroyed = 0;
 143 #endif
 144 
 145 static gpointer parent_class = NULL;
 146 
 147 GType
 148 ea_calendar_item_get_type (void)
 149 {
 150 	static GType type = 0;
 151 	AtkObjectFactory *factory;
 152 	GTypeQuery query;
 153 	GType derived_atk_type;
 154 
 155 	if (!type) {
 156 		static GTypeInfo tinfo = {
 157 			sizeof (EaCalendarItemClass),
 158 			(GBaseInitFunc) NULL, /* base init */
 159 			(GBaseFinalizeFunc) NULL, /* base finalize */
 160 			(GClassInitFunc) ea_calendar_item_class_init, /* class init */
 161 			(GClassFinalizeFunc) NULL, /* class finalize */
 162 			NULL, /* class data */
 163 			sizeof (EaCalendarItem), /* instance size */
 164 			0, /* nb preallocs */
 165 			(GInstanceInitFunc) NULL, /* instance init */
 166 			NULL /* value table */
 167 		};
 168 
 169 		static const GInterfaceInfo atk_table_info = {
 170 			(GInterfaceInitFunc) atk_table_interface_init,
 171 			(GInterfaceFinalizeFunc) NULL,
 172 			NULL
 173 		};
 174 		static const GInterfaceInfo atk_selection_info = {
 175 			(GInterfaceInitFunc) atk_selection_interface_init,
 176 			(GInterfaceFinalizeFunc) NULL,
 177 			NULL
 178 		};
 179 
 180 		/*
 181 		 * Figure out the size of the class and instance
 182 		 * we are run-time deriving from (GailCanvasItem, in this case)
 183 		 */
 184 
 185 		factory = atk_registry_get_factory (
 186 			atk_get_default_registry (),
 187 			GNOME_TYPE_CANVAS_ITEM);
 188 		derived_atk_type = atk_object_factory_get_accessible_type (factory);
 189 		g_type_query (derived_atk_type, &query);
 190 
 191 		tinfo.class_size = query.class_size;
 192 		tinfo.instance_size = query.instance_size;
 193 
 194 		type = g_type_register_static (
 195 			derived_atk_type,
 196 			"EaCalendarItem", &tinfo, 0);
 197 		g_type_add_interface_static (
 198 			type, ATK_TYPE_TABLE,
 199 			&atk_table_info);
 200 		g_type_add_interface_static (
 201 			type, ATK_TYPE_SELECTION,
 202 			&atk_selection_info);
 203 	}
 204 
 205 	return type;
 206 }
 207 
 208 static void
 209 ea_calendar_item_class_init (EaCalendarItemClass *klass)
 210 {
 211 	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 212 	AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
 213 
 214 	gobject_class->finalize = ea_calendar_item_finalize;
 215 	parent_class = g_type_class_peek_parent (klass);
 216 
 217 	class->get_name = ea_calendar_item_get_name;
 218 	class->get_description = ea_calendar_item_get_description;
 219 	class->ref_state_set = ea_calendar_item_ref_state_set;
 220 
 221 	class->get_n_children = ea_calendar_item_get_n_children;
 222 	class->ref_child = ea_calendar_item_ref_child;
 223 }
 224 
 225 AtkObject *
 226 ea_calendar_item_new (GObject *obj)
 227 {
 228 	gpointer object;
 229 	AtkObject *atk_object;
 230 	AtkObject *item_cell;
 231 
 232 	g_return_val_if_fail (E_IS_CALENDAR_ITEM (obj), NULL);
 233 	object = g_object_new (EA_TYPE_CALENDAR_ITEM, NULL);
 234 	atk_object = ATK_OBJECT (object);
 235 	atk_object_initialize (atk_object, obj);
 236 	atk_object->role = ATK_ROLE_CALENDAR;
 237 
 238 	item_cell = atk_selection_ref_selection (
 239 		ATK_SELECTION (atk_object), 0);
 240 	if (item_cell)
 241 		ea_calendar_set_focus_object (EA_CALENDAR_ITEM (atk_object), item_cell);
 242 
 243 #ifdef ACC_DEBUG
 244 	++n_ea_calendar_item_created;
 245 	g_print (
 246 		"ACC_DEBUG: n_ea_calendar_item_created = %d\n",
 247 		n_ea_calendar_item_created);
 248 #endif
 249 	/* connect signal handlers */
 250 	g_signal_connect (
 251 		obj, "selection_preview_changed",
 252 		G_CALLBACK (selection_preview_change_cb), atk_object);
 253 	g_signal_connect (
 254 		obj, "date_range_changed",
 255 		G_CALLBACK (date_range_changed_cb), atk_object);
 256 
 257 	return atk_object;
 258 }
 259 
 260 static void
 261 ea_calendar_item_finalize (GObject *object)
 262 {
 263 	EaCalendarItem *ea_calitem;
 264 
 265 	g_return_if_fail (EA_IS_CALENDAR_ITEM (object));
 266 
 267 	ea_calitem = EA_CALENDAR_ITEM (object);
 268 
 269 	/* Free the allocated cell data */
 270 	ea_calendar_item_destory_cell_data (ea_calitem);
 271 
 272 	G_OBJECT_CLASS (parent_class)->finalize (object);
 273 #ifdef ACC_DEBUG
 274 	++n_ea_calendar_item_destroyed;
 275 	printf (
 276 		"ACC_DEBUG: n_ea_calendar_item_destroyed = %d\n",
 277 		n_ea_calendar_item_destroyed);
 278 #endif
 279 }
 280 
 281 static const gchar *
 282 ea_calendar_item_get_name (AtkObject *accessible)
 283 {
 284 	GObject *g_obj;
 285 	ECalendarItem *calitem;
 286 	gint start_year, start_month, start_day;
 287 	gint end_year, end_month, end_day;
 288 	gchar *name_str = NULL;
 289 	gchar buffer_start[128] = "";
 290 	gchar buffer_end[128] = "";
 291 	struct tm day_start = { 0 };
 292 	struct tm day_end = { 0 };
 293 
 294 	g_return_val_if_fail (EA_IS_CALENDAR_ITEM (accessible), NULL);
 295 
 296 	g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (accessible));
 297 	if (!g_obj)
 298 		return NULL;
 299 	g_return_val_if_fail (E_IS_CALENDAR_ITEM (g_obj), NULL);
 300 
 301 	calitem = E_CALENDAR_ITEM (g_obj);
 302 	if (e_calendar_item_get_date_range (
 303 		calitem,
 304 		&start_year, &start_month, &start_day,
 305 		&end_year, &end_month, &end_day)) {
 306 
 307 		day_start.tm_year = start_year - 1900;
 308 		day_start.tm_mon = start_month;
 309 		day_start.tm_mday = start_day;
 310 		day_start.tm_isdst = -1;
 311 
 312 		e_utf8_strftime (
 313 			buffer_start, sizeof (buffer_start),
 314 			_("%d %B %Y"), &day_start);
 315 
 316 		day_end.tm_year = end_year - 1900;
 317 		day_end.tm_mon = end_month;
 318 		day_end.tm_mday = end_day;
 319 		day_end.tm_isdst = -1;
 320 
 321 		e_utf8_strftime (
 322 			buffer_end, sizeof (buffer_end),
 323 			_("%d %B %Y"), &day_end);
 324 
 325 		name_str = g_strdup_printf (
 326 			_("Calendar: from %s to %s"),
 327 			buffer_start, buffer_end);
 328 	}
 329 
 330 #if 0
 331 	if (e_calendar_item_get_selection (calitem, &select_start, &select_end)) {
 332 		GDate select_start, select_end;
 333 		gint year1, year2, month1, month2, day1, day2;
 334 
 335 		year1 = g_date_get_year (&select_start);
 336 		month1  = g_date_get_month (&select_start);
 337 		day1 = g_date_get_day (&select_start);
 338 
 339 		year2 = g_date_get_year (&select_end);
 340 		month2  = g_date_get_month (&select_end);
 341 		day2 = g_date_get_day (&select_end);
 342 
 343 		sprintf (
 344 			new_name + strlen (new_name),
 345 			" : current selection: from %d-%d-%d to %d-%d-%d.",
 346 			year1, month1, day1,
 347 			year2, month2, day2);
 348 	}
 349 #endif
 350 
 351 	ATK_OBJECT_CLASS (parent_class)->set_name (accessible, name_str);
 352 	g_free (name_str);
 353 
 354 	return accessible->name;
 355 }
 356 
 357 static const gchar *
 358 ea_calendar_item_get_description (AtkObject *accessible)
 359 {
 360 	if (accessible->description)
 361 		return accessible->description;
 362 
 363 	return _("evolution calendar item");
 364 }
 365 
 366 static AtkStateSet *
 367 ea_calendar_item_ref_state_set (AtkObject *accessible)
 368 {
 369 	AtkStateSet *state_set;
 370 	GObject *g_obj;
 371 
 372 	state_set = ATK_OBJECT_CLASS (parent_class)->ref_state_set (accessible);
 373 	g_obj = atk_gobject_accessible_get_object (
 374 		ATK_GOBJECT_ACCESSIBLE (accessible));
 375 	if (!g_obj)
 376 		return state_set;
 377 
 378 	atk_state_set_add_state (state_set, ATK_STATE_ENABLED);
 379 	atk_state_set_add_state (state_set, ATK_STATE_SENSITIVE);
 380 
 381 	return state_set;
 382 }
 383 
 384 static gint
 385 ea_calendar_item_get_n_children (AtkObject *accessible)
 386 {
 387 	AtkGObjectAccessible *atk_gobj;
 388 	GObject *g_obj;
 389 	ECalendarItem *calitem;
 390 	gint n_children = 0;
 391 	gint start_year, start_month, start_day;
 392 	gint end_year, end_month, end_day;
 393 	GDate *start_date, *end_date;
 394 
 395 	g_return_val_if_fail (EA_IS_CALENDAR_ITEM (accessible), -1);
 396 
 397 	atk_gobj = ATK_GOBJECT_ACCESSIBLE (accessible);
 398 	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 399 	if (!g_obj)
 400 		return -1;
 401 
 402 	calitem = E_CALENDAR_ITEM (g_obj);
 403 	if (!e_calendar_item_get_date_range (calitem, &start_year,
 404 					     &start_month, &start_day,
 405 					     &end_year, &end_month,
 406 					     &end_day))
 407 		return 0;
 408 
 409 	start_date = g_date_new_dmy (start_day, start_month + 1, start_year);
 410 	end_date = g_date_new_dmy (end_day, end_month + 1, end_year);
 411 
 412 	n_children = g_date_days_between (start_date, end_date) + 1;
 413 	g_free (start_date);
 414 	g_free (end_date);
 415 	return n_children;
 416 }
 417 
 418 static AtkObject *
 419 ea_calendar_item_ref_child (AtkObject *accessible,
 420                             gint index)
 421 {
 422 	AtkGObjectAccessible *atk_gobj;
 423 	GObject *g_obj;
 424 	ECalendarItem *calitem;
 425 	gint n_children;
 426 	ECalendarCell *cell;
 427 	EaCellTable *cell_data;
 428 	EaCalendarItem *ea_calitem;
 429 
 430 	g_return_val_if_fail (EA_IS_CALENDAR_ITEM (accessible), NULL);
 431 
 432 	atk_gobj = ATK_GOBJECT_ACCESSIBLE (accessible);
 433 	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 434 	if (!g_obj)
 435 		return NULL;
 436 
 437 	calitem = E_CALENDAR_ITEM (g_obj);
 438 
 439 	n_children = ea_calendar_item_get_n_children (accessible);
 440 	if (index < 0 || index >= n_children)
 441 		return NULL;
 442 
 443 	ea_calitem = EA_CALENDAR_ITEM (accessible);
 444 	cell_data = ea_calendar_item_get_cell_data (ea_calitem);
 445 	if (!cell_data)
 446 		return NULL;
 447 
 448 	cell = ea_cell_table_get_cell_at_index (cell_data, index);
 449 	if (!cell) {
 450 		cell = e_calendar_cell_new (
 451 			calitem,
 452 			index / EA_CALENDAR_COLUMN_NUM,
 453 			index % EA_CALENDAR_COLUMN_NUM);
 454 		ea_cell_table_set_cell_at_index (cell_data, index, cell);
 455 		g_object_unref (cell);
 456 	}
 457 
 458 #ifdef ACC_DEBUG
 459 	g_print (
 460 		"AccDebug: ea_calendar_item children[%d]=%p\n", index,
 461 		(gpointer) cell);
 462 #endif
 463 	return g_object_ref (atk_gobject_accessible_for_object (G_OBJECT (cell)));
 464 }
 465 
 466 /* atk table interface */
 467 
 468 static void
 469 atk_table_interface_init (AtkTableIface *iface)
 470 {
 471 	g_return_if_fail (iface != NULL);
 472 
 473 	iface->ref_at = table_interface_ref_at;
 474 
 475 	iface->get_n_rows = table_interface_get_n_rows;
 476 	iface->get_n_columns = table_interface_get_n_columns;
 477 	iface->get_index_at = table_interface_get_index_at;
 478 	iface->get_column_at_index = table_interface_get_column_at_index;
 479 	iface->get_row_at_index = table_interface_get_row_at_index;
 480 	iface->get_column_extent_at = table_interface_get_column_extent_at;
 481 	iface->get_row_extent_at = table_interface_get_row_extent_at;
 482 
 483 	iface->is_selected = table_interface_is_selected;
 484 	iface->get_selected_rows = table_interface_get_selected_rows;
 485 	iface->get_selected_columns = table_interface_get_selected_columns;
 486 	iface->is_row_selected = table_interface_is_row_selected;
 487 	iface->is_column_selected = table_interface_is_column_selected;
 488 	iface->add_row_selection = table_interface_add_row_selection;
 489 	iface->remove_row_selection = table_interface_remove_row_selection;
 490 	iface->add_column_selection = table_interface_add_column_selection;
 491 	iface->remove_column_selection = table_interface_remove_column_selection;
 492 
 493 	iface->get_row_header = table_interface_get_row_header;
 494 	iface->get_column_header = table_interface_get_column_header;
 495 	iface->get_caption = table_interface_get_caption;
 496 	iface->get_summary = table_interface_get_summary;
 497 	iface->get_row_description = table_interface_get_row_description;
 498 	iface->get_column_description = table_interface_get_column_description;
 499 }
 500 
 501 static AtkObject *
 502 table_interface_ref_at (AtkTable *table,
 503                         gint row,
 504                         gint column)
 505 {
 506 	gint index;
 507 
 508 	EaCalendarItem * ea_calitem = EA_CALENDAR_ITEM (table);
 509 	index = EA_CALENDAR_COLUMN_NUM * row + column;
 510 	return ea_calendar_item_ref_child (ATK_OBJECT (ea_calitem), index);
 511 }
 512 
 513 static gint
 514 table_interface_get_n_rows (AtkTable *table)
 515 {
 516 	AtkGObjectAccessible *atk_gobj;
 517 	GObject *g_obj;
 518 	EaCalendarItem * ea_calitem = EA_CALENDAR_ITEM (table);
 519 	gint n_children;
 520 
 521 	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 522 	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 523 	if (!g_obj)
 524 		return -1;
 525 
 526 	n_children = ea_calendar_item_get_n_children (ATK_OBJECT (ea_calitem));
 527 	return (n_children - 1) / EA_CALENDAR_COLUMN_NUM + 1;
 528 }
 529 
 530 static gint
 531 table_interface_get_n_columns (AtkTable *table)
 532 {
 533 	AtkGObjectAccessible *atk_gobj;
 534 	GObject *g_obj;
 535 	EaCalendarItem * ea_calitem = EA_CALENDAR_ITEM (table);
 536 
 537 	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 538 	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 539 	if (!g_obj)
 540 		return -1;
 541 
 542 	return EA_CALENDAR_COLUMN_NUM;
 543 }
 544 
 545 static gint
 546 table_interface_get_index_at (AtkTable *table,
 547                               gint row,
 548                               gint column)
 549 {
 550 	AtkGObjectAccessible *atk_gobj;
 551 	GObject *g_obj;
 552 	EaCalendarItem * ea_calitem = EA_CALENDAR_ITEM (table);
 553 
 554 	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 555 	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 556 	if (!g_obj)
 557 		return -1;
 558 
 559 	return row * EA_CALENDAR_COLUMN_NUM + column;
 560 }
 561 
 562 static gint
 563 table_interface_get_column_at_index (AtkTable *table,
 564                                      gint index)
 565 {
 566 	AtkGObjectAccessible *atk_gobj;
 567 	GObject *g_obj;
 568 	EaCalendarItem * ea_calitem = EA_CALENDAR_ITEM (table);
 569 	gint n_children;
 570 
 571 	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 572 	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 573 	if (!g_obj)
 574 		return -1;
 575 
 576 	n_children = ea_calendar_item_get_n_children (ATK_OBJECT (ea_calitem));
 577 	if (index >= 0 && index < n_children)
 578 		return index % EA_CALENDAR_COLUMN_NUM;
 579 	return -1;
 580 }
 581 
 582 static gint
 583 table_interface_get_row_at_index (AtkTable *table,
 584                                   gint index)
 585 {
 586 	AtkGObjectAccessible *atk_gobj;
 587 	GObject *g_obj;
 588 	EaCalendarItem * ea_calitem = EA_CALENDAR_ITEM (table);
 589 	gint n_children;
 590 
 591 	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 592 	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 593 	if (!g_obj)
 594 		return -1;
 595 
 596 	n_children = ea_calendar_item_get_n_children (ATK_OBJECT (ea_calitem));
 597 	if (index >= 0 && index < n_children)
 598 		return index / EA_CALENDAR_COLUMN_NUM;
 599 	return -1;
 600 }
 601 
 602 static gint
 603 table_interface_get_column_extent_at (AtkTable *table,
 604                                       gint row,
 605                                       gint column)
 606 {
 607 	AtkGObjectAccessible *atk_gobj;
 608 	GObject *g_obj;
 609 	ECalendarItem *calitem;
 610 	EaCalendarItem * ea_calitem = EA_CALENDAR_ITEM (table);
 611 
 612 	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 613 	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 614 	if (!g_obj)
 615 		return FALSE;
 616 
 617 	calitem = E_CALENDAR_ITEM (g_obj);
 618 	return calitem->cell_width;
 619 }
 620 
 621 static gint
 622 table_interface_get_row_extent_at (AtkTable *table,
 623                                    gint row,
 624                                    gint column)
 625 {
 626 	AtkGObjectAccessible *atk_gobj;
 627 	GObject *g_obj;
 628 	ECalendarItem *calitem;
 629 	EaCalendarItem * ea_calitem = EA_CALENDAR_ITEM (table);
 630 
 631 	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 632 	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 633 	if (!g_obj)
 634 		return FALSE;
 635 
 636 	calitem = E_CALENDAR_ITEM (g_obj);
 637 	return calitem->cell_height;
 638 }
 639 
 640 /* any day in the row is selected, the row is selected */
 641 static gboolean
 642 table_interface_is_row_selected (AtkTable *table,
 643                                  gint row)
 644 {
 645 	AtkGObjectAccessible *atk_gobj;
 646 	GObject *g_obj;
 647 	gint n_rows;
 648 	ECalendarItem *calitem;
 649 	gint row_index_start, row_index_end;
 650 	gint sel_index_start, sel_index_end;
 651 
 652 	GDate start_date, end_date;
 653 
 654 	g_return_val_if_fail (EA_IS_CALENDAR_ITEM (table), FALSE);
 655 
 656 	atk_gobj = ATK_GOBJECT_ACCESSIBLE (table);
 657 	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 658 	if (!g_obj)
 659 		return FALSE;
 660 
 661 	n_rows = table_interface_get_n_rows (table);
 662 	if (row < 0 || row >= n_rows)
 663 		return FALSE;
 664 
 665 	row_index_start = row * EA_CALENDAR_COLUMN_NUM;
 666 	row_index_end = row_index_start + EA_CALENDAR_COLUMN_NUM - 1;
 667 
 668 	calitem = E_CALENDAR_ITEM (g_obj);
 669 	if (!e_calendar_item_get_selection (calitem, &start_date, &end_date))
 670 		return FALSE;
 671 
 672 	e_calendar_item_get_offset_for_date (calitem,
 673 					     g_date_get_year (&start_date),
 674 					     g_date_get_month (&start_date),
 675 					     g_date_get_day (&start_date),
 676 					     &sel_index_start);
 677 	e_calendar_item_get_offset_for_date (calitem,
 678 					     g_date_get_year (&end_date),
 679 					     g_date_get_month (&end_date),
 680 					     g_date_get_day (&end_date),
 681 					     &sel_index_end);
 682 
 683 	if ((sel_index_start < row_index_start &&
 684 	     sel_index_end >= row_index_start) ||
 685 	    (sel_index_start >= row_index_start &&
 686 	     sel_index_start <= row_index_end))
 687 	    return TRUE;
 688 	return FALSE;
 689 }
 690 
 691 static gboolean
 692 table_interface_is_selected (AtkTable *table,
 693                              gint row,
 694                              gint column)
 695 {
 696 	AtkGObjectAccessible *atk_gobj;
 697 	GObject *g_obj;
 698 	gint n_rows, n_columns;
 699 	ECalendarItem *calitem;
 700 	gint index;
 701 	gint sel_index_start, sel_index_end;
 702 
 703 	GDate start_date, end_date;
 704 
 705 	g_return_val_if_fail (EA_IS_CALENDAR_ITEM (table), FALSE);
 706 
 707 	atk_gobj = ATK_GOBJECT_ACCESSIBLE (table);
 708 	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 709 	if (!g_obj)
 710 		return FALSE;
 711 
 712 	n_rows = table_interface_get_n_rows (table);
 713 	if (row < 0 || row >= n_rows)
 714 		return FALSE;
 715 	n_columns = table_interface_get_n_columns (table);
 716 	if (column < 0 || column >= n_columns)
 717 		return FALSE;
 718 
 719 	index = table_interface_get_index_at (table, row, column);
 720 
 721 	calitem = E_CALENDAR_ITEM (g_obj);
 722 	if (!e_calendar_item_get_selection (calitem, &start_date, &end_date))
 723 		return FALSE;
 724 
 725 	e_calendar_item_get_offset_for_date (calitem,
 726 					     g_date_get_year (&start_date),
 727 					     g_date_get_month (&start_date),
 728 					     g_date_get_day (&start_date),
 729 					     &sel_index_start);
 730 	e_calendar_item_get_offset_for_date (calitem,
 731 					     g_date_get_year (&end_date),
 732 					     g_date_get_month (&end_date),
 733 					     g_date_get_day (&end_date), &sel_index_end);
 734 
 735 	if (sel_index_start <= index && sel_index_end >= index)
 736 	    return TRUE;
 737 	return FALSE;
 738 }
 739 
 740 static gboolean
 741 table_interface_is_column_selected (AtkTable *table,
 742                                     gint column)
 743 {
 744 	return FALSE;
 745 }
 746 
 747 static gint
 748 table_interface_get_selected_rows (AtkTable *table,
 749                                    gint **rows_selected)
 750 {
 751 	*rows_selected = NULL;
 752 	return -1;
 753 }
 754 
 755 static gint
 756 table_interface_get_selected_columns (AtkTable *table,
 757                                       gint **columns_selected)
 758 {
 759 	*columns_selected = NULL;
 760 	return -1;
 761 }
 762 
 763 static gboolean
 764 table_interface_add_row_selection (AtkTable *table,
 765                                    gint row)
 766 {
 767 	return FALSE;
 768 }
 769 
 770 static gboolean
 771 table_interface_remove_row_selection (AtkTable *table,
 772                                       gint row)
 773 {
 774 	return FALSE;
 775 }
 776 
 777 static gboolean
 778 table_interface_add_column_selection (AtkTable *table,
 779                                       gint column)
 780 {
 781 	return FALSE;
 782 }
 783 
 784 static gboolean
 785 table_interface_remove_column_selection (AtkTable *table,
 786                                          gint column)
 787 {
 788 	/* FIXME: NOT IMPLEMENTED */
 789 	return FALSE;
 790 }
 791 
 792 static AtkObject *
 793 table_interface_get_row_header (AtkTable *table,
 794                                 gint row)
 795 {
 796 	/* FIXME: NOT IMPLEMENTED */
 797 	return NULL;
 798 }
 799 
 800 static AtkObject *
 801 table_interface_get_column_header (AtkTable *table,
 802                                    gint in_col)
 803 {
 804 	/* FIXME: NOT IMPLEMENTED */
 805 	return NULL;
 806 }
 807 
 808 static AtkObject *
 809 table_interface_get_caption (AtkTable *table)
 810 {
 811 	/* FIXME: NOT IMPLEMENTED */
 812 	return NULL;
 813 }
 814 
 815 static const gchar *
 816 table_interface_get_column_description (AtkTable *table,
 817                                         gint in_col)
 818 {
 819 	AtkGObjectAccessible *atk_gobj;
 820 	GObject *g_obj;
 821 	EaCalendarItem * ea_calitem = EA_CALENDAR_ITEM (table);
 822 	const gchar *description = NULL;
 823 	EaCellTable *cell_data;
 824 	gint n_columns;
 825 
 826 	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 827 	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 828 	if (!g_obj)
 829 		return NULL;
 830 
 831 	n_columns = table_interface_get_n_columns (table);
 832 	if (in_col < 0 || in_col >= n_columns)
 833 		return NULL;
 834 	cell_data = ea_calendar_item_get_cell_data (ea_calitem);
 835 	if (!cell_data)
 836 		return NULL;
 837 
 838 	description = ea_cell_table_get_column_label (cell_data, in_col);
 839 	if (!description) {
 840 		gchar buffer[128] = "column description";
 841 		ea_calendar_item_get_column_label (
 842 			ea_calitem, in_col,
 843 			buffer, sizeof (buffer));
 844 		ea_cell_table_set_column_label (cell_data, in_col, buffer);
 845 		description = ea_cell_table_get_column_label (
 846 			cell_data, in_col);
 847 	}
 848 	return description;
 849 }
 850 
 851 static const gchar *
 852 table_interface_get_row_description (AtkTable *table,
 853                                      gint row)
 854 {
 855 	AtkGObjectAccessible *atk_gobj;
 856 	GObject *g_obj;
 857 	EaCalendarItem * ea_calitem = EA_CALENDAR_ITEM (table);
 858 	const gchar *description = NULL;
 859 	EaCellTable *cell_data;
 860 	gint n_rows;
 861 
 862 	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 863 	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 864 	if (!g_obj)
 865 		return NULL;
 866 
 867 	n_rows = table_interface_get_n_rows (table);
 868 	if (row < 0 || row >= n_rows)
 869 		return NULL;
 870 	cell_data = ea_calendar_item_get_cell_data (ea_calitem);
 871 	if (!cell_data)
 872 		return NULL;
 873 
 874 	description = ea_cell_table_get_row_label (cell_data, row);
 875 	if (!description) {
 876 		gchar buffer[128] = "row description";
 877 		ea_calendar_item_get_row_label (
 878 			ea_calitem, row,
 879 						buffer, sizeof (buffer));
 880 		ea_cell_table_set_row_label (cell_data, row, buffer);
 881 		description = ea_cell_table_get_row_label (
 882 			cell_data,
 883 			row);
 884 	}
 885 	return description;
 886 }
 887 
 888 static AtkObject *
 889 table_interface_get_summary (AtkTable *table)
 890 {
 891 	/* FIXME: NOT IMPLEMENTED */
 892 	return NULL;
 893 }
 894 
 895 /* atkselection interface */
 896 
 897 static void
 898 atk_selection_interface_init (AtkSelectionIface *iface)
 899 {
 900 	g_return_if_fail (iface != NULL);
 901 
 902 	iface->add_selection = selection_interface_add_selection;
 903 	iface->clear_selection = selection_interface_clear_selection;
 904 	iface->ref_selection = selection_interface_ref_selection;
 905 	iface->get_selection_count = selection_interface_get_selection_count;
 906 	iface->is_child_selected = selection_interface_is_child_selected;
 907 }
 908 
 909 static gboolean
 910 selection_interface_add_selection (AtkSelection *selection,
 911                                    gint index)
 912 {
 913 	AtkGObjectAccessible *atk_gobj;
 914 	GObject *g_obj;
 915 	ECalendarItem *calitem;
 916 	EaCalendarItem * ea_calitem = EA_CALENDAR_ITEM (selection);
 917 	gint year, month, day;
 918 	GDate start_date, end_date;
 919 
 920 	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 921 	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 922 	if (!g_obj)
 923 		return FALSE;
 924 
 925 	calitem = E_CALENDAR_ITEM (g_obj);
 926 	if (!e_calendar_item_get_date_for_offset (calitem, index,
 927 						  &year, &month, &day))
 928 		return FALSE;
 929 
 930 	/* FIXME: not support mulit-selection */
 931 	g_date_set_dmy (&start_date, day, month + 1, year);
 932 	end_date = start_date;
 933 	e_calendar_item_set_selection (calitem, &start_date, &end_date);
 934 	return TRUE;
 935 }
 936 
 937 static gboolean
 938 selection_interface_clear_selection (AtkSelection *selection)
 939 {
 940 	AtkGObjectAccessible *atk_gobj;
 941 	GObject *g_obj;
 942 	ECalendarItem *calitem;
 943 	EaCalendarItem * ea_calitem = EA_CALENDAR_ITEM (selection);
 944 
 945 	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 946 	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 947 	if (!g_obj)
 948 		return FALSE;
 949 
 950 	calitem = E_CALENDAR_ITEM (g_obj);
 951 	e_calendar_item_set_selection (calitem, NULL, NULL);
 952 
 953 	return TRUE;
 954 }
 955 
 956 static AtkObject *
 957 selection_interface_ref_selection (AtkSelection *selection,
 958                                    gint i)
 959 {
 960 	GObject *g_obj;
 961 	ECalendarItem *calitem;
 962 	EaCalendarItem * ea_calitem = EA_CALENDAR_ITEM (selection);
 963 	gint count, sel_offset;
 964 	GDate start_date, end_date;
 965 
 966 	count = selection_interface_get_selection_count (selection);
 967 	if (i < 0 || i >= count)
 968 		return NULL;
 969 
 970 	g_obj = atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (ea_calitem));
 971 
 972 	calitem = E_CALENDAR_ITEM (g_obj);
 973 	if (!e_calendar_item_get_selection (calitem, &start_date, &end_date))
 974 		return NULL;
 975 	if (!e_calendar_item_get_offset_for_date (calitem,
 976 						  g_date_get_year (&start_date),
 977 						  g_date_get_month (&start_date) - 1,
 978 						  g_date_get_day (&start_date),
 979 						  &sel_offset))
 980 		return NULL;
 981 
 982 	return ea_calendar_item_ref_child (ATK_OBJECT (selection), sel_offset + i);
 983 }
 984 
 985 static gint
 986 selection_interface_get_selection_count (AtkSelection *selection)
 987 {
 988 	AtkGObjectAccessible *atk_gobj;
 989 	GObject *g_obj;
 990 	ECalendarItem *calitem;
 991 	EaCalendarItem * ea_calitem = EA_CALENDAR_ITEM (selection);
 992 	GDate start_date, end_date;
 993 
 994 	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
 995 	g_obj = atk_gobject_accessible_get_object (atk_gobj);
 996 	if (!g_obj)
 997 		return 0;
 998 
 999 	calitem = E_CALENDAR_ITEM (g_obj);
1000 	if (e_calendar_item_get_selection (calitem, &start_date, &end_date))
1001 		return g_date_days_between (&start_date, &end_date) + 1;
1002 	else
1003 		return 0;
1004 }
1005 
1006 static gboolean
1007 selection_interface_is_child_selected (AtkSelection *selection,
1008                                        gint index)
1009 {
1010 	AtkGObjectAccessible *atk_gobj;
1011 	GObject *g_obj;
1012 	EaCalendarItem * ea_calitem = EA_CALENDAR_ITEM (selection);
1013 	gint row, column, n_children;
1014 
1015 	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
1016 	g_obj = atk_gobject_accessible_get_object (atk_gobj);
1017 	if (!g_obj)
1018 		return FALSE;
1019 
1020 	n_children = atk_object_get_n_accessible_children (ATK_OBJECT (selection));
1021 	if (index < 0 || index >= n_children)
1022 		return FALSE;
1023 
1024 	row = index / EA_CALENDAR_COLUMN_NUM;
1025 	column = index % EA_CALENDAR_COLUMN_NUM;
1026 
1027 	return table_interface_is_selected (ATK_TABLE (selection), row, column);
1028 }
1029 
1030 /* callbacks */
1031 
1032 static void
1033 selection_preview_change_cb (ECalendarItem *calitem)
1034 {
1035 	AtkObject *atk_obj;
1036 	AtkObject *item_cell;
1037 
1038 	g_return_if_fail (E_IS_CALENDAR_ITEM (calitem));
1039 	atk_obj = atk_gobject_accessible_for_object (G_OBJECT (calitem));
1040 	ea_calendar_item_destory_cell_data (EA_CALENDAR_ITEM (atk_obj));
1041 
1042 	/* only deal with the first selected child, for now */
1043 	item_cell = atk_selection_ref_selection (
1044 		ATK_SELECTION (atk_obj), 0);
1045 
1046 	if (item_cell)
1047 		ea_calendar_set_focus_object (EA_CALENDAR_ITEM (atk_obj), item_cell);
1048 
1049 	g_signal_emit_by_name (
1050 		atk_obj,
1051 		"active-descendant-changed",
1052 		item_cell);
1053 	g_signal_emit_by_name (atk_obj, "selection_changed");
1054 }
1055 
1056 static void
1057 date_range_changed_cb (ECalendarItem *calitem)
1058 {
1059 	AtkObject *atk_obj;
1060 	AtkObject *item_cell;
1061 
1062 	g_return_if_fail (E_IS_CALENDAR_ITEM (calitem));
1063 	atk_obj = atk_gobject_accessible_for_object (G_OBJECT (calitem));
1064 	ea_calendar_item_destory_cell_data (EA_CALENDAR_ITEM (atk_obj));
1065 
1066 	item_cell = atk_selection_ref_selection (
1067 		ATK_SELECTION (atk_obj), 0);
1068 	if (item_cell)
1069 		ea_calendar_set_focus_object (EA_CALENDAR_ITEM (atk_obj), item_cell);
1070 
1071 	g_signal_emit_by_name (atk_obj, "model_changed");
1072 }
1073 
1074 /* helpers */
1075 
1076 static EaCellTable *
1077 ea_calendar_item_get_cell_data (EaCalendarItem *ea_calitem)
1078 {
1079 	AtkGObjectAccessible *atk_gobj;
1080 	GObject *g_obj;
1081 	EaCellTable *cell_data;
1082 
1083 	g_return_val_if_fail (ea_calitem, NULL);
1084 
1085 	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
1086 	g_obj = atk_gobject_accessible_get_object (atk_gobj);
1087 	if (!g_obj)
1088 		return NULL;
1089 
1090 	cell_data = g_object_get_data (
1091 		G_OBJECT (ea_calitem),
1092 		"ea-calendar-cell-table");
1093 
1094 	if (!cell_data) {
1095 		gint n_cells = ea_calendar_item_get_n_children (ATK_OBJECT (ea_calitem));
1096 		cell_data = ea_cell_table_create (
1097 			n_cells / EA_CALENDAR_COLUMN_NUM,
1098 			EA_CALENDAR_COLUMN_NUM,
1099 			FALSE);
1100 		g_object_set_data (
1101 			G_OBJECT (ea_calitem),
1102 			"ea-calendar-cell-table", cell_data);
1103 	}
1104 	return cell_data;
1105 }
1106 
1107 static void
1108 ea_calendar_item_destory_cell_data (EaCalendarItem *ea_calitem)
1109 {
1110 	EaCellTable *cell_data;
1111 
1112 	g_return_if_fail (ea_calitem);
1113 
1114 	cell_data = g_object_get_data (
1115 		G_OBJECT (ea_calitem),
1116 		"ea-calendar-cell-table");
1117 	if (cell_data) {
1118 		g_object_set_data (
1119 			G_OBJECT (ea_calitem),
1120 			"ea-calendar-cell-table", NULL);
1121 		ea_cell_table_destroy (cell_data);
1122 	}
1123 }
1124 
1125 static gboolean
1126 ea_calendar_item_get_row_label (EaCalendarItem *ea_calitem,
1127                                 gint row,
1128                                 gchar *buffer,
1129                                 gint buffer_size)
1130 {
1131 	AtkGObjectAccessible *atk_gobj;
1132 	GObject *g_obj;
1133 	ECalendarItem *calitem;
1134 	gint index, week_num;
1135 	gint year, month, day;
1136 
1137 	g_return_val_if_fail (ea_calitem, FALSE);
1138 
1139 	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
1140 	g_obj = atk_gobject_accessible_get_object (atk_gobj);
1141 	if (!g_obj)
1142 		return FALSE;
1143 
1144 	calitem = E_CALENDAR_ITEM (g_obj);
1145 
1146 	index = atk_table_get_index_at (ATK_TABLE (ea_calitem), row, 0);
1147 	if (!e_calendar_item_get_date_for_offset (calitem, index,
1148 						  &year, &month, &day))
1149 		return FALSE;
1150 
1151 	week_num = e_calendar_item_get_week_number (
1152 		calitem, day, month, year);
1153 
1154 	g_snprintf (buffer, buffer_size, "week number : %d", week_num);
1155 	return TRUE;
1156 }
1157 
1158 static gboolean
1159 ea_calendar_item_get_column_label (EaCalendarItem *ea_calitem,
1160                                    gint column,
1161                                    gchar *buffer,
1162                                    gint buffer_size)
1163 {
1164 	AtkGObjectAccessible *atk_gobj;
1165 	GObject *g_obj;
1166 	const gchar *abbr_name;
1167 
1168 	g_return_val_if_fail (ea_calitem, FALSE);
1169 
1170 	atk_gobj = ATK_GOBJECT_ACCESSIBLE (ea_calitem);
1171 	g_obj = atk_gobject_accessible_get_object (atk_gobj);
1172 	if (!g_obj)
1173 		return FALSE;
1174 
1175 	/* Columns are 0 = Monday ... 6 = Sunday */
1176 	abbr_name = e_get_weekday_name (column + 1, TRUE);
1177 	g_strlcpy (buffer, abbr_name, buffer_size);
1178 
1179 	return TRUE;
1180 }
1181 
1182 /* the coordinate the e-calendar canvas coord */
1183 gboolean
1184 e_calendar_item_get_day_extents (ECalendarItem *calitem,
1185                                  gint year,
1186                                  gint month,
1187                                  gint date,
1188                                  gint *x,
1189                                  gint *y,
1190                                  gint *width,
1191                                  gint *height)
1192 {
1193 	GnomeCanvasItem *item;
1194 	GtkWidget *widget;
1195 	GtkStyle *style;
1196 	PangoFontDescription *font_desc;
1197 	PangoContext *pango_context;
1198 	PangoFontMetrics *font_metrics;
1199 	gint char_height, xthickness, ythickness, text_y;
1200 	gint new_year, new_month, num_months, months_offset;
1201 	gint month_x, month_y, month_cell_x, month_cell_y;
1202 	gint month_row, month_col;
1203 	gint day_row, day_col;
1204 	gint days_from_week_start;
1205 
1206 	g_return_val_if_fail (E_IS_CALENDAR_ITEM (calitem), FALSE);
1207 
1208 	item = GNOME_CANVAS_ITEM (calitem);
1209 	widget = GTK_WIDGET (item->canvas);
1210 	style = gtk_widget_get_style (widget);
1211 
1212 	/* Set up Pango prerequisites */
1213 	font_desc = calitem->font_desc;
1214 	if (!font_desc)
1215 		font_desc = style->font_desc;
1216 	pango_context = gtk_widget_get_pango_context (widget);
1217 	font_metrics = pango_context_get_metrics (
1218 		pango_context, font_desc,
1219 		pango_context_get_language (pango_context));
1220 
1221 	char_height =
1222 		PANGO_PIXELS (pango_font_metrics_get_ascent (font_metrics)) +
1223 		PANGO_PIXELS (pango_font_metrics_get_descent (font_metrics));
1224 
1225 	xthickness = style->xthickness;
1226 	ythickness = style->ythickness;
1227 
1228 	new_year = year;
1229 	new_month = month;
1230 	e_calendar_item_normalize_date (calitem, &new_year, &new_month);
1231 	num_months = calitem->rows * calitem->cols;
1232 	months_offset = (new_year - calitem->year) * 12
1233 		+ new_month - calitem->month;
1234 
1235 	if (months_offset > num_months || months_offset < 0)
1236 		return FALSE;
1237 
1238 	month_row = months_offset / calitem->cols;
1239 	month_col = months_offset % calitem->cols;
1240 
1241 	month_x = item->x1 + xthickness + calitem->x_offset
1242 		+ month_col * calitem->month_width;
1243 	month_y = item->y1 + ythickness + month_row * calitem->month_height;
1244 
1245 	month_cell_x = month_x + E_CALENDAR_ITEM_XPAD_BEFORE_WEEK_NUMBERS
1246 		+ calitem->month_lpad + E_CALENDAR_ITEM_XPAD_BEFORE_CELLS;
1247 	text_y = month_y + ythickness * 2
1248 		+ E_CALENDAR_ITEM_YPAD_ABOVE_MONTH_NAME
1249 		+ char_height + E_CALENDAR_ITEM_YPAD_BELOW_MONTH_NAME
1250 		+ E_CALENDAR_ITEM_YPAD_ABOVE_DAY_LETTERS + calitem->month_tpad;
1251 
1252 	month_cell_y = text_y + char_height
1253 		+ E_CALENDAR_ITEM_YPAD_BELOW_DAY_LETTERS + 1
1254 		+ E_CALENDAR_ITEM_YPAD_ABOVE_CELLS;
1255 
1256 	days_from_week_start = e_calendar_item_get_n_days_from_week_start (
1257 		calitem, new_year, new_month);
1258 	day_row = (date + days_from_week_start - 1) / EA_CALENDAR_COLUMN_NUM;
1259 	day_col = (date + days_from_week_start - 1) % EA_CALENDAR_COLUMN_NUM;
1260 
1261 	*x = month_cell_x + day_col * calitem->cell_width;
1262 	*y = month_cell_y + day_row * calitem->cell_height;
1263 	*width = calitem->cell_width;
1264 	*height = calitem->cell_height;
1265 
1266 	return TRUE;
1267 }
1268 
1269 /* month is from 0 to 11 */
1270 gboolean
1271 e_calendar_item_get_date_for_offset (ECalendarItem *calitem,
1272                                      gint day_offset,
1273                                      gint *year,
1274                                      gint *month,
1275                                      gint *day)
1276 {
1277 	gint start_year, start_month, start_day;
1278 	gint end_year, end_month, end_day;
1279 	GDate *start_date;
1280 
1281 	g_return_val_if_fail (E_IS_CALENDAR_ITEM (calitem), FALSE);
1282 
1283 	if (!e_calendar_item_get_date_range (calitem, &start_year,
1284 					     &start_month, &start_day,
1285 					     &end_year, &end_month,
1286 					     &end_day))
1287 		return FALSE;
1288 
1289 	start_date = g_date_new_dmy (start_day, start_month + 1, start_year);
1290 
1291 	g_date_add_days (start_date, day_offset);
1292 
1293 	*year = g_date_get_year (start_date);
1294 	*month = g_date_get_month (start_date) - 1;
1295 	*day = g_date_get_day (start_date);
1296 
1297 	return TRUE;
1298 }
1299 
1300 /* the arg month is from 0 to 11 */
1301 static gboolean
1302 e_calendar_item_get_offset_for_date (ECalendarItem *calitem,
1303                                      gint year,
1304                                      gint month,
1305                                      gint day,
1306                                      gint *offset)
1307 {
1308 	gint start_year, start_month, start_day;
1309 	gint end_year, end_month, end_day;
1310 	GDate *start_date, *end_date;
1311 
1312 	*offset = 0;
1313 	g_return_val_if_fail (E_IS_CALENDAR_ITEM (calitem), FALSE);
1314 
1315 	if (!e_calendar_item_get_date_range (calitem, &start_year,
1316 					     &start_month, &start_day,
1317 					     &end_year, &end_month,
1318 					     &end_day))
1319 		return FALSE;
1320 
1321 	start_date = g_date_new_dmy (start_day, start_month + 1, start_year);
1322 	end_date = g_date_new_dmy (day, month + 1, year);
1323 
1324 	*offset = g_date_days_between (start_date, end_date);
1325 	g_free (start_date);
1326 	g_free (end_date);
1327 
1328 	return TRUE;
1329 }
1330 
1331 gint
1332 e_calendar_item_get_n_days_from_week_start (ECalendarItem *calitem,
1333                                             gint year,
1334                                             gint month)
1335 {
1336 	struct tm tmp_tm;
1337 	gint start_weekday, days_from_week_start;
1338 
1339 	memset (&tmp_tm, 0, sizeof (tmp_tm));
1340 	tmp_tm.tm_year = year - 1900;
1341 	tmp_tm.tm_mon = month;
1342 	tmp_tm.tm_mday = 1;
1343 	tmp_tm.tm_isdst = -1;
1344 	mktime (&tmp_tm);
1345 	start_weekday = (tmp_tm.tm_wday + 6) % 7;   /* 0 to 6 */
1346 	days_from_week_start = (start_weekday + 7 - calitem->week_start_day)
1347 		% 7;
1348 	return days_from_week_start;
1349 }
1350 
1351 static void
1352 ea_calendar_set_focus_object (EaCalendarItem *ea_calitem,
1353                               AtkObject *item_cell)
1354 {
1355 	AtkStateSet *state_set, *old_state_set;
1356 	AtkObject *old_cell;
1357 
1358 	old_cell = (AtkObject *) g_object_get_data (
1359 		G_OBJECT (ea_calitem), "gail-focus-object");
1360 	if (old_cell && EA_IS_CALENDAR_CELL (old_cell)) {
1361 		old_state_set = atk_object_ref_state_set (old_cell);
1362 		atk_state_set_remove_state (old_state_set, ATK_STATE_FOCUSED);
1363 		g_object_unref (old_state_set);
1364 	}
1365 	if (old_cell)
1366 		g_object_unref (old_cell);
1367 
1368 	state_set = atk_object_ref_state_set (item_cell);
1369 	atk_state_set_add_state (state_set, ATK_STATE_FOCUSED);
1370 	g_object_set_data (G_OBJECT (ea_calitem), "gail-focus-object", item_cell);
1371 	g_object_unref (state_set);
1372 }