/* * * Evolution calendar - Utilities for tagging ECalendar widgets * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with the program; if not, see * * * Authors: * Damon Chaplin * Federico Mena-Quintero * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * */ #ifdef HAVE_CONFIG_H #include #endif #include #include "shell/e-shell.h" #include "shell/e-shell-settings.h" #include "calendar-config.h" #include "tag-calendar.h" struct calendar_tag_closure { ECalendarItem *calitem; icaltimezone *zone; time_t start_time; time_t end_time; gboolean skip_transparent_events; gboolean recur_events_italic; }; /* Clears all the tags in a calendar and fills a closure structure with the * necessary information for iterating over occurrences. Returns FALSE if * the calendar has no dates shown. */ static gboolean prepare_tag (ECalendar *ecal, struct calendar_tag_closure *c, icaltimezone *zone, gboolean clear_first) { gint start_year, start_month, start_day; gint end_year, end_month, end_day; struct icaltimetype start_tt = icaltime_null_time (); struct icaltimetype end_tt = icaltime_null_time (); if (clear_first) e_calendar_item_clear_marks (ecal->calitem); if (!e_calendar_item_get_date_range ( ecal->calitem, &start_year, &start_month, &start_day, &end_year, &end_month, &end_day)) return FALSE; start_tt.year = start_year; start_tt.month = start_month + 1; start_tt.day = start_day; end_tt.year = end_year; end_tt.month = end_month + 1; end_tt.day = end_day; icaltime_adjust (&end_tt, 1, 0, 0, 0); c->calitem = ecal->calitem; if (zone) c->zone = zone; else c->zone = calendar_config_get_icaltimezone (); c->start_time = icaltime_as_timet_with_zone (start_tt, c->zone); c->end_time = icaltime_as_timet_with_zone (end_tt, c->zone); return TRUE; } /* Marks the specified range in an ECalendar; * called from e_cal_generate_instances() */ static gboolean tag_calendar_cb (ECalComponent *comp, time_t istart, time_t iend, gpointer data) { struct calendar_tag_closure *c = data; struct icaltimetype start_tt, end_tt; ECalComponentTransparency transparency; guint8 style = 0; /* If we are skipping TRANSPARENT events, return if the event is * transparent. */ e_cal_component_get_transparency (comp, &transparency); if (transparency == E_CAL_COMPONENT_TRANSP_TRANSPARENT) { if (c->skip_transparent_events) return TRUE; style = E_CALENDAR_ITEM_MARK_ITALIC; } else if (c->recur_events_italic && e_cal_component_is_instance (comp)) { style = E_CALENDAR_ITEM_MARK_ITALIC; } else { style = E_CALENDAR_ITEM_MARK_BOLD; } start_tt = icaltime_from_timet_with_zone (istart, FALSE, c->zone); end_tt = icaltime_from_timet_with_zone (iend - 1, FALSE, c->zone); e_calendar_item_mark_days ( c->calitem, start_tt.year, start_tt.month - 1, start_tt.day, end_tt.year, end_tt.month - 1, end_tt.day, style, TRUE); return TRUE; } static gboolean get_recur_events_italic (void) { EShell *shell; EShellSettings *shell_settings; shell = e_shell_get_default (); shell_settings = e_shell_get_shell_settings (shell); return e_shell_settings_get_boolean (shell_settings, "cal-recur-events-italic"); } /** * tag_calendar_by_client: * @ecal: Calendar widget to tag. * @client: A calendar client object. * @cancellable: A #GCancellable; can be %NULL * * Tags an #ECalendar widget with the events that occur in its current time * range. The occurrences are extracted from the specified calendar @client. **/ void tag_calendar_by_client (ECalendar *ecal, ECalClient *client, GCancellable *cancellable) { struct calendar_tag_closure *c; g_return_if_fail (E_IS_CALENDAR (ecal)); g_return_if_fail (E_IS_CAL_CLIENT (client)); /* If the ECalendar isn't visible, we just return. */ if (!gtk_widget_get_visible (GTK_WIDGET (ecal))) return; if (!e_client_is_opened (E_CLIENT (client))) return; c = g_new0 (struct calendar_tag_closure, 1); if (!prepare_tag (ecal, c, NULL, TRUE)) { g_free (c); return; } c->skip_transparent_events = TRUE; c->recur_events_italic = get_recur_events_italic (); e_cal_client_generate_instances ( client, c->start_time, c->end_time, cancellable, tag_calendar_cb, c, g_free); } /* Resolves TZIDs for the recurrence generator, for when the comp is not on * the server. We need to try to use builtin timezones first, as they may not * be added to the server yet. */ static icaltimezone * resolve_tzid_cb (const gchar *tzid, gpointer data) { ECalClient *client; icaltimezone *zone = NULL; g_return_val_if_fail (E_IS_CAL_CLIENT (data), NULL); client = E_CAL_CLIENT (data); /* Try to find the builtin timezone first. */ zone = icaltimezone_get_builtin_timezone_from_tzid (tzid); if (!zone && tzid) { /* FIXME: Handle errors. */ GError *error = NULL; e_cal_client_get_timezone_sync ( client, tzid, &zone, NULL, &error); if (error != NULL) { g_warning ( "%s: Failed to get timezone '%s': %s", G_STRFUNC, tzid, error->message); g_error_free (error); } } return zone; } /** * tag_calendar_by_comp: * @ecal: Calendar widget to tag. * @comp: A calendar component object. * @clear_first: Whether the #ECalendar should be cleared of any marks first. * * Tags an #ECalendar widget with any occurrences of a specific calendar * component that occur within the calendar's current time range. * Note that TRANSPARENT events are also tagged here. * * If comp_is_on_server is FALSE, it will try to resolve TZIDs using builtin * timezones first, before querying the server, since the timezones may not * have been added to the calendar on the server yet. **/ void tag_calendar_by_comp (ECalendar *ecal, ECalComponent *comp, ECalClient *client, icaltimezone *display_zone, gboolean clear_first, gboolean comp_is_on_server, gboolean can_recur_events_italic, GCancellable *cancellable) { struct calendar_tag_closure c; g_return_if_fail (E_IS_CALENDAR (ecal)); g_return_if_fail (E_IS_CAL_COMPONENT (comp)); /* If the ECalendar isn't visible, we just return. */ if (!gtk_widget_get_visible (GTK_WIDGET (ecal))) return; if (!prepare_tag (ecal, &c, display_zone, clear_first)) return; c.skip_transparent_events = FALSE; c.recur_events_italic = can_recur_events_italic && get_recur_events_italic (); if (comp_is_on_server) { struct calendar_tag_closure *closure = g_new0 (struct calendar_tag_closure, 1); *closure = c; e_cal_client_generate_instances_for_object ( client, e_cal_component_get_icalcomponent (comp), c.start_time, c.end_time, cancellable, tag_calendar_cb, closure, g_free); } else e_cal_recur_generate_instances ( comp, c.start_time, c.end_time, tag_calendar_cb, &c, resolve_tzid_cb, client, c.zone); }