/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* e-summary.c * * Authors: Iain Holmes * * Copyright (C) 2000 Helix Code, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * 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 * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include "e-summary.h" #define PARENT_TYPE (gtk_vbox_get_type ()) static GtkObjectClass *e_summary_parent_class; struct _ESummaryPrivate { GtkWidget *html_scroller; GtkWidget *html; GHashTable *id_to_view; GHashTable *summary_to_window; GList *window_list; guint idle; GtkHTMLStream *stream; }; typedef struct _ESummaryWindow { ExecutiveSummary *summary; ExecutiveSummaryComponentView *view; } ESummaryWindow; static gboolean on_object_requested (GtkHTML *html, GtkHTMLEmbedded *eb, ESummary *summary); static void e_summary_window_free (ESummaryWindow *window, ESummaryPrivate *priv); /* GtkObject methods */ static void s2w_foreach (gpointer *key, gpointer *value, ESummaryPrivate *priv) { g_print ("%s\n", __FUNCTION__); e_summary_window_free ((ESummaryWindow *) value, priv); g_free (value); } static void e_summary_destroy (GtkObject *object) { ESummary *esummary = E_SUMMARY (object); ESummaryPrivate *priv; g_print ("Destroy\n"); priv = esummary->private; if (priv == NULL) return; g_hash_table_foreach (priv->summary_to_window, s2w_foreach, priv); g_hash_table_destroy (priv->summary_to_window); g_hash_table_destroy (priv->id_to_view); g_free (esummary->private); esummary->private = NULL; e_summary_parent_class->destroy (object); } static void e_summary_class_init (GtkObjectClass *object_class) { object_class->destroy = e_summary_destroy; e_summary_parent_class = gtk_type_class (PARENT_TYPE); } 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; } /* 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; } /* Fall back to the gnome_pixmap_file */ return gnome_pixmap_file (filename); } static void request_cb (GtkHTML *html, const gchar *url, GtkHTMLStream *stream) { char *filename; GnomeVFSHandle *handle = NULL; GnomeVFSResult result; 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; } result = gnome_vfs_open (&handle, filename, GNOME_VFS_OPEN_READ); if (result != GNOME_VFS_OK) { g_warning ("%s: %s", filename, gnome_vfs_result_to_string (result)); g_free (filename); gtk_html_stream_close (stream, GTK_HTML_STREAM_ERROR); return; } g_free (filename); while (1) { char buffer[4096]; GnomeVFSFileSize size; /* Clear buffer */ memset (buffer, 0x00, 4096); result = gnome_vfs_read (handle, buffer, 4096, &size); if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_EOF) { g_warning ("Error reading data: %s", gnome_vfs_result_to_string (result)); gnome_vfs_close (handle); gtk_html_stream_close (stream, GTK_HTML_STREAM_ERROR); } if (size == 0) break; /* EOF */ gtk_html_stream_write (stream, buffer, size); } gtk_html_stream_close (stream, GTK_HTML_STREAM_OK); gnome_vfs_close (handle); } static void e_summary_start_load (ESummary *summary) { ESummaryPrivate *priv; char *header = ""; priv = summary->private; priv->stream = gtk_html_begin (GTK_HTML (priv->html)); gtk_html_write (GTK_HTML (priv->html), priv->stream, header, strlen (header)); } static void load_default (ESummary *summary) { ESummaryPrivate *priv; char *def = "

