evolution-3.6.4/calendar/gui/e-cal-component-preview.c

No issues found

  1 /*
  2  * This program is free software; you can redistribute it and/or
  3  * modify it under the terms of the GNU Lesser General Public
  4  * License as published by the Free Software Foundation; either
  5  * version 2 of the License, or (at your option) version 3.
  6  *
  7  * This program is distributed in the hope that it will be useful,
  8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 10  * Lesser General Public License for more details.
 11  *
 12  * You should have received a copy of the GNU Lesser General Public
 13  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 14  *
 15  *
 16  * Authors:
 17  *		Federico Mena Quintero <federico@ximian.com>
 18  *	    Damon Chaplin <damon@ximian.com>
 19  *      Rodrigo Moya <rodrigo@ximian.com>
 20  *
 21  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 22  *
 23  */
 24 
 25 #ifdef HAVE_CONFIG_H
 26 #include <config.h>
 27 #endif
 28 
 29 #include "e-cal-component-preview.h"
 30 
 31 #include <string.h>
 32 #include <gtk/gtk.h>
 33 #include <glib/gi18n.h>
 34 #include <camel/camel.h>
 35 
 36 #include <e-util/e-util.h>
 37 #include <e-util/e-categories-config.h>
 38 
 39 #define E_CAL_COMPONENT_PREVIEW_GET_PRIVATE(obj) \
 40 	(G_TYPE_INSTANCE_GET_PRIVATE \
 41 	((obj), E_TYPE_CAL_COMPONENT_PREVIEW, ECalComponentPreviewPrivate))
 42 
 43 G_DEFINE_TYPE (
 44 	ECalComponentPreview,
 45 	e_cal_component_preview,
 46 	E_TYPE_WEB_VIEW)
 47 
 48 struct _ECalComponentPreviewPrivate {
 49 	/* information about currently showing component in a preview;
 50 	 * if it didn't change then the preview is not updated */
 51 	gchar *cal_uid;
 52 	gchar *comp_uid;
 53 	struct icaltimetype comp_last_modified;
 54 	gint comp_sequence;
 55 
 56 	ECalClient *client;
 57 	ECalComponent *comp;
 58 	icaltimezone *timezone;
 59 	gboolean use_24_hour_format;
 60 };
 61 
 62 #define HTML_HEADER "<!doctype html public \"-//W3C//DTD HTML 4.0 TRANSITIONAL//EN\">\n<html>\n"  \
 63                     "<head>\n<meta name=\"generator\" content=\"Evolution Calendar Component\">\n" \
 64 		    "<link type=\"text/css\" rel=\"stylesheet\" href=\"evo-file://" EVOLUTION_PRIVDATADIR "/theme/webview.css\">\n" \
 65 		    "<style>\n" \
 66 		    ".description { font-family: monospace; font-size: 1em; }\n" \
 67 		    "</style>\n" \
 68 		    "</head>"
 69 
 70 static void
 71 clear_comp_info (ECalComponentPreview *preview)
 72 {
 73 	ECalComponentPreviewPrivate *priv;
 74 
 75 	g_return_if_fail (E_IS_CAL_COMPONENT_PREVIEW (preview));
 76 
 77 	priv = preview->priv;
 78 
 79 	g_free (priv->cal_uid);
 80 	priv->cal_uid = NULL;
 81 	g_free (priv->comp_uid);
 82 	priv->comp_uid = NULL;
 83 	priv->comp_last_modified = icaltime_null_time ();
 84 	priv->comp_sequence = -1;
 85 
 86 	g_clear_object (&priv->client);
 87 	g_clear_object (&priv->comp);
 88 	if (priv->timezone) {
 89 		icaltimezone_free (priv->timezone, 1);
 90 		priv->timezone = NULL;
 91 	}
 92 }
 93 
 94 /* Stores information about actually shown component and
 95  * returns whether component in the preview changed */
 96 static gboolean
 97 update_comp_info (ECalComponentPreview *preview,
 98                   ECalClient *client,
 99                   ECalComponent *comp,
100                   icaltimezone *zone,
101                   gboolean use_24_hour_format)
102 {
103 	ECalComponentPreviewPrivate *priv;
104 	gboolean changed;
105 
106 	g_return_val_if_fail (preview != NULL, TRUE);
107 	g_return_val_if_fail (E_IS_CAL_COMPONENT_PREVIEW (preview), TRUE);
108 
109 	priv = preview->priv;
110 
111 	if (!E_IS_CAL_COMPONENT (comp) || !E_IS_CAL_CLIENT (client)) {
112 		changed = !priv->cal_uid;
113 		clear_comp_info (preview);
114 	} else {
115 		ESource *source;
116 		const gchar *uid;
117 		gchar *cal_uid;
118 		gchar *comp_uid;
119 		struct icaltimetype comp_last_modified, *itm = NULL;
120 		gint *sequence = NULL;
121 		gint comp_sequence;
122 
123 		source = e_client_get_source (E_CLIENT (client));
124 		cal_uid = g_strdup (e_source_get_uid (source));
125 		e_cal_component_get_uid (comp, &uid);
126 		comp_uid = g_strdup (uid);
127 		e_cal_component_get_last_modified (comp, &itm);
128 		if (itm) {
129 			comp_last_modified = *itm;
130 			e_cal_component_free_icaltimetype (itm);
131 		} else
132 			comp_last_modified = icaltime_null_time ();
133 		e_cal_component_get_sequence (comp, &sequence);
134 		if (sequence) {
135 			comp_sequence = *sequence;
136 			e_cal_component_free_sequence (sequence);
137 		} else
138 			comp_sequence = 0;
139 
140 		changed = !priv->cal_uid || !priv->comp_uid || !cal_uid || !comp_uid ||
141 			  !g_str_equal (priv->cal_uid, cal_uid) ||
142 			  !g_str_equal (priv->comp_uid, comp_uid) ||
143 			  priv->comp_sequence != comp_sequence ||
144 			  icaltime_compare (priv->comp_last_modified, comp_last_modified) != 0;
145 
146 		clear_comp_info (preview);
147 
148 		priv->cal_uid = cal_uid;
149 		priv->comp_uid = comp_uid;
150 		priv->comp_sequence = comp_sequence;
151 		priv->comp_last_modified = comp_last_modified;
152 
153 		priv->comp = g_object_ref (comp);
154 		priv->client = g_object_ref (client);
155 		priv->timezone = icaltimezone_copy (zone);
156 		priv->use_24_hour_format = use_24_hour_format;
157 	}
158 
159 	return changed;
160 }
161 
162 /* Converts a time_t to a string, relative to the specified timezone */
163 static gchar *
164 timet_to_str_with_zone (ECalComponentDateTime *dt,
165                         ECalClient *client,
166                         icaltimezone *default_zone,
167                         gboolean use_24_hour_format)
168 {
169 	struct icaltimetype itt;
170 	icaltimezone *zone;
171 	struct tm tm;
172 	gchar buf[256];
173 
174 	if (dt->tzid) {
175 		/* If we can't find the zone, we'll guess its "local" */
176 		if (!e_cal_client_get_timezone_sync (client, dt->tzid, &zone, NULL, NULL))
177 			zone = NULL;
178 	} else if (dt->value->is_utc) {
179 		zone = icaltimezone_get_utc_timezone ();
180 	} else {
181 		zone = NULL;
182 	}
183 
184 	itt = *dt->value;
185 	if (zone)
186 		icaltimezone_convert_time (&itt, zone, default_zone);
187 	tm = icaltimetype_to_tm (&itt);
188 
189 	e_time_format_date_and_time (
190 		&tm, use_24_hour_format,
191 		FALSE, FALSE, buf, sizeof (buf));
192 
193 	return g_locale_to_utf8 (buf, -1, NULL, NULL, NULL);
194 }
195 
196 static void
197 cal_component_preview_write_html (ECalComponentPreview *preview,
198                                   GString *buffer)
199 {
200 	ECalClient *client;
201 	ECalComponent *comp;
202 	icaltimezone *default_zone;
203 	gboolean use_24_hour_format;
204 	ECalComponentText text;
205 	ECalComponentDateTime dt;
206 	gchar *str;
207 	GString *string;
208 	GSList *list, *iter;
209 	icalcomponent *icalcomp;
210 	icalproperty *icalprop;
211 	icalproperty_status status;
212 	const gchar *location;
213 	gint *priority_value;
214 	GtkStyle *style;
215 	GtkStateType state;
216 
217 	client = preview->priv->client;
218 	comp = preview->priv->comp;
219 	default_zone = preview->priv->timezone;
220 	use_24_hour_format = preview->priv->use_24_hour_format;
221 
222 	/* write document header */
223 	e_cal_component_get_summary (comp, &text);
224 
225 	style = gtk_widget_get_style (GTK_WIDGET (preview));
226 	state = gtk_widget_get_state (GTK_WIDGET (preview));
227 
228 	g_string_append (buffer, HTML_HEADER);
229 	g_string_append_printf (
230 		buffer, "<body bgcolor=\"#%06x\" text=\"#%06x\">",
231 		e_color_to_value (&style->base[state]),
232 		e_color_to_value (&style->text[state]));
233 
234 	if (text.value)
235 		g_string_append_printf (buffer, "<h2>%s</h2>", text.value);
236 	else
237 		g_string_append_printf (buffer, "<h2><i>%s</i></h2>",_("Untitled"));
238 
239 	g_string_append (buffer, "<table border=\"0\" cellspacing=\"5\">");
240 
241 	/* write icons for the categories */
242 	string = g_string_new (NULL);
243 	e_cal_component_get_categories_list (comp, &list);
244 	if (list != NULL)
245 		g_string_append_printf (buffer, "<tr><th>%s</th><td>", _("Categories:"));
246 	for (iter = list; iter != NULL; iter = iter->next) {
247 		const gchar *category = iter->data;
248 		const gchar *icon_file;
249 
250 		icon_file = e_categories_get_icon_file_for (category);
251 		if (icon_file && g_file_test (icon_file, G_FILE_TEST_EXISTS)) {
252 			gchar *uri;
253 
254 			uri = g_filename_to_uri (icon_file, NULL, NULL);
255 			g_string_append_printf (
256 				buffer, "<img alt=\"%s\" src=\"evo-%s\">",
257 				category, uri);
258 			g_free (uri);
259 		} else {
260 			if (iter != list)
261 				g_string_append_len (string, ", ", 2);
262 			g_string_append (string, category);
263 		}
264 	}
265 	if (string->len > 0)
266 		g_string_append_printf (buffer, "%s", string->str);
267 	if (list != NULL)
268 		g_string_append (buffer, "</td></tr>");
269 	e_cal_component_free_categories_list (list);
270 	g_string_free (string, TRUE);
271 
272 	/* write location */
273 	e_cal_component_get_location (comp, &location);
274 	if (location)
275 		g_string_append_printf (
276 			buffer, "<tr><th>%s</th><td>%s</td></tr>",
277 			_("Summary:"), text.value);
278 
279 	/* write start date */
280 	e_cal_component_get_dtstart (comp, &dt);
281 	if (dt.value != NULL) {
282 		str = timet_to_str_with_zone (
283 			&dt, client, default_zone, use_24_hour_format);
284 		g_string_append_printf (
285 			buffer, "<tr><th>%s</th><td>%s</td></tr>",
286 			_("Start Date:"), str);
287 		g_free (str);
288 	}
289 	e_cal_component_free_datetime (&dt);
290 
291 	/* write end date */
292 	e_cal_component_get_dtend (comp, &dt);
293 	if (dt.value != NULL) {
294 		str = timet_to_str_with_zone (
295 			&dt, client, default_zone, use_24_hour_format);
296 		g_string_append_printf (
297 			buffer,"<tr><th>%s</th><td>%s</td></tr>",
298 			_("End Date:"), str);
299 		g_free (str);
300 	}
301 	e_cal_component_free_datetime (&dt);
302 
303 	/* write Due Date */
304 	e_cal_component_get_due (comp, &dt);
305 	if (dt.value != NULL) {
306 		str = timet_to_str_with_zone (
307 			&dt, client, default_zone, use_24_hour_format);
308 		g_string_append_printf (
309 			buffer, "<tr><th>%s</th><td>%s</td></tr>",
310 			_("Due Date:"), str);
311 		g_free (str);
312 	}
313 	e_cal_component_free_datetime (&dt);
314 
315 	/* write status */
316 	icalcomp = e_cal_component_get_icalcomponent (comp);
317 	icalprop = icalcomponent_get_first_property (
318 		icalcomp, ICAL_STATUS_PROPERTY);
319 	if (icalprop != NULL) {
320 		g_string_append_printf (
321 			buffer, "<tr><th>%s</th>",
322 			_("Status:"));
323 		e_cal_component_get_status (comp, &status);
324 		switch (status) {
325 		case ICAL_STATUS_INPROCESS :
326 			str = g_strdup (_("In Progress"));
327 			break;
328 		case ICAL_STATUS_COMPLETED :
329 			str = g_strdup (_("Completed"));
330 			break;
331 		case ICAL_STATUS_CANCELLED :
332 			str = g_strdup (_("Canceled"));
333 			break;
334 		case ICAL_STATUS_NONE :
335 		default :
336 			str = g_strdup (_("Not Started"));
337 			break;
338 		}
339 
340 		g_string_append_printf (buffer, "<td>%s</td></tr>", str);
341 		g_free (str);
342 	}
343 
344 	/* write priority */
345 	e_cal_component_get_priority (comp, &priority_value);
346 	if (priority_value && *priority_value != 0) {
347 		g_string_append_printf (
348 			buffer, "<tr><th>%s</th>",
349 			_("Priority:"));
350 		if (*priority_value <= 4)
351 			str = g_strdup (_("High"));
352 		else if (*priority_value == 5)
353 			str = g_strdup (_("Normal"));
354 		else
355 			str = g_strdup (_("Low"));
356 
357 		g_string_append_printf (buffer, "<td>%s</td></tr>", str);
358 
359 		g_free (str);
360 	}
361 
362 	if (priority_value)
363 		e_cal_component_free_priority (priority_value);
364 
365 	/* write description and URL */
366 	g_string_append (buffer, "<tr><td colspan=\"2\"><hr></td></tr>");
367 
368 	e_cal_component_get_description_list (comp, &list);
369 	if (list) {
370 		GSList *node;
371 
372 		g_string_append_printf (
373 			buffer, "<tr><th>%s</th>",
374 			_("Description:"));
375 
376 		g_string_append (buffer, "<td class=\"description\">");
377 
378 		for (node = list; node != NULL; node = node->next) {
379 			gchar *html;
380 
381 			text = * (ECalComponentText *) node->data;
382 			html = camel_text_to_html (
383 				text.value ? text.value : "",
384 				CAMEL_MIME_FILTER_TOHTML_CONVERT_NL |
385 				CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES |
386 				CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS |
387 				CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES, 0);
388 
389 			if (html)
390 				g_string_append_printf (buffer, "%s", html);
391 
392 			g_free (html);
393 		}
394 
395 		g_string_append (buffer, "</td></tr>");
396 
397 		e_cal_component_free_text_list (list);
398 	}
399 
400 	/* URL */
401 	e_cal_component_get_url (comp, (const gchar **) &str);
402 	if (str) {
403 		g_string_append_printf (
404 			buffer, "<tr><th>%s</th><td><a href=\"%s\">%s</a></td></tr>",
405 			_("Web Page:"), str, str);
406 	}
407 
408 	g_string_append (buffer, "</table>");
409 
410 	/* close document */
411 	g_string_append (buffer, "</body></html>");
412 }
413 
414 static void
415 load_comp (ECalComponentPreview *preview)
416 {
417 	GString *buffer;
418 
419 	if (!preview->priv->comp) {
420 		e_cal_component_preview_clear (preview);
421 		return;
422 	}
423 
424 	buffer = g_string_sized_new (4096);
425 	cal_component_preview_write_html (preview, buffer);
426 	e_web_view_load_string (E_WEB_VIEW (preview), buffer->str);
427 	g_string_free (buffer, TRUE);
428 }
429 
430 static void
431 cal_component_preview_finalize (GObject *object)
432 {
433 	clear_comp_info (E_CAL_COMPONENT_PREVIEW (object));
434 
435 	/* Chain up to parent's finalize() method. */
436 	G_OBJECT_CLASS (e_cal_component_preview_parent_class)->finalize (object);
437 }
438 
439 static void
440 e_cal_component_preview_class_init (ECalComponentPreviewClass *class)
441 {
442 	GObjectClass *object_class;
443 
444 	g_type_class_add_private (class, sizeof (ECalComponentPreviewPrivate));
445 
446 	object_class = G_OBJECT_CLASS (class);
447 	object_class->finalize = cal_component_preview_finalize;
448 }
449 
450 static void
451 e_cal_component_preview_init (ECalComponentPreview *preview)
452 {
453 	preview->priv = E_CAL_COMPONENT_PREVIEW_GET_PRIVATE (preview);
454 
455 	g_signal_connect (
456 		preview, "style-set",
457 		G_CALLBACK (load_comp), NULL);
458 }
459 
460 GtkWidget *
461 e_cal_component_preview_new (void)
462 {
463 	return g_object_new (E_TYPE_CAL_COMPONENT_PREVIEW, NULL);
464 }
465 
466 void
467 e_cal_component_preview_display (ECalComponentPreview *preview,
468                                  ECalClient *client,
469                                  ECalComponent *comp,
470                                  icaltimezone *zone,
471                                  gboolean use_24_hour_format)
472 {
473 	g_return_if_fail (E_IS_CAL_COMPONENT_PREVIEW (preview));
474 	g_return_if_fail (E_IS_CAL_COMPONENT (comp));
475 
476 	/* do not update preview when setting the same component as last time,
477 	 * which even didn't change */
478 	if (!update_comp_info (preview, client, comp, zone, use_24_hour_format))
479 		return;
480 
481 	load_comp (preview);
482 }
483 
484 void
485 e_cal_component_preview_clear (ECalComponentPreview *preview)
486 {
487 	g_return_if_fail (E_IS_CAL_COMPONENT_PREVIEW (preview));
488 
489 	clear_comp_info (preview);
490 	e_web_view_clear (E_WEB_VIEW (preview));
491 }