aboutsummaryrefslogblamecommitdiffstats
path: root/executive-summary/test-service/rdf-summary.c
blob: 876dae97a4c5dd932b20be8af88bb8980448f503 (plain) (tree)
1
2
3
4

                                                                           

                                               












                              
                             
                                
 




                                           
                                                           
                                                           








                                                                             
                                                                                   
 







                                

                                                


                           
                           


                                      




                       
                           
 



                          

                     

                                    

                        


                                      













































































                                                                                    
                               

                         
                       





                                  
                                   
















































                                                                                 
 
                                                 






                                                
                                                    

                                                                      

                                 
                                                




                                                                              
                                                            



                                                                              



                                                                                               
                                   


                                                                                  












































                                                                                                                     

                                                  
                                   


                                                         




                                            



                                
                        
                                                       


                                 
                                   

 


























                                                                             
                                            






                                                 







                                                                                  








                                                                                  








                                                                                  





                                                  

















                                                                                  
















                                                               
                                                                  







                                                                   



                                                             







                                                            
                                                   



































                                                                                      











                                                                                                      



                                            
 
                      
                  
 

                            
 
                               



                                            


                                            

                                                 
                           
                               
 







                                                                       
                                                                             
                                                           
                                                                                                         
                              

                             
         

                     
 




                                
 
 










                                                                      
 











                                                                                                         




                                                                                   
         
 

                              


                                                                                   


                                                                      

                                                                                


                                               
 






                                           
 















                                                                                                         
                                       
                       

         

                                             
 


                                                                         
 
 



                                    



                                                                                          



                                                                              
 
                                 



                     


                                 
                                





















                                                            
                                









                                                                        
                                               








                                                                          
                                                









                                                                         
                                
                                  
 





                                                                                              
                                                                          








                                                          
                                                               













                                                                                 
                                                                     















                                                                         
                                                                     


                                                                             













                                                                             



























                                                                              
 

                                                                                               





                                                                      
                                                                        

                                                           











                                                      


                                 

                                          
                                                 
                                                                                                         
                                                                                             


                                                                   
                                                                                          











                                                                                  












                                                        

                           
                            

                                        
                                    

                                        
        




                                                                              
                                  
 






                                                                                





                                                                       



                                                                              

                               
                                                                   
 
                             

                                                      
                                 

                                                                   
 
                           
                                     


                                                                            
                                     


                                                                            
                                                                    

                                     
                                                                         
                                                                  
                                                              




                                                                        
                                                                         
 




                                                                             
                        
                                                       

                         





                                           
                                        
 
                                                                                        
                                 































                                                                                
 
                 

        
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
/* RDF viewer Evolution Executive Summary Component.
 * Bonoboised by Iain Holmes  <iain@ximian.com>
 * Copyright (C) 2000 Ximian, Inc.
 *
 * Based on code from Portaloo
 * Channel retrieval tool
 *
 * (C) 1998 Alan Cox.
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
 
#include <glib.h>
#include <gnome-xml/parser.h>
#include <gnome-xml/xmlmemory.h>

#include <bonobo/bonobo-generic-factory.h>
#include <bonobo/bonobo-persist-stream.h>
#include <bonobo/bonobo-property.h>
#include <bonobo/bonobo-property-bag.h>
#include <bonobo/bonobo-property-control.h>
#include <evolution-services/executive-summary-component.h>
#include <evolution-services/executive-summary-html-view.h>
#include <liboaf/liboaf.h>
#include <libgnomevfs/gnome-vfs.h>

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;
    BonoboPropertyBag *bag;
    BonoboPropertyControl *property_control;

    GtkWidget *rdf;
    GtkWidget *g_limit;
    GtkWidget *g_title;
    GtkWidget *g_update;
    GtkWidget *g_update_container;
    GtkAdjustment *adjustment;

    char *title;
    char *icon;
    char *location;
    int limit;
    gboolean showtitle;

    gboolean usetimer;
    int time;
    int timer;

    GString *str;
    char *buffer;

    GnomeVFSAsyncHandle *handle;

    xmlDocPtr cache;
};
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, "&amp;", 5) == 0) {
            *w++ = '&';
            r += 5;
            continue;
        }
        if (memcmp (r, "&lt;", 4) == 0) {
            *w++ = '<';
            r += 4;
            continue;
        }
        if (memcmp (r, "&gt;", 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);

    if (summary->showtitle) {
        BONOBO_ARG_SET_STRING (arg, t);
    } else {
        BONOBO_ARG_SET_STRING (arg, "");
    }

    bonobo_property_bag_set_value (summary->bag,
                       "window_title", 
                       (const BonoboArg *) arg, NULL);
    bonobo_arg_release (arg);

    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 (summary->bag,
                           "window_icon", 
                           (const BonoboArg *) arg, NULL);
        bonobo_arg_release (arg);
            
    }

    g_string_append (html, "<br clear=all><FONT size=\"-1\" face=\"helvetica\"><P><UL>\n");

    items = MIN (limit, items);
    for (i = 0; i < items; i++) {
        char *p = layer_find (item[i]->childs, "title", "No information");
        
        if (wipe_trackers) {
            char *p = layer_find_url (item[i]->childs, "link", "");
            char *x = strchr (p, '?');
            unsigned char *r, *w;
            int n;
            if (x == NULL)
                continue;
            x++;
            r = x;
            w = x;
            while (*r) {
                if (*r == '+') {
                    *w++ = ' ';
                } else if (*r == '%') {
                    sscanf (r+1, "%02x", &n);
                    *w++ = n;
                    r += 2;
                } else {
                    *w++ = *r;
                }
                r++;
            }
            *w = 0;
            tmp = g_strdup_printf ("<LI><A href=\"%s\">\n", x+4);
            g_string_append (html, tmp);
            g_free (tmp);
        }
        else {
            tmp = g_strdup_printf ("<LI><A href=\"%s\">\n", layer_find_url(item[i]->childs, "link", ""));
            g_string_append (html, tmp);
            g_free (tmp);
        }

        tmp = g_strdup_printf ("%s\n</A>\n", p);
        g_string_append (html, tmp);
        g_free (tmp);
    }
    g_string_append (html, "</UL></FONT>\n");
}

/********* ExecutiveSummaryComponent section **************/
static void 
view_destroyed (GtkObject *object,
        gpointer data)
{
    RdfSummary *summary = (RdfSummary *) data;

    g_warning ("RDF: Point 1");
    if (summary->handle)
        gnome_vfs_async_cancel (summary->handle);

    g_warning ("RDF: Point 2");

    if (summary->cache != NULL)
        xmlFreeDoc (summary->cache);

    g_free (summary->title);
    g_free (summary->icon);
    g_free (summary);

    running_views--;
    g_print ("Running_views: %d\n", running_views);
    if (running_views <= 0) {
        gtk_main_quit ();
    }
    g_warning ("RDF: Point 3");
}

