/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* RDF viewer Evolution Executive Summary Component. * Bonoboised by Iain Holmes * Copyright (C) 2000 Helix Code, Inc. * * Based on code from Portaloo * Channel retrieval tool * * (C) 1998 Alan Cox. * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include int xmlSubstituteEntitiesDefaultValue = 1; /* DV thinks of everything */ static int wipe_trackers = FALSE; static int running_views = 0; static BonoboGenericFactory *factory = NULL; #define RDF_SUMMARY_ID "OAFIID:GNOME_Evolution_Summary_rdf_SummaryComponentFactory" enum { PROPERTY_TITLE, PROPERTY_ICON }; struct _RdfSummary { BonoboObject *component; BonoboObject *view; BonoboObject *bag; BonoboObject *property_control; GtkWidget *rdf; GtkWidget *g_limit; char *title; char *icon; char *location; int limit; }; typedef struct _RdfSummary RdfSummary; /************ RDF Parser *******************/ static char * layer_find (xmlNodePtr node, char *match, char *fail) { while (node!=NULL) { #ifdef RDF_DEBUG xmlDebugDumpNode (stdout, node, 32); printf("%s.\n", node->name); #endif if (strcasecmp (node->name, match)==0) { if (node->childs != NULL && node->childs->content != NULL) { return node->childs->content; } else { return fail; } } node = node->next; } return fail; } static char * layer_find_url (xmlNodePtr node, char *match, char *fail) { char *p = layer_find (node, match, fail); char *r = p; static char *wb = NULL; char *w; if (wb) { free (wb); } wb = w = malloc (3 * strlen (p)); if (w == NULL) { fprintf(stderr, "Out of memory\n"); exit(1); } if (*r == ' ') r++; /* Fix UF bug */ while (*r) { if (memcmp (r, "&", 5) == 0) { *w++ = '&'; r += 5; continue; } if (memcmp (r, "<", 4) == 0) { *w++ = '<'; r += 4; continue; } if (memcmp (r, ">", 4) == 0) { *w++ = '>'; r += 4; continue; } if (*r == '"' || *r == ' '){ *w++ = '%'; *w++ = "0123456789ABCDEF"[*r/16]; *w++ = "0123456789ABCDEF"[*r&15]; r++; continue; } *w++ = *r++; } *w = 0; return wb; } static void tree_walk (xmlNodePtr root, RdfSummary *summary, GString *html) { BonoboArg *arg; xmlNodePtr walk; xmlNodePtr rewalk = root; xmlNodePtr channel = NULL; xmlNodePtr image = NULL; xmlNodePtr item[16]; int items = 0; int limit = summary->limit; int i; char *t; char n[512]; char *tmp; do { walk = rewalk; rewalk = NULL; while (walk!=NULL){ #ifdef RDF_DEBUG printf ("%p, %s\n", walk, walk->name); #endif if (strcasecmp (walk->name, "rdf") == 0) { rewalk = walk->childs; walk = walk->next; continue; } if (strcasecmp (walk->name, "rss") == 0){ rewalk = walk->childs; walk = walk->next; continue; } /* This is the channel top level */ #ifdef RDF_DEBUG printf ("Top level '%s'.\n", walk->name); #endif if (strcasecmp (walk->name, "channel") == 0) { channel = walk; rewalk = channel->childs; } if (strcasecmp (walk->name, "image") == 0) { image = walk; g_print ("Image\n"); } if (strcasecmp (walk->name, "item") == 0 && items < 16) { item[items++] = walk; } walk = walk->next; } } while (rewalk); if (channel == NULL) { fprintf(stderr, "No channel definition.\n"); exit(1); } t = layer_find(channel->childs, "title", "No title"); arg = bonobo_arg_new (BONOBO_ARG_STRING); BONOBO_ARG_SET_STRING (arg, t); bonobo_property_bag_set_value (BONOBO_PROPERTY_BAG (summary->bag), "window_title", (const BonoboArg *) arg, NULL); bonobo_arg_release (arg); #if 0 tmp = g_strdup_printf ("%s", layer_find(channel->childs, "description", "")); g_string_append (html, tmp); g_free (tmp); #endif if (image && !wipe_trackers) { char *icon; icon = layer_find_url (image->childs, "url", "apple-red.png"); arg = bonobo_arg_new (BONOBO_ARG_STRING); BONOBO_ARG_SET_STRING (arg, icon); bonobo_property_bag_set_value (BONOBO_PROPERTY_BAG (summary->bag), "window_icon", (const BonoboArg *) arg, NULL); bonobo_arg_release (arg); } g_string_append (html, "

