[evolution-patches] Save-calendar plugin. saving to comma separated files



Hi there,

I will probably have to explain why the patch has gotten so large?

well ..

Not only I've added a combobox this time, I also added a GtkExpander to
the GtkFileChooserDialog with the label "Advanced options for the CSV
format". It will, of course, only be visible if you select the
CSV-format in the combobox.

Those advanced CSV-options allow the user to specify whether or not
he/she wants a header, what delimiter is to be used, what
record-delimiter is to be used and what quote-char is to be used.

I've fixed all CSV-format issues and also added a small API for writing
calendar stuff to CSV-files. I based myself on the CSV-format guidelines
which I've found on this url:

	http://www.creativyst.com/Doc/Articles/CSV/CSV01.htm

I've also checked the CSV-format after creating a calendar with a few
very complex records using their free online tool:

	http://www.creativyst.com/cgi-bin/Prod/15/eg/csv2xml.pl


I've added a lot memory-freeing which was not being done in previous
patches (I've finally really read the ECalComponent documentation this
time). And I simplified the writing to the file a bit (using that CSV
API).

I haven't fixed the fact that the ical-format will be saved to a
directory with only one file in it, rather than just that one file. I
will take a look at this sooner or later (I first wanted to get CSV
working).


I also added some code-comments, you are free to remove them

I attached a diff for the ChangeLog-file too.

I attached this patch to the Bounty-bug for it here:

http://bugzilla.gnome.org/attachment.cgi?id=34308&action=view
http://bugzilla.gnome.org/show_bug.cgi?id=127557


ps. That copyright assignment contract which I had to sign to get myself
the right to contribute to Evolution, has been mailed. I'd really
prefer, however, if Evolution got relicensed under a license that
commercially fits Novell better. Rather than raping the GPL.

This contract isn't making things more easy for non-Novell employees to
contribute to Evolution. Such contributions are very important for any
free software package.

ps. can somebody check the documentation about 'e-cal-component-
get-last-modified'. It sais I don't have to free the returned value, but
I am unsure about that (other such functions do require freeing)

http://www.gnome.org/projects/evolution/developer-doc/libecal/ECalComponent.html#e-cal-component-get-last-modified

-- 
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
Index: save-calendar.c
===================================================================
RCS file: /cvs/gnome/evolution/plugins/save-calendar/save-calendar.c,v
retrieving revision 1.3
diff -u -r1.3 save-calendar.c
--- save-calendar.c	21 Oct 2004 11:21:42 -0000	1.3
+++ save-calendar.c	29 Nov 2004 22:47:55 -0000
@@ -36,13 +36,37 @@
 #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 <string.h>
 
+
+enum {  /* GtkComboBox enum */
+	DEST_NAME_COLUMN,
+	DEST_HANDLER,
+	N_DEST_COLUMNS
+
+};
+enum { /* CSV helper enum */
+	ECALCOMPONENTTEXT,
+	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)
@@ -55,41 +79,368 @@
 	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 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 (EPlugin *ep, ECalPopupTargetSource *target, ECalSourceType type)
+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;
-	char *dest_uri;
-	ECal *source_client, *dest_client;
-	GtkWidget *dialog;
+	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);
 
-	/* ask the user for destination file */
-#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, GTK_RESPONSE_OK,
-					      NULL);
-	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
-#else
-	dialog = gtk_file_selection_new (_("Select destination file"));
-#endif
+	if (!dest_uri)
+		return;
 