/* PersistStream callbacks */
static void
load_from_stream (BonoboPersistStream *ps,
          Bonobo_Stream stream,
          Bonobo_Persist_ContentType type,
          gpointer data,
          CORBA_Environment *ev)
{
    RdfSummary *summary = (RdfSummary *) data;
    char *str;
    xmlChar *xml_str;
    xmlDocPtr doc;
    xmlNodePtr root, children;

    if (*type && g_strcasecmp (type, "application/x-rdf-summary") != 0) {
        CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
                     ex_Bonobo_Persist_WrongDataType, NULL);
        return;
    }

    bonobo_stream_client_read_string (stream, &str, ev);
    if (ev->_major != CORBA_NO_EXCEPTION || str == NULL) {
        CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
                     ex_Bonobo_Persist_WrongDataType, NULL);
        return;
    }

    doc = xmlParseDoc ((xmlChar *) str);
    
    if (doc == NULL) {
        g_warning ("Bad data: %s!", str);
        g_free (str);
        return;
    }

    g_free (str);

    root = doc->root;
    children = root->childs;
    while (children) {
        if (strcasecmp (children->name, "location") == 0) {
            xml_str = xmlNodeListGetString (doc, children->childs, 1);
            summary->location = g_strdup (xml_str);
            xmlFree (xml_str);

            children = children->next;
            continue;
        } 

        if (strcasecmp (children->name, "limit") == 0) {
            xml_str = xmlNodeListGetString (doc, children->childs, 1);
            summary->limit = atoi (xml_str);
            xmlFree (xml_str);

            children = children->next;
            continue;
        }

        if (strcasecmp (children->name, "showtitle") == 0) {
            xml_str = xmlNodeListGetString (doc, children->childs, 1);
            summary->showtitle = atoi (xml_str);
            xmlFree (xml_str);

            children = children->next;
            continue;
        }

        if (strcasecmp (children->name, "usetimer") == 0) {
            xml_str = xmlNodeListGetString (doc, children->childs, 1);
            summary->usetimer = atoi (xml_str);
            xmlFree (xml_str);

            children = children->next;
            continue;
        }

        if (strcasecmp (children->name, "timer") == 0) {
            xml_str = xmlNodeListGetString (doc, children->childs, 1);
            summary->timer = atoi (xml_str);
            xmlFree (xml_str);

            children = children->next;
            continue;
        }

        g_print ("Unknown name: %s\n", children->name);
        children = children->next;
    }
    xmlFreeDoc (doc);
}