\n"); } /********* ExecutiveSummaryComponent section **************/ static void view_destroyed (GtkObject *object, gpointer data) { RdfSummary *summary = (RdfSummary *) data; g_free (summary->title); g_free (summary->icon); g_free (summary); running_views--; if (running_views <= 0) { gtk_main_quit (); } } static int download (RdfSummary *summary) { ExecutiveSummaryHtmlView *view; GString *rdf; GString *html; char *xml; GnomeVFSHandle *handle = NULL; GnomeVFSResult result; xmlDocPtr doc; char *location; int len = 0; /* Download the RDF file here */ /* Then parse it */ /* The update it */ g_print ("Starting download\n"); view = EXECUTIVE_SUMMARY_HTML_VIEW (summary->view); result = gnome_vfs_open (&handle, summary->location, GNOME_VFS_OPEN_READ); if (result != GNOME_VFS_OK) { char *emsg; emsg = g_strdup_printf ("Cannot open location:
%s
", summary->location); executive_summary_html_view_set_html (view, emsg); g_free (emsg); return FALSE; } rdf = g_string_new (""); while (1) { char buffer[4096]; GnomeVFSFileSize size; memset (buffer, 0x00, 4096); result = gnome_vfs_read (handle, buffer, 4096, &size); if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_EOF) { executive_summary_html_view_set_html (view, "Error reading data."); g_string_free (rdf, TRUE); return FALSE; } if (size == 0) { break; } rdf = g_string_append (rdf, buffer); len += size; } gnome_vfs_close (handle); xml = rdf->str; g_string_free (rdf, FALSE); doc = xmlParseMemory (xml, len); if (doc == NULL) { g_warning ("Unable to parse document."); return FALSE; } g_free (xml); html = g_string_new (""); tree_walk (doc->root, summary, html); executive_summary_html_view_set_html (view, html->str); g_string_free (html, TRUE); g_print ("Finished Download\n"); return FALSE; } static void get_prop (BonoboPropertyBag *bag, BonoboArg *arg, guint arg_id, gpointer user_data) { RdfSummary *summary = (RdfSummary *) user_data; switch (arg_id) { case PROPERTY_TITLE: BONOBO_ARG_SET_STRING (arg, summary->title); break; case PROPERTY_ICON: BONOBO_ARG_SET_STRING (arg, summary->icon); break; default: break; } } static void set_prop (BonoboPropertyBag *bag, const BonoboArg *arg, guint arg_id, gpointer user_data) { RdfSummary *summary = (RdfSummary *) user_data; switch (arg_id) { case PROPERTY_TITLE: if (summary->title) g_free (summary->title); summary->title = g_strdup (BONOBO_ARG_GET_STRING (arg)); bonobo_property_bag_notify_listeners (bag, "window_title", arg, NULL); break; case PROPERTY_ICON: if (summary->icon) g_free (summary->icon); summary->icon = g_strdup (BONOBO_ARG_GET_STRING (arg)); bonobo_property_bag_notify_listeners (bag, "window_icon", arg, NULL); break; default: break; } } static void entry_changed (GtkEntry *entry, RdfSummary *summary) { bonobo_property_control_changed (BONOBO_PROPERTY_CONTROL (summary->property_control), NULL); } static BonoboControl * property_control (BonoboPropertyControl *property_control, int page_num, gpointer user_data) { BonoboControl *control; RdfSummary *summary = (RdfSummary *) user_data; GtkWidget *container, *label, *hbox; char *climit; container = gtk_vbox_new (FALSE, 2); gtk_container_set_border_width (GTK_CONTAINER (container), 2); hbox = gtk_hbox_new (FALSE, 2); label = gtk_label_new ("Location:"); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); summary->rdf = gtk_entry_new (); if (summary->location) gtk_entry_set_text (GTK_ENTRY (summary->rdf), summary->location); gtk_signal_connect (GTK_OBJECT (summary->rdf), "changed", GTK_SIGNAL_FUNC (entry_changed), summary); gtk_box_pack_start (GTK_BOX (hbox), summary->rdf, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (container), hbox, FALSE, FALSE, 0); hbox = gtk_hbox_new (FALSE, 2); label = gtk_label_new ("Maximum number of entries:"); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); summary->g_limit = gtk_entry_new (); climit = g_strdup_printf ("%d", summary->limit); gtk_entry_set_text (GTK_ENTRY (summary->g_limit), climit); g_free (climit); gtk_signal_connect (GTK_OBJECT (summary->g_limit), "changed", GTK_SIGNAL_FUNC (entry_changed), summary); gtk_box_pack_start (GTK_BOX (hbox), summary->g_limit, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (container), hbox, FALSE, FALSE, 0); gtk_widget_show_all (container); control = bonobo_control_new (container); return control; } static void property_action (GtkObject *property_control, int page_num, Bonobo_PropertyControl_Action action, RdfSummary *summary) { switch (action) { case Bonobo_PropertyControl_APPLY: g_free (summary->location); summary->location = g_strdup (gtk_entry_get_text (GTK_ENTRY (summary->rdf))); summary->limit = atoi (gtk_entry_get_text (GTK_ENTRY (summary->g_limit))); g_idle_add (download, summary); break; case Bonobo_PropertyControl_HELP: g_print ("HELP: Page %d!\n", page_num); break; default: break; } } static BonoboObject * create_view (ExecutiveSummaryComponentFactory *_factory, void *closure) { RdfSummary *summary; BonoboObject *component, *view, *bag, *property, *event_source; char *html = "Loading RDF file. . .
Please wait
"; summary = g_new (RdfSummary, 1); summary->icon = g_strdup ("apple-green.png"); summary->title = g_strdup ("Downloading..."); summary->location = g_strdup ("http://news.gnome.org/gnome-news/rdf"); summary->limit = 10; component = executive_summary_component_new (); gtk_signal_connect (GTK_OBJECT (component), "destroy", GTK_SIGNAL_FUNC (view_destroyed), summary); summary->component = component; /* Share the event source between the ExecutiveSummaryHtmlView and the BonoboPropertyControl as we can only have one Bonobo::EventSource interface aggregated */ event_source = bonobo_event_source_new (); view = executive_summary_html_view_new_full (BONOBO_EVENT_SOURCE (event_source)); summary->view = view; executive_summary_html_view_set_html (EXECUTIVE_SUMMARY_HTML_VIEW (view), html); bonobo_object_add_interface (component, view); bag = bonobo_property_bag_new (get_prop, set_prop, summary); summary->bag = bag; bonobo_property_bag_add (BONOBO_PROPERTY_BAG (bag), "window_title", PROPERTY_TITLE, BONOBO_ARG_STRING, NULL, "The title of this component's window", 0); bonobo_property_bag_add (BONOBO_PROPERTY_BAG (bag), "window_icon", PROPERTY_ICON, BONOBO_ARG_STRING, NULL, "The icon for this component's window", 0); bonobo_object_add_interface (component, bag); property = bonobo_property_control_new_full (property_control, 1, BONOBO_EVENT_SOURCE (event_source), summary); summary->property_control = property; gtk_signal_connect (GTK_OBJECT (property), "action", GTK_SIGNAL_FUNC (property_action), summary); bonobo_object_add_interface (component, property); running_views++; gtk_timeout_add (5000, download, summary); return component; } static BonoboObject * factory_fn (BonoboGenericFactory *_factory, void *closure) { ExecutiveSummaryComponentFactory *component_factory; component_factory = executive_summary_component_factory_new (create_view, NULL); return BONOBO_OBJECT (component_factory); } static void factory_init (void) { if (factory != NULL) { return; } factory = bonobo_generic_factory_new (RDF_SUMMARY_ID, factory_fn, NULL); if (factory == NULL) { g_error ("Cannot initialize factory"); } } int main (int argc, char *argv[]) { CORBA_ORB orb; gnome_init_with_popt_table ("RDF-Summary", VERSION, argc, argv, oaf_popt_options, 0, NULL); orb = oaf_init (argc, argv); gnome_vfs_init (); if (bonobo_init (orb, CORBA_OBJECT_NIL, CORBA_OBJECT_NIL) == FALSE) { g_error ("Could not initialize Bonobo"); } factory_init (); bonobo_main (); if (factory != NULL) bonobo_object_unref (BONOBO_OBJECT (factory)); return 0; }