evolution-3.6.4/calendar/gui/gnome-cal.c

Location Tool Test ID Function Issue
gnome-cal.c:1737:2 clang-analyzer Function call argument is an uninitialized value
gnome-cal.c:1737:2 clang-analyzer Function call argument is an uninitialized value
   1 /*
   2  * Evolution calendar - Main calendar view widget
   3  *
   4  * This program 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) version 3.
   8  *
   9  * This program 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
  15  * License along with the program; if not, see <http://www.gnu.org/licenses/>
  16  *
  17  *
  18  * Authors:
  19  *		Miguel de Icaza <miguel@ximian.com>
  20  *      Federico Mena-Quintero <federico@ximian.com>
  21  *      Seth Alves <alves@hungry.com>
  22  *      Rodrigo Moya <rodrigo@ximian.com>
  23  *
  24  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  25  *
  26  */
  27 
  28 #ifdef HAVE_CONFIG_H
  29 #include <config.h>
  30 #endif
  31 
  32 #include <unistd.h>
  33 #include <math.h>
  34 #include <signal.h>
  35 #include <fcntl.h>
  36 #include <gdk/gdkkeysyms.h>
  37 #include <glib/gi18n.h>
  38 
  39 #include <widgets/menus/gal-view-factory-etable.h>
  40 #include <widgets/menus/gal-view-etable.h>
  41 #include <widgets/menus/gal-define-views-dialog.h>
  42 #include "e-util/e-util.h"
  43 #include "libevolution-utils/e-alert-dialog.h"
  44 #include "e-util/e-util-private.h"
  45 #include "shell/e-shell.h"
  46 #include "dialogs/delete-error.h"
  47 #include "dialogs/event-editor.h"
  48 #include "comp-util.h"
  49 #include "e-cal-model-calendar.h"
  50 #include "e-day-view.h"
  51 #include "e-day-view-time-item.h"
  52 #include "e-month-view.h"
  53 #include "e-week-view.h"
  54 #include "e-cal-list-view.h"
  55 #include "gnome-cal.h"
  56 #include "calendar-config.h"
  57 #include "calendar-view.h"
  58 #include "calendar-view-factory.h"
  59 #include "tag-calendar.h"
  60 #include "misc.h"
  61 #include "ea-calendar.h"
  62 #include "e-memo-table.h"
  63 #include "e-task-table.h"
  64 
  65 #define d(x)
  66 
  67 #define GNOME_CALENDAR_GET_PRIVATE(obj) \
  68 	(G_TYPE_INSTANCE_GET_PRIVATE \
  69 	((obj), GNOME_TYPE_CALENDAR, GnomeCalendarPrivate))
  70 
  71 /* Private part of the GnomeCalendar structure */
  72 struct _GnomeCalendarPrivate {
  73 	ESourceRegistry *registry;
  74 	ECalModel *model;
  75 
  76 	/*
  77 	 * Fields for the calendar view
  78 	 */
  79 
  80 	/* This is the last time explicitly selected by the user */
  81 	time_t base_view_time;
  82 
  83 	/* Widgets */
  84 
  85 	GtkWidget   *hpane;
  86 
  87 	ECalendar   *date_navigator;
  88 	GtkWidget   *memo_table; /* EMemoTable, but can be NULL */
  89 	GtkWidget   *task_table; /* ETaskTable, but can be NULL */
  90 
  91 	/* Calendar query for the date navigator */
  92 	GMutex      *dn_query_lock;
  93 	GList       *dn_queries; /* list of CalQueries */
  94 	gchar        *sexp;
  95 	gchar        *todo_sexp;
  96 	gchar        *memo_sexp;
  97 	guint        update_timeout;
  98 	guint        update_marcus_bains_line_timeout;
  99 
 100 	/* This is the view currently shown. We use it to keep track of the
 101 	 * positions of the panes. range_selected is TRUE if a range of dates
 102 	 * was selected in the date navigator to show the view. */
 103 	ECalendarView    *views[GNOME_CAL_LAST_VIEW];
 104 	GnomeCalendarViewType current_view_type;
 105 
 106 	gboolean range_selected;
 107 
 108 	/* These are the saved positions of the panes. They are multiples of
 109 	 * calendar month widths & heights in the date navigator, so that they
 110 	 * will work OK after theme changes. */
 111 	gint	     hpane_pos;
 112 	gint	     hpane_pos_month_view;
 113 
 114 	/* The signal handler id for our GtkCalendar "day_selected" handler. */
 115 	guint	     day_selected_id;
 116 
 117 	/* The dates currently shown. If they are -1 then we have no dates
 118 	 * shown. We only use these to check if we need to emit a
 119 	 * 'dates-shown-changed' signal.*/
 120 	time_t visible_start;
 121 	time_t visible_end;
 122 	gboolean updating;
 123 
 124 	/* If this is true, list view uses range of showing the events
 125 	 * as the dates selected in date navigator which is one month,
 126 	 * else it uses the date range set in search bar. */
 127 	gboolean lview_select_daten_range;
 128 
 129 	/* Used in update_todo_view, to prevent interleaving when
 130 	 * called in separate thread. */
 131 	GMutex *todo_update_lock;
 132 
 133 	GCancellable *cancellable;
 134 };
 135 
 136 enum {
 137 	PROP_0,
 138 	PROP_DATE_NAVIGATOR,
 139 	PROP_MEMO_TABLE,
 140 	PROP_REGISTRY,
 141 	PROP_TASK_TABLE,
 142 	PROP_VIEW
 143 };
 144 
 145 enum {
 146 	DATES_SHOWN_CHANGED,
 147 	CALENDAR_SELECTION_CHANGED,
 148 	GOTO_DATE,
 149 	SOURCE_ADDED,
 150 	SOURCE_REMOVED,
 151 	CHANGE_VIEW,
 152 	LAST_SIGNAL
 153 };
 154 
 155 static guint signals[LAST_SIGNAL];
 156 
 157 static void gnome_calendar_do_dispose (GObject *object);
 158 static void gnome_calendar_finalize   (GObject *object);
 159 static void gnome_calendar_goto_date (GnomeCalendar *gcal,
 160 				      GnomeCalendarGotoDateType goto_date);
 161 
 162 static void gnome_calendar_update_date_navigator (GnomeCalendar *gcal);
 163 
 164 static void update_todo_view (GnomeCalendar *gcal);
 165 static void update_memo_view (GnomeCalendar *gcal);
 166 
 167 /* Simple asynchronous message dispatcher */
 168 typedef struct _Message Message;
 169 typedef void (*MessageFunc) (Message *msg);
 170 
 171 struct _Message {
 172 	MessageFunc func;
 173 	GSourceFunc done;
 174 };
 175 
 176 static void
 177 message_proxy (Message *msg)
 178 {
 179 	g_return_if_fail (msg->func != NULL);
 180 
 181 	msg->func (msg);
 182 	if (msg->done)
 183 		g_idle_add (msg->done, msg);
 184 }
 185 
 186 static gpointer
 187 create_thread_pool (void)
 188 {
 189 	/* once created, run forever */
 190 	return g_thread_pool_new ((GFunc) message_proxy, NULL, 1, FALSE, NULL);
 191 }
 192 
 193 static void
 194 message_push (Message *msg)
 195 {
 196 	static GOnce once = G_ONCE_INIT;
 197 
 198 	g_once (&once, (GThreadFunc) create_thread_pool, NULL);
 199 
 200 	g_thread_pool_push ((GThreadPool *) once.retval, msg, NULL);
 201 }
 202 
 203 G_DEFINE_TYPE (GnomeCalendar, gnome_calendar, G_TYPE_OBJECT)
 204 
 205 static void
 206 gcal_update_status_message (GnomeCalendar *gcal,
 207                             const gchar *message,
 208                             gdouble percent)
 209 {
 210 	ECalModel *model;
 211 
 212 	g_return_if_fail (gcal != NULL);
 213 
 214 	model = gnome_calendar_get_model (gcal);
 215 	g_return_if_fail (model != NULL);
 216 
 217 	e_cal_model_update_status_message (model, message, percent);
 218 }
 219 
 220 static void
 221 update_adjustment (GnomeCalendar *gcal,
 222                    GtkAdjustment *adjustment,
 223                    EWeekView *week_view)
 224 {
 225 	GDate date;
 226 	ECalModel *model;
 227 	gint week_offset;
 228 	struct icaltimetype start_tt = icaltime_null_time ();
 229 	time_t lower;
 230 	guint32 old_first_day_julian, new_first_day_julian;
 231 	icaltimezone *timezone;
 232 	gdouble value;
 233 
 234 	/* If we don't have a valid date set yet, just return. */
 235 	if (!g_date_valid (&week_view->first_day_shown))
 236 		return;
 237 
 238 	value = gtk_adjustment_get_value (adjustment);
 239 
 240 	/* Determine the first date shown. */
 241 	date = week_view->base_date;
 242 	week_offset = floor (value + 0.5);
 243 	g_date_add_days (&date, week_offset * 7);
 244 
 245 	/* Convert the old & new first days shown to julian values. */
 246 	old_first_day_julian = g_date_get_julian (&week_view->first_day_shown);
 247 	new_first_day_julian = g_date_get_julian (&date);
 248 
 249 	/* If we are already showing the date, just return. */
 250 	if (old_first_day_julian == new_first_day_julian)
 251 		return;
 252 
 253 	/* Convert it to a time_t. */
 254 	start_tt.year = g_date_get_year (&date);
 255 	start_tt.month = g_date_get_month (&date);
 256 	start_tt.day = g_date_get_day (&date);
 257 
 258 	model = gnome_calendar_get_model (gcal);
 259 	timezone = e_cal_model_get_timezone (model);
 260 	lower = icaltime_as_timet_with_zone (start_tt, timezone);
 261 
 262 	e_week_view_set_update_base_date (week_view, FALSE);
 263 	gnome_calendar_set_selected_time_range (gcal, lower);
 264 	e_week_view_set_update_base_date (week_view, TRUE);
 265 }
 266 
 267 static void
 268 week_view_adjustment_changed_cb (GtkAdjustment *adjustment,
 269                                  GnomeCalendar *gcal)
 270 {
 271 	ECalendarView *view;
 272 
 273 	view = gnome_calendar_get_calendar_view (gcal, GNOME_CAL_WEEK_VIEW);
 274 	update_adjustment (gcal, adjustment, E_WEEK_VIEW (view));
 275 }
 276 
 277 static void
 278 month_view_adjustment_changed_cb (GtkAdjustment *adjustment,
 279                                   GnomeCalendar *gcal)
 280 {
 281 	ECalendarView *view;
 282 
 283 	view = gnome_calendar_get_calendar_view (gcal, GNOME_CAL_MONTH_VIEW);
 284 	update_adjustment (gcal, adjustment, E_WEEK_VIEW (view));
 285 }
 286 
 287 static void
 288 view_selection_changed_cb (GnomeCalendar *gcal)
 289 {
 290 	g_signal_emit (gcal, signals[CALENDAR_SELECTION_CHANGED], 0);
 291 }
 292 
 293 static void
 294 view_progress_cb (ECalModel *model,
 295                   const gchar *message,
 296                   gint percent,
 297                   ECalClientSourceType type,
 298                   GnomeCalendar *gcal)
 299 {
 300 	gcal_update_status_message (gcal, message, percent);
 301 }
 302 
 303 static void
 304 view_complete_cb (ECalModel *model,
 305                   const GError *error,
 306                   ECalClientSourceType type,
 307                   GnomeCalendar *gcal)
 308 {
 309 	gcal_update_status_message (gcal, NULL, -1);
 310 }
 311 
 312 static void
 313 gnome_calendar_notify_week_start_day_cb (GnomeCalendar *gcal)
 314 {
 315 	time_t start_time;
 316 
 317 	start_time = gcal->priv->base_view_time;
 318 	gnome_calendar_set_selected_time_range (gcal, start_time);
 319 }
 320 
 321 static void
 322 gnome_calendar_update_time_range (GnomeCalendar *gcal)
 323 {
 324 	time_t start_time;
 325 
 326 	start_time = gcal->priv->base_view_time;
 327 	gnome_calendar_set_selected_time_range (gcal, start_time);
 328 }
 329 
 330 static void
 331 gnome_calendar_set_registry (GnomeCalendar *gcal,
 332                              ESourceRegistry *registry)
 333 {
 334 	g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
 335 	g_return_if_fail (gcal->priv->registry == NULL);
 336 
 337 	gcal->priv->registry = g_object_ref (registry);
 338 }
 339 
 340 static void
 341 gnome_calendar_set_property (GObject *object,
 342                              guint property_id,
 343                              const GValue *value,
 344                              GParamSpec *pspec)
 345 {
 346 	switch (property_id) {
 347 		case PROP_DATE_NAVIGATOR:
 348 			gnome_calendar_set_date_navigator (
 349 				GNOME_CALENDAR (object),
 350 				g_value_get_object (value));
 351 			return;
 352 
 353 		case PROP_MEMO_TABLE:
 354 			gnome_calendar_set_memo_table (
 355 				GNOME_CALENDAR (object),
 356 				g_value_get_object (value));
 357 			return;
 358 
 359 		case PROP_REGISTRY:
 360 			gnome_calendar_set_registry (
 361 				GNOME_CALENDAR (object),
 362 				g_value_get_object (value));
 363 			return;
 364 
 365 		case PROP_TASK_TABLE:
 366 			gnome_calendar_set_task_table (
 367 				GNOME_CALENDAR (object),
 368 				g_value_get_object (value));
 369 			return;
 370 
 371 		case PROP_VIEW:
 372 			gnome_calendar_set_view (
 373 				GNOME_CALENDAR (object),
 374 				g_value_get_int (value));
 375 			return;
 376 	}
 377 
 378 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 379 }
 380 
 381 static void
 382 gnome_calendar_get_property (GObject *object,
 383                              guint property_id,
 384                              GValue *value,
 385                              GParamSpec *pspec)
 386 {
 387 	switch (property_id) {
 388 		case PROP_DATE_NAVIGATOR:
 389 			g_value_set_object (
 390 				value, gnome_calendar_get_date_navigator (
 391 				GNOME_CALENDAR (object)));
 392 			return;
 393 
 394 		case PROP_MEMO_TABLE:
 395 			g_value_set_object (
 396 				value, gnome_calendar_get_memo_table (
 397 				GNOME_CALENDAR (object)));
 398 			return;
 399 
 400 		case PROP_REGISTRY:
 401 			g_value_set_object (
 402 				value, gnome_calendar_get_registry (
 403 				GNOME_CALENDAR (object)));
 404 			return;
 405 
 406 		case PROP_TASK_TABLE:
 407 			g_value_set_object (
 408 				value, gnome_calendar_get_task_table (
 409 				GNOME_CALENDAR (object)));
 410 			return;
 411 
 412 		case PROP_VIEW:
 413 			g_value_set_int (
 414 				value, gnome_calendar_get_view (
 415 				GNOME_CALENDAR (object)));
 416 			return;
 417 	}
 418 
 419 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 420 }
 421 
 422 static void
 423 gnome_calendar_constructed (GObject *object)
 424 {
 425 	GnomeCalendar *gcal = GNOME_CALENDAR (object);
 426 	ECalendarView *calendar_view;
 427 	ESourceRegistry *registry;
 428 	ECalModel *model;
 429 	GtkAdjustment *adjustment;
 430 
 431 	registry = gnome_calendar_get_registry (gcal);
 432 
 433 	/* Create the model for the views. */
 434 	model = e_cal_model_calendar_new (registry);
 435 	e_cal_model_set_flags (model, E_CAL_MODEL_FLAGS_EXPAND_RECURRENCES);
 436 	gcal->priv->model = model;
 437 
 438 	g_signal_connect (
 439 		model, "cal-view-progress",
 440 		G_CALLBACK (view_progress_cb), gcal);
 441 
 442 	g_signal_connect (
 443 		model, "cal-view-complete",
 444 		G_CALLBACK (view_complete_cb), gcal);
 445 
 446 	/* Day View */
 447 	calendar_view = e_day_view_new (model);
 448 	e_calendar_view_set_calendar (calendar_view, gcal);
 449 	gcal->priv->views[GNOME_CAL_DAY_VIEW] = calendar_view;
 450 	g_object_ref_sink (calendar_view);
 451 
 452 	g_signal_connect_swapped (
 453 		calendar_view, "selection-changed",
 454 		G_CALLBACK (view_selection_changed_cb), gcal);
 455 
 456 	/* Work Week View */
 457 	calendar_view = e_day_view_new (model);
 458 	e_day_view_set_work_week_view (E_DAY_VIEW (calendar_view), TRUE);
 459 	e_day_view_set_days_shown (E_DAY_VIEW (calendar_view), 5);
 460 	e_calendar_view_set_calendar (calendar_view, gcal);
 461 	gcal->priv->views[GNOME_CAL_WORK_WEEK_VIEW] = calendar_view;
 462 	g_object_ref_sink (calendar_view);
 463 
 464 	g_signal_connect_swapped (
 465 		calendar_view, "notify::working-days",
 466 		G_CALLBACK (gnome_calendar_update_time_range), gcal);
 467 
 468 	/* Week View */
 469 	calendar_view = e_week_view_new (model);
 470 	e_calendar_view_set_calendar (calendar_view, gcal);
 471 	gcal->priv->views[GNOME_CAL_WEEK_VIEW] = calendar_view;
 472 	g_object_ref_sink (calendar_view);
 473 
 474 	g_signal_connect_swapped (
 475 		calendar_view, "selection-changed",
 476 		G_CALLBACK (view_selection_changed_cb), gcal);
 477 
 478 	adjustment = gtk_range_get_adjustment (
 479 		GTK_RANGE (E_WEEK_VIEW (calendar_view)->vscrollbar));
 480 	g_signal_connect (
 481 		adjustment, "value-changed",
 482 		G_CALLBACK (week_view_adjustment_changed_cb), gcal);
 483 
 484 	/* Month View */
 485 	calendar_view = e_month_view_new (model);
 486 	e_week_view_set_multi_week_view (E_WEEK_VIEW (calendar_view), TRUE);
 487 	e_week_view_set_weeks_shown (E_WEEK_VIEW (calendar_view), 6);
 488 	e_calendar_view_set_calendar (calendar_view, gcal);
 489 	gcal->priv->views[GNOME_CAL_MONTH_VIEW] = calendar_view;
 490 	g_object_ref_sink (calendar_view);
 491 
 492 	g_signal_connect_swapped (
 493 		calendar_view, "selection-changed",
 494 		G_CALLBACK (view_selection_changed_cb), gcal);
 495 
 496 	adjustment = gtk_range_get_adjustment (
 497 		GTK_RANGE (E_WEEK_VIEW (calendar_view)->vscrollbar));
 498 	g_signal_connect (
 499 		adjustment, "value-changed",
 500 		G_CALLBACK (month_view_adjustment_changed_cb), gcal);
 501 
 502 	/* List View */
 503 	calendar_view = e_cal_list_view_new (model);
 504 	e_calendar_view_set_calendar (calendar_view, gcal);
 505 	gcal->priv->views[GNOME_CAL_LIST_VIEW] = calendar_view;
 506 	g_object_ref_sink (calendar_view);
 507 
 508 	g_signal_connect_swapped (
 509 		calendar_view, "selection-changed",
 510 		G_CALLBACK (view_selection_changed_cb), gcal);
 511 
 512 	g_signal_connect_swapped (
 513 		model, "notify::week-start-day",
 514 		G_CALLBACK (gnome_calendar_notify_week_start_day_cb), gcal);
 515 
 516 	gnome_calendar_goto_today (gcal);
 517 
 518 	/* Chain up to parent's constructed() method. */
 519 	G_OBJECT_CLASS (gnome_calendar_parent_class)->constructed (object);
 520 }
 521 
 522 /* Class initialization function for the gnome calendar */
 523 static void
 524 gnome_calendar_class_init (GnomeCalendarClass *class)
 525 {
 526 	GObjectClass *object_class;
 527 	GtkBindingSet *binding_set;
 528 
 529 	g_type_class_add_private (class, sizeof (GnomeCalendarPrivate));
 530 
 531 	object_class = G_OBJECT_CLASS (class);
 532 	object_class->set_property = gnome_calendar_set_property;
 533 	object_class->get_property = gnome_calendar_get_property;
 534 	object_class->constructed = gnome_calendar_constructed;
 535 	object_class->dispose = gnome_calendar_do_dispose;
 536 	object_class->finalize = gnome_calendar_finalize;
 537 
 538 	class->dates_shown_changed = NULL;
 539 	class->calendar_selection_changed = NULL;
 540 	class->source_added = NULL;
 541 	class->source_removed = NULL;
 542 	class->goto_date = gnome_calendar_goto_date;
 543 	class->change_view = gnome_calendar_set_view;
 544 
 545 	g_object_class_install_property (
 546 		object_class,
 547 		PROP_DATE_NAVIGATOR,
 548 		g_param_spec_object (
 549 			"date-navigator",
 550 			"Date Navigator",
 551 			NULL,
 552 			E_TYPE_CALENDAR,
 553 			G_PARAM_READWRITE));
 554 
 555 	g_object_class_install_property (
 556 		object_class,
 557 		PROP_MEMO_TABLE,
 558 		g_param_spec_object (
 559 			"memo-table",
 560 			"Memo table",
 561 			NULL,
 562 			E_TYPE_MEMO_TABLE,
 563 			G_PARAM_READWRITE));
 564 
 565 	g_object_class_install_property (
 566 		object_class,
 567 		PROP_REGISTRY,
 568 		g_param_spec_object (
 569 			"registry",
 570 			"Registry",
 571 			"Data source registry",
 572 			E_TYPE_SOURCE_REGISTRY,
 573 			G_PARAM_READWRITE |
 574 			G_PARAM_CONSTRUCT_ONLY |
 575 			G_PARAM_STATIC_STRINGS));
 576 
 577 	g_object_class_install_property (
 578 		object_class,
 579 		PROP_TASK_TABLE,
 580 		g_param_spec_object (
 581 			"task-table",
 582 			"Task table",
 583 			NULL,
 584 			E_TYPE_TASK_TABLE,
 585 			G_PARAM_READWRITE));
 586 
 587 	g_object_class_install_property (
 588 		object_class,
 589 		PROP_VIEW,
 590 		g_param_spec_int (
 591 			"view",
 592 			"View",
 593 			NULL,
 594 			GNOME_CAL_DAY_VIEW,
 595 			GNOME_CAL_LIST_VIEW,
 596 			GNOME_CAL_DAY_VIEW,
 597 			G_PARAM_READWRITE));
 598 
 599 	signals[DATES_SHOWN_CHANGED] = g_signal_new (
 600 		"dates_shown_changed",
 601 		G_TYPE_FROM_CLASS (object_class),
 602 		G_SIGNAL_RUN_LAST,
 603 		G_STRUCT_OFFSET (GnomeCalendarClass, dates_shown_changed),
 604 		NULL, NULL,
 605 		g_cclosure_marshal_VOID__VOID,
 606 		G_TYPE_NONE, 0);
 607 
 608 	signals[CALENDAR_SELECTION_CHANGED] = g_signal_new (
 609 		"calendar_selection_changed",
 610 		G_TYPE_FROM_CLASS (object_class),
 611 		G_SIGNAL_RUN_LAST,
 612 		G_STRUCT_OFFSET (GnomeCalendarClass, calendar_selection_changed),
 613 		NULL, NULL,
 614 		g_cclosure_marshal_VOID__VOID,
 615 		G_TYPE_NONE, 0);
 616 
 617 	signals[SOURCE_ADDED] = g_signal_new (
 618 		"source_added",
 619 		G_TYPE_FROM_CLASS (object_class),
 620 		G_SIGNAL_RUN_FIRST,
 621 		G_STRUCT_OFFSET (GnomeCalendarClass, source_added),
 622 		NULL, NULL,
 623 		e_marshal_VOID__INT_OBJECT,
 624 		G_TYPE_NONE, 2,
 625 		G_TYPE_INT,
 626 		G_TYPE_OBJECT);
 627 
 628 	signals[SOURCE_REMOVED] = g_signal_new (
 629 		"source_removed",
 630 		G_TYPE_FROM_CLASS (object_class),
 631 		G_SIGNAL_RUN_FIRST,
 632 		G_STRUCT_OFFSET (GnomeCalendarClass, source_removed),
 633 		NULL, NULL,
 634 		e_marshal_VOID__INT_OBJECT,
 635 		G_TYPE_NONE, 2,
 636 		G_TYPE_INT,
 637 		G_TYPE_OBJECT);
 638 
 639 	signals[GOTO_DATE] = g_signal_new (
 640 		"goto_date",
 641 		G_TYPE_FROM_CLASS (object_class),
 642 		G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
 643 		G_STRUCT_OFFSET (GnomeCalendarClass, goto_date),
 644 		NULL, NULL,
 645 		g_cclosure_marshal_VOID__INT,
 646 		G_TYPE_NONE, 1,
 647 		G_TYPE_INT);
 648 
 649 	signals[CHANGE_VIEW] = g_signal_new (
 650 		"change_view",
 651 		G_TYPE_FROM_CLASS (object_class),
 652 		G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
 653 		G_STRUCT_OFFSET (GnomeCalendarClass, change_view),
 654 		NULL, NULL,
 655 		g_cclosure_marshal_VOID__INT,
 656 		G_TYPE_NONE, 1,
 657 		G_TYPE_INT);
 658 
 659 	/*
 660 	 * Key bindings
 661 	 */
 662 
 663 	binding_set = gtk_binding_set_new (G_OBJECT_CLASS_NAME (class));
 664 
 665 	/* Alt+PageUp/PageDown, go to the first/last day of the month */
 666 	gtk_binding_entry_add_signal (
 667 		binding_set, GDK_KEY_Page_Up,
 668 		GDK_MOD1_MASK,
 669 		"goto_date", 1,
 670 		G_TYPE_ENUM,
 671 		GNOME_CAL_GOTO_FIRST_DAY_OF_MONTH);
 672 	gtk_binding_entry_add_signal (
 673 		binding_set, GDK_KEY_KP_Page_Up,
 674 		GDK_MOD1_MASK,
 675 		"goto_date", 1,
 676 		G_TYPE_ENUM,
 677 		GNOME_CAL_GOTO_FIRST_DAY_OF_MONTH);
 678 	gtk_binding_entry_add_signal (
 679 		binding_set, GDK_KEY_Page_Down,
 680 		GDK_MOD1_MASK,
 681 		"goto_date", 1,
 682 		G_TYPE_ENUM,
 683 		GNOME_CAL_GOTO_LAST_DAY_OF_MONTH);
 684 	gtk_binding_entry_add_signal (
 685 		binding_set, GDK_KEY_KP_Page_Down,
 686 		GDK_MOD1_MASK,
 687 		"goto_date", 1,
 688 		G_TYPE_ENUM,
 689 		GNOME_CAL_GOTO_LAST_DAY_OF_MONTH);
 690 
 691 	/* Alt+Home/End, go to the first/last day of the week */
 692 	gtk_binding_entry_add_signal (
 693 		binding_set, GDK_KEY_Home,
 694 		GDK_MOD1_MASK,
 695 		"goto_date", 1,
 696 		G_TYPE_ENUM,
 697 		GNOME_CAL_GOTO_FIRST_DAY_OF_WEEK);
 698 	gtk_binding_entry_add_signal (
 699 		binding_set, GDK_KEY_End,
 700 		GDK_MOD1_MASK,
 701 		"goto_date", 1,
 702 		G_TYPE_ENUM,
 703 		GNOME_CAL_GOTO_LAST_DAY_OF_WEEK);
 704 	gtk_binding_entry_add_signal (
 705 		binding_set, GDK_KEY_KP_Home,
 706 		GDK_MOD1_MASK,
 707 		"goto_date", 1,
 708 		G_TYPE_ENUM,
 709 		GNOME_CAL_GOTO_FIRST_DAY_OF_WEEK);
 710 	gtk_binding_entry_add_signal (
 711 		binding_set, GDK_KEY_KP_End,
 712 		GDK_MOD1_MASK,
 713 		"goto_date", 1,
 714 		G_TYPE_ENUM,
 715 		GNOME_CAL_GOTO_LAST_DAY_OF_WEEK);
 716 
 717 	/*Alt+Left/Right, go to the same day of the previous/next week*/
 718 	gtk_binding_entry_add_signal (
 719 		binding_set,GDK_KEY_Left,
 720 		GDK_MOD1_MASK,
 721 		"goto_date",1,
 722 		G_TYPE_ENUM,
 723 		GNOME_CAL_GOTO_SAME_DAY_OF_PREVIOUS_WEEK);
 724 	gtk_binding_entry_add_signal (
 725 		binding_set,GDK_KEY_KP_Left,
 726 		GDK_MOD1_MASK,
 727 		"goto_date",1,
 728 		G_TYPE_ENUM,
 729 		GNOME_CAL_GOTO_SAME_DAY_OF_PREVIOUS_WEEK);
 730 	gtk_binding_entry_add_signal (
 731 		binding_set,GDK_KEY_Right,
 732 		GDK_MOD1_MASK,
 733 		"goto_date",1,
 734 		G_TYPE_ENUM,
 735 		GNOME_CAL_GOTO_SAME_DAY_OF_NEXT_WEEK);
 736 	gtk_binding_entry_add_signal (
 737 		binding_set,GDK_KEY_KP_Right,
 738 		GDK_MOD1_MASK,
 739 		"goto_date",1,
 740 		G_TYPE_ENUM,
 741 		GNOME_CAL_GOTO_SAME_DAY_OF_NEXT_WEEK);
 742 
 743 	/* Ctrl+Y/J/K/M/L to switch between
 744 	 * DayView/WorkWeekView/WeekView/MonthView/ListView */
 745 	gtk_binding_entry_add_signal (
 746 		binding_set, GDK_KEY_y,
 747 		GDK_CONTROL_MASK,
 748 		"change_view", 1,
 749 		G_TYPE_ENUM,
 750 		GNOME_CAL_DAY_VIEW);
 751 	gtk_binding_entry_add_signal (
 752 		binding_set, GDK_KEY_j,
 753 		GDK_CONTROL_MASK,
 754 		"change_view", 1,
 755 		G_TYPE_ENUM,
 756 		GNOME_CAL_WORK_WEEK_VIEW);
 757 	gtk_binding_entry_add_signal (
 758 		binding_set, GDK_KEY_k,
 759 		GDK_CONTROL_MASK,
 760 		"change_view", 1,
 761 		G_TYPE_ENUM,
 762 		GNOME_CAL_WEEK_VIEW);
 763 	gtk_binding_entry_add_signal (
 764 		binding_set, GDK_KEY_m,
 765 		GDK_CONTROL_MASK,
 766 		"change_view", 1,
 767 		G_TYPE_ENUM,
 768 		GNOME_CAL_MONTH_VIEW);
 769 	gtk_binding_entry_add_signal (
 770 		binding_set, GDK_KEY_l,
 771 		GDK_CONTROL_MASK,
 772 		"change_view", 1,
 773 		G_TYPE_ENUM,
 774 		GNOME_CAL_LIST_VIEW);
 775 
 776 	/* init the accessibility support for gnome_calendar */
 777 	gnome_calendar_a11y_init ();
 778 
 779 }
 780 
 781 /* We do this check since the calendar items are downloaded from the server
 782  * in the open_method, since the default timezone might not be set there. */
 783 static void
 784 ensure_dates_are_in_default_zone (GnomeCalendar *gcal,
 785                                   icalcomponent *icalcomp)
 786 {
 787 	ECalModel *model;
 788 	icaltimezone *timezone;
 789 	icaltimetype dt;
 790 
 791 	model = gnome_calendar_get_model (gcal);
 792 	timezone = e_cal_model_get_timezone (model);
 793 
 794 	if (timezone == NULL)
 795 		return;
 796 
 797 	dt = icalcomponent_get_dtstart (icalcomp);
 798 	if (dt.is_utc) {
 799 		dt = icaltime_convert_to_zone (dt, timezone);
 800 		icalcomponent_set_dtstart (icalcomp, dt);
 801 	}
 802 
 803 	dt = icalcomponent_get_dtend (icalcomp);
 804 	if (dt.is_utc) {
 805 		dt = icaltime_convert_to_zone (dt, timezone);
 806 		icalcomponent_set_dtend (icalcomp, dt);
 807 	}
 808 }
 809 
 810 /* Callback used when the calendar query reports of an updated object */
 811 static void
 812 dn_client_view_objects_added_cb (ECalClientView *view,
 813                                  const GSList *objects,
 814                                  gpointer data)
 815 {
 816 	GnomeCalendar *gcal;
 817 	GnomeCalendarPrivate *priv;
 818 	const GSList *l;
 819 
 820 	gcal = GNOME_CALENDAR (data);
 821 	priv = gcal->priv;
 822 
 823 	for (l = objects; l; l = l->next) {
 824 		ECalComponent *comp = NULL;
 825 
 826 		ensure_dates_are_in_default_zone (gcal, l->data);
 827 		comp = e_cal_component_new ();
 828 		if (!e_cal_component_set_icalcomponent (
 829 			comp, icalcomponent_new_clone (l->data))) {
 830 			g_object_unref (comp);
 831 			continue;
 832 		}
 833 
 834 		tag_calendar_by_comp (
 835 			priv->date_navigator, comp,
 836 			e_cal_client_view_get_client (view),
 837 			NULL, FALSE, TRUE, TRUE, priv->cancellable);
 838 		g_object_unref (comp);
 839 	}
 840 }
 841 
 842 static void
 843 dn_client_view_objects_modified_cb (ECalClientView *view,
 844                                     const GSList *objects,
 845                                     gpointer data)
 846 {
 847 	GnomeCalendar *gcal;
 848 
 849 	gcal = GNOME_CALENDAR (data);
 850 
 851 	/* We have to retag the whole thing: an event may change dates
 852 	 * and the tag_calendar_by_comp() below would not know how to
 853 	 * untag the old dates. */
 854 	gnome_calendar_update_query (gcal);
 855 }
 856 
 857 /* Callback used when the calendar query reports of a removed object */
 858 static void
 859 dn_client_view_objects_removed_cb (ECalClientView *view,
 860                                    const GSList *ids,
 861                                    gpointer data)
 862 {
 863 	GnomeCalendar *gcal;
 864 
 865 	gcal = GNOME_CALENDAR (data);
 866 
 867 	/* Just retag the whole thing */
 868 	gnome_calendar_update_query (gcal);
 869 }
 870 
 871 /* Callback used when the calendar query is done */
 872 static void
 873 dn_client_view_complete_cb (ECalClientView *query,
 874                             const GError *error,
 875                             gpointer data)
 876 {
 877 	/* FIXME Better error reporting */
 878 	if (error != NULL)
 879 		g_warning (
 880 			"%s: Query did not complete successfully: %s",
 881 			G_STRFUNC, error->message);
 882 }
 883 
 884 ECalendarView *
 885 gnome_calendar_get_calendar_view (GnomeCalendar *gcal,
 886                                   GnomeCalendarViewType view_type)
 887 {
 888 	g_return_val_if_fail (GNOME_IS_CALENDAR (gcal), NULL);
 889 	g_return_val_if_fail (view_type < GNOME_CAL_LAST_VIEW, NULL);
 890 
 891 	return gcal->priv->views[view_type];
 892 }
 893 
 894 static void
 895 get_times_for_views (GnomeCalendar *gcal,
 896                      GnomeCalendarViewType view_type,
 897                      time_t *start_time,
 898                      time_t *end_time,
 899                      time_t *select_time)
 900 {
 901 	GnomeCalendarPrivate *priv;
 902 	ECalModel *model;
 903 	EDayView *day_view;
 904 	EWeekView *week_view;
 905 	gint shown, display_start;
 906 	GDate date;
 907 	gint week_start_day;
 908 	gint weekday, first_day, last_day, days_shown, i;
 909 	gboolean has_working_days = FALSE;
 910 	guint offset;
 911 	struct icaltimetype tt = icaltime_null_time ();
 912 	icaltimezone *timezone;
 913 	gboolean range_selected;
 914 
 915 	model = gnome_calendar_get_model (gcal);
 916 	range_selected = gnome_calendar_get_range_selected (gcal);
 917 
 918 	timezone = e_cal_model_get_timezone (model);
 919 	week_start_day = e_cal_model_get_week_start_day (model);
 920 
 921 	priv = gcal->priv;
 922 
 923 	switch (view_type) {
 924 	case GNOME_CAL_DAY_VIEW:
 925 		day_view = E_DAY_VIEW (priv->views[view_type]);
 926 		shown  = e_day_view_get_days_shown (day_view);
 927 		*start_time = time_day_begin_with_zone (*start_time, timezone);
 928 		*end_time = time_add_day_with_zone (*start_time, shown, timezone);
 929 		break;
 930 	case GNOME_CAL_WORK_WEEK_VIEW:
 931 		/* FIXME Kind of gross, but it works */
 932 		day_view = E_DAY_VIEW (priv->views[view_type]);
 933 		time_to_gdate_with_zone (&date, *start_time, timezone);
 934 
 935 		/* The start of the work-week is the first working day after the
 936 		 * week start day. */
 937 
 938 		/* Get the weekday corresponding to start_time, 0 (Mon) to 6 (Sun). */
 939 		weekday = (g_date_get_weekday (&date) + 6) % 7;
 940 
 941 		/* Find the first working day in the week, 0 (Mon) to 6 (Sun). */
 942 		first_day = week_start_day % 7;
 943 		for (i = 0; i < 7; i++) {
 944 			/* the working_days has stored 0 (Sun) to 6 (Sat) */
 945 			if (day_view->working_days & (1 << ((first_day + 1) % 7))) {
 946 				has_working_days = TRUE;
 947 				break;
 948 			}
 949 			first_day = (first_day + 1) % 7;
 950 		}
 951 
 952 		if (has_working_days) {
 953 			/* Now find the last working day of the week, backwards. */
 954 			last_day = (first_day + 6) % 7;
 955 			for (i = 0; i < 7; i++) {
 956 				/* the working_days has stored 0 (Sun) to 6 (Sat) */
 957 				if (day_view->working_days & (1 << ((last_day + 1) % 7)))
 958 					break;
 959 				last_day = (last_day + 6) % 7;
 960 			}
 961 			/* Now calculate the days we need to show to include all the
 962 			 * working days in the week. Add 1 to make it inclusive. */
 963 			days_shown = (last_day + 7 - first_day) % 7 + 1;
 964 		} else {
 965 			/* If no working days are set, just use 7. */
 966 			days_shown = 7;
 967 		}
 968 
 969 		/* Calculate how many days we need to go back to the first workday. */
 970 		if (weekday < first_day) {
 971 			offset = (7 - first_day + weekday) % 7;
 972 		} else {
 973 			offset = (weekday - first_day) % 7;
 974 		}
 975 		if (offset)
 976 			g_date_subtract_days (&date, offset);
 977 
 978 		tt.year = g_date_get_year (&date);
 979 		tt.month = g_date_get_month (&date);
 980 		tt.day = g_date_get_day (&date);
 981 
 982 		*start_time = icaltime_as_timet_with_zone (tt, timezone);
 983 		*end_time = time_add_day_with_zone (*start_time, days_shown, timezone);
 984 
 985 		if (select_time && day_view->selection_start_day == -1)
 986 			time (select_time);
 987 		break;
 988 	case GNOME_CAL_WEEK_VIEW:
 989 		/* FIXME We should be using the same day
 990 		 *       of the week enum everywhere. */
 991 		week_view = E_WEEK_VIEW (priv->views[view_type]);
 992 		display_start = (week_view->display_start_day + 1) % 7;
 993 
 994 		*start_time = time_week_begin_with_zone (
 995 			*start_time, display_start, timezone);
 996 		*end_time = time_add_week_with_zone (
 997 			*start_time, 1, timezone);
 998 
 999 		if (select_time && week_view->selection_start_day == -1)
1000 			time (select_time);
1001 		break;
1002 	case GNOME_CAL_MONTH_VIEW:
1003 		/* FIXME We should be using the same day
1004 		 *       of the week enum everywhere. */
1005 		week_view = E_WEEK_VIEW (priv->views[view_type]);
1006 		shown = e_week_view_get_weeks_shown (week_view);
1007 		display_start = (week_view->display_start_day + 1) % 7;
1008 
1009 		if (!range_selected && (
1010 			!week_view->multi_week_view ||
1011 			!week_view->month_scroll_by_week))
1012 			*start_time = time_month_begin_with_zone (
1013 				*start_time, timezone);
1014 		*start_time = time_week_begin_with_zone (
1015 			*start_time, display_start, timezone);
1016 		*end_time = time_add_week_with_zone (
1017 			*start_time, shown, timezone);
1018 
1019 		if (select_time && week_view->selection_start_day == -1)
1020 			time (select_time);
1021 		break;
1022 	case GNOME_CAL_LIST_VIEW:
1023 		/* FIXME What to do here? */
1024 		*start_time = time_month_begin_with_zone (*start_time, timezone);
1025 		*end_time = time_add_month_with_zone (*start_time, 1, timezone);
1026 		break;
1027 	default:
1028 		g_return_if_reached ();
1029 	}
1030 }
1031 
1032 /* Computes the range of time that the date navigator is showing */
1033 static void
1034 get_date_navigator_range (GnomeCalendar *gcal,
1035                           time_t *start_time,
1036                           time_t *end_time)
1037 {
1038 	ECalModel *model;
1039 	gint start_year, start_month, start_day;
1040 	gint end_year, end_month, end_day;
1041 	struct icaltimetype start_tt;
1042 	struct icaltimetype end_tt;
1043 	icaltimezone *timezone;
1044 
1045 	model = gnome_calendar_get_model (gcal);
1046 	timezone = e_cal_model_get_timezone (model);
1047 
1048 	start_tt = icaltime_null_time ();
1049 	end_tt = icaltime_null_time ();
1050 
1051 	if (!e_calendar_item_get_date_range (
1052 		gcal->priv->date_navigator->calitem,
1053 		&start_year, &start_month, &start_day,
1054 		&end_year, &end_month, &end_day)) {
1055 		*start_time = -1;
1056 		*end_time = -1;
1057 		return;
1058 	}
1059 
1060 	start_tt.year = start_year;
1061 	start_tt.month = start_month + 1;
1062 	start_tt.day = start_day;
1063 
1064 	end_tt.year = end_year;
1065 	end_tt.month = end_month + 1;
1066 	end_tt.day = end_day;
1067 
1068 	icaltime_adjust (&end_tt, 1, 0, 0, 0);
1069 
1070 	*start_time = icaltime_as_timet_with_zone (start_tt, timezone);
1071 	*end_time = icaltime_as_timet_with_zone (end_tt, timezone);
1072 }
1073 
1074 static const gchar *
1075 gcal_get_default_tzloc (GnomeCalendar *gcal)
1076 {
1077 	ECalModel *model;
1078 	icaltimezone *timezone;
1079 	const gchar *tzloc = NULL;
1080 
1081 	g_return_val_if_fail (gcal != NULL, "");
1082 
1083 	model = gnome_calendar_get_model (gcal);
1084 	timezone = e_cal_model_get_timezone (model);
1085 
1086 	if (timezone && timezone != icaltimezone_get_utc_timezone ())
1087 		tzloc = icaltimezone_get_location (timezone);
1088 
1089 	return tzloc ? tzloc : "";
1090 }
1091 
1092 /* Adjusts a given query sexp with the time range of the date navigator */
1093 static gchar *
1094 adjust_client_view_sexp (GnomeCalendar *gcal,
1095                          const gchar *sexp)
1096 {
1097 	time_t start_time, end_time;
1098 	gchar *start, *end;
1099 	gchar *new_sexp;
1100 
1101 	get_date_navigator_range (gcal, &start_time, &end_time);
1102 	if (start_time == -1 || end_time == -1)
1103 		return NULL;
1104 
1105 	start = isodate_from_time_t (start_time);
1106 	end = isodate_from_time_t (end_time);
1107 
1108 	if (sexp) {
1109 		new_sexp = g_strdup_printf (
1110 			"(and (occur-in-time-range? (make-time \"%s\") (make-time \"%s\") \"%s\") %s)",
1111 			start, end, gcal_get_default_tzloc (gcal), sexp);
1112 	} else {
1113 		new_sexp = g_strdup_printf (
1114 			"(occur-in-time-range? (make-time \"%s\") (make-time \"%s\") \"%s\")",
1115 			start, end, gcal_get_default_tzloc (gcal));
1116 	}
1117 
1118 	g_free (start);
1119 	g_free (end);
1120 
1121 	return new_sexp;
1122 }
1123 
1124 struct _date_query_msg {
1125 	Message header;
1126 	GnomeCalendar *gcal;
1127 };
1128 
1129 static void
1130 free_dn_queries (GnomeCalendar *gcal)
1131 {
1132 	GList *l;
1133 	GnomeCalendarPrivate *priv;
1134 
1135 	priv = gcal->priv;
1136 
1137 	g_mutex_lock (priv->dn_query_lock);
1138 
1139 	for (l = priv->dn_queries; l != NULL; l = l->next) {
1140 		if (!l->data)
1141 			continue;
1142 		g_signal_handlers_disconnect_matched (
1143 			l->data, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, gcal);
1144 		g_object_unref (l->data);
1145 	}
1146 
1147 	g_list_free (priv->dn_queries);
1148 	priv->dn_queries = NULL;
1149 
1150 	g_mutex_unlock (priv->dn_query_lock);
1151 }
1152 
1153 static void
1154 update_query_async (struct _date_query_msg *msg)
1155 {
1156 	GnomeCalendar *gcal = msg->gcal;
1157 	GnomeCalendarPrivate *priv;
1158 	ECalClientView *new_view;
1159 	gchar *real_sexp;
1160 	GList *list, *iter;
1161 
1162 	priv = gcal->priv;
1163 
1164 	/* free the previous queries */
1165 	free_dn_queries (gcal);
1166 
1167 	g_return_if_fail (priv->sexp != NULL);
1168 
1169 	real_sexp = adjust_client_view_sexp (gcal, priv->sexp);
1170 	if (!real_sexp) {
1171 		return; /* No time range is set, so don't start a query */
1172 	}
1173 
1174 	list = e_cal_model_get_client_list (priv->model);
1175 	g_list_foreach (list, (GFunc) g_object_ref, NULL);
1176 
1177 	/* create queries for each loaded client */
1178 	for (iter = list; iter != NULL; iter = iter->next) {
1179 		ECalClient *client = E_CAL_CLIENT (iter->data);
1180 		GError *error = NULL;
1181 		gint tries = 0;
1182 
1183 		/* don't create queries for clients not loaded yet */
1184 		if (!e_client_is_opened (E_CLIENT (client)))
1185 			continue;
1186 
1187  try_again:
1188 		new_view = NULL;
1189 		if (!e_cal_client_get_view_sync (client, real_sexp, &new_view, NULL, &error)) {
1190 			/* If calendar is busy try again for 3 times. */
1191 			if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_BUSY) && tries != 10) {
1192 				tries++;
1193 				/*TODO chose an optimal value */
1194 				g_usleep (500);
1195 
1196 				g_clear_error (&error);
1197 				goto try_again;
1198 			}
1199 
1200 			g_warning (G_STRLOC ": Could not create the view: %s ", error->message);
1201 			g_clear_error (&error);
1202 
1203 			continue;
1204 		}
1205 
1206 		g_signal_connect (
1207 			new_view, "objects-added",
1208 			G_CALLBACK (dn_client_view_objects_added_cb), gcal);
1209 		g_signal_connect (
1210 			new_view, "objects-modified",
1211 			G_CALLBACK (dn_client_view_objects_modified_cb), gcal);
1212 		g_signal_connect (
1213 			new_view, "objects-removed",
1214 			G_CALLBACK (dn_client_view_objects_removed_cb), gcal);
1215 		g_signal_connect (
1216 			new_view, "complete",
1217 			G_CALLBACK (dn_client_view_complete_cb), gcal);
1218 
1219 		g_mutex_lock (priv->dn_query_lock);
1220 		priv->dn_queries = g_list_append (priv->dn_queries, new_view);
1221 		e_cal_client_view_start (new_view, &error);
1222 		if (error != NULL) {
1223 			g_warning (
1224 				"%s: Failed to start view: %s",
1225 				G_STRFUNC, error->message);
1226 			g_clear_error (&error);
1227 		}
1228 		g_mutex_unlock (priv->dn_query_lock);
1229 	}
1230 
1231 	g_list_foreach (list, (GFunc) g_object_unref, NULL);
1232 	g_list_free (list);
1233 
1234 	/* free memory */
1235 	g_free (real_sexp);
1236 	update_todo_view (gcal);
1237 }
1238 
1239 static gboolean
1240 update_query_done (struct _date_query_msg *msg)
1241 {
1242 	g_object_unref (msg->gcal);
1243 	g_slice_free (struct _date_query_msg, msg);
1244 
1245 	return FALSE;
1246 }
1247 
1248 /* Restarts a query for the date navigator in the calendar */
1249 void
1250 gnome_calendar_update_query (GnomeCalendar *gcal)
1251 {
1252 	struct _date_query_msg *msg;
1253 
1254 	g_return_if_fail (GNOME_IS_CALENDAR (gcal));
1255 
1256 	e_calendar_item_clear_marks (gcal->priv->date_navigator->calitem);
1257 
1258 	msg = g_slice_new0 (struct _date_query_msg);
1259 	msg->header.func = (MessageFunc) update_query_async;
1260 	msg->header.done = (GSourceFunc) update_query_done;
1261 	msg->gcal = g_object_ref (gcal);
1262 
1263 	message_push ((Message *) msg);
1264 }
1265 
1266 void
1267 gnome_calendar_set_search_query (GnomeCalendar *gcal,
1268                                  const gchar *sexp,
1269                                  gboolean range_search,
1270                                  time_t start_range,
1271                                  time_t end_range)
1272 {
1273 	GnomeCalendarPrivate *priv;
1274 	ECalModel *model;
1275 	gint i;
1276 	time_t start, end;
1277 
1278 	g_return_if_fail (GNOME_IS_CALENDAR (gcal));
1279 	g_return_if_fail (sexp != NULL);
1280 
1281 	priv = gcal->priv;
1282 
1283 	model = gnome_calendar_get_model (gcal);
1284 
1285 	/* Set the query on the date navigator */
1286 
1287 	g_free (priv->sexp);
1288 	priv->sexp = g_strdup (sexp);
1289 
1290 	priv->lview_select_daten_range = !range_search;
1291 	start = start_range;
1292 	end = end_range;
1293 
1294 	d (g_print ("Changing the queries %s \n", sexp));
1295 
1296 	gnome_calendar_update_query (gcal);
1297 
1298 	i = priv->current_view_type;
1299 
1300 	/* Set the query on the views */
1301 	if (i == GNOME_CAL_LIST_VIEW && !priv->lview_select_daten_range) {
1302 		start = priv->base_view_time;
1303 		get_times_for_views (gcal, GNOME_CAL_LIST_VIEW, &start, &end, NULL);
1304 
1305 		e_cal_model_set_search_query_with_time_range (
1306 			model, sexp, start, end);
1307 
1308 		if (priv->current_view_type == GNOME_CAL_LIST_VIEW)
1309 			gnome_calendar_update_date_navigator (gcal);
1310 	} else
1311 		e_cal_model_set_search_query (model, sexp);
1312 }
1313 
1314 struct _mupdate_todo_msg {
1315 	Message header;
1316 	GnomeCalendar *gcal;
1317 };
1318 
1319 static void
1320 update_todo_view_async (struct _mupdate_todo_msg *msg)
1321 {
1322 	GnomeCalendar *gcal;
1323 	GnomeCalendarPrivate *priv;
1324 	ECalModel *model;
1325 	gchar *sexp = NULL;
1326 
1327 	g_return_if_fail (msg != NULL);
1328 
1329 	gcal = msg->gcal;
1330 	priv = gcal->priv;
1331 
1332 	g_return_if_fail (priv->task_table != NULL);
1333 
1334 	g_mutex_lock (priv->todo_update_lock);
1335 
1336 	/* Set the query on the task pad */
1337 	if (priv->todo_sexp) {
1338 		g_free (priv->todo_sexp);
1339 		priv->todo_sexp = NULL;
1340 	}
1341 
1342 	model = e_task_table_get_model (E_TASK_TABLE (priv->task_table));
1343 
1344 	if ((sexp = calendar_config_get_hide_completed_tasks_sexp (FALSE)) != NULL) {
1345 		priv->todo_sexp = g_strdup_printf (
1346 			"(and %s %s)", sexp,
1347 			priv->sexp ? priv->sexp : "");
1348 		e_cal_model_set_search_query (model, priv->todo_sexp);
1349 		g_free (sexp);
1350 	} else {
1351 		priv->todo_sexp = g_strdup (priv->sexp);
1352 		e_cal_model_set_search_query (model, priv->todo_sexp);
1353 	}
1354 
1355 	update_memo_view (msg->gcal);
1356 
1357 	g_mutex_unlock (priv->todo_update_lock);
1358 }
1359 
1360 static gboolean
1361 update_todo_view_done (struct _mupdate_todo_msg *msg)
1362 {
1363 	EMemoTable *memo_table;
1364 	ETaskTable *task_table;
1365 	EShellView *shell_view;
1366 	GnomeCalendar *gcal;
1367 
1368 	g_return_val_if_fail (msg != NULL, FALSE);
1369 
1370 	gcal = msg->gcal;
1371 
1372 	g_return_val_if_fail (gcal->priv->task_table != NULL, FALSE);
1373 	g_return_val_if_fail (gcal->priv->memo_table != NULL, FALSE);
1374 
1375 	task_table = E_TASK_TABLE (gcal->priv->task_table);
1376 	shell_view = e_task_table_get_shell_view (task_table);
1377 	e_shell_view_unblock_update_actions (shell_view);
1378 
1379 	memo_table = E_MEMO_TABLE (gcal->priv->memo_table);
1380 	shell_view = e_memo_table_get_shell_view (memo_table);
1381 	e_shell_view_unblock_update_actions (shell_view);
1382 
1383 	g_object_unref (msg->gcal);
1384 	g_slice_free (struct _mupdate_todo_msg, msg);
1385 
1386 	return FALSE;
1387 }
1388 
1389 static void
1390 update_todo_view (GnomeCalendar *gcal)
1391 {
1392 	EMemoTable *memo_table;
1393 	ETaskTable *task_table;
1394 	EShellView *shell_view;
1395 	struct _mupdate_todo_msg *msg;
1396 
1397 	/* they are both or none anyway */
1398 	if (!gcal->priv->task_table || !gcal->priv->memo_table)
1399 		return;
1400 
1401 	msg = g_slice_new0 (struct _mupdate_todo_msg);
1402 	msg->header.func = (MessageFunc) update_todo_view_async;
1403 	msg->header.done = (GSourceFunc) update_todo_view_done;
1404 	msg->gcal = g_object_ref (gcal);
1405 
1406 	task_table = E_TASK_TABLE (gcal->priv->task_table);
1407 	shell_view = e_task_table_get_shell_view (task_table);
1408 	e_shell_view_block_update_actions (shell_view);
1409 
1410 	memo_table = E_MEMO_TABLE (gcal->priv->memo_table);
1411 	shell_view = e_memo_table_get_shell_view (memo_table);
1412 	e_shell_view_block_update_actions (shell_view);
1413 
1414 	message_push ((Message *) msg);
1415 }
1416 
1417 static void
1418 update_memo_view (GnomeCalendar *gcal)
1419 {
1420 	GnomeCalendarPrivate *priv;
1421 	ECalModel *model, *view_model;
1422 	time_t start = -1, end = -1;
1423 	gchar *iso_start, *iso_end;
1424 
1425 	priv = gcal->priv;
1426 	if (!priv->memo_table)
1427 		return;
1428 
1429 	/* Set the query on the memo pad*/
1430 	model = e_memo_table_get_model (E_MEMO_TABLE (priv->memo_table));
1431 	view_model = gnome_calendar_get_model (gcal);
1432 	e_cal_model_get_time_range (view_model, &start, &end);
1433 
1434 	if (start != -1 && end != -1) {
1435 		iso_start = isodate_from_time_t (start);
1436 		iso_end = isodate_from_time_t (end);
1437 
1438 		g_free (priv->memo_sexp);
1439 
1440 		priv->memo_sexp = g_strdup_printf (
1441 			"(and (or (not (has-start?)) (occur-in-time-range? (make-time \"%s\") (make-time \"%s\") \"%s\")) %s)",
1442 			iso_start, iso_end, gcal_get_default_tzloc (gcal),
1443 			priv->sexp ? priv->sexp : "");
1444 
1445 		e_cal_model_set_search_query (model, priv->memo_sexp);
1446 
1447 		g_free (iso_start);
1448 		g_free (iso_end);
1449 	}
1450 }
1451 
1452 static gboolean
1453 update_marcus_bains_line_cb (GnomeCalendar *gcal)
1454 {
1455 	GnomeCalendarViewType view_type;
1456 	ECalendarView *view;
1457 	time_t now, day_begin;
1458 
1459 	view_type = gnome_calendar_get_view (gcal);
1460 	view = gnome_calendar_get_calendar_view (gcal, view_type);
1461 
1462 	if (E_IS_DAY_VIEW (view))
1463 		e_day_view_marcus_bains_update (E_DAY_VIEW (view));
1464 
1465 	time (&now);
1466 	day_begin = time_day_begin (now);
1467 
1468 	/* check in the first two minutes */
1469 	if (now >= day_begin && now <= day_begin + 120) {
1470 		time_t start_time = 0, end_time = 0;
1471 
1472 		g_return_val_if_fail (view != NULL, TRUE);
1473 
1474 		e_calendar_view_get_selected_time_range (view, &start_time, &end_time);
1475 
1476 		if (end_time >= time_add_day (day_begin, -1) && start_time <= day_begin) {
1477 			gnome_calendar_goto (gcal, now);
1478 		}
1479 	}
1480 
1481 	return TRUE;
1482 }
1483 
1484 static void
1485 setup_widgets (GnomeCalendar *gcal)
1486 {
1487 	GnomeCalendarPrivate *priv;
1488 
1489 	priv = gcal->priv;
1490 
1491 	/* update_todo_view (gcal); */
1492 
1493 	/* Timeout check to hide completed items */
1494 #if 0 /* KILL-BONOBO */
1495 	priv->update_timeout = g_timeout_add_full (
1496 		G_PRIORITY_LOW, 60000, (GSourceFunc)
1497 		update_todo_view_cb, gcal, NULL);
1498 #endif
1499 
1500 	/* The Marcus Bains line */
1501 	priv->update_marcus_bains_line_timeout = g_timeout_add_full (
1502 		G_PRIORITY_LOW, 60000, (GSourceFunc)
1503 		update_marcus_bains_line_cb, gcal, NULL);
1504 
1505 	/* update_memo_view (gcal); */
1506 }
1507 
1508 /* Object initialization function for the gnome calendar */
1509 static void
1510 gnome_calendar_init (GnomeCalendar *gcal)
1511 {
1512 	gcal->priv = GNOME_CALENDAR_GET_PRIVATE (gcal);
1513 
1514 	gcal->priv->todo_update_lock = g_mutex_new ();
1515 	gcal->priv->dn_query_lock = g_mutex_new ();
1516 
1517 	gcal->priv->current_view_type = GNOME_CAL_WORK_WEEK_VIEW;
1518 	gcal->priv->range_selected = FALSE;
1519 	gcal->priv->lview_select_daten_range = TRUE;
1520 
1521 	setup_widgets (gcal);
1522 
1523 	gcal->priv->dn_queries = NULL;
1524 	gcal->priv->sexp = g_strdup ("#t"); /* Match all */
1525 	gcal->priv->todo_sexp = g_strdup ("#t");
1526 	gcal->priv->memo_sexp = g_strdup ("#t");
1527 
1528 	gcal->priv->visible_start = -1;
1529 	gcal->priv->visible_end = -1;
1530 	gcal->priv->updating = FALSE;
1531 
1532 	gcal->priv->cancellable = g_cancellable_new ();
1533 }
1534 
1535 static void
1536 gnome_calendar_do_dispose (GObject *object)
1537 {
1538 	GnomeCalendarPrivate *priv;
1539 	gint ii;
1540 
1541 	priv = GNOME_CALENDAR_GET_PRIVATE (object);
1542 
1543 	if (priv->registry != NULL) {
1544 		g_object_unref (priv->registry);
1545 		priv->registry = NULL;
1546 	}
1547 
1548 	if (priv->model != NULL) {
1549 		g_signal_handlers_disconnect_by_func (
1550 			priv->model, view_progress_cb, object);
1551 		g_signal_handlers_disconnect_by_func (
1552 			priv->model, view_complete_cb, object);
1553 		g_object_unref (priv->model);
1554 		priv->model = NULL;
1555 	}
1556 
1557 	for (ii = 0; ii < GNOME_CAL_LAST_VIEW; ii++) {
1558 		if (priv->views[ii] != NULL) {
1559 			g_object_unref (priv->views[ii]);
1560 			priv->views[ii] = NULL;
1561 		}
1562 	}
1563 
1564 	free_dn_queries (GNOME_CALENDAR (object));
1565 
1566 	if (priv->sexp) {
1567 		g_free (priv->sexp);
1568 		priv->sexp = NULL;
1569 	}
1570 
1571 	if (priv->update_timeout) {
1572 		g_source_remove (priv->update_timeout);
1573 		priv->update_timeout = 0;
1574 	}
1575 
1576 	if (priv->update_marcus_bains_line_timeout) {
1577 		g_source_remove (priv->update_marcus_bains_line_timeout);
1578 		priv->update_marcus_bains_line_timeout = 0;
1579 	}
1580 
1581 	if (priv->cancellable) {
1582 		g_cancellable_cancel (priv->cancellable);
1583 		g_object_unref (priv->cancellable);
1584 		priv->cancellable = NULL;
1585 	}
1586 
1587 	/* Chain up to parent's dispose() method. */
1588 	G_OBJECT_CLASS (gnome_calendar_parent_class)->dispose (object);
1589 }
1590 
1591 static void
1592 gnome_calendar_finalize (GObject *object)
1593 {
1594 	GnomeCalendarPrivate *priv;
1595 
1596 	priv = GNOME_CALENDAR_GET_PRIVATE (object);
1597 
1598 	g_mutex_free (priv->todo_update_lock);
1599 	g_mutex_free (priv->dn_query_lock);
1600 
1601 	/* Chain up to parent's finalize() method. */
1602 	G_OBJECT_CLASS (gnome_calendar_parent_class)->finalize (object);
1603 }
1604 
1605 static void
1606 notify_selected_time_changed (GnomeCalendar *gcal)
1607 {
1608 	GnomeCalendarPrivate *priv;
1609 	gint i;
1610 
1611 	priv = gcal->priv;
1612 	for (i = 0; i < GNOME_CAL_LAST_VIEW; i++) {
1613 		g_signal_emit_by_name (priv->views[i], "selected_time_changed");
1614 	}
1615 }
1616 
1617 static void
1618 gnome_calendar_goto_date (GnomeCalendar *gcal,
1619                           GnomeCalendarGotoDateType goto_date)
1620 {
1621 	ECalModel *model;
1622 	time_t	 new_time = 0;
1623 	gint week_start_day;
1624 	gboolean need_updating = FALSE;
1625 	icaltimezone *timezone;
1626 
1627 	g_return_if_fail (GNOME_IS_CALENDAR (gcal));
1628 
1629 	model = gnome_calendar_get_model (gcal);
1630 	week_start_day = e_cal_model_get_week_start_day (model);
1631 	timezone = e_cal_model_get_timezone (model);
1632 
1633 	switch (goto_date) {
1634 		/* GNOME_CAL_GOTO_TODAY and GNOME_CAL_GOTO_DATE are
1635 		 * currently not used
1636 		*/
1637 	case GNOME_CAL_GOTO_TODAY:
1638 		break;
1639 	case GNOME_CAL_GOTO_DATE:
1640 		break;
1641 	case GNOME_CAL_GOTO_FIRST_DAY_OF_MONTH:
1642 		new_time = time_month_begin_with_zone (
1643 			gcal->priv->base_view_time, timezone);
1644 		need_updating = TRUE;
1645 		break;
1646 	case GNOME_CAL_GOTO_LAST_DAY_OF_MONTH:
1647 		new_time = time_add_month_with_zone (
1648 			gcal->priv->base_view_time, 1, timezone);
1649 		new_time = time_month_begin_with_zone (new_time, timezone);
1650 		new_time = time_add_day_with_zone (new_time, -1, timezone);
1651 		need_updating = TRUE;
1652 		break;
1653 	case GNOME_CAL_GOTO_FIRST_DAY_OF_WEEK:
1654 		new_time = time_week_begin_with_zone (
1655 			gcal->priv->base_view_time, week_start_day, timezone);
1656 		need_updating = TRUE;
1657 		break;
1658 	case GNOME_CAL_GOTO_LAST_DAY_OF_WEEK:
1659 		new_time = time_week_begin_with_zone (
1660 			gcal->priv->base_view_time, week_start_day, timezone);
1661 		if (gcal->priv->current_view_type == GNOME_CAL_DAY_VIEW ||
1662 		    gcal->priv->current_view_type == GNOME_CAL_WORK_WEEK_VIEW) {
1663 			/* FIXME Shouldn't hard code work week end */
1664 			/* goto Friday of this week */
1665 			new_time = time_add_day_with_zone (new_time, 4, timezone);
1666 		} else {
1667 			/* goto Sunday of this week */
1668 			/* FIXME Shouldn't hard code week end */
1669 			new_time = time_add_day_with_zone (new_time, 6, timezone);
1670 		}
1671 		need_updating = TRUE;
1672 		break;
1673 	case GNOME_CAL_GOTO_SAME_DAY_OF_PREVIOUS_WEEK:
1674 		new_time = time_add_week_with_zone (
1675 			gcal->priv->base_view_time, -1, timezone);
1676 		need_updating = TRUE;
1677 		break;
1678 	case GNOME_CAL_GOTO_SAME_DAY_OF_NEXT_WEEK:
1679 		new_time = time_add_week_with_zone (
1680 			gcal->priv->base_view_time, 1, timezone);
1681 		need_updating = TRUE;
1682 		break;
1683 	default:
1684 		break;
1685 	}
1686 
1687 	if (need_updating) {
1688 		gnome_calendar_set_selected_time_range (gcal, new_time);
1689 		notify_selected_time_changed (gcal);
1690 	}
1691 }
1692 
1693 void
1694 gnome_calendar_goto (GnomeCalendar *gcal,
1695                      time_t new_time)
1696 {
1697 	GnomeCalendarPrivate *priv;
1698 	gint i;
1699 
1700 	g_return_if_fail (GNOME_IS_CALENDAR (gcal));
1701 	g_return_if_fail (new_time != -1);
1702 
1703 	priv = gcal->priv;
1704 
1705 	gnome_calendar_set_selected_time_range (gcal, new_time);
1706 
1707 	for (i = 0; i < GNOME_CAL_LAST_VIEW; i++)
1708 		e_calendar_view_set_selected_time_range (
1709 			priv->views[i], new_time, new_time);
1710 }
1711 
1712 void
1713 gnome_calendar_update_view_times (GnomeCalendar *gcal,
1714                                   time_t start_time)
1715 {
1716 	GnomeCalendarPrivate *priv;
1717 	ECalModel *model;
1718 	time_t real_start_time = start_time;
1719 	time_t end_time, select_time = 0;
1720 
1721 	g_return_if_fail (GNOME_IS_CALENDAR (gcal));
1722 
1723 	priv = gcal->priv;
1724 
1725 	priv->base_view_time = start_time;
1726 
1727 	model = gnome_calendar_get_model (gcal);
1728 
1729 	get_times_for_views (
1730 		gcal, priv->current_view_type,
1731 		&real_start_time, &end_time, &select_time);
1732 
1733 	if (priv->current_view_type == GNOME_CAL_LIST_VIEW &&
1734 		!priv->lview_select_daten_range)
1735 		return;
1736 
1737 	e_cal_model_set_time_range (model, real_start_time, end_time);
Function call argument is an uninitialized value
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

Function call argument is an uninitialized value
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

1738 1739 if (select_time != 0 && select_time >= real_start_time && select_time <= end_time) 1740 e_calendar_view_set_selected_time_range ( 1741 priv->views[priv->current_view_type], 1742 select_time, select_time); 1743 } 1744 1745 static void 1746 gnome_calendar_direction (GnomeCalendar *gcal, 1747 gint direction) 1748 { 1749 ECalModel *model; 1750 icaltimezone *timezone; 1751 1752 model = gnome_calendar_get_model (gcal); 1753 timezone = e_cal_model_get_timezone (model); 1754 1755 switch (gnome_calendar_get_view (gcal)) { 1756 case GNOME_CAL_DAY_VIEW: 1757 gcal->priv->base_view_time = time_add_day_with_zone ( 1758 gcal->priv->base_view_time, direction, timezone); 1759 break; 1760 case GNOME_CAL_WORK_WEEK_VIEW: 1761 case GNOME_CAL_WEEK_VIEW: 1762 gcal->priv->base_view_time = time_add_week_with_zone ( 1763 gcal->priv->base_view_time, direction, timezone); 1764 break; 1765 case GNOME_CAL_MONTH_VIEW: 1766 case GNOME_CAL_LIST_VIEW: 1767 gcal->priv->base_view_time = time_add_month_with_zone ( 1768 gcal->priv->base_view_time, direction, timezone); 1769 break; 1770 default: 1771 g_return_if_reached (); 1772 } 1773 1774 gnome_calendar_set_selected_time_range ( 1775 gcal, gcal->priv->base_view_time); 1776 } 1777 1778 void 1779 gnome_calendar_next (GnomeCalendar *gcal) 1780 { 1781 g_return_if_fail (GNOME_IS_CALENDAR (gcal)); 1782 1783 gnome_calendar_direction (gcal, 1); 1784 } 1785 1786 void 1787 gnome_calendar_previous (GnomeCalendar *gcal) 1788 { 1789 g_return_if_fail (GNOME_IS_CALENDAR (gcal)); 1790 1791 gnome_calendar_direction (gcal, -1); 1792 } 1793 1794 void 1795 gnome_calendar_dayjump (GnomeCalendar *gcal, 1796 time_t time) 1797 { 1798 ECalModel *model; 1799 icaltimezone *timezone; 1800 1801 g_return_if_fail (GNOME_IS_CALENDAR (gcal)); 1802 1803 model = gnome_calendar_get_model (gcal); 1804 timezone = e_cal_model_get_timezone (model); 1805 1806 gcal->priv->base_view_time = 1807 time_day_begin_with_zone (time, timezone); 1808 1809 gnome_calendar_update_view_times (gcal, gcal->priv->base_view_time); 1810 gnome_calendar_set_view (gcal, GNOME_CAL_DAY_VIEW); 1811 } 1812 1813 void 1814 gnome_calendar_goto_today (GnomeCalendar *gcal) 1815 { 1816 GnomeCalendarViewType view_type; 1817 ECalendarView *view; 1818 1819 g_return_if_fail (GNOME_IS_CALENDAR (gcal)); 1820 1821 view_type = gnome_calendar_get_view (gcal); 1822 view = gnome_calendar_get_calendar_view (gcal, view_type); 1823 1824 gnome_calendar_goto (gcal, time (NULL)); 1825 gtk_widget_grab_focus (GTK_WIDGET (view)); 1826 } 1827 1828 /** 1829 * gnome_calendar_get_view: 1830 * @gcal: A calendar. 1831 * 1832 * Queries the type of the view that is being shown in a calendar. 1833 * 1834 * Return value: Type of the view that is currently shown. 1835 **/ 1836 GnomeCalendarViewType 1837 gnome_calendar_get_view (GnomeCalendar *gcal) 1838 { 1839 g_return_val_if_fail (GNOME_IS_CALENDAR (gcal), GNOME_CAL_DAY_VIEW); 1840 1841 return gcal->priv->current_view_type; 1842 } 1843 1844 /** 1845 * gnome_calendar_set_view: 1846 * @gcal: A calendar. 1847 * @view_type: Type of view to show. 1848 * 1849 * Sets the view that should be shown in a calendar. If @reset_range is true, 1850 * this function will automatically set the number of days or weeks shown in 1851 * the view; otherwise the last configuration will be kept. 1852 **/ 1853 void 1854 gnome_calendar_set_view (GnomeCalendar *gcal, 1855 GnomeCalendarViewType view_type) 1856 { 1857 ECalendarView *calendar_view; 1858 gint ii; 1859 1860 g_return_if_fail (GNOME_IS_CALENDAR (gcal)); 1861 1862 if (gcal->priv->current_view_type == view_type && 1863 E_CALENDAR_VIEW (gcal->priv->views[view_type])->in_focus) 1864 return; 1865 1866 gcal->priv->current_view_type = view_type; 1867 gnome_calendar_set_range_selected (gcal, FALSE); 1868 1869 E_CALENDAR_VIEW (gcal->priv->views[view_type])->in_focus = TRUE; 1870 for (ii = 0; ii < GNOME_CAL_LAST_VIEW; ii++) { 1871 if (ii == view_type) 1872 continue; 1873 E_CALENDAR_VIEW (gcal->priv->views[ii])->in_focus = FALSE; 1874 } 1875 1876 calendar_view = gnome_calendar_get_calendar_view (gcal, view_type); 1877 gtk_widget_grab_focus (GTK_WIDGET (calendar_view)); 1878 1879 g_object_notify (G_OBJECT (gcal), "view"); 1880 } 1881 1882 void 1883 gnome_calendar_display_view (GnomeCalendar *gcal, 1884 GnomeCalendarViewType view_type) 1885 { 1886 ECalendarView *view; 1887 gboolean preserve_day; 1888 gboolean range_selected; 1889 time_t start_time; 1890 1891 view = gnome_calendar_get_calendar_view (gcal, view_type); 1892 1893 /* Set the view without changing the selection or updating the date 1894 * navigator. If a range of dates isn't selected, also reset the 1895 * number of days/weeks shown to the default (i.e. 1 day for the 1896 * day view or 6 weeks for the month view). */ 1897 1898 preserve_day = FALSE; 1899 1900 switch (view_type) { 1901 case GNOME_CAL_DAY_VIEW: 1902 if (!gnome_calendar_get_range_selected (gcal)) 1903 e_day_view_set_days_shown (E_DAY_VIEW (view), 1); 1904 1905 gtk_widget_show (GTK_WIDGET (gcal->priv->date_navigator)); 1906 break; 1907 1908 case GNOME_CAL_WORK_WEEK_VIEW: 1909 preserve_day = TRUE; 1910 gtk_widget_show (GTK_WIDGET (gcal->priv->date_navigator)); 1911 break; 1912 1913 case GNOME_CAL_WEEK_VIEW: 1914 preserve_day = TRUE; 1915 gtk_widget_show (GTK_WIDGET (gcal->priv->date_navigator)); 1916 break; 1917 1918 case GNOME_CAL_MONTH_VIEW: 1919 if (!gnome_calendar_get_range_selected (gcal)) 1920 e_week_view_set_weeks_shown (E_WEEK_VIEW (view), 6); 1921 1922 preserve_day = TRUE; 1923 gtk_widget_show (GTK_WIDGET (gcal->priv->date_navigator)); 1924 break; 1925 1926 case GNOME_CAL_LIST_VIEW: 1927 if (!gcal->priv->lview_select_daten_range) 1928 gtk_widget_hide (GTK_WIDGET (gcal->priv->date_navigator)); 1929 else 1930 gtk_widget_show (GTK_WIDGET (gcal->priv->date_navigator)); 1931 break; 1932 1933 default: 1934 g_return_if_reached (); 1935 } 1936 1937 range_selected = gnome_calendar_get_range_selected (gcal); 1938 gnome_calendar_set_view (gcal, view_type); 1939 gnome_calendar_set_range_selected (gcal, range_selected); 1940 1941 /* For the week & month views we want the selection in the date 1942 * navigator to be rounded to the nearest week when the arrow buttons 1943 * are pressed to move to the previous/next month. */ 1944 g_object_set ( 1945 gcal->priv->date_navigator->calitem, 1946 "preserve_day_when_moving", preserve_day, NULL); 1947 1948 /* keep week days selected as before for a work week view */ 1949 g_object_set ( 1950 gcal->priv->date_navigator->calitem, 1951 "keep_wdays_on_weeknum_click", 1952 view_type == GNOME_CAL_WORK_WEEK_VIEW, 1953 NULL); 1954 1955 if (!gcal->priv->base_view_time) 1956 start_time = time (NULL); 1957 else 1958 start_time = gcal->priv->base_view_time; 1959 1960 gnome_calendar_set_selected_time_range (gcal, start_time); 1961 1962 } 1963 1964 GtkWidget * 1965 gnome_calendar_new (ESourceRegistry *registry) 1966 { 1967 g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL); 1968 1969 return g_object_new ( 1970 GNOME_TYPE_CALENDAR, 1971 "registry", registry, NULL); 1972 } 1973 1974 ESourceRegistry * 1975 gnome_calendar_get_registry (GnomeCalendar *gcal) 1976 { 1977 g_return_val_if_fail (GNOME_IS_CALENDAR (gcal), NULL); 1978 1979 return gcal->priv->registry; 1980 } 1981 1982 ECalendar * 1983 gnome_calendar_get_date_navigator (GnomeCalendar *gcal) 1984 { 1985 g_return_val_if_fail (GNOME_IS_CALENDAR (gcal), NULL); 1986 1987 return gcal->priv->date_navigator; 1988 } 1989 1990 void 1991 gnome_calendar_set_date_navigator (GnomeCalendar *gcal, 1992 ECalendar *date_navigator) 1993 { 1994 g_return_if_fail (GNOME_IS_CALENDAR (gcal)); 1995 1996 if (gcal->priv->date_navigator == date_navigator) 1997 return; 1998 1999 if (date_navigator != NULL) { 2000 g_return_if_fail (E_IS_CALENDAR (date_navigator)); 2001 g_object_ref (date_navigator); 2002 } 2003 2004 if (gcal->priv->date_navigator != NULL) 2005 g_object_unref (gcal->priv->date_navigator); 2006 2007 gcal->priv->date_navigator = date_navigator; 2008 2009 /* Update the new date navigator */ 2010 gnome_calendar_update_date_navigator (gcal); 2011 2012 g_object_notify (G_OBJECT (gcal), "date-navigator"); 2013 } 2014 2015 GtkWidget * 2016 gnome_calendar_get_memo_table (GnomeCalendar *gcal) 2017 { 2018 g_return_val_if_fail (GNOME_IS_CALENDAR (gcal), NULL); 2019 2020 return gcal->priv->memo_table; 2021 } 2022 2023 void 2024 gnome_calendar_set_memo_table (GnomeCalendar *gcal, 2025 GtkWidget *memo_table) 2026 { 2027 g_return_if_fail (GNOME_IS_CALENDAR (gcal)); 2028 2029 if (gcal->priv->memo_table == memo_table) 2030 return; 2031 2032 if (memo_table != NULL) { 2033 g_return_if_fail (E_IS_MEMO_TABLE (memo_table)); 2034 g_object_ref (memo_table); 2035 } 2036 2037 if (gcal->priv->memo_table != NULL) 2038 g_object_unref (gcal->priv->memo_table); 2039 2040 gcal->priv->memo_table = memo_table; 2041 2042 g_object_notify (G_OBJECT (gcal), "memo-table"); 2043 } 2044 2045 GtkWidget * 2046 gnome_calendar_get_task_table (GnomeCalendar *gcal) 2047 { 2048 g_return_val_if_fail (GNOME_IS_CALENDAR (gcal), NULL); 2049 2050 return gcal->priv->task_table; 2051 } 2052 2053 void 2054 gnome_calendar_set_task_table (GnomeCalendar *gcal, 2055 GtkWidget *task_table) 2056 { 2057 g_return_if_fail (GNOME_IS_CALENDAR (gcal)); 2058 2059 if (gcal->priv->task_table == task_table) 2060 return; 2061 2062 if (task_table != NULL) { 2063 g_return_if_fail (E_IS_TASK_TABLE (task_table)); 2064 g_object_ref (task_table); 2065 } 2066 2067 if (gcal->priv->task_table != NULL) 2068 g_object_unref (gcal->priv->task_table); 2069 2070 gcal->priv->task_table = task_table; 2071 2072 g_object_notify (G_OBJECT (gcal), "task-table"); 2073 } 2074 2075 /** 2076 * gnome_calendar_get_model: 2077 * @gcal: A calendar view. 2078 * 2079 * Queries the calendar model object that a calendar view is using. 2080 * 2081 * Return value: A calendar client interface object. 2082 **/ 2083 ECalModel * 2084 gnome_calendar_get_model (GnomeCalendar *gcal) 2085 { 2086 g_return_val_if_fail (GNOME_IS_CALENDAR (gcal), NULL); 2087 2088 return gcal->priv->model; 2089 } 2090 2091 gboolean 2092 gnome_calendar_get_range_selected (GnomeCalendar *gcal) 2093 { 2094 g_return_val_if_fail (GNOME_IS_CALENDAR (gcal), FALSE); 2095 2096 return gcal->priv->range_selected; 2097 } 2098 2099 void 2100 gnome_calendar_set_range_selected (GnomeCalendar *gcal, 2101 gboolean range_selected) 2102 { 2103 g_return_if_fail (GNOME_IS_CALENDAR (gcal)); 2104 2105 gcal->priv->range_selected = range_selected; 2106 } 2107 2108 void 2109 gnome_calendar_set_selected_time_range (GnomeCalendar *gcal, 2110 time_t start_time) 2111 { 2112 gnome_calendar_update_view_times (gcal, start_time); 2113 gnome_calendar_update_date_navigator (gcal); 2114 gnome_calendar_notify_dates_shown_changed (gcal); 2115 } 2116 2117 /** 2118 * gnome_calendar_new_task: 2119 * @gcal: An Evolution calendar. 2120 * @dtstart: Start time of the task, in same timezone as model. 2121 * @dtend: End time of the task, in same timezone as model. 2122 * 2123 * Opens a task editor dialog for a new task. dtstart or dtend can be NULL. 2124 **/ 2125 #if 0 /* KILL-BONOBO */ 2126 void 2127 gnome_calendar_new_task (GnomeCalendar *gcal, 2128 time_t *dtstart, 2129 time_t *dtend) 2130 { 2131 GnomeCalendarPrivate *priv; 2132 ECal *ecal; 2133 ECalModel *model; 2134 CompEditor *editor; 2135 ECalComponent *comp; 2136 icalcomponent *icalcomp; 2137 const gchar *category; 2138 guint32 flags = 0; 2139 ECalComponentDateTime dt; 2140 struct icaltimetype itt; 2141 2142 g_return_if_fail (GNOME_IS_CALENDAR (gcal)); 2143 2144 priv = gcal->priv; 2145 model = e_calendar_table_get_model (E_CALENDAR_TABLE (priv->todo)); 2146 ecal = e_cal_model_get_default_client (model); 2147 if (!ecal) 2148 return; 2149 2150 flags |= COMP_EDITOR_NEW_ITEM; 2151 editor = task_editor_new (ecal, flags); 2152 2153 icalcomp = e_cal_model_create_component_with_defaults (model, FALSE); 2154 comp = e_cal_component_new (); 2155 e_cal_component_set_icalcomponent (comp, icalcomp); 2156 2157 dt.value = &itt; 2158 dt.tzid = icaltimezone_get_tzid (e_cal_model_get_timezone (model)); 2159 2160 if (dtstart) { 2161 itt = icaltime_from_timet_with_zone ( 2162 *dtstart, FALSE, e_cal_model_get_timezone (model)); 2163 e_cal_component_set_dtstart (comp, &dt); 2164 } 2165 2166 if (dtend) { 2167 itt = icaltime_from_timet_with_zone ( 2168 *dtend, FALSE, e_cal_model_get_timezone (model)); 2169 e_cal_component_set_due (comp, &dt); /* task uses 'due' not 'dtend' */ 2170 } 2171 2172 if (dtstart || dtend) 2173 e_cal_component_commit_sequence (comp); 2174 2175 comp_editor_edit_comp (editor, comp); 2176 g_object_unref (comp); 2177 2178 gtk_window_present (GTK_WINDOW (editor)); 2179 } 2180 #endif 2181 2182 /* Returns the selected time range for the current view. Note that this may be 2183 * different from the fields in the GnomeCalendar, since the view may clip 2184 * this or choose a more appropriate time. */ 2185 void 2186 gnome_calendar_get_current_time_range (GnomeCalendar *gcal, 2187 time_t *start_time, 2188 time_t *end_time) 2189 { 2190 GnomeCalendarViewType view_type; 2191 ECalendarView *view; 2192 2193 view_type = gnome_calendar_get_view (gcal); 2194 view = gnome_calendar_get_calendar_view (gcal, view_type); 2195 2196 e_calendar_view_get_selected_time_range (view, start_time, end_time); 2197 } 2198 2199 /* This updates the month shown and the days selected in the calendar, if 2200 * necessary. */ 2201 static void 2202 gnome_calendar_update_date_navigator (GnomeCalendar *gcal) 2203 { 2204 GnomeCalendarPrivate *priv; 2205 ECalModel *model; 2206 time_t start, end; 2207 gint week_start_day; 2208 GDate start_date, end_date; 2209 icaltimezone *timezone; 2210 2211 priv = gcal->priv; 2212 2213 /* If the ECalendar is not yet set, we just return. */ 2214 if (priv->date_navigator == NULL) 2215 return; 2216 2217 /* If the ECalendar isn't visible, we just return. */ 2218 if (!gtk_widget_get_visible (GTK_WIDGET (priv->date_navigator))) 2219 return; 2220 2221 if (priv->current_view_type == GNOME_CAL_LIST_VIEW && 2222 !priv->lview_select_daten_range) 2223 return; 2224 2225 model = gnome_calendar_get_model (gcal); 2226 timezone = e_cal_model_get_timezone (model); 2227 week_start_day = e_cal_model_get_week_start_day (model); 2228 e_cal_model_get_time_range (model, &start, &end); 2229 2230 time_to_gdate_with_zone (&start_date, start, timezone); 2231 if (priv->current_view_type == GNOME_CAL_MONTH_VIEW) { 2232 EWeekView *week_view = E_WEEK_VIEW (priv->views[priv->current_view_type]); 2233 2234 if (week_start_day == 0 2235 && (!week_view->multi_week_view || week_view->compress_weekend)) 2236 g_date_add_days (&start_date, 1); 2237 } 2238 time_to_gdate_with_zone (&end_date, end, timezone); 2239 g_date_subtract_days (&end_date, 1); 2240 2241 e_calendar_item_set_selection ( 2242 priv->date_navigator->calitem, 2243 &start_date, &end_date); 2244 } 2245 2246 void 2247 gnome_calendar_notify_dates_shown_changed (GnomeCalendar *gcal) 2248 { 2249 GnomeCalendarViewType view_type; 2250 ECalendarView *calendar_view; 2251 GnomeCalendarPrivate *priv; 2252 time_t start_time, end_time; 2253 gboolean has_time_range; 2254 2255 g_return_if_fail (GNOME_IS_CALENDAR (gcal)); 2256 2257 priv = gcal->priv; 2258 2259 view_type = gnome_calendar_get_view (gcal); 2260 calendar_view = gnome_calendar_get_calendar_view (gcal, view_type); 2261 2262 /* If no time range is set yet, just return. */ 2263 has_time_range = e_calendar_view_get_visible_time_range ( 2264 calendar_view, &start_time, &end_time); 2265 if (!has_time_range) 2266 return; 2267 2268 /* We check if the visible date range has changed, and only emit the 2269 * signal if it has. (This makes sure we only change the folder title 2270 * bar label in the shell when we need to.) */ 2271 if (priv->visible_start != start_time 2272 || priv->visible_end != end_time) { 2273 priv->visible_start = start_time; 2274 priv->visible_end = end_time; 2275 2276 gtk_widget_queue_draw (GTK_WIDGET (calendar_view)); 2277 g_signal_emit (gcal, signals[DATES_SHOWN_CHANGED], 0); 2278 } 2279 update_todo_view (gcal); 2280 } 2281 2282 /* Returns the number of selected events (0 or 1 at present). */ 2283 gint 2284 gnome_calendar_get_num_events_selected (GnomeCalendar *gcal) 2285 { 2286 GnomeCalendarViewType view_type; 2287 ECalendarView *view; 2288 gint retval = 0; 2289 2290 g_return_val_if_fail (GNOME_IS_CALENDAR (gcal), 0); 2291 2292 view_type = gnome_calendar_get_view (gcal); 2293 view = gnome_calendar_get_calendar_view (gcal, view_type); 2294 2295 if (E_IS_DAY_VIEW (view)) 2296 retval = e_day_view_get_num_events_selected (E_DAY_VIEW (view)); 2297 else 2298 retval = e_week_view_get_num_events_selected (E_WEEK_VIEW (view)); 2299 2300 return retval; 2301 } 2302 2303 struct purge_data { 2304 gboolean remove; 2305 time_t older_than; 2306 }; 2307 2308 static gboolean 2309 check_instance_cb (ECalComponent *comp, 2310 time_t instance_start, 2311 time_t instance_end, 2312 gpointer data) 2313 { 2314 struct purge_data *pd = data; 2315 2316 if (instance_end >= pd->older_than) 2317 pd->remove = FALSE; 2318 2319 return pd->remove; 2320 } 2321 2322 void 2323 gnome_calendar_purge (GnomeCalendar *gcal, 2324 time_t older_than) 2325 { 2326 gchar *sexp, *start, *end; 2327 GList *clients, *l; 2328 2329 g_return_if_fail (GNOME_IS_CALENDAR (gcal)); 2330 2331 start = isodate_from_time_t (0); 2332 end = isodate_from_time_t (older_than); 2333 sexp = g_strdup_printf ( 2334 "(occur-in-time-range? (make-time \"%s\") (make-time \"%s\") \"%s\")", 2335 start, end, gcal_get_default_tzloc (gcal)); 2336 2337 gcal_update_status_message (gcal, _("Purging"), -1); 2338 2339 /* FIXME Confirm expunge */ 2340 clients = e_cal_model_get_client_list (gnome_calendar_get_model (gcal)); 2341 for (l = clients; l != NULL; l = l->next) { 2342 ECalClient *client = l->data; 2343 GSList *objects, *m; 2344 GError *error = NULL; 2345 2346 if (e_client_is_readonly (E_CLIENT (client))) 2347 continue; 2348 2349 e_cal_client_get_object_list_sync ( 2350 client, sexp, &objects, NULL, &error); 2351 2352 if (error != NULL) { 2353 g_warning ( 2354 "%s: Could not get the objects: %s", 2355 G_STRFUNC, error->message); 2356 g_error_free (error); 2357 continue; 2358 } 2359 2360 for (m = objects; m; m = m->next) { 2361 gboolean remove = TRUE; 2362 2363 /* FIXME write occur-before and occur-after 2364 * sexp funcs so we don't have to use the max 2365 * gint */ 2366 if (!e_cal_client_check_recurrences_no_master (client)) { 2367 struct purge_data pd; 2368 2369 pd.remove = TRUE; 2370 pd.older_than = older_than; 2371 2372 e_cal_client_generate_instances_for_object_sync (client, m->data, 2373 older_than, G_MAXINT32, 2374 check_instance_cb, 2375 &pd); 2376 2377 remove = pd.remove; 2378 } 2379 2380 /* FIXME Better error handling */ 2381 if (remove) { 2382 const gchar *uid = icalcomponent_get_uid (m->data); 2383 GError *error = NULL; 2384 2385 if (e_cal_util_component_is_instance (m->data) || 2386 e_cal_util_component_has_recurrences (m->data)) { 2387 gchar *rid = NULL; 2388 struct icaltimetype recur_id; 2389 2390 recur_id = icalcomponent_get_recurrenceid (m->data); 2391 2392 if (!icaltime_is_null_time (recur_id)) 2393 rid = icaltime_as_ical_string_r (recur_id); 2394 2395 e_cal_client_remove_object_sync ( 2396 client, uid, rid, 2397 CALOBJ_MOD_ALL, NULL, &error); 2398 g_free (rid); 2399 } else { 2400 e_cal_client_remove_object_sync ( 2401 client, uid, NULL, 2402 CALOBJ_MOD_THIS, NULL, &error); 2403 } 2404 2405 if (error != NULL) { 2406 g_warning ( 2407 "%s: Unable to purge events: %s", 2408 G_STRFUNC, error->message); 2409 g_error_free (error); 2410 } 2411 } 2412 } 2413 2414 g_slist_foreach (objects, (GFunc) icalcomponent_free, NULL); 2415 g_slist_free (objects); 2416 } 2417 2418 g_list_free (clients); 2419 2420 gcal_update_status_message (gcal, NULL, -1); 2421 2422 g_free (sexp); 2423 g_free (start); 2424 g_free (end); 2425 2426 }