static char *
summary_to_string (RdfSummary *summary)
{
    xmlChar *out_str;
    int out_len = 0;
    xmlDocPtr doc;
    xmlNodePtr root;
    xmlNsPtr ns;
    char *tmp_str;
    
    doc = xmlNewDoc ("1.0");
    ns = xmlNewGlobalNs (doc, "http://www.ximian.com", "rdf");
    
    doc->root = xmlNewDocNode (doc, ns, "rdf-summary", NULL);

    xmlNewChild (doc->root, ns, "location", summary->location);
    tmp_str = g_strdup_printf ("%d", summary->limit);
    xmlNewChild (doc->root, ns, "limit", tmp_str);
    g_free (tmp_str);

    tmp_str = g_strdup_printf ("%d", summary->showtitle);
    xmlNewChild (doc->root, ns, "showtitle", tmp_str);
    g_free (tmp_str);

    tmp_str = g_strdup_printf ("%d", summary->usetimer);
    xmlNewChild (doc->root, ns, "usetimer", tmp_str);
    g_free (tmp_str);

    tmp_str = g_strdup_printf ("%d", summary->timer);
    xmlNewChild (doc->root, ns, "timer", tmp_str);
    g_free (tmp_str);

    xmlDocDumpMemory (doc, &out_str, &out_len);

    return out_str;
}

static void
save_to_stream (BonoboPersistStream *ps,
        const Bonobo_Stream stream,
        Bonobo_Persist_ContentType type,
        gpointer data,
        CORBA_Environment *ev)
{
    RdfSummary *summary = (RdfSummary *) data;
    char *str;

    if (*type && g_strcasecmp (type, "application/x-rdf-summary") != 0) {
        CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
                     ex_Bonobo_Persist_WrongDataType, NULL);
        return;
    }

    str = summary_to_string (summary);
    if (str)
        bonobo_stream_client_printf (stream, TRUE, ev, str);
    xmlFree (str);

    return;
}

static Bonobo_Persist_ContentTypeList *
content_types (BonoboPersistStream *ps,
           void *closure,
           CORBA_Environment *ev)
{
    return bonobo_persist_generate_content_types (1, "application/x-rdf-summary");
}

static void 
display_doc (RdfSummary *summary)
{
    GString *html;

    html = g_string_new ("");

    tree_walk (summary->cache->root, summary, html);
    executive_summary_html_view_set_html (EXECUTIVE_SUMMARY_HTML_VIEW (summary->view), html->str);
    g_string_free (html, TRUE);
}

static void
close_callback (GnomeVFSAsyncHandle *handle,
        GnomeVFSResult result,
        RdfSummary *summary)
{
    xmlDocPtr doc;
    char *xml;

    if (summary == NULL)
        return;

    summary->handle = NULL;
    g_free (summary->buffer);
    xml = summary->str->str;
    g_string_free (summary->str, FALSE);

    if (summary->cache != NULL)
        xmlFreeDoc (summary->cache);

    doc = xmlParseMemory (xml, strlen (xml));
    if (doc == NULL) {
        char *emsg;
        BonoboArg *arg;

        arg = bonobo_arg_new (BONOBO_ARG_STRING);
        BONOBO_ARG_SET_STRING (arg, _("Error"));
        bonobo_property_bag_set_value (summary->bag,
                           "window_title", 
                           (const BonoboArg *) arg,
                           NULL);
        bonobo_arg_release (arg);
        
        emsg = g_strdup_printf ("<b>Cannot open location:<br>%s</b>",
                    summary->location);
        executive_summary_html_view_set_html (EXECUTIVE_SUMMARY_HTML_VIEW (summary->view), emsg);
        g_free (emsg);
        g_free (xml);
        return;
    }
    
    g_free (xml);

    /* Cache it for later */
    summary->cache = doc;

    /* Draw it */
    display_doc (summary);
}

