/* * 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: * Federico Mena Quintero * Damon Chaplin * Rodrigo Moya * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * */ #ifdef HAVE_CONFIG_H #include #endif #include "e-cal-component-preview.h" #include #include #include #include #define E_CAL_COMPONENT_PREVIEW_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ ((obj), E_TYPE_CAL_COMPONENT_PREVIEW, ECalComponentPreviewPrivate)) G_DEFINE_TYPE ( ECalComponentPreview, e_cal_component_preview, E_TYPE_WEB_VIEW) struct _ECalComponentPreviewPrivate { /* information about currently showing component in a preview; * if it didn't change then the preview is not updated */ gchar *cal_uid; gchar *comp_uid; struct icaltimetype comp_last_modified; gint comp_sequence; ECalClient *client; ECalComponent *comp; icaltimezone *timezone; gboolean use_24_hour_format; }; #define HTML_HEADER "\n\n" \ "\n\n" \ "\n" \ "\n" \ "" static void clear_comp_info (ECalComponentPreview *preview) { ECalComponentPreviewPrivate *priv; g_return_if_fail (E_IS_CAL_COMPONENT_PREVIEW (preview)); priv = preview->priv; g_free (priv->cal_uid); priv->cal_uid = NULL; g_free (priv->comp_uid); priv->comp_uid = NULL; priv->comp_last_modified = icaltime_null_time (); priv->comp_sequence = -1; g_clear_object (&priv->client); g_clear_object (&priv->comp); if (priv->timezone) { icaltimezone_free (priv->timezone, 1); priv->timezone = NULL; } } /* Stores information about actually shown component and * returns whether component in the preview changed */ static gboolean update_comp_info (ECalComponentPreview *preview, ECalClient *client, ECalComponent *comp, icaltimezone *zone, gboolean use_24_hour_format) { ECalComponentPreviewPrivate *priv; gboolean changed; g_return_val_if_fail (preview != NULL, TRUE); g_return_val_if_fail (E_IS_CAL_COMPONENT_PREVIEW (preview), TRUE); priv = preview->priv; if (!E_IS_CAL_COMPONENT (comp) || !E_IS_CAL_CLIENT (client)) { changed = !priv->cal_uid; clear_comp_info (preview); } else { ESource *source; const gchar *uid; gchar *cal_uid; gchar *comp_uid; struct icaltimetype comp_last_modified, *itm = NULL; gint *sequence = NULL; gint comp_sequence; source = e_client_get_source (E_CLIENT (client)); cal_uid = g_strdup (e_source_get_uid (source)); e_cal_component_get_uid (comp, &uid); comp_uid = g_strdup (uid); e_cal_component_get_last_modified (comp, &itm); if (itm) { comp_last_modified = *itm; e_cal_component_free_icaltimetype (itm); } else comp_last_modified = icaltime_null_time (); e_cal_component_get_sequence (comp, &sequence); if (sequence) { comp_sequence = *sequence; e_cal_component_free_sequence (sequence); } else comp_sequence = 0; changed = !priv->cal_uid || !priv->comp_uid || !cal_uid || !comp_uid || !g_str_equal (priv->cal_uid, cal_uid) || !g_str_equal (priv->comp_uid, comp_uid) || priv->comp_sequence != comp_sequence || icaltime_compare (priv->comp_last_modified, comp_last_modified) != 0; clear_comp_info (preview); priv->cal_uid = cal_uid; priv->comp_uid = comp_uid; priv->comp_sequence = comp_sequence; priv->comp_last_modified = comp_last_modified; priv->comp = g_object_ref (comp); priv->client = g_object_ref (client); priv->timezone = icaltimezone_copy (zone); priv->use_24_hour_format = use_24_hour_format; } return changed; } /* Converts a time_t to a string, relative to the specified timezone */ static gchar * timet_to_str_with_zone (ECalComponentDateTime *dt, ECalClient *client, icaltimezone *default_zone, gboolean use_24_hour_format) { struct icaltimetype itt; icaltimezone *zone; struct tm tm; gchar buf[256]; if (dt->tzid) { /* If we can't find the zone, we'll guess its "local" */ if (!e_cal_client_get_timezone_sync (client, dt->tzid, &zone, NULL, NULL)) zone = NULL; } else if (dt->value->is_utc) { zone = icaltimezone_get_utc_timezone (); } else { zone = NULL; } itt = *dt->value; if (zone) icaltimezone_convert_time (&itt, zone, default_zone); tm = icaltimetype_to_tm (&itt); e_time_format_date_and_time ( &tm, use_24_hour_format, FALSE, FALSE, buf, sizeof (buf)); return g_locale_to_utf8 (buf, -1, NULL, NULL, NULL); } static void cal_component_preview_write_html (ECalComponentPreview *preview, GString *buffer) { ECalClient *client; ECalComponent *comp; icaltimezone *default_zone; gboolean use_24_hour_format; ECalComponentText text; ECalComponentDateTime dt; gchar *str; GString *string; GSList *list, *iter; icalcomponent *icalcomp; icalproperty *icalprop; icalproperty_status status; const gchar *location; gint *priority_value; GtkStyle *style; GtkStateType state; client = preview->priv->client; comp = preview->priv->comp; default_zone = preview->priv->timezone; use_24_hour_format = preview->priv->use_24_hour_format; /* write document header */ e_cal_component_get_summary (comp, &text); style = gtk_widget_get_style (GTK_WIDGET (preview)); state = gtk_widget_get_state (GTK_WIDGET (preview)); g_string_append (buffer, HTML_HEADER); g_string_append_printf ( buffer, "", e_color_to_value (&style->base[state]), e_color_to_value (&style->text[state])); if (text.value) g_string_append_printf (buffer, "

