Re: [evolution-patches] Re: Save-calendar plugin: corrected GTK_STOCK_SAVE_AS behavior and support for comma seperated files



On Wed, 2004-11-24 at 14:45 -0500, JP Rosevear wrote:

> The person who should probably review this is away right now, but let me
> give a few comments.

Okay. I've received a request for copyright assignment from Novell
employee Srinivasa Ragavan. Is this the person who is to review this?

Know what .. I'll put everybody involved in CC ;-)


> I think the the type for "Save As" should probably be set by a widget in
> the save dialog, rather than via a submenu.  I also think we need to
> work around the ical folder saving issue, either by picking the folder
> correctly or altering the file backend to allow overriding of the file
> name used on disk (right now it uses either calendar.ics or tasks.ics).

I have a feeling you will like it this way. Please check it out and
comment on this. -- Note that the eplug.in-file is be restored if you
used my previous patches --

This will make the GtkFileChooserDialog like the one shipped with
OpenOffice.org. So with a combobox. If there's a chance that this gets
in Evolution, I'll proceed and fix the CSV-format issues and add
checkboxes about the filename extension (just like OpenOffice.org has:
[x] Automatic filename extension).

I'll then also look at the API-internals/backend to try add support for
storing ical-"files" in stead of it saving a directory with one .ical
file (task.ical of calendar.ical) in it.


> For CSV an option to insert a header row would be good and the date and
> time spacing seems borked, its using " 6" instead of "06" for instance.
> Descriptions don't seem to be written out properly either.

I've send my Copyright assignment letter towards Novell today (one of
you Novell guys requested I sign this document first). I don't know when
the letter will arrive. I'd personally prefer to do such things over E-
mail. So I suggest for the ease of making contributions to Evolution,
you Novell people talk to your legal guys about whether or not it's
possible to arrange this copyright assignment over E-mail. It's even
costing me money to get that letter in Cambridge! I have to pay to
contribute to Evolution?? Luckily there's a GNOME bounty attached to
this contribution, so it's okay.

Also note (and I wrote it on that document) that I only want copyright
assignment to happen with my code and patches that are

1.	 .. related to Evolution
2.	 .. posted, by myself, to this specific mailinglist.

I can imagine myself writing code related to Evolution which I want to
make GPL (or any other compatible license) while not transferring nor
assigning any copyrights to Novell. In which case I will not post it on
this mailinglist.

The example on the document sais 'any' contribution to the Evolution
project. No. I wouldn't sign that. I want to specify which ones of my
contributions are eligible for copyright assignment.

So, this contribution is eligible


-- 
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	26 Nov 2004 14:13:03 -0000
@@ -36,10 +36,13 @@
 #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>
 
 void org_gnome_save_calendar (EPlugin *ep, ECalPopupTargetSource *target);
 void org_gnome_save_tasks (EPlugin *ep, ECalPopupTargetSource *target);
@@ -55,41 +58,158 @@
 	gtk_widget_destroy (dialog);
 }
 
+
+/* Some helpers for the csv stuff */
+
+/* Turns a text-GSLis into a comma-separated, unquoted string (result should be freed) */
+static GString *
+gslist_to_csv (GSList *list_in)
+{
+	GSList *list = list_in;
+	GString *str = g_string_new ("");
+	while (list) {
+		str = g_string_append (str, (const char*)list->data);
+		list = g_slist_next (list);
+		if (list) str = g_string_append (str, ", ");
+	}
+	return str;
+}
+
+/* Returns an icaltimetype as a (localized) string (result should be freed) */
+static gchar *
+icaltimetype_to_gchar (icaltimetype *t)
+{
+	if (t) return g_strdup_printf (_("%2d/%2d/%4d %2d:%2d:%2d"), t->month, t->day, t->year, t->hour, t->minute, t->second);
+	else return g_strdup ("");
+}
+
 static void