static void
read_callback (GnomeVFSAsyncHandle *handle,
           GnomeVFSResult result,
           gpointer buffer,
           GnomeVFSFileSize bytes_requested,
           GnomeVFSFileSize bytes_read,
           RdfSummary *summary)
{
    if (result != GNOME_VFS_OK && result != GNOME_VFS_ERROR_EOF) {
        char *emsg;
        BonoboArg *arg;

        arg = bonobo_arg_new (BONOBO_ARG_STRING);
        BONOBO_ARG_SET_STRING (arg, _("Error"));
        bonobo_property_bag_set_value (summary->bag,
                           "window_title", 
                           (const BonoboArg *) arg,
                           NULL);
        bonobo_arg_release (arg);
        
        emsg = g_strdup_printf ("<b>Cannot open location:<br>%s</b>",
                    summary->location);
        executive_summary_html_view_set_html (EXECUTIVE_SUMMARY_HTML_VIEW (summary->view), emsg);
        g_free (emsg);
        gnome_vfs_async_close (handle, 
                       (GnomeVFSAsyncCloseCallback) close_callback,
                       NULL);
        g_print ("NULLING\n");
        summary->handle = NULL;
    }

    if (bytes_read == 0) {
        /* EOF */
        gnome_vfs_async_close (handle, 
                       (GnomeVFSAsyncCloseCallback) close_callback,
                       summary);
    } else {
        *((char *) buffer + bytes_read) = 0;
        g_string_append (summary->str, (const char *) buffer);
        gnome_vfs_async_read (handle, buffer, 4095, 
                      (GnomeVFSAsyncReadCallback) read_callback,
                      summary);
    }
}

static void
open_callback (GnomeVFSAsyncHandle *handle,
           GnomeVFSResult result,
           RdfSummary *summary)
{
    GList *uri;
    char *buffer;

    if (result != GNOME_VFS_OK) {
        char *emsg;
        BonoboArg *arg;

        arg = bonobo_arg_new (BONOBO_ARG_STRING);
        BONOBO_ARG_SET_STRING (arg, _("Error"));
        bonobo_property_bag_set_value (summary->bag,
                           "window_title", 
                           (const BonoboArg *) arg,
                           NULL);
        bonobo_arg_release (arg);
        
        emsg = g_strdup_printf ("<b>Cannot open location:<br>%s</b>",
                    summary->location);
        executive_summary_html_view_set_html (EXECUTIVE_SUMMARY_HTML_VIEW (summary->view), emsg);
        g_free (emsg);
        summary->handle = NULL;
        return;
    }

    summary->str = g_string_new ("");
    summary->buffer = g_new (char, 4096);

    gnome_vfs_async_read (handle, summary->buffer, 4095, 
                  (GnomeVFSAsyncReadCallback) read_callback, 
                  summary);
}

static int
download (RdfSummary *summary)
{
    GnomeVFSAsyncHandle *handle;
    char *html = "<b>Loading RDF file. . .<br>Please wait</b>";
    
    executive_summary_html_view_set_html (EXECUTIVE_SUMMARY_HTML_VIEW (summary->view),
                          html);

    gnome_vfs_async_open (&handle, summary->location, GNOME_VFS_OPEN_READ,
                  (GnomeVFSAsyncOpenCallback) open_callback, 
                  summary);

    summary->handle = handle;
    return FALSE;
}

static void
get_prop (BonoboPropertyBag *bag,
      BonoboArg *arg,
      guint arg_id,
      CORBA_Environment *ev,
      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,
      CORBA_Environment *ev,
      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));
        g_print ("Notify listener!\n");
        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));
        g_print ("Notify listener 2\n");
        bonobo_property_bag_notify_listeners (bag, "window_icon",
                              arg, NULL);
        break;

    default:
        break;
    }
}

