Hi there, I've tested a few calendars to export them to the RDF-format. It looks like the generated result is correct using this version. More information about this RDF-format: Website: http://www.w3.org/2002/12/cal/ Schema: http://www.w3.org/2002/12/cal/ical http://www.w3.org/2002/12/cal/ical.rdf http://www.w3.org/2002/12/cal/ical.n3 Test data: http://www.w3.org/2002/12/cal/test/ [freax lort save-calendar]$ tar cvf rdfformat-01.tar * ChangeLog csv-format.c format-handler.h ical-format.c Makefile.am org-gnome-save-calendar.eplug.in rdf-format.c save-calendar.c [freax lort save-calendar]$ [freax lort save-calendar]$ cvs diff -u > patch.diff cvs server: Diffing . [freax lort save-calendar]$ pwd /home/freax/cvs/gnome/evolution/plugins/save-calendar [freax lort save-calendar]$ Please review. -- Philip Van Hoof, Software Developer @ Cronos home: me at freax dot org gnome: pvanhoof at gnome dot org work: philip dot vanhoof at cronos dot be junk: philip dot vanhoof at gmail dot com http://www.freax.be, http://www.freax.eu.org
? csv-format.c ? format-handler.h ? ical-format.c ? patch.diff ? rdf-format.c Index: ChangeLog =================================================================== RCS file: /cvs/gnome/evolution/plugins/save-calendar/ChangeLog,v retrieving revision 1.6 diff -u -r1.6 ChangeLog Binary files /tmp/cvstOFfsD and ChangeLog differ Index: Makefile.am =================================================================== RCS file: /cvs/gnome/evolution/plugins/save-calendar/Makefile.am,v retrieving revision 1.2 diff -u -r1.2 Makefile.am --- Makefile.am 1 Nov 2004 18:39:17 -0000 1.2 +++ Makefile.am 20 Dec 2004 09:12:08 -0000 @@ -7,7 +7,7 @@ plugin_DATA = org-gnome-save-calendar.eplug plugin_LTLIBRARIES = liborg-gnome-save-calendar.la -liborg_gnome_save_calendar_la_SOURCES = save-calendar.c +liborg_gnome_save_calendar_la_SOURCES = save-calendar.c ical-format.c csv-format.c rdf-format.c liborg_gnome_save_calendar_la_LDFLAGS = -module -avoid-version -EXTRA_DIST = org-gnome-save-calendar.eplug.in \ No newline at end of file +EXTRA_DIST = org-gnome-save-calendar.eplug.in Index: save-calendar.c =================================================================== RCS file: /cvs/gnome/evolution/plugins/save-calendar/save-calendar.c,v retrieving revision 1.4 diff -u -r1.4 save-calendar.c --- save-calendar.c 8 Dec 2004 11:33:07 -0000 1.4 +++ save-calendar.c 20 Dec 2004 09:12:08 -0000 @@ -44,6 +44,7 @@ #include <libgnomevfs/gnome-vfs.h> #include <string.h> +#include "format-handler.h" enum { /* GtkComboBox enum */ DEST_NAME_COLUMN, @@ -51,643 +52,200 @@ N_DEST_COLUMNS }; -enum { /* CSV helper enum */ - ECALCOMPONENTTEXT, - ECALCOMPONENTATTENDEE, - CONSTCHAR -}; -typedef struct _CsvConfig CsvConfig; -struct _CsvConfig { - gchar *newline; - gchar *quote; - gchar *delimiter; - gboolean header; -}; void org_gnome_save_calendar (EPlugin *ep, ECalPopupTargetSource *target); void org_gnome_save_tasks (EPlugin *ep, ECalPopupTargetSource *target); -static gboolean string_needsquotes (const char *value, CsvConfig *config); - -static void -display_error_message (GtkWidget *parent, GError *error) -{ - GtkWidget *dialog; - - dialog = gtk_message_dialog_new (GTK_WINDOW (parent), 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, - error->message); - gtk_dialog_run (GTK_DIALOG (dialog)); - gtk_widget_destroy (dialog); -} - - -/* Some helpers for the csv stuff */ -static GString * -add_list_to_csv (GString *line, GSList *list_in, CsvConfig *config, gint type) -{ - - /* - * This one will write 'ECalComponentText' and 'const char' GSLists. It will - * put quotes around the complete written value if there's was only one value - * but it required having quotes and if there was more than one value (in which - * case delimiters are used to separate them, hence the need for the quotes). - */ - - if (list_in) { - gboolean needquotes = FALSE; - GSList *list = list_in; - GString *tmp = NULL; - gint cnt=0; - while (list) { - const char *str = NULL; - if (cnt == 0) - tmp = g_string_new (""); - if (cnt > 0) - needquotes = TRUE; - switch (type) { - case ECALCOMPONENTATTENDEE: - str = ((ECalComponentAttendee*)list->data)->value; - break; - case ECALCOMPONENTTEXT: - str = ((ECalComponentText*)list->data)->value; - break; - case CONSTCHAR: - default: - str = list->data; - break; - } - if (!needquotes) - needquotes = string_needsquotes (str, config); - if (str) - tmp = g_string_append (tmp, (const gchar*)str); - list = g_slist_next (list); cnt++; - if (list) - tmp = g_string_append (tmp, config->delimiter); - } - - if (needquotes) - line = g_string_append (line, config->quote); - line = g_string_append_len (line, tmp->str, tmp->len); - g_string_free (tmp, TRUE); - if (needquotes) - line = g_string_append (line, config->quote); - } - - line = g_string_append (line, config->delimiter); - return line; -} - -static GString * -add_nummeric_to_csv (GString *line, gint *nummeric, CsvConfig *config) -{ - - /* - * This one will write {-1}..{00}..{01}..{99} - * it prepends a 0 if it's < 10 and > -1 - */ - - if (nummeric) - g_string_append_printf (line, "%s%d", (*nummeric<10 && *nummeric>-1)?"0":"", *nummeric); - - line = g_string_append (line, config->delimiter); - return line; -} - -static GString * -add_time_to_csv (GString *line, icaltimetype *time, CsvConfig *config) -{ - /* - * Perhaps we should check for quotes, delimiter and newlines in the - * resulting string: The translators can put it there! - * - * Or perhaps we shouldn't make this translatable? - * Or perhaps there is a library-function to do this? - */ - - if (time) { - g_string_append_printf (line, _("%s%d/%s%d/%s%d %s%d:%s%d:%s%d"), - (time->month < 10)?"0":"", time->month, - (time->day < 10)?"0":"", time->day, - (time->year < 10)?"0":"", time->year, - (time->hour < 10)?"0":"", time->hour, - (time->minute < 10)?"0":"", time->minute, - (time->second < 10)?"0":"", time->second); - } - - line = g_string_append (line, config->delimiter); - return line; -} - -static gboolean -string_needsquotes (const char *value, CsvConfig *config) -{ - - /* This is the actual need for quotes-checker */ - - /* - * These are the simple substring-checks - * - * Example: {Mom, can you please do that for me?} - * Will be written as {"Mom, can you please do that for me?"} - */ - - gboolean needquotes = strstr (value, config->delimiter) ? TRUE:FALSE; - - if (!needquotes) { - needquotes = strstr (value, config->newline) ? TRUE:FALSE; - if (!needquotes) - needquotes = strstr (value, config->quote) ? TRUE:FALSE; - } - - - /* - * If the special-char is char+onespace (so like {, } {" }, {\n }) and it occurs - * the value that is going to be written - * - * In this case we don't trust the user . . . and are going to quote the string - * just to play save -- Quoting is always allowed in the CSV format. If you can - * avoid it, it's better to do so since a lot applications don't support CSV - * correctly! --. - * - * Example: {Mom,can you please do that for me?} - * This example will be written as {"Mom,can you please do that for me?"} because - * there's a {,} behind {Mom} and the delimiter is {, } (so we searched only the - * first character of {, } and didn't trust the user). - */ - - - if (!needquotes) { - gint len = strlen (config->delimiter); - if ((len == 2) && (config->delimiter[1] = ' ')) { - needquotes = strchr (value, config->delimiter[0])?TRUE:FALSE; - if (!needquotes) { - gint len = strlen (config->newline); - if ((len == 2) && (config->newline[1] = ' ')) { - needquotes = strchr (value, config->newline[0])?TRUE:FALSE; - if (!needquotes) { - gint len = strlen (config->quote); - if ((len == 2) && (config->quote[1] = ' ')) { - needquotes = strchr - (value, config->quote[0])?TRUE:FALSE; - } - } - } - } - } - } - - return needquotes; -} - -static GString * -add_string_to_csv (GString *line, const char *value, CsvConfig *config) -{ - /* Will add a string to the record and will check for the need for quotes */ - - if ((value) && (strlen(value)>0)) { - gboolean needquotes = string_needsquotes (value, config); - - if (needquotes) - line = g_string_append (line, config->quote); - line = g_string_append (line, (const gchar*)value); - if (needquotes) - line = g_string_append (line, config->quote); - } - line = g_string_append (line, config->delimiter); - return line; -} - -static void -do_save_calendar_csv (EPlugin *ep, ECalPopupTargetSource *target, ECalSourceType type, char *dest_uri, gpointer data) -{ - - /* - * According to some documentation about CSV, newlines 'are' allowed - * in CSV-files. But you 'do' have to put the value between quotes. - * The helper 'string_needsquotes' will check for that - * - * http://www.creativyst.com/Doc/Articles/CSV/CSV01.htm - * http://www.creativyst.com/cgi-bin/Prod/15/eg/csv2xml.pl - */ - - ESource *primary_source; - ECal *source_client; - GError *error = NULL; - GList *objects=NULL; - GnomeVFSResult result; - GnomeVFSHandle *handle; - GnomeVFSURI *uri; - GString *line = NULL; - CsvConfig *config = data; - - primary_source = e_source_selector_peek_primary_selection (target->selector); - - if (!dest_uri) - return; - - /* open source client */ - source_client = e_cal_new (primary_source, type); - if (!e_cal_open (source_client, TRUE, &error)) { - display_error_message (gtk_widget_get_toplevel (GTK_WIDGET (target->selector)), error); - g_object_unref (source_client); - g_error_free (error); - return; - } - - uri = gnome_vfs_uri_new (dest_uri); - result = gnome_vfs_open_uri (&handle, uri, GNOME_VFS_OPEN_WRITE); - if (result != GNOME_VFS_OK) { - gnome_vfs_create (&handle, dest_uri, GNOME_VFS_OPEN_WRITE, TRUE, GNOME_VFS_PERM_USER_ALL); - result = gnome_vfs_open_uri (&handle, uri, GNOME_VFS_OPEN_WRITE); - } - - if (result == GNOME_VFS_OK && e_cal_get_object_list_as_comp (source_client, "#t", &objects, NULL)) { - - if (config->header) { - line = g_string_new (""); - g_string_append_printf (line, _("Uid%sSummary%sDescription List%sCategories List%s" - "Comment List%sCompleted%sCreated%sContact List%s" - "Start%sEnd%sDue%sPercent Done%sPriority%sUrl%s" - "Attendees List%sLocation%sModified%s"), - config->delimiter, config->delimiter, config->delimiter, config->delimiter, - config->delimiter, config->delimiter, config->delimiter, config->delimiter, - config->delimiter, config->delimiter, config->delimiter, config->delimiter, - config->delimiter, config->delimiter, config->delimiter, config->delimiter, - config->newline); - gnome_vfs_write (handle, line->str, line->len, NULL); - g_string_free (line, TRUE); - } - - - while (objects != NULL) { - ECalComponent *comp = objects->data; - gchar *delimiter_temp = NULL; - const char *temp_constchar; - GSList *temp_list; - ECalComponentDateTime temp_dt; - struct icaltimetype *temp_time; - int *temp_int; - ECalComponentText temp_comptext; - - line = g_string_new (""); - - /* Getting the stuff */ - e_cal_component_get_uid (comp, &temp_constchar); - line = add_string_to_csv (line, temp_constchar, config); - - e_cal_component_get_summary (comp, &temp_comptext); - line = add_string_to_csv (line, &temp_comptext?temp_comptext.value:NULL, config); - - e_cal_component_get_description_list (comp, &temp_list); - line = add_list_to_csv (line, temp_list, config, ECALCOMPONENTTEXT); - if (temp_list) - e_cal_component_free_text_list (temp_list); - - e_cal_component_get_categories_list (comp, &temp_list); - line = add_list_to_csv (line, temp_list, config, CONSTCHAR); - if (temp_list) - e_cal_component_free_categories_list (temp_list); - - e_cal_component_get_comment_list (comp, &temp_list); - line = add_list_to_csv (line, temp_list, config, ECALCOMPONENTTEXT); - if (temp_list) - e_cal_component_free_text_list (temp_list); - - e_cal_component_get_completed (comp, &temp_time); - line = add_time_to_csv (line, temp_time, config); - if (temp_time) - e_cal_component_free_icaltimetype (temp_time); - - e_cal_component_get_created (comp, &temp_time); - line = add_time_to_csv (line, temp_time, config); - if (temp_time) - e_cal_component_free_icaltimetype (temp_time); - - e_cal_component_get_contact_list (comp, &temp_list); - line = add_list_to_csv (line, temp_list, config, ECALCOMPONENTTEXT); - if (temp_list) - e_cal_component_free_text_list (temp_list); - - e_cal_component_get_dtstart (comp, &temp_dt); - line = add_time_to_csv (line, temp_dt.value ? temp_dt.value : NULL, config); - if (temp_dt.value) - e_cal_component_free_datetime (&temp_dt); - - e_cal_component_get_dtend (comp, &temp_dt); - line = add_time_to_csv (line, temp_dt.value ? temp_dt.value : NULL, config); - if (temp_dt.value) - e_cal_component_free_datetime (&temp_dt); - - e_cal_component_get_due (comp, &temp_dt); - line = add_time_to_csv (line, temp_dt.value ? temp_dt.value : NULL, config); - if (temp_dt.value) - e_cal_component_free_datetime (&temp_dt); - - e_cal_component_get_percent (comp, &temp_int); - line = add_nummeric_to_csv (line, temp_int, config); - - e_cal_component_get_priority (comp, &temp_int); - line = add_nummeric_to_csv (line, temp_int, config); - - e_cal_component_get_url (comp, &temp_constchar); - line = add_string_to_csv (line, temp_constchar, config); - - if (e_cal_component_has_attendees (comp)) { - e_cal_component_get_attendee_list (comp, &temp_list); - line = add_list_to_csv (line, temp_list, config, ECALCOMPONENTATTENDEE); - if (temp_list) - e_cal_component_free_attendee_list (temp_list); - } else { - line = add_list_to_csv (line, NULL, config, ECALCOMPONENTATTENDEE); - } - - e_cal_component_get_location (comp, &temp_constchar); - line = add_string_to_csv (line, temp_constchar, config); - - e_cal_component_get_last_modified (comp, &temp_time); - - /* Append a newline (record delimiter) */ - delimiter_temp = config->delimiter; - config->delimiter = config->newline; - - line = add_time_to_csv (line, temp_time, config); - - /* And restore for the next record */ - config->delimiter = delimiter_temp; - - /* Important note! - * The documentation is not requiring this! - * - * if (temp_time) e_cal_component_free_icaltimetype (temp_time); - * - * Please uncomment and fix documentation if untrue - * http://www.gnome.org/projects/evolution/developer-doc/libecal/ECalComponent.html - * #e-cal-component-get-last-modified - */ - gnome_vfs_write (handle, line->str, line->len, NULL); - /* It's written, so we can free it */ - g_string_free (line, TRUE); - - objects = g_list_next (objects); - } - - gnome_vfs_close (handle); - } - g_object_unref (source_client); -} - -static void -do_save_calendar_ical (EPlugin *ep, ECalPopupTargetSource *target, ECalSourceType type, char *dest_uri, gpointer data) +static void +extra_widget_foreach_hide (GtkWidget *widget, gpointer data) { - ESource *primary_source; - ECal *source_client, *dest_client; - GError *error = NULL; - - primary_source = e_source_selector_peek_primary_selection (target->selector); - - if (!dest_uri) - return; - - /* open source client */ - source_client = e_cal_new (primary_source, type); - if (!e_cal_open (source_client, TRUE, &error)) { - display_error_message (gtk_widget_get_toplevel (GTK_WIDGET (target->selector)), error); - g_object_unref (source_client); - g_error_free (error); - return; - } - - /* open destination client */ - error = NULL; - dest_client = e_cal_new_from_uri (dest_uri, type); - if (e_cal_open (dest_client, FALSE, &error)) { - GList *objects; - - if (e_cal_get_object_list (source_client, "#t", &objects, NULL)) { - while (objects != NULL) { - icalcomponent *icalcomp = objects->data; - - /* FIXME: deal with additions/modifications */ - - /* FIXME: This stores a directory with one file in it, the user expects only a file */ - - /* FIXME: It would be nice if this ical-handler would use gnome-vfs rather than e_cal_* */ - - error = NULL; - if (!e_cal_create_object (dest_client, icalcomp, NULL, &error)) { - display_error_message (gtk_widget_get_toplevel (GTK_WIDGET (target->selector)), error); - g_error_free (error); - } - - /* remove item from the list */ - objects = g_list_remove (objects, icalcomp); - icalcomponent_free (icalcomp); - } - } - } else { - display_error_message (gtk_widget_get_toplevel (GTK_WIDGET (target->selector)), error); - g_error_free (error); - } - - /* terminate */ - g_object_unref (source_client); - g_object_unref (dest_client); + if (widget != data) + gtk_widget_hide (widget); } - static void on_type_combobox_changed (GtkComboBox *combobox, gpointer data) { - void (*handler) (EPlugin *ep, ECalPopupTargetSource *target, ECalSourceType type, char *dest_uri, gpointer data); + FormatHandler *handler = NULL; + GtkWidget *extra_widget = data; GtkTreeIter iter; - GtkWidget *csv_options = data; GtkTreeModel *model = gtk_combo_box_get_model (combobox); + gtk_container_foreach (GTK_CONTAINER (extra_widget), + extra_widget_foreach_hide, combobox); + gtk_combo_box_get_active_iter (combobox, &iter); gtk_tree_model_get (model, &iter, DEST_HANDLER, &handler, -1); - if (handler == do_save_calendar_csv) { - gtk_widget_show (csv_options); - } else { - gtk_widget_hide (csv_options); - } + + if (handler->options_widget) + { + gtk_widget_show (handler->options_widget); + } + } -/* Convert what the user types to what he probably means */ -static gchar * -userstring_to_systemstring (const gchar *userstring) +static void +format_handlers_foreach_free (gpointer data, gpointer user_data) { - const gchar *text = userstring; - gint i=0, len = strlen(text); - GString *str = g_string_new (""); - gchar *retval = NULL; - - while (i < len) { - if (text[i] == '\\') { - switch (text[i+1]) { - case 'n': - str = g_string_append_c (str, '\n'); - i++; - break; - case '\\': - str = g_string_append_c (str, '\\'); - i++; - break; - case 'r': - str = g_string_append_c (str, '\r'); - i++; - break; - case 't': - str = g_string_append_c (str, '\t'); - i++; - break; - } - } else { - str = g_string_append_c (str, text[i]); - } + FormatHandler *handler = data; - i++; - } + if (handler->options_widget) + gtk_widget_destroy (handler->options_widget); - retval = str->str; - g_string_free (str, FALSE); + if (handler->data) + g_free (handler->data); - return retval; + g_free (data); } static void ask_destination_and_save (EPlugin *ep, ECalPopupTargetSource *target, ECalSourceType type) { - void (*handler) (EPlugin *ep, ECalPopupTargetSource *target, ECalSourceType type, char *dest_uri, gpointer data); - gpointer data = NULL; - CsvConfig *config = NULL; + FormatHandler *handler = NULL; GtkWidget *extra_widget = gtk_vbox_new (FALSE, 0); GtkComboBox *combo = GTK_COMBO_BOX(gtk_combo_box_new ()); - GtkTreeModel *model = GTK_TREE_MODEL (gtk_list_store_new (N_DEST_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER)); + GtkTreeModel *model = GTK_TREE_MODEL (gtk_list_store_new + (N_DEST_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER)); GtkCellRenderer *renderer=NULL; GtkListStore *store = GTK_LIST_STORE (model); GtkTreeIter iter; GtkWidget *dialog = NULL; char *dest_uri = NULL; - GtkWidget *header_check = gtk_check_button_new_with_label (_("Prepend a header")), - *delimiter_entry = gtk_entry_new (), - *newline_entry = gtk_entry_new (), - *quote_entry = gtk_entry_new (), - *table = gtk_table_new (4, 2, FALSE), *label = NULL, - *csv_options = gtk_expander_new (_("Advanced options for the CSV format")), - *vbox = gtk_vbox_new (FALSE, 0); + gboolean proceed = FALSE; + + GList *format_handlers = NULL; + + /* The available formathandlers */ + format_handlers = g_list_append (format_handlers, + ical_format_handler_new ()); + format_handlers = g_list_append (format_handlers, + csv_format_handler_new ()); + format_handlers = g_list_append (format_handlers, + rdf_format_handler_new ()); + /* The Type GtkComboBox */ + gtk_box_pack_start (GTK_BOX (extra_widget), GTK_WIDGET (combo), + TRUE, TRUE, 0); gtk_combo_box_set_model (combo, model); + + gtk_list_store_clear (store); renderer = gtk_cell_renderer_text_new (); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE); gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), - renderer, "text", DEST_NAME_COLUMN, NULL); + renderer, "text", DEST_NAME_COLUMN, NULL); - gtk_box_pack_start (GTK_BOX (extra_widget), GTK_WIDGET (combo), TRUE, TRUE, 0); - gtk_list_store_clear (store); - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, DEST_NAME_COLUMN, _("iCalendar format (.ics)"), -1); - gtk_list_store_set (store, &iter, DEST_HANDLER, do_save_calendar_ical, -1); - gtk_combo_box_set_active_iter (combo, &iter); - - gtk_list_store_append (store, &iter); - gtk_list_store_set (store, &iter, DEST_NAME_COLUMN, _("Comma separated value format (.csv)"), -1); - gtk_list_store_set (store, &iter, DEST_HANDLER, do_save_calendar_csv, -1); - - /* Advanced CSV options */ - gtk_entry_set_text (GTK_ENTRY(delimiter_entry), ", "); - gtk_entry_set_text (GTK_ENTRY(quote_entry), "\""); - gtk_entry_set_text (GTK_ENTRY(newline_entry), "\\n"); - - gtk_table_set_row_spacings (GTK_TABLE (table), 5); - gtk_table_set_col_spacings (GTK_TABLE (table), 5); - label = gtk_label_new (_("Value delimiter:")); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.0); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, - (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); - gtk_table_attach (GTK_TABLE (table), delimiter_entry, 1, 2, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0), 0, 0); - label = gtk_label_new (_("Record delimiter:")); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.0); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, - (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); - gtk_table_attach (GTK_TABLE (table), newline_entry, 1, 2, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0), 0, 0); - label = gtk_label_new (_("Encapsulate values with:")); - gtk_misc_set_alignment (GTK_MISC (label), 0, 0.0); - gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, - (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); - gtk_table_attach (GTK_TABLE (table), quote_entry, 1, 2, 2, 3, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (0), 0, 0); - gtk_box_pack_start (GTK_BOX (extra_widget), GTK_WIDGET (csv_options), TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (vbox), header_check, TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0); - gtk_container_add (GTK_CONTAINER (csv_options), vbox); - gtk_widget_show_all (vbox); + while (format_handlers) { + FormatHandler *handler = format_handlers->data; + + gtk_list_store_append (store, &iter); + gtk_list_store_set (store, &iter, DEST_NAME_COLUMN, + handler->combo_label, -1); + gtk_list_store_set (store, &iter, DEST_HANDLER, handler, -1); + + if (handler->options_widget) { + gtk_box_pack_start (GTK_BOX (extra_widget), + GTK_WIDGET (handler->options_widget), TRUE, TRUE, 0); + gtk_widget_hide (handler->options_widget); + } + + if (handler->isdefault) { + gtk_combo_box_set_active_iter (combo, &iter); + if (handler->options_widget) + gtk_widget_show (handler->options_widget); + } + + format_handlers = g_list_next (format_handlers); + } - g_signal_connect (G_OBJECT(combo), "changed", G_CALLBACK (on_type_combobox_changed), csv_options); + + g_signal_connect (G_OBJECT(combo), "changed", + G_CALLBACK (on_type_combobox_changed), extra_widget); #ifdef USE_GTKFILECHOOSER + dialog = gtk_file_chooser_dialog_new (_("Select destination file"), NULL, GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE_AS, GTK_RESPONSE_OK, NULL); + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), extra_widget); #else - /* I haven't tested this yet */ dialog = gtk_file_selection_new (_("Select destination file")); gtk_box_pack_start (GTK_BOX (GTK_FILE_SELECTION (dialog)->main_vbox), extra_widget); #endif - gtk_widget_show_all (extra_widget); + gtk_widget_show (GTK_WIDGET(combo)); + gtk_widget_show (extra_widget); - /* The default is ical, so hide the new options for now */ - gtk_widget_hide (csv_options); - if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK) { - gtk_widget_destroy (dialog); - return; - } + if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { + char *tmp = NULL; - gtk_combo_box_get_active_iter (combo, &iter); - gtk_tree_model_get (model, &iter, DEST_HANDLER, &handler, -1); + gtk_combo_box_get_active_iter (combo, &iter); + gtk_tree_model_get (model, &iter, + DEST_HANDLER, &handler, -1); #ifdef USE_GTKFILECHOOSER - dest_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog)); + dest_uri = gtk_file_chooser_get_uri + (GTK_FILE_CHOOSER (dialog)); #else - dest_uri = g_strdup (gtk_file_selection_get_filename (GTK_FILE_SELECTION (dialog))); + dest_uri = g_strdup (gtk_file_selection_get_filename + (GTK_FILE_SELECTION (dialog))); #endif - if (handler == do_save_calendar_csv) { - config = g_new (CsvConfig, 1); + tmp = strstr (dest_uri, handler->filename_ext); - config->delimiter = userstring_to_systemstring (gtk_entry_get_text (GTK_ENTRY(delimiter_entry))); - config->newline = userstring_to_systemstring (gtk_entry_get_text (GTK_ENTRY(newline_entry))); - config->quote = userstring_to_systemstring (gtk_entry_get_text (GTK_ENTRY(quote_entry))); - config->header = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (header_check)); + if (tmp && *(tmp + strlen (handler->filename_ext)) == '\0') { - data = config; - } + proceed = TRUE; + + } else { - gtk_widget_destroy (dialog); + GtkWidget *warning = + gtk_message_dialog_new (NULL, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_YES_NO, + _("The suggested filename extension of this filetype (%s)" + " is unused in the chosen filename. Do you want to " + "continue?"), handler->filename_ext); + + if (gtk_dialog_run (GTK_DIALOG (warning)) == GTK_RESPONSE_YES) + proceed = TRUE; + + gtk_widget_destroy (warning); - handler (ep, target, type, dest_uri, data); + } - if (handler == do_save_calendar_csv) { - g_free (config->delimiter); - g_free (config->quote); - g_free (config->newline); - g_free (config); - } + if (proceed) + { + handler->save (handler, ep, target, type, dest_uri); + /* Free the handlers */ + g_list_foreach (format_handlers, format_handlers_foreach_free, NULL); + g_list_free (format_handlers); + + /* Now we can destroy it */ + gtk_widget_destroy (dialog); + g_free (dest_uri); + } - g_free (dest_uri); + } else { + /* Free the handlers */ + g_list_foreach (format_handlers, format_handlers_foreach_free, NULL); + g_list_free (format_handlers); + + /* Now we can destroy it */ + gtk_widget_destroy (dialog); + g_free (dest_uri); + } } void
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- * * Authors: Philip Van Hoof <pvanhoof gnome org> * * Copyright 2004 Novell, Inc. (www.novell.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * 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 Street #330, Boston, MA 02111-1307, USA. * */ #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <glib.h> #include <glib/gi18n.h> #ifdef USE_GTKFILECHOOSER # include <gtk/gtkfilechooser.h> # include <gtk/gtkfilechooserdialog.h> #else # include <gtk/gtkfilesel.h> #endif #include <gtk/gtkmessagedialog.h> #include <gtk/gtkstock.h> #include <gtk/gtk.h> #include <libedataserver/e-source.h> #include <libedataserverui/e-source-selector.h> #include <libecal/e-cal.h> #include <calendar/gui/e-cal-popup.h> #include <libgnomevfs/gnome-vfs.h> #include <libxml/xmlmemory.h> #include <libxml/parser.h> #include <libxml/tree.h> #include <libxml/xmlIO.h> #include <libxml/xpath.h> #include <string.h> #include "format-handler.h" static void add_string_to_rdf (xmlNodePtr node, const gchar *tag, const char *value); /* Use { */ /* #include <calendar/gui/calendar-config-keys.h> */ /* #include <calendar/gui/calendar-config.h> */ /* } or { */ #define CALENDAR_CONFIG_PREFIX "/apps/evolution/calendar" #define CALENDAR_CONFIG_TIMEZONE CALENDAR_CONFIG_PREFIX "/display/timezone" GConfClient *config = NULL; static gchar * calendar_config_get_timezone (void) { gchar *retval = NULL; if (!config) config = gconf_client_get_default (); retval = gconf_client_get_string (config, CALENDAR_CONFIG_TIMEZONE, NULL); if (!retval) retval = g_strdup ("UTC"); return retval; } /* } */ enum { /* XML helper enum */ ECALCOMPONENTTEXT, ECALCOMPONENTATTENDEE, CONSTCHAR }; static void display_error_message (GtkWidget *parent, GError *error) { GtkWidget *dialog; dialog = gtk_message_dialog_new (GTK_WINDOW (parent), 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, error->message); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); } /* Some helpers for the xml stuff */ static void add_list_to_rdf (xmlNodePtr node, const gchar *tag, GSList *list_in, gint type) { if (list_in) { GSList *list = list_in; while (list) { const char *str = NULL; switch (type) { case ECALCOMPONENTATTENDEE: str = ((ECalComponentAttendee*)list->data)->value; break; case ECALCOMPONENTTEXT: str = ((ECalComponentText*)list->data)->value; break; case CONSTCHAR: default: str = list->data; break; } add_string_to_rdf (node, tag, str); list = g_slist_next (list); } } } static void add_nummeric_to_rdf (xmlNodePtr node, const gchar *tag, gint *nummeric) { if (nummeric) { gchar *value = g_strdup_printf ("%d", *nummeric); xmlNodePtr cur_node = xmlNewChild (node, NULL, tag, value); xmlSetProp (cur_node, "rdf:datatype", "http://www.w3.org/2001/XMLSchema#integer"); g_free (value); } } static void add_time_to_rdf (xmlNodePtr node, const gchar *tag, icaltimetype *time) { if (time) { xmlNodePtr cur_node = NULL; gchar *tmp = NULL; gchar *str = g_strdup_printf ("%s%d-%s%d-%s%dT%s%d:%s%d:%s%d", (time->year < 10)?"0":"", time->year, (time->month < 10)?"0":"", time->month, (time->day < 10)?"0":"", time->day, (time->hour < 10)?"0":"", time->hour, (time->minute < 10)?"0":"", time->minute, (time->second < 10)?"0":"", time->second); cur_node = xmlNewChild (node, NULL, tag, str); /* Not sure about this property */ tmp = g_strdup_printf ("http://www.w3.org/2002/12/cal/tzd/%s#tz", calendar_config_get_timezone ()); xmlSetProp (cur_node, "rdf:datatype", tmp); g_free (tmp); g_free (str); } } static void add_string_to_rdf (xmlNodePtr node, const gchar *tag, const char *value) { if (value) { xmlNodePtr cur_node = NULL; cur_node = xmlNewChild (node, NULL, tag, value); xmlSetProp (cur_node, "rdf:datatype", "http://www.w3.org/2001/XMLSchema#string"); } } static void do_save_calendar_rdf (FormatHandler *handler, EPlugin *ep, ECalPopupTargetSource *target, ECalSourceType type, char *dest_uri) { /* * According to some documentation about CSV, newlines 'are' allowed * in CSV-files. But you 'do' have to put the value between quotes. * The helper 'string_needsquotes' will check for that * * http://www.creativyst.com/Doc/Articles/CSV/CSV01.htm * http://www.creativyst.com/cgi-bin/Prod/15/eg/csv2xml.pl */ ESource *primary_source; ECal *source_client; GError *error = NULL; GList *objects=NULL; GnomeVFSResult result; GnomeVFSHandle *handle; GnomeVFSURI *uri; gchar *temp = NULL; if (!dest_uri) return; primary_source = e_source_selector_peek_primary_selection (target->selector); /* open source client */ source_client = e_cal_new (primary_source, type); if (!e_cal_open (source_client, TRUE, &error)) { display_error_message (gtk_widget_get_toplevel (GTK_WIDGET (target->selector)), error); g_object_unref (source_client); g_error_free (error); return; } uri = gnome_vfs_uri_new (dest_uri); result = gnome_vfs_open_uri (&handle, uri, GNOME_VFS_OPEN_WRITE); if (result != GNOME_VFS_OK) { gnome_vfs_create (&handle, dest_uri, GNOME_VFS_OPEN_WRITE, TRUE, GNOME_VFS_PERM_USER_ALL); result = gnome_vfs_open_uri (&handle, uri, GNOME_VFS_OPEN_WRITE); } if (result == GNOME_VFS_OK && e_cal_get_object_list_as_comp (source_client, "#t", &objects, NULL)) { xmlBufferPtr buffer=xmlBufferCreate(); xmlDocPtr doc = xmlNewDoc((xmlChar *) "1.0"); xmlNodePtr fnode = doc->children; doc->children = xmlNewDocNode (doc, NULL, "rdf:RDF", NULL); xmlSetProp (doc->children, "xmlns:rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"); xmlSetProp (doc->children, "xmlns", "http://www.w3.org/2002/12/cal/ical#"); fnode = xmlNewChild (doc->children, NULL, "Vcalendar", NULL); /* Should Evolution publicise these? */ xmlSetProp (fnode, "xmlns:x-wr", "http://www.w3.org/2002/12/cal/prod/Apple_Comp_628d9d8459c556fa#"); xmlSetProp (fnode, "xmlns:x-lic", "http://www.w3.org/2002/12/cal/prod/Apple_Comp_628d9d8459c556fa#"); /* Not sure if it's correct like this */ xmlNewChild (fnode, NULL, "prodid", "-//" PACKAGE_STRING "//iCal 1.0//EN"); /* Assuming GREGORIAN is the only supported calendar scale */ xmlNewChild (fnode, NULL, "calscale", "GREGORIAN"); temp = calendar_config_get_timezone (); xmlNewChild (fnode, NULL, "x-wr:timezone", temp); g_free (temp); xmlNewChild (fnode, NULL, "method", "PUBLISH"); xmlNewChild (fnode, NULL, "x-wr:relcalid", e_source_peek_uid (primary_source)); xmlNewChild (fnode, NULL, "x-wr:calname", e_source_peek_name (primary_source)); /* Version of this RDF-format */ xmlNewChild (fnode, NULL, "version", "2.0"); while (objects != NULL) { ECalComponent *comp = objects->data; const char *temp_constchar; gchar *tmp_str = NULL; GSList *temp_list; ECalComponentDateTime temp_dt; struct icaltimetype *temp_time; int *temp_int; ECalComponentText temp_comptext; xmlNodePtr c_node = xmlNewChild (fnode, NULL, "component", NULL); xmlNodePtr node = xmlNewChild (c_node, NULL, "Vevent", NULL); /* Getting the stuff */ e_cal_component_get_uid (comp, &temp_constchar); tmp_str = g_strdup_printf ("#%s", temp_constchar); xmlSetProp (node, "about", tmp_str); g_free (tmp_str); add_string_to_rdf (node, "uid",temp_constchar); e_cal_component_get_summary (comp, &temp_comptext); add_string_to_rdf (node, "summary",&temp_comptext?temp_comptext.value:NULL); e_cal_component_get_description_list (comp, &temp_list); add_list_to_rdf (node, "description", temp_list, ECALCOMPONENTTEXT); if (temp_list) e_cal_component_free_text_list (temp_list); e_cal_component_get_categories_list (comp, &temp_list); add_list_to_rdf (node, "categories", temp_list, CONSTCHAR); if (temp_list) e_cal_component_free_categories_list (temp_list); e_cal_component_get_comment_list (comp, &temp_list); add_list_to_rdf (node, "comment", temp_list, ECALCOMPONENTTEXT); if (temp_list) e_cal_component_free_text_list (temp_list); e_cal_component_get_completed (comp, &temp_time); add_time_to_rdf (node, "completed", temp_time); if (temp_time) e_cal_component_free_icaltimetype (temp_time); e_cal_component_get_created (comp, &temp_time); add_time_to_rdf (node, "created", temp_time); if (temp_time) e_cal_component_free_icaltimetype (temp_time); e_cal_component_get_contact_list (comp, &temp_list); add_list_to_rdf (node, "contact", temp_list, ECALCOMPONENTTEXT); if (temp_list) e_cal_component_free_text_list (temp_list); e_cal_component_get_dtstart (comp, &temp_dt); add_time_to_rdf (node, "dtstart", temp_dt.value ? temp_dt.value : NULL); if (temp_dt.value) e_cal_component_free_datetime (&temp_dt); e_cal_component_get_dtend (comp, &temp_dt); add_time_to_rdf (node, "dtend", temp_dt.value ? temp_dt.value : NULL); if (temp_dt.value) e_cal_component_free_datetime (&temp_dt); e_cal_component_get_due (comp, &temp_dt); add_time_to_rdf (node, "due", temp_dt.value ? temp_dt.value : NULL); if (temp_dt.value) e_cal_component_free_datetime (&temp_dt); e_cal_component_get_percent (comp, &temp_int); add_nummeric_to_rdf (node, "percentComplete", temp_int); e_cal_component_get_priority (comp, &temp_int); add_nummeric_to_rdf (node, "priority", temp_int); e_cal_component_get_url (comp, &temp_constchar); add_string_to_rdf (node, "URL", temp_constchar); if (e_cal_component_has_attendees (comp)) { e_cal_component_get_attendee_list (comp, &temp_list); add_list_to_rdf (node, "attendee", temp_list, ECALCOMPONENTATTENDEE); if (temp_list) e_cal_component_free_attendee_list (temp_list); } e_cal_component_get_location (comp, &temp_constchar); add_string_to_rdf (node, "location", temp_constchar); e_cal_component_get_last_modified (comp, &temp_time); add_time_to_rdf (node, "lastModified",temp_time); /* Important note! * The documentation is not requiring this! * * if (temp_time) e_cal_component_free_icaltimetype (temp_time); * * Please uncomment and fix documentation if untrue * http://www.gnome.org/projects/evolution/developer-doc/libecal/ECalComponent.html * #e-cal-component-get-last-modified */ objects = g_list_next (objects); } /* I used a buffer rather than xmlDocDump: I want gnome-vfs support */ xmlNodeDump (buffer, doc, doc->children, 2, 1); gnome_vfs_write (handle, xmlBufferContent (buffer), xmlBufferLength (buffer), NULL); xmlBufferFree (buffer); xmlFreeDoc (doc); gnome_vfs_close (handle); } g_object_unref (source_client); return; } FormatHandler *rdf_format_handler_new (void) { FormatHandler *handler = g_new (FormatHandler, 1); handler->isdefault = FALSE; handler->combo_label = _("RDF format (.rdf)"); handler->filename_ext = ".rdf"; handler->options_widget = NULL; handler->save = do_save_calendar_rdf; return handler; }
Attachment:
rdfformat-01.tar
Description: Unix tar archive