-	if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK) {
-		gtk_widget_destroy (dialog);
+	/* 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;
 	}
 
-#ifdef USE_GTKFILECHOOSER
-	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)));
-#endif
-	gtk_widget_destroy (dialog);
+	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 ("");
+
+			/* I don't know, the documentation told me to do this */
+			e_cal_component_commit_sequence (comp);
+
+			/* 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.value, 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, config);
+			if (&temp_dt) e_cal_component_free_datetime (&temp_dt);
+
+			e_cal_component_get_dtend (comp, &temp_dt);
+			line = add_time_to_csv (line, temp_dt.value, config);
+			if (&temp_dt) e_cal_component_free_datetime (&temp_dt);
+
+
+			e_cal_component_get_due (comp, &temp_dt);
+			line = add_time_to_csv (line, temp_dt.value, config);
+			if (&temp_dt) 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, CONSTCHAR);
+				if (temp_list) e_cal_component_free_attendee_list (temp_list);
+			} else {
+				line = add_list_to_csv (line, NULL, config, CONSTCHAR);
+			}
+
+			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)
+{
+	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;
 
@@ -98,7 +449,6 @@
 	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_free (dest_uri);
 		g_error_free (error);
 		return;
 	}
@@ -114,6 +464,8 @@
 				icalcomponent *icalcomp = objects->data;
 
 				/* FIXME: deal with additions/modifications */
+
+				/* FIXME: This stores a direcotory with one file in it, the user expects only a file */
 				error = NULL;
 				if (!e_cal_create_object (dest_client, icalcomp, NULL, &error)) {
 					display_error_message (gtk_widget_get_toplevel (GTK_WIDGET (target->selector)), error);
@@ -133,17 +485,207 @@
 	/* terminate */
 	g_object_unref (source_client);
 	g_object_unref (dest_client);
+}
+
+
+static void 
+on_type_combobox_changed (GtkComboBox *combobox, gpointer data)
+{
+	void (*handler) (EPlugin *ep, ECalPopupTargetSource *target, ECalSourceType type, char *dest_uri, gpointer data);
+	GtkTreeIter iter;
+	GtkWidget *csv_options = data;
+	GtkTreeModel *model = gtk_combo_box_get_model (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);
+	}
+}
+
+/* Convert what the user types to what he probably means */
+static gchar *
+userstring_to_systemstring (const gchar *userstring)
+{
+	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;
+			}
+		} else {
+			str = g_string_append_c (str, text[i]);
+		}
+
+		i++;
+	}
+
+	retval = str->str;
+	g_string_free (str, FALSE);
+
+	return retval; 
+}
+
+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;
+
+	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));
+	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);
+
+
+	/* The Type GtkComboBox */
+	gtk_combo_box_set_model (combo, model);
+	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);
+
+	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);
+
+	g_signal_connect (G_OBJECT(combo), "changed", G_CALLBACK (on_type_combobox_changed), csv_options);
+
+	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);
+
+	gtk_widget_show_all (extra_widget);
+
+	/* The default is ical */
+	gtk_widget_hide (csv_options);
+
+	if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK) {
+		gtk_widget_destroy (dialog);
+		return;
+	}
+
+	gtk_combo_box_get_active_iter (combo, &iter);
+	gtk_tree_model_get (model, &iter, 
+		DEST_HANDLER, &handler, -1);
+
+	dest_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
+
+	if (handler == do_save_calendar_csv)
+	{
+		config = g_new (CsvConfig, 1);
+
+		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));
+
+		data = config;
+	}
+
+	gtk_widget_destroy (dialog);
+
+	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);
+	}
+
 	g_free (dest_uri);
 }
 
 void
 org_gnome_save_calendar (EPlugin *ep, ECalPopupTargetSource *target)
 {
-	do_save_calendar (ep, target, E_CAL_SOURCE_TYPE_EVENT);
+	ask_destination_and_save (ep, target, E_CAL_SOURCE_TYPE_EVENT);
 }
 
 void
 org_gnome_save_tasks (EPlugin *ep, ECalPopupTargetSource *target)
 {
-	do_save_calendar (ep, target, E_CAL_SOURCE_TYPE_TODO);
+	ask_destination_and_save (ep, target, E_CAL_SOURCE_TYPE_TODO);
 }
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution/plugins/save-calendar/ChangeLog,v
retrieving revision 1.5
diff -u -r1.5 ChangeLog
--- ChangeLog	1 Nov 2004 18:39:17 -0000	1.5
+++ ChangeLog	29 Nov 2004 23:11:23 -0000
@@ -1,3 +1,7 @@
+2004-11-30  Philip Van Hoof  <pvanhoof gnome org
+
+	* save-calendar.c: Support for CSV files
+
 2004-11-01  JP Rosevear  <jpr novell com>
 
 	* Makefile.am: dist .eplug.in file


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]