/* * e-summary.c: ESummary object. * * Copyright (C) 2001 Ximian, Inc. * * Authors: Iain Holmes */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "e-summary.h" #include "e-summary-preferences.h" #include "my-evolution-html.h" #include "Mail.h" #include #include #define PARENT_TYPE (gtk_vbox_get_type ()) extern char *evolution_dir; static GtkObjectClass *e_summary_parent_class; struct _ESummaryMailFolderInfo { char *name; int count; int unread; }; typedef struct _DownloadInfo { GtkHTMLStream *stream; char *uri; char *buffer; gboolean error; } DownloadInfo; struct _ESummaryPrivate { GNOME_Evolution_Shell shell; GNOME_Evolution_ShellView shell_view_interface; GtkWidget *html_scroller; GtkWidget *html; GHashTable *protocol_hash; GList *connections; gpointer alarm; }; typedef struct _ProtocolListener { ESummaryProtocolListener listener; void *closure; } ProtocolListener; static void free_protocol (gpointer key, gpointer value, gpointer user_data) { g_free (key); g_free (value); } static void destroy (GtkObject *object) { ESummary *summary; ESummaryPrivate *priv; summary = E_SUMMARY (object); priv = summary->priv; if (priv == NULL) { return; } if (summary->mail) { e_summary_mail_free (summary); } if (summary->calendar) { e_summary_calendar_free (summary); } if (summary->rdf) { e_summary_rdf_free (summary); } if (summary->weather) { e_summary_weather_free (summary); } if (summary->tasks) { e_summary_tasks_free (summary); } alarm_remove (priv->alarm); alarm_done (); if (priv->protocol_hash) { g_hash_table_foreach (priv->protocol_hash, free_protocol, NULL); g_hash_table_destroy (priv->protocol_hash); } g_free (priv); summary->priv = NULL; e_summary_parent_class->destroy (object); } void e_summary_draw (ESummary *summary) { GString *string; GtkHTMLStream *stream; char *html; char date[256], *date_utf; time_t t; g_return_if_fail (summary != NULL); g_return_if_fail (IS_E_SUMMARY (summary)); if (summary->mail == NULL || summary->calendar == NULL || summary->rdf == NULL || summary->weather == NULL || summary->tasks == NULL) { return; } string = g_string_new (HTML_1); t = time (NULL); strftime (date, 255, _("%A, %B %e %Y"), localtime (&t)); date_utf = e_utf8_from_locale_string (date); html = g_strdup_printf (HTML_2, date_utf); g_free (date_utf); g_string_append (string, html); g_free (html); g_string_append (string, HTML_3); /* Weather and RDF stuff here */ html = e_summary_weather_get_html (summary); if (html != NULL) { g_string_append (string, html); g_free (html); } html = e_summary_rdf_get_html (summary); if (html != NULL) { g_string_append (string, html); g_free (html); } g_string_append (string, HTML_4); html = (char *) e_summary_mail_get_html (summary); if (html != NULL) { g_string_append (string, html); } html = (char *) e_summary_calendar_get_html (summary); if (html != NULL) { g_string_append (string, html); } html = (char *) e_summary_tasks_get_html (summary); if (html != NULL) { g_string_append (string, html); } g_string_append (string, HTML_5); stream = gtk_html_begin (GTK_HTML (summary->priv->html)); GTK_HTML (summary->priv->html)->engine->newPage = FALSE; gtk_html_write (GTK_HTML (summary->priv->html), stream, string->str, strlen (string->str)); gtk_html_end (GTK_HTML (summary->priv->html), stream, GTK_HTML_STREAM_OK); g_string_free (string, TRUE); } static char * e_pixmap_file (const char *filename) { char *ret; char *edir; if (g_file_exists (filename)) { ret = g_strdup (filename); return ret; } /* Try the evolution images dir */ edir = g_concat_dir_and_file (EVOLUTION_DATADIR "/images/evolution", filename); if (g_file_exists (edir)) { ret = g_strdup (edir); g_free (edir); return ret; } g_free (edir); /* Try the evolution button images dir */ edir = g_concat_dir_and_file (EVOLUTION_DATADIR "/images/evolution/buttons", filename); if (g_file_exists (edir)) { ret = g_strdup (edir); g_free (edir); return ret; } g_free (edir); /* Fall back to the gnome_pixmap_file */ return gnome_pixmap_file (filename); } static void close_callback (GnomeVFSAsyncHandle *handle, GnomeVFSResult result, gpointer data) { DownloadInfo *info = data; if (info->error) { gtk_html_stream_close (info->stream, GTK_HTML_STREAM_ERROR); } else { gtk_html_stream_close (info->stream, GTK_HTML_STREAM_OK); } g_free (info->uri); g_free (info->buffer); g_free (info); } static void read_callback (GnomeVFSAsyncHandle *handle, GnomeVFSResult result, gpointer buffer, GnomeVFSFileSize bytes_requested, GnomeVFSFileSize bytes_read, gpointer data) { DownloadInfo *info = data; if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_EOF) { info->error = TRUE; gnome_vfs_async_close (handle, close_callback, info); } if (bytes_read == 0) { info->error = FALSE; gnome_vfs_async_close (handle, close_callback, info); } else { gtk_html_stream_write (info->stream, buffer, bytes_read); gnome_vfs_async_read (handle, buffer, 4095, read_callback, info); } } static void open_callback (GnomeVFSAsyncHandle *handle, GnomeVFSResult result, DownloadInfo *info) { if (result != GNOME_VFS_OK) { gtk_html_stream_close (info->stream, GTK_HTML_STREAM_ERROR); g_free (info->uri); g_free (info); return; } info->buffer = g_new (char, 4096); gnome_vfs_async_read (handle, info->buffer, 4095, read_callback, info); } static void e_summary_url_clicked (GtkHTML *html, const char *url, ESummary *summary) { char *protocol, *protocol_end; ProtocolListener *protocol_listener; protocol_end = strchr (url, ':'); if (protocol_end == NULL) { /* No url, let gnome work it out */ gnome_url_show (url); return; } protocol = g_strndup (url, protocol_end - url); protocol_listener = g_hash_table_lookup (summary->priv->protocol_hash, protocol); g_free (protocol); if (protocol_listener == NULL) { /* Again, let gnome work it out */ gnome_url_show (url); return; } protocol_listener->listener (summary, url, protocol_listener->closure); } static void e_summary_url_requested (GtkHTML *html, const char *url, GtkHTMLStream *stream, ESummary *summary) { char *filename; GnomeVFSAsyncHandle *handle; DownloadInfo *info; if (strncasecmp (url, "file:", 5) == 0) { url += 5; filename = e_pixmap_file (url); } else if (strchr (url, ':') >= strchr (url, '/')) { filename = e_pixmap_file (url); } else { filename = g_strdup (url); } if (filename == NULL) { gtk_html_stream_close (stream, GTK_HTML_STREAM_ERROR); return; } info = g_new (DownloadInfo, 1); info->stream = stream; info->uri = filename; info->error = FALSE; gnome_vfs_async_open (&handle, filename, GNOME_VFS_OPEN_READ, (GnomeVFSAsyncOpenCallback) open_callback, info); } static void e_summary_evolution_protocol_listener (ESummary *summary, const char *uri, void *closure) { e_summary_change_current_view (summary, uri); } static void e_summary_class_init (GtkObjectClass *object_class) { object_class->destroy = destroy; e_summary_parent_class = gtk_type_class (PARENT_TYPE); } static void alarm_fn (gpointer alarm_id, time_t trigger, gpointer data) { ESummary *summary; time_t t, day_end; summary = data; t = time (NULL); day_end = time_day_end (t); summary->priv->alarm = alarm_add (day_end, alarm_fn, summary, NULL); e_summary_reconfigure (summary); } #define DEFAULT_HTML "Summaryhello" static void e_summary_init (ESummary *summary) { Bonobo_ConfigDatabase db; CORBA_Environment ev; ESummaryPrivate *priv; GdkColor bgcolor = {0, 0xffff, 0xffff, 0xffff}; time_t t, day_end; summary->priv = g_new (ESummaryPrivate, 1); priv = summary->priv; priv->html_scroller = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->html_scroller), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); priv->html = gtk_html_new (); gtk_html_set_editable (GTK_HTML (priv->html), FALSE); gtk_html_set_default_content_type (GTK_HTML (priv->html), "text/html; charset=utf-8"); gtk_html_set_default_background_color (GTK_HTML (priv->html), &bgcolor); gtk_html_load_from_string (GTK_HTML (priv->html), DEFAULT_HTML, strlen (DEFAULT_HTML)); gtk_signal_connect (GTK_OBJECT (priv->html), "url-requested", GTK_SIGNAL_FUNC (e_summary_url_requested), summary); gtk_signal_connect (GTK_OBJECT (priv->html), "link-clicked", GTK_SIGNAL_FUNC (e_summary_url_clicked), summary); #if 0 gtk_signal_connect (GTK_OBJECT (priv->html), "on-url", GTK_SIGNAL_FUNC (e_summary_on_url), summary); #endif gtk_container_add (GTK_CONTAINER (priv->html_scroller), priv->html); gtk_widget_show_all (priv->html_scroller); gtk_box_pack_start (GTK_BOX (summary), priv->html_scroller, TRUE, TRUE, 0); priv->protocol_hash = NULL; priv->connections = NULL; summary->prefs_window = NULL; e_summary_preferences_init (summary); CORBA_exception_init (&ev); db = bonobo_get_object ("wombat:", "Bonobo/ConfigDatabase", &ev); if (BONOBO_EX (&ev) || db == CORBA_OBJECT_NIL) { CORBA_exception_free (&ev); g_warning ("Error getting Wombat. Using defaults"); return; } summary->timezone = bonobo_config_get_string (db, "/Calendar/Display/Timezone", NULL); summary->tz = icaltimezone_get_builtin_timezone (summary->timezone); bonobo_object_release_unref (db, NULL); CORBA_exception_free (&ev); t = time (NULL); if (summary->tz == NULL) { day_end = time_day_end (t); } else { day_end = time_day_end_with_zone (t, summary->tz); } priv->alarm = alarm_add (day_end, alarm_fn, summary, NULL); } E_MAKE_TYPE (e_summary, "ESummary", ESummary, e_summary_class_init, e_summary_init, PARENT_TYPE); GtkWidget * e_summary_new (const GNOME_Evolution_Shell shell) { ESummary *summary; summary = gtk_type_new (e_summary_get_type ()); summary->priv->shell = shell; e_summary_add_protocol_listener (summary, "evolution", e_summary_evolution_protocol_listener, summary); e_summary_mail_init (summary, shell); e_summary_calendar_init (summary); e_summary_tasks_init (summary); e_summary_rdf_init (summary); e_summary_weather_init (summary); e_summary_draw (summary); return GTK_WIDGET (summary); } static void do_summary_print (ESummary *summary, gboolean preview) { GnomePrintContext *print_context; GnomePrintMaster *print_master; GnomePrintDialog *gpd; GnomePrinter *printer = NULL; int copies = 1; int collate = FALSE; if (!preview) { gpd = GNOME_PRINT_DIALOG (gnome_print_dialog_new (_("Print Summary"), GNOME_PRINT_DIALOG_COPIES)); gnome_dialog_set_default (GNOME_DIALOG (gpd), GNOME_PRINT_PRINT); switch (gnome_dialog_run (GNOME_DIALOG (gpd))) { case GNOME_PRINT_PRINT: break; case GNOME_PRINT_PREVIEW: preview = TRUE; break; case -1: return; default: gnome_dialog_close (GNOME_DIALOG (gpd)); return; } gnome_print_dialog_get_copies (gpd, &copies, &collate); printer = gnome_print_dialog_get_printer (gpd); gnome_dialog_close (GNOME_DIALOG (gpd)); } print_master = gnome_print_master_new (); if (printer) { gnome_print_master_set_printer (print_master, printer); } gnome_print_master_set_copies (print_master, copies, collate); print_context = gnome_print_master_get_context (print_master); gtk_html_print (GTK_HTML (summary->priv->html), print_context); gnome_print_master_close (print_master); if (preview) { gboolean landscape = FALSE; GnomePrintMasterPreview *preview; preview = gnome_print_master_preview_new_with_orientation ( print_master, _("Print Preview"), landscape); gtk_widget_show (GTK_WIDGET (preview)); } else { int result = gnome_print_master_print (print_master); if (result == -1) { e_notice (NULL, GNOME_MESSAGE_BOX_ERROR, _("Printing of Summary failed")); } } gtk_object_unref (GTK_OBJECT (print_master)); } void e_summary_print (GtkWidget *widget, ESummary *summary) { do_summary_print (summary, FALSE); } void e_summary_add_protocol_listener (ESummary *summary, const char *protocol, ESummaryProtocolListener listener, void *closure) { ProtocolListener *old; g_return_if_fail (summary != NULL); g_return_if_fail (IS_E_SUMMARY (summary)); g_return_if_fail (protocol != NULL); g_return_if_fail (listener != NULL); if (summary->priv->protocol_hash == NULL) { summary->priv->protocol_hash = g_hash_table_new (g_str_hash, g_str_equal); old = NULL; } else { old = g_hash_table_lookup (summary->priv->protocol_hash, protocol); } if (old != NULL) { return; } old = g_new (ProtocolListener, 1); old->listener = listener; old->closure = closure; g_hash_table_insert (summary->priv->protocol_hash, g_strdup (protocol), old); } void e_summary_change_current_view (ESummary *summary, const char *uri) { GNOME_Evolution_ShellView svi; CORBA_Environment ev; g_return_if_fail (summary != NULL); g_return_if_fail (IS_E_SUMMARY (summary)); svi = summary->shell_view_interface; if (svi == NULL) { return; } CORBA_exception_init (&ev); GNOME_Evolution_ShellView_changeCurrentView (svi, uri, &ev); CORBA_exception_free (&ev); } void e_summary_set_message (ESummary *summary, const char *message, gboolean busy) { GNOME_Evolution_ShellView svi; CORBA_Environment ev; g_return_if_fail (summary != NULL); g_return_if_fail (IS_E_SUMMARY (summary)); svi = summary->shell_view_interface; if (svi == NULL) { return; } CORBA_exception_init (&ev); GNOME_Evolution_ShellView_setMessage (svi, message ? message : "", busy, &ev); CORBA_exception_free (&ev); } void e_summary_unset_message (ESummary *summary) { GNOME_Evolution_ShellView svi; CORBA_Environment ev; g_return_if_fail (summary != NULL); g_return_if_fail (IS_E_SUMMARY (summary)); svi = summary->shell_view_interface; if (svi == NULL) { return; } CORBA_exception_init (&ev); GNOME_Evolution_ShellView_unsetMessage (svi, &ev); CORBA_exception_free (&ev); } void e_summary_reconfigure (ESummary *summary) { if (summary->mail != NULL) { e_summary_mail_reconfigure (summary); } if (summary->rdf != NULL) { e_summary_rdf_reconfigure (summary); } if (summary->weather != NULL) { e_summary_weather_reconfigure (summary); } if (summary->calendar != NULL) { e_summary_calendar_reconfigure (summary); } if (summary->tasks != NULL) { e_summary_tasks_reconfigure (summary); } } void e_summary_reload (GtkWidget *widget, ESummary *summary) { e_summary_reconfigure (summary); } int e_summary_count_connections (ESummary *summary) { GList *p; int count = 0; if (summary == NULL) { return 0; } for (p = summary->priv->connections; p; p = p->next) { ESummaryConnection *c; c = p->data; count += c->count (summary, c->closure); } return count; } GList * e_summary_add_connections (ESummary *summary) { GList *p; GList *connections = NULL; if (summary == NULL) { return NULL; } for (p = summary->priv->connections; p; p = p->next) { ESummaryConnection *c; GList *r; c = p->data; r = c->add (summary, c->closure); connections = g_list_concat (connections, r); } return connections; } void e_summary_set_online (ESummary *summary, GNOME_Evolution_OfflineProgressListener progress, gboolean online, ESummaryOnlineCallback callback, void *closure) { GList *p; if (summary == NULL) { return; } for (p = summary->priv->connections; p; p = p->next) { ESummaryConnection *c; c = p->data; c->callback = callback; c->callback_closure = closure; c->set_online (summary, progress, online, c->closure); } } void e_summary_add_online_connection (ESummary *summary, ESummaryConnection *connection) { g_return_if_fail (summary != NULL); g_return_if_fail (IS_E_SUMMARY (summary)); g_return_if_fail (connection != NULL); summary->priv->connections = g_list_prepend (summary->priv->connections, connection); } void e_summary_remove_online_connection (ESummary *summary, ESummaryConnection *connection) { GList *p; g_return_if_fail (summary != NULL); g_return_if_fail (IS_E_SUMMARY (summary)); g_return_if_fail (connection != NULL); p = g_list_find (summary->priv->connections, connection); g_return_if_fail (p != NULL); summary->priv->connections = g_list_remove_link (summary->priv->connections, p); g_list_free (p); }