-do_save_calendar (EPlugin *ep, ECalPopupTargetSource *target, ECalSourceType type)
+do_save_calendar_csv (EPlugin *ep, ECalPopupTargetSource *target, ECalSourceType type, char *dest_uri)
 {
 	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;
 
 	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_free (dest_uri);
+		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)) {
+		while (objects != NULL) {
+			const char *uid, *categories, *url;
+			GString *comment_list_str, *contact_list_str, *description_list_str, *attendee_list_str;
+			GSList *comment_list, *contact_list, *description_list, *attendee_list;
+			struct icaltimetype *completed, *created;
+			gchar *completed_gchar, *created_gchar, *dtend_gchar, *dtstart_gchar, *dtdue_gchar, *line=NULL;
+			ECalComponentDateTime dtend, dtstart, dtdue;
+			int *percent, *priority;
+			ECalComponentText summary; 
+			ECalComponent *comp = objects->data;
+
+			/* I don't know, the documentation told me to do this */
+			e_cal_component_commit_sequence (comp);
+
+			/* Question: In what format and what information do you (bounty-team)/we want this? */
+
+			/* Getting the stuff */
+			e_cal_component_get_uid (comp, &uid);
+			e_cal_component_get_categories (comp, &categories);
+			e_cal_component_get_comment_list (comp, &comment_list);
+			e_cal_component_get_completed (comp, &completed);
+			e_cal_component_get_contact_list (comp, &contact_list);
+			e_cal_component_get_created (comp, &created);
+			e_cal_component_get_description_list (comp, &description_list);
+			e_cal_component_get_dtend (comp, &dtend);
+			e_cal_component_get_dtstart (comp, &dtstart);
+			e_cal_component_get_due (comp, &dtdue);
+			e_cal_component_get_percent (comp, &percent);
+			e_cal_component_get_priority (comp, &priority);
+			e_cal_component_get_summary (comp, &summary);
+			e_cal_component_get_url (comp, &url);
+			e_cal_component_get_attendee_list (comp, &attendee_list);
+
+			/* Convertions */
+			dtend_gchar = icaltimetype_to_gchar (dtend.value);
+			dtstart_gchar = icaltimetype_to_gchar (dtstart.value);
+			dtdue_gchar = icaltimetype_to_gchar (dtdue.value);
+			completed_gchar = icaltimetype_to_gchar (completed);
+			created_gchar = icaltimetype_to_gchar (created);
+			comment_list_str = gslist_to_csv (comment_list);
+			contact_list_str = gslist_to_csv (contact_list);
+			description_list_str = gslist_to_csv (description_list);
+			attendee_list_str = gslist_to_csv (attendee_list);
+
+			/* Dump it as a CSV in the file */
+
+			line = g_strdup_printf (
+
+					"\"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", "
+					"\"%s\", \"%s\", \"%s\", %d, %d, \"%s\", \"%s\", \"%s\"\n",
+
+					uid?uid:"", categories?categories:"", 
+					comment_list_str->str, completed_gchar, 
+					contact_list_str->str, created_gchar, 
+					description_list_str->str, dtend_gchar, 
+					dtstart_gchar, dtdue_gchar, 
+					percent?*percent:-1, priority?*priority:-1, 
+					summary.value?summary.value:"", url?url:"", 
+					attendee_list_str->str);
+
+			
+
+			/* Free memory for this record */
+			g_string_free (comment_list_str, TRUE);
+			g_string_free (contact_list_str, TRUE);
+			g_string_free (description_list_str, TRUE);
+			g_string_free (attendee_list_str, TRUE);
+			g_free (completed_gchar); g_free (created_gchar);
+			g_free (dtend_gchar); g_free (dtstart_gchar); 
+			g_free (dtdue_gchar);
+
+			gnome_vfs_write (handle, line, strlen (line), NULL);
+
+			g_free (line);
+
+			objects = g_list_next (objects);
+		}
+
+		gnome_vfs_close (handle);
+	}
+	g_object_unref (source_client);
+	g_free (dest_uri);
+}
+
+static void
+do_save_calendar_ical (EPlugin *ep, ECalPopupTargetSource *target, ECalSourceType type, char *dest_uri)
+{
+	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;
 
@@ -136,14 +256,79 @@
 	g_free (dest_uri);
 }
 
+enum {
+	DEST_NAME_COLUMN,
+	DEST_HANDLER,
+	N_DEST_COLUMNS
+};
+
+static void 
+ask_destination_and_save (EPlugin *ep, ECalPopupTargetSource *target, ECalSourceType type)
+{
+	void (*handler) (EPlugin *ep, ECalPopupTargetSource *target, ECalSourceType type, char *dest_uri);
+
+	GtkWidget *extra_widget = gtk_vbox_new (FALSE, 0);
+	GtkComboBox *combo = 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;
+
+	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 (.ical)"), -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);
+
+	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);
+
+
+	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));
+	gtk_widget_destroy (dialog);
+
+	handler (ep, target, type, 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);
 }


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