static void
item_changed (GtkWidget *widget,
          RdfSummary *summary)
{
    if (widget == summary->g_update) {
        summary->usetimer = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
        gtk_widget_set_sensitive (summary->g_update_container, 
                      summary->usetimer);
    }

    bonobo_property_control_changed (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, *spinner, *button;
    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 (item_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 (item_changed), summary);

    gtk_box_pack_start (GTK_BOX (hbox), summary->g_limit, TRUE, TRUE, 0);

    hbox = gtk_hbox_new (FALSE, 2);

    /* FIXME: Do this better? */
    label = gtk_label_new ("Show window title");
    gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);

    summary->g_title = gtk_check_button_new ();
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (summary->g_title),
                      summary->showtitle);

    gtk_signal_connect (GTK_OBJECT (summary->g_title), "toggled",
                GTK_SIGNAL_FUNC (item_changed), summary);

    gtk_box_pack_start (GTK_BOX (hbox), summary->g_title, TRUE, TRUE, 0);
    gtk_box_pack_start (GTK_BOX (container), hbox, FALSE, FALSE, 0);

    hbox = gtk_hbox_new (FALSE, 2);

    /* Update */
    hbox = gtk_hbox_new (FALSE, 2);
    label = gtk_label_new (_("Update automatically"));
    gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
    summary->g_update = gtk_check_button_new ();
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (summary->g_update),
                      summary->usetimer);

    gtk_signal_connect (GTK_OBJECT (summary->g_update), "toggled",
                GTK_SIGNAL_FUNC (item_changed), summary);
    gtk_box_pack_start (GTK_BOX (hbox), summary->g_update, TRUE, TRUE, 0);

    button = gtk_button_new_with_label (_("Update now"));
    gtk_signal_connect (GTK_OBJECT (button), "clicked",
                GTK_SIGNAL_FUNC (download), summary);
    gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
    gtk_box_pack_start (GTK_BOX (container), hbox, FALSE, FALSE, 0);

    /* Timer */
    hbox = gtk_hbox_new (FALSE, 2);
    summary->g_update_container = hbox;

    label = gtk_label_new (_("Update every "));
    gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);

    summary->adjustment = GTK_ADJUSTMENT(gtk_adjustment_new (summary->time / 1000 / 60,
                                 0.0, 1000.0, 1.0, 10.0, 1.0));
    spinner = gtk_spin_button_new (summary->adjustment, 1.0, 0);
    gtk_box_pack_start (GTK_BOX (hbox), spinner, FALSE, FALSE, 0);
    
    label = gtk_label_new (_("minutes"));
    gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
    
    gtk_box_pack_start (GTK_BOX (container), hbox, FALSE, FALSE, 0);
    gtk_widget_set_sensitive (hbox, summary->usetimer);

    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)
{
    gboolean changed = FALSE;
    char *old_location;

    switch (action) {
    case Bonobo_PropertyControl_APPLY:
        old_location = summary->location;
        summary->showtitle = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (summary->g_title));
        summary->location = g_strdup (gtk_entry_get_text (GTK_ENTRY (summary->rdf)));
        if (strcmp (old_location, summary->location) != 0) 
            changed = TRUE;

        summary->limit = atoi (gtk_entry_get_text (GTK_ENTRY (summary->g_limit)));
        summary->time = summary->adjustment->value * 60 * 1000;
        if (summary->timer)
            gtk_timeout_remove (summary->timer);
        summary->timer = gtk_timeout_add (summary->time, 
                          (GSourceFunc)download, summary);
        
        if (changed)
            g_idle_add ((GSourceFunc) download, summary);
        else
            g_idle_add ((GSourceFunc) display_doc, summary);

        g_free (old_location);
        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;
    BonoboEventSource *event_source;
    BonoboPersistStream *stream;
    BonoboPropertyBag *bag;
    BonoboPropertyControl *property;
    
    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;
    summary->showtitle = TRUE;

    summary->cache = NULL;
    
    summary->usetimer = TRUE;
    summary->time = 600000; /* 10 minutes */
    summary->timer = gtk_timeout_add (summary->time, (GSourceFunc) download,
                      summary);

    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 ();

    /* Summary::HtmlView */
    view = executive_summary_html_view_new_full (event_source);

    summary->view = view;
    bonobo_object_add_interface (component, view);

    /* Bonobo::PropertyBag */
    bag = bonobo_property_bag_new_full (get_prop, set_prop, 
                        event_source, summary);

    summary->bag = bag;
    bonobo_property_bag_add (bag,
                 "window_title", PROPERTY_TITLE,
                 BONOBO_ARG_STRING, NULL,
                 "The title of this component's window", 0);
    bonobo_property_bag_add (bag,
                 "window_icon", PROPERTY_ICON,
                 BONOBO_ARG_STRING, NULL,
                 "The icon for this component's window", 0);
    bonobo_object_add_interface (component, BONOBO_OBJECT(bag));

    /* Bonobo::PropertyControl */
    property = bonobo_property_control_new_full (property_control, 1,
                             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, BONOBO_OBJECT(property));

    /* Bonobo::PersistStream */
    stream = bonobo_persist_stream_new (load_from_stream, save_to_stream,
                        NULL, content_types, summary);
    bonobo_object_add_interface (component, BONOBO_OBJECT (stream));

    running_views++;
    gtk_idle_add ((GSourceFunc) download, summary);

    return component;
}

static BonoboObject *
factory_fn (BonoboGenericFactory *_factory,
        void *closure)
{
    BonoboObject *component_factory;

    component_factory = executive_summary_component_factory_new (create_view, NULL);
    return 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 ();

    return 0;
}