"; g_return_if_fail (summary != NULL); g_return_if_fail (IS_E_SUMMARY (summary)); priv = summary->private; g_return_if_fail (priv->stream != NULL); gtk_html_write (GTK_HTML (priv->html), priv->stream, def, strlen (def)); } static void e_summary_end_load (ESummary *summary) { ESummaryPrivate *priv; char *footer = ""; priv = summary->private; gtk_html_write (GTK_HTML (priv->html), priv->stream, footer, strlen (footer)); gtk_html_end (GTK_HTML (priv->html), priv->stream, GTK_HTML_STREAM_OK); priv->stream = NULL; } static void e_summary_init (ESummary *esummary) { GdkColor bgcolour = {0, 0xdfff, 0xdfff, 0xffff}; ESummaryPrivate *priv; esummary->private = g_new0 (ESummaryPrivate, 1); priv = esummary->private; priv->window_list = NULL; priv->idle = 0; /* HTML widget */ priv->html_scroller = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->html_scroller), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); priv->html = gtk_html_new (); gtk_html_set_editable (GTK_HTML (priv->html), FALSE); gtk_html_set_default_background_color (GTK_HTML (priv->html), &bgcolour); gtk_signal_connect (GTK_OBJECT (priv->html), "url-requested", GTK_SIGNAL_FUNC (request_cb), NULL); gtk_signal_connect (GTK_OBJECT (priv->html), "object-requested", GTK_SIGNAL_FUNC (on_object_requested), esummary); gtk_container_add (GTK_CONTAINER (priv->html_scroller), priv->html); gtk_widget_show_all (priv->html_scroller); e_summary_rebuild_page (esummary); /* Pack stuff */ gtk_box_pack_start (GTK_BOX (esummary), priv->html_scroller, TRUE, TRUE, 0); /* Init hashtables */ priv->summary_to_window = g_hash_table_new (NULL, NULL); priv->id_to_view = g_hash_table_new (NULL, NULL); } E_MAKE_TYPE (e_summary, "ESummary", ESummary, e_summary_class_init, e_summary_init, PARENT_TYPE); GtkWidget * e_summary_new (const Evolution_Shell shell) { ESummary *esummary; esummary = gtk_type_new (e_summary_get_type ()); return GTK_WIDGET (esummary); } static gboolean on_object_requested (GtkHTML *html, GtkHTMLEmbedded *eb, ESummary *summary) { ESummaryWindow *window; int type; if (sscanf (eb->classid, "cid:%d-%p", &type, &window) != 2) { g_warning ("Could not get the window reference\n"); return FALSE; } switch (type) { case 1: g_assert_not_reached (); break; case 2: g_warning ("Bonobo services are not supported in this version."); break; default: g_assert_not_reached (); } return TRUE; } static void e_summary_display_window (ESummary *esummary, ESummaryWindow *window, int col) { ESummaryPrivate *priv; char *footer = ""; char *title_html; char *colour[2] = {"e6e8e4", "edeeeb"}; char *title_colour[2] = {"bac1b6", "cdd1c7"}; const char *title, *icon, *html; priv = esummary->private; title = executive_summary_component_view_get_title (window->view); icon = executive_summary_component_view_get_icon (window->view); html = executive_summary_component_view_get_html (window->view); /** FIXME: Make this faster by caching it? */ title_html = g_strdup_printf ("" "" "
" "" "
" "" "%s
", title_colour[col % 2], icon, title, colour[col % 2]); gtk_html_write (GTK_HTML (priv->html), priv->stream, title_html, strlen (title_html)); g_free (title_html); if (html != NULL && *html != '\0') { gtk_html_write (GTK_HTML (priv->html), priv->stream, html, strlen (html)); } else { g_warning ("Bonobo executive summary components are not supported at this time."); #if 0 body_cid = g_strdup_printf ("", window); gtk_html_write (GTK_HTML (priv->html), priv->stream, body_cid, strlen (body_cid)); #endif } gtk_html_write (GTK_HTML (priv->html), priv->stream, footer, strlen (footer)); } int e_summary_rebuild_page (ESummary *esummary) { ESummaryPrivate *priv; GList *windows; char *service_table = ""; int loc; g_return_val_if_fail (esummary != NULL, FALSE); g_return_val_if_fail (IS_E_SUMMARY (esummary), FALSE); priv = esummary->private; gtk_layout_freeze (GTK_LAYOUT (priv->html)); e_summary_start_load (esummary); load_default (esummary); /* Load the start of the services */ gtk_html_write (GTK_HTML (priv->html), priv->stream, service_table, strlen (service_table)); /* Load each of the services */ loc = 0; for (windows = priv->window_list; windows; windows = windows->next) { ESummaryWindow *window; char *td = "", 5); } gtk_html_write (GTK_HTML (priv->html), priv->stream, "", 18); } gtk_html_write (GTK_HTML (priv->html), priv->stream, td, strlen (td)); e_summary_display_window (esummary, window, (loc % 3)); gtk_html_write (GTK_HTML (priv->html), priv->stream, "", 5); loc++; } gtk_html_write (GTK_HTML (priv->html), priv->stream, "
"; window = windows->data; if (loc % 3 == 0) { if (loc != 0) { gtk_html_write (GTK_HTML (priv->html), priv->stream, "
", 13); e_summary_end_load (esummary); gtk_layout_thaw (GTK_LAYOUT (priv->html)); priv->idle = 0; return FALSE; } void e_summary_add_service (ESummary *esummary, ExecutiveSummary *summary, ExecutiveSummaryComponentView *view) { ESummaryWindow *window; ESummaryPrivate *priv; int id; g_return_if_fail (esummary != NULL); g_return_if_fail (IS_E_SUMMARY (esummary)); g_return_if_fail (summary != NULL); g_return_if_fail (IS_EXECUTIVE_SUMMARY (summary)); g_return_if_fail (view != NULL); g_return_if_fail (IS_EXECUTIVE_SUMMARY_COMPONENT_VIEW (view)); window = g_new0 (ESummaryWindow, 1); window->summary = summary; window->view = view; priv = esummary->private; priv->window_list = g_list_append (priv->window_list, window); g_hash_table_insert (priv->summary_to_window, summary, window); id = executive_summary_component_view_get_id (view); g_print ("--%d: %p\n", id, view); g_hash_table_insert (priv->id_to_view, GINT_TO_POINTER (id), view); } #if 0 void e_summary_add_html_service (ESummary *esummary, ExecutiveSummary *summary, ExecutiveSummaryComponentClient *client, const char *html, const char *title, const char *icon) { ESummaryWindow *window; ESummaryPrivate *priv; window = g_new0 (ESummaryWindow, 1); window->type = E_SUMMARY_WINDOW_HTML; window->html = g_strdup (html); window->title = g_strdup (title); window->icon = icon ? g_strdup (icon) : NULL; window->client = client; window->summary = summary; priv = esummary->private; priv->window_list = g_list_append (priv->window_list, window); g_hash_table_insert (priv->summary_to_window, summary, window); } void e_summary_add_bonobo_service (ESummary *esummary, ExecutiveSummary *summary, ExecutiveSummaryComponentClient *client, GtkWidget *control, const char *title, const char *icon) { ESummaryWindow *window; ESummaryPrivate *priv; window = g_new0 (ESummaryWindow, 1); window->type = E_SUMMARY_WINDOW_BONOBO; window->control = control; window->client = client; window->title = g_strdup (title); window->summary = summary; window->icon = icon ? g_strdup (icon): NULL; priv = esummary->private; priv->window_list = g_list_append (priv->window_list, window); g_hash_table_insert (priv->summary_to_window, summary, window); } #endif static void e_summary_window_free (ESummaryWindow *window, ESummaryPrivate *priv) { g_print ("%s\n", __FUNCTION__); priv->window_list = g_list_remove (priv->window_list, window); bonobo_object_unref (BONOBO_OBJECT (window->summary)); gtk_object_unref (GTK_OBJECT (window->view)); } /* Call this before e_summary_window_free, execpt when you are freeing the hash table */ static void e_summary_window_remove_from_ht (ESummaryWindow *window, ESummaryPrivate *priv) { g_hash_table_remove (priv->summary_to_window, window->summary); } void e_summary_update_window (ESummary *esummary, ExecutiveSummary *summary, const char *html) { ESummaryPrivate *priv; g_return_if_fail (esummary != NULL); g_return_if_fail (IS_E_SUMMARY (esummary)); g_return_if_fail (summary != NULL); priv = esummary->private; if (priv->idle != 0) return; priv->idle = g_idle_add (e_summary_rebuild_page, esummary); } ExecutiveSummaryComponentView * e_summary_view_from_id (ESummary *esummary, int id) { ESummaryPrivate *priv; ExecutiveSummaryComponentView *view; g_return_val_if_fail (esummary != NULL, NULL); g_return_val_if_fail (IS_E_SUMMARY (esummary), NULL); g_return_val_if_fail (id > 0, NULL); priv = esummary->private; view = g_hash_table_lookup (priv->id_to_view, GINT_TO_POINTER (id)); g_print ("%d: %p\n", id, view); return view; }