%s

", text.value); else g_string_append_printf (buffer, "

%s

",_("Untitled")); g_string_append (buffer, ""); /* write icons for the categories */ string = g_string_new (NULL); e_cal_component_get_categories_list (comp, &list); if (list != NULL) g_string_append_printf (buffer, ""); e_cal_component_free_categories_list (list); g_string_free (string, TRUE); /* write location */ e_cal_component_get_location (comp, &location); if (location) g_string_append_printf ( buffer, "", _("Summary:"), text.value); /* write start date */ e_cal_component_get_dtstart (comp, &dt); if (dt.value != NULL) { str = timet_to_str_with_zone ( &dt, client, default_zone, use_24_hour_format); g_string_append_printf ( buffer, "", _("Start Date:"), str); g_free (str); } e_cal_component_free_datetime (&dt); /* write end date */ e_cal_component_get_dtend (comp, &dt); if (dt.value != NULL) { str = timet_to_str_with_zone ( &dt, client, default_zone, use_24_hour_format); g_string_append_printf ( buffer,"", _("End Date:"), str); g_free (str); } e_cal_component_free_datetime (&dt); /* write Due Date */ e_cal_component_get_due (comp, &dt); if (dt.value != NULL) { str = timet_to_str_with_zone ( &dt, client, default_zone, use_24_hour_format); g_string_append_printf ( buffer, "", _("Due Date:"), str); g_free (str); } e_cal_component_free_datetime (&dt); /* write status */ icalcomp = e_cal_component_get_icalcomponent (comp); icalprop = icalcomponent_get_first_property ( icalcomp, ICAL_STATUS_PROPERTY); if (icalprop != NULL) { g_string_append_printf ( buffer, "", _("Status:")); e_cal_component_get_status (comp, &status); switch (status) { case ICAL_STATUS_INPROCESS : str = g_strdup (_("In Progress")); break; case ICAL_STATUS_COMPLETED : str = g_strdup (_("Completed")); break; case ICAL_STATUS_CANCELLED : str = g_strdup (_("Canceled")); break; case ICAL_STATUS_NONE : default : str = g_strdup (_("Not Started")); break; } g_string_append_printf (buffer, "", str); g_free (str); } /* write priority */ e_cal_component_get_priority (comp, &priority_value); if (priority_value && *priority_value != 0) { g_string_append_printf ( buffer, "", _("Priority:")); if (*priority_value <= 4) str = g_strdup (_("High")); else if (*priority_value == 5) str = g_strdup (_("Normal")); else str = g_strdup (_("Low")); g_string_append_printf (buffer, "", str); g_free (str); } if (priority_value) e_cal_component_free_priority (priority_value); /* write description and URL */ g_string_append (buffer, ""); e_cal_component_get_description_list (comp, &list); if (list) { GSList *node; g_string_append_printf ( buffer, "", _("Description:")); g_string_append (buffer, ""); e_cal_component_free_text_list (list); } /* URL */ e_cal_component_get_url (comp, (const gchar **) &str); if (str) { g_string_append_printf ( buffer, "", _("Web Page:"), str, str); } g_string_append (buffer, "
%s", _("Categories:")); for (iter = list; iter != NULL; iter = iter->next) { const gchar *category = iter->data; const gchar *icon_file; icon_file = e_categories_get_icon_file_for (category); if (icon_file && g_file_test (icon_file, G_FILE_TEST_EXISTS)) { gchar *uri; uri = g_filename_to_uri (icon_file, NULL, NULL); g_string_append_printf ( buffer, "\"%s\"", category, uri); g_free (uri); } else { if (iter != list) g_string_append_len (string, ", ", 2); g_string_append (string, category); } } if (string->len > 0) g_string_append_printf (buffer, "%s", string->str); if (list != NULL) g_string_append (buffer, "
%s%s
%s%s
%s%s
%s%s
%s%s
%s%s

%s"); for (node = list; node != NULL; node = node->next) { gchar *html; text = * (ECalComponentText *) node->data; html = camel_text_to_html ( text.value ? text.value : "", CAMEL_MIME_FILTER_TOHTML_CONVERT_NL | CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES | CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS | CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES, 0); if (html) g_string_append_printf (buffer, "%s", html); g_free (html); } g_string_append (buffer, "
%s%s
"); /* close document */ g_string_append (buffer, ""); } static void load_comp (ECalComponentPreview *preview) { GString *buffer; if (!preview->priv->comp) { e_cal_component_preview_clear (preview); return; } buffer = g_string_sized_new (4096); cal_component_preview_write_html (preview, buffer); e_web_view_load_string (E_WEB_VIEW (preview), buffer->str); g_string_free (buffer, TRUE); } static void cal_component_preview_finalize (GObject *object) { clear_comp_info (E_CAL_COMPONENT_PREVIEW (object)); /* Chain up to parent's finalize() method. */ G_OBJECT_CLASS (e_cal_component_preview_parent_class)->finalize (object); } static void e_cal_component_preview_class_init (ECalComponentPreviewClass *class) { GObjectClass *object_class; g_type_class_add_private (class, sizeof (ECalComponentPreviewPrivate)); object_class = G_OBJECT_CLASS (class); object_class->finalize = cal_component_preview_finalize; } static void e_cal_component_preview_init (ECalComponentPreview *preview) { preview->priv = E_CAL_COMPONENT_PREVIEW_GET_PRIVATE (preview); g_signal_connect ( preview, "style-set", G_CALLBACK (load_comp), NULL); } GtkWidget * e_cal_component_preview_new (void) { return g_object_new (E_TYPE_CAL_COMPONENT_PREVIEW, NULL); } void e_cal_component_preview_display (ECalComponentPreview *preview, ECalClient *client, ECalComponent *comp, icaltimezone *zone, gboolean use_24_hour_format) { g_return_if_fail (E_IS_CAL_COMPONENT_PREVIEW (preview)); g_return_if_fail (E_IS_CAL_COMPONENT (comp)); /* do not update preview when setting the same component as last time, * which even didn't change */ if (!update_comp_info (preview, client, comp, zone, use_24_hour_format)) return; load_comp (preview); } void e_cal_component_preview_clear (ECalComponentPreview *preview) { g_return_if_fail (E_IS_CAL_COMPONENT_PREVIEW (preview)); clear_comp_info (preview); e_web_view_clear (E_WEB_VIEW (preview)); }