[evolution-patches] 62911 async loading of calendars



-JP
-- 
JP Rosevear <jpr novell com>
Novell, Inc.
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/evolution/calendar/ChangeLog,v
retrieving revision 1.2497
diff -u -p -r1.2497 ChangeLog
--- ChangeLog	27 Aug 2004 15:41:04 -0000	1.2497
+++ ChangeLog	27 Aug 2004 16:27:02 -0000
@@ -1,5 +1,46 @@
 2004-08-27  JP Rosevear  <jpr novell com>
 
+	Fixes #62911, #54101
+	
+	* gui/e-itip-control.c (set_ok_sens): util routine to set
+	sensitivity of OK button
+	(cal_opened_cb): cal back when calendar opens, sensitize ok button
+	(start_calendar_server): open async and take call back arg
+	(source_selected_cb): desensitize ok button until calendar is
+	loaded
+	(find_cal_opened_cb): check to see if the calendar contains the
+	object we are looking for, if none do show the source selector
+	option menu
+	(find_server): search async for the server
+	(destroy): clean up html widget
+	(finalize): instead of here
+	(get_publish_options): use only object tag
+	(get_request_options): ditto
+	(get_request_fb_options): ditto
+	(get_reply_options): ditto
+	(get_refresh_options): ditto
+	(get_cancel_options): ditto
+	(show_current_event): use new options, remove groupwise NEEDS
+	ACTION check, handle async loading
+	(show_current_todo): use new options, handle async loading
+	(option_activated_cb): record action
+	(add_option): add action item
+	(insert_boxes): layout widgets
+	(insert_label): insert label
+	(rsvp_clicked_cb): record rsvp status
+	(insert_rsvp): insert rsvp check box
+	(insert_ok): insert ok button
+	(publish_options_object): spit out relevant options
+	(request_options_object): ditto
+	(freebusy_options_object): ditto
+	(reply_options_object): ditto
+	(refresh_options_object): ditto
+	(cancel_options_object): ditto
+	(object_requested_cb): handle object requests
+	(ok_clicked_cb): use recorded actions
+
+2004-08-27  JP Rosevear  <jpr novell com>
+	
 	* gui/alarm-notify/alarm-notify.h: update proto
 
 	* gui/alarm-notify/alarm-notify.c (list_changed_cb): use per
@@ -23,7 +64,7 @@
 	record correctly, should fix copy to/from problems when syncing
 
 	* conduits/calendar/calendar-conduit.c (for_each): ditto
-	
+
 2004-08-25  Frederic Crozat  <fcrozat mandrakesoft com>
 
 	* gui/dialogs/recur-comp.c: (recur_component_dialog):
Index: gui/e-itip-control.c
===================================================================
RCS file: /cvs/gnome/evolution/calendar/gui/e-itip-control.c,v
retrieving revision 1.158
diff -u -p -r1.158 e-itip-control.c
--- gui/e-itip-control.c	9 Aug 2004 12:57:15 -0000	1.158
+++ gui/e-itip-control.c	27 Aug 2004 16:27:02 -0000
@@ -40,6 +40,7 @@
 #include <bonobo/bonobo-object.h>
 #include <bonobo/bonobo-exception.h>
 #include <gtkhtml/gtkhtml.h>
+#include <gtkhtml/gtkhtml-embedded.h>
 #include <gtkhtml/gtkhtml-stream.h>
 #include <libedataserver/e-source-list.h>
 #include <libical/ical.h>
@@ -66,6 +67,13 @@ struct _EItipControlPrivate {
 	ECal *current_ecal;
 	ECalSourceType type;
 
+	char action;
+	gboolean rsvp;
+
+	GtkWidget *ok;
+	GtkWidget *hbox;
+	GtkWidget *vbox;
+	
 	char *vcalendar;
 	ECalComponent *comp;
 	icalcomponent *main_comp;
@@ -90,6 +98,8 @@ struct _EItipControlPrivate {
 	gboolean destroyed;
 };
 
+#define ACTION_DATA "EItipControl:Action"
+
 /* HTML Strings */
 #define HTML_BODY_START "<body bgcolor=\"#ffffff\" text=\"#000000\" link=\"#336699\">"
 #define HTML_SEP        "<hr color=#336699 align=\"left\" width=450>"
@@ -101,9 +111,10 @@ static void init	(EItipControl		 *itip);
 static void destroy	(GtkObject               *obj);
 static void finalize	(GObject               *obj);
 
+static void find_my_address (EItipControl *itip, icalcomponent *ical_comp, icalparameter_partstat *status);
 static void url_requested_cb (GtkHTML *html, const gchar *url, GtkHTMLStream *handle, gpointer data);
 static gboolean object_requested_cb (GtkHTML *html, GtkHTMLEmbedded *eb, gpointer data);
-static void ok_clicked_cb (GtkHTML *html, const gchar *method, const gchar *url, const gchar *encoding, gpointer data);
+static void ok_clicked_cb (GtkWidget *widget, gpointer data);
 
 static GtkVBoxClass *parent_class = NULL;
 
@@ -126,28 +137,78 @@ class_init (EItipControlClass *klass)
 	object_class->finalize = finalize;
 }
 
+static void
+set_ok_sens (EItipControl *itip)
+{
+	EItipControlPrivate *priv;
+	gboolean read_only = TRUE;
+	
+	priv = itip->priv;
+
+	if (!priv->ok)
+		return;
+	
+	if (priv->current_ecal)
+		e_cal_is_read_only (priv->current_ecal, &read_only, NULL);
+	
+	gtk_widget_set_sensitive (priv->ok, priv->current_ecal != NULL && !read_only);
+}
+
+static void
+cal_opened_cb (ECal *ecal, ECalendarStatus status, gpointer data)
+{
+	EItipControl *itip = data;
+	EItipControlPrivate *priv;
+	ESource *source;
+	ECalSourceType source_type;
+	icaltimezone *zone;
+
+	priv = itip->priv;
+
+	source_type = e_cal_get_source_type (ecal);
+	source = e_cal_get_source (ecal);
+	
+	g_signal_handlers_disconnect_matched (ecal, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, cal_opened_cb, NULL);
+
+	if (status != E_CALENDAR_STATUS_OK) {
+		g_hash_table_remove (priv->ecals[source_type], e_source_peek_uid (source));
+
+		return;
+	}
+
+	g_message ("Opened single calendar");
+	
+	zone = calendar_config_get_icaltimezone ();
+	e_cal_set_default_timezone (ecal, zone, NULL);
+
+	priv->current_ecal = ecal;
+	set_ok_sens (itip);
+}
+
+typedef void (* EItipControlOpenFunc) (ECal *ecal, ECalendarStatus status, gpointer data);
+
 static ECal *
-start_calendar_server (EItipControl *itip, ESource *source, ECalSourceType type)
+start_calendar_server (EItipControl *itip, ESource *source, ECalSourceType type, EItipControlOpenFunc func, gpointer data)
 {
 	EItipControlPrivate *priv;
 	ECal *ecal;
-	icaltimezone *zone;
 
 	priv = itip->priv;
 	
 	ecal = g_hash_table_lookup (priv->ecals[type], e_source_peek_uid (source));
-	if (ecal)
-		return ecal;
+	if (ecal) {
+		priv->current_ecal = ecal;
+		set_ok_sens (itip);
+		return ecal;		
+	}
 	
 	ecal = auth_new_cal_from_source (source, type);
-	if (!e_cal_open (ecal, TRUE, NULL))
-		return NULL;
-	
-	zone = calendar_config_get_icaltimezone ();
-	e_cal_set_default_timezone (ecal, zone, NULL);
+	g_signal_connect (G_OBJECT (ecal), "cal_opened", G_CALLBACK (func), data);
 
 	g_hash_table_insert (priv->ecals[type], g_strdup (e_source_peek_uid (source)), ecal);
 	
+	e_cal_open_async (ecal, TRUE);
+
 	return ecal;
 }
 
@@ -164,16 +225,123 @@ start_calendar_server_by_uid (EItipContr
 
 		source = e_source_list_peek_source_by_uid (priv->source_lists[i], uid);
 		if (source)
-			return start_calendar_server (itip, source, type);
+			return start_calendar_server (itip, source, type, cal_opened_cb, itip);
 	}
 	
 	return NULL;
 }
 
-static ECal *
-find_server (EItipControl *itip, ECalComponent *comp)
+typedef struct {
+	EItipControl *itip;	
+	char *uid;
+	int count;
+	gboolean show_selector;
+} EItipControlFindData;
+
+static void
+source_selected_cb (ESourceOptionMenu *esom, ESource *source, gpointer data)
+{
+	EItipControl *itip = data;
+	EItipControlPrivate *priv;
+	
+	priv = itip->priv;
+
+	if (priv->ok)
+		gtk_widget_set_sensitive (priv->ok, FALSE);
+
+	start_calendar_server (itip, source, priv->type, cal_opened_cb, itip);
+}
+
+static void
+find_cal_opened_cb (ECal *ecal, ECalendarStatus status, gpointer data)
+{
+	EItipControlFindData *fd = data;
+	EItipControlPrivate *priv;
+	ESource *source;
+	ECalSourceType source_type;
+	icalcomponent *icalcomp;
+	icaltimezone *zone;
+
+	source_type = e_cal_get_source_type (ecal);
+	source = e_cal_get_source (ecal);
+
+	priv = fd->itip->priv;
+	
+	fd->count--;
+	
+	g_signal_handlers_disconnect_matched (ecal, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, find_cal_opened_cb, NULL);
+
+	if (status != E_CALENDAR_STATUS_OK) {
+		g_hash_table_remove (priv->ecals[source_type], e_source_peek_uid (source));
+
+		goto cleanup;
+	}
+
+	g_message ("Opened find calendar");
+	
+	if (e_cal_get_object (ecal, fd->uid, NULL, &icalcomp, NULL)) {
+		icalcomponent_free (icalcomp);
+		
+		priv->current_ecal = ecal;
+		set_ok_sens (fd->itip);
+	}
+
+	zone = calendar_config_get_icaltimezone ();
+	e_cal_set_default_timezone (ecal, zone, NULL);
+
+ cleanup:
+	if (fd->count == 0) {
+		if (fd->show_selector && !priv->current_ecal && priv->vbox) {
+			GtkWidget *esom;
+			ESource *source = NULL;
+			char *uid;
+
+			switch (priv->type) {
+			case E_CAL_SOURCE_TYPE_EVENT:
+				uid = calendar_config_get_primary_calendar ();
+				break;
+			case E_CAL_SOURCE_TYPE_TODO:
+				uid = calendar_config_get_primary_tasks ();
+				break;
+			default:
+				uid = NULL;
+				g_assert_not_reached ();
+			}	
+	
+			if (uid) {
+				source = e_source_list_peek_source_by_uid (priv->source_lists[priv->type], uid);
+				g_free (uid);
+			}
+
+			/* Try to create a default if there isn't one */
+			if (!source)
+				source = e_source_list_peek_source_any (priv->source_lists[priv->type]);
+
+			esom = e_source_option_menu_new (priv->source_lists[priv->type]);
+			g_signal_connect_object (esom, "source_selected",
+						 G_CALLBACK (source_selected_cb), 
+						 fd->itip, 0);
+
+			gtk_box_pack_start (GTK_BOX (priv->vbox), esom, FALSE, TRUE, 0);
+			gtk_widget_show (esom);
+
+			/* FIXME What if there is no source? */
+			if (source)
+				e_source_option_menu_select (E_SOURCE_OPTION_MENU (esom), source);
+		} else {
+			/* FIXME Display error message to user */
+		}
+		
+		g_free (fd->uid);
+		g_free (fd);
+	}
+}
+
+static void
+find_server (EItipControl *itip, ECalComponent *comp, gboolean show_selector)
 {
 	EItipControlPrivate *priv;
+	EItipControlFindData *fd = NULL;
 	GSList *groups, *l;
 	const char *uid;
 
@@ -192,20 +360,20 @@ find_server (EItipControl *itip, ECalCom
 		for (m = sources; m; m = m->next) {
 			ESource *source;
 			ECal *ecal;
-			icalcomponent *icalcomp;
 			
 			source = m->data;
-			ecal = start_calendar_server (itip, source, priv->type);
 			
-			if (ecal && e_cal_get_object (ecal, uid, NULL, &icalcomp, NULL)) {
-				icalcomponent_free (icalcomp);
-
-				return ecal;
+			if (!fd) {
+				fd = g_new0 (EItipControlFindData, 1);
+				fd->itip = itip;
+				fd->uid = g_strdup (uid);
+				fd->show_selector = show_selector;
 			}
+			fd->count++;
+
+			ecal = start_calendar_server (itip, source, priv->type, find_cal_opened_cb, fd);				
 		}		
 	}
-
-	return NULL;
 }
 
 static void
@@ -266,7 +434,7 @@ init (EItipControl *itip)
 	gtk_widget_show (scrolled_window);
 
 	gtk_container_add (GTK_CONTAINER (scrolled_window), priv->html);
-	gtk_object_weakref (GTK_OBJECT (priv->html), html_destroyed, itip);
+	g_object_weak_ref (G_OBJECT (priv->html), (GWeakNotify)html_destroyed, itip);
 	gtk_widget_set_usize (scrolled_window, 600, 400);
 	gtk_box_pack_start (GTK_BOX (itip), scrolled_window, FALSE, FALSE, 6);
 
@@ -326,9 +494,14 @@ destroy (GtkObject *obj)
 {
 	EItipControl *itip = E_ITIP_CONTROL (obj);
 	EItipControlPrivate *priv;
-
+	
 	priv = itip->priv;
 
+ 	if (priv->html) {
+		g_signal_handlers_disconnect_matched (priv->html, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, itip);
+ 		g_object_weak_unref (G_OBJECT (priv->html), (GWeakNotify)html_destroyed, itip);
+	}
+	
 	priv->destroyed = TRUE;
 
 	(* GTK_OBJECT_CLASS (parent_class)->destroy) (obj);
@@ -345,9 +518,6 @@ finalize (GObject *obj)
 
 	clean_up (itip);
 
- 	if (priv->html)
- 		gtk_object_weakunref (GTK_OBJECT (priv->html), html_destroyed, itip);
-
 	priv->accounts = NULL;
 
 	for (i = 0; i < E_CAL_SOURCE_TYPE_LAST; i++) {
@@ -1040,99 +1210,33 @@ write_html (EItipControl *itip, const gc
 
 
 static char*
-get_publish_options (gboolean selector)
+get_publish_options (void)
 {
-	char *html;
-	
-	html = g_strdup_printf ("<form><b>%s</b>&nbsp"
-				"<select NAME=\"action\" SIZE=\"1\"> "
-				"<option VALUE=\"U\">%s</option>"
-				"</select>&nbsp &nbsp "
-				"<input TYPE=Submit name=\"ok\" value=\"%s\">"
-				"</form>",
-				_("Choose an action:"),
-				_("Update"),
-				_("OK"));
-
-	if (selector) {
-		char *sel;
-		
-		sel = g_strconcat (html, "<object classid=\"gtk:label\">", NULL);
-		g_free (html);
-		html = sel;
-	}
-	
-	return html;
+	return g_strdup_printf ("<object classid=\"itip:publish_options\"></object>");
 }
 
 static char*
-get_request_options (gboolean selector)
+get_request_options (void)
 {
-	char *html;
-	
-	html = g_strdup_printf ("<form><b>%s</b>&nbsp"
-				"<select NAME=\"action\" SIZE=\"1\"> "
-				"<option VALUE=\"A\">%s</option> "
-				"<option VALUE=\"T\">%s</option> "
-				"<option VALUE=\"D\">%s</option></select>&nbsp "
-				"<input TYPE=\"checkbox\" name=\"rsvp\" value=\"1\" checked>%s&nbsp&nbsp"
-				"<input TYPE=\"submit\" name=\"ok\" value=\"%s\"><br> "
-				"</form>",
-				_("Choose an action:"),
-				_("Accept"),
-				_("Tentatively accept"),
-				_("Decline"),
-				_("RSVP"),
-				_("OK"));
-
-	if (selector) {
-		char *sel;
-		
-		sel = g_strconcat (html, "<object classid=\"gtk:label\">", NULL);
-		g_free (html);
-		html = sel;
-	}
-	
-	return html;
+	return g_strdup_printf ("<object classid=\"itip:request_options\"></object>");
 }
 
 static char*
 get_request_fb_options ()
 {
-	return g_strdup_printf ("<form><b>%s</b>&nbsp"
-				"<select NAME=\"action\" SIZE=\"1\"> "
-				"<option VALUE=\"F\">%s</option></select>&nbsp &nbsp "
-				"<input TYPE=Submit name=\"ok\" value=\"%s\">"
-				"</form>",
-				_("Choose an action:"),
-				_("Send Free/Busy Information"),
-				_("OK"));
+	return g_strdup_printf ("<object classid=\"itip:freebusy_options\"></object>");
 }
 
 static char*
 get_reply_options ()
 {
-	return g_strdup_printf ("<form><b>%s</b>&nbsp"
-				"<select NAME=\"action\" SIZE=\"1\"> "
-				"<option VALUE=\"R\">%s</option></select>&nbsp &nbsp "
-				"<input TYPE=Submit name=\"ok\" value=\"%s\">"
-				"</form>",
-				_("Choose an action:"),
-				_("Update respondent status"),
-				_("OK"));
+	return g_strdup_printf ("<object classid=\"itip:reply_options\"></object>");
 }
 
 static char*
 get_refresh_options ()
 {
-	return g_strdup_printf ("<form><b>%s</b>&nbsp"
-				"<select NAME=\"action\" SIZE=\"1\"> "
-				"<option VALUE=\"S\">%s</option></select>&nbsp &nbsp "
-				"<input TYPE=Submit name=\"ok\" value=\"%s\">"
-				"</form>",
-				_("Choose an action:"),
-				_("Send Latest Information"),
-				_("OK"));
+	return g_strdup_printf ("<object classid=\"itip:refresh_options\"></object>");
 }
 
 static char*
@@ -1149,15 +1253,8 @@ get_cancel_options (gboolean found, ical
 			return NULL;
 		}		
 	}
-	
-	return g_strdup_printf ("<form><b>%s</b>&nbsp"
-				"<select NAME=\"action\" SIZE=\"1\"> "
-				"<option VALUE=\"C\">%s</option></select>&nbsp &nbsp "
-				"<input TYPE=Submit name=\"ok\" value=\"%s\">"
-				"</form>",
-				_("Choose an action:"),
-				_("Cancel"),
-				_("OK"));
+
+	return g_strdup_printf ("<object classid=\"itip:cancel_options\"></object>");
 }
 
 
@@ -1221,20 +1318,18 @@ show_current_event (EItipControl *itip)
 	EItipControlPrivate *priv;
 	const gchar *itip_title, *itip_desc;
 	char *options;
-
+	gboolean show_selector = FALSE;
+	
 	priv = itip->priv;
 
 	priv->type = E_CAL_SOURCE_TYPE_EVENT;
-	if (priv->calendar_uid)
-		priv->current_ecal = start_calendar_server_by_uid (itip, priv->calendar_uid, priv->type);
-	else 
-		priv->current_ecal = find_server (itip, priv->comp);
-	
+
 	switch (priv->method) {
 	case ICAL_METHOD_PUBLISH:
 		itip_desc = _("<b>%s</b> has published meeting information.");
 		itip_title = _("Meeting Information");
-		options = get_publish_options (priv->current_ecal ? FALSE : TRUE);
+		options = get_publish_options ();
+		show_selector = TRUE;
 		break;
 	case ICAL_METHOD_REQUEST:
 		if (priv->delegator_address != NULL)
@@ -1242,29 +1337,14 @@ show_current_event (EItipControl *itip)
 		else
 			itip_desc = _("<b>%s</b> requests your presence at a meeting.");
 		itip_title = _("Meeting Proposal");
-		if (priv->current_ecal) {
-			icalparameter_partstat status;
-			
-			find_my_address (itip, priv->ical_comp, &status);
-
-			switch (status) {
-			case ICAL_PARTSTAT_ACCEPTED: 
-			case ICAL_PARTSTAT_DECLINED:
-			case ICAL_PARTSTAT_TENTATIVE:
-				options = get_request_options (FALSE);
-				break;
-				
-				/* otherwise it must be needs action */			
-			default:
-				options = get_request_options (TRUE);
-			}
-		} else
-			options = get_request_options (TRUE);
+		options = get_request_options ();
+		show_selector = TRUE;
 		break;
 	case ICAL_METHOD_ADD:
+		/* FIXME Whats going on here? */
 		itip_desc = _("<b>%s</b> wishes to add to an existing meeting.");
 		itip_title = _("Meeting Update");
-		options = get_publish_options (priv->current_ecal ? FALSE : TRUE);
+		options = get_publish_options ();
 		break;
 	case ICAL_METHOD_REFRESH:
 		itip_desc = _("<b>%s</b> wishes to receive the latest meeting information.");
@@ -1285,6 +1365,9 @@ show_current_event (EItipControl *itip)
 	case ICAL_METHOD_CANCEL:
 		itip_desc = _("<b>%s</b> has cancelled a meeting.");
 		itip_title = _("Meeting Cancellation");
+		/* FIXME priv->current_ecal will always be NULL so the
+		 * user won't see an error message, the OK button will
+		 * just be de-sensitized */
 		options = get_cancel_options (priv->current_ecal ? TRUE : FALSE, ICAL_VEVENT_COMPONENT);
 
 		/* Provide extra info, since might not be in the component */
@@ -1298,6 +1381,11 @@ show_current_event (EItipControl *itip)
 
 	write_html (itip, itip_desc, itip_title, options);
 	g_free (options);
+
+	if (priv->calendar_uid)
+		priv->current_ecal = start_calendar_server_by_uid (itip, priv->calendar_uid, priv->type);
+	else 
+		find_server (itip, priv->comp, show_selector);
 }
 
 static void
@@ -1306,33 +1394,34 @@ show_current_todo (EItipControl *itip)
 	EItipControlPrivate *priv;
 	const gchar *itip_title, *itip_desc;
 	char *options;
-
+	gboolean show_selector = FALSE;
+	
 	priv = itip->priv;
 
 	priv->type = E_CAL_SOURCE_TYPE_TODO;
-	if (priv->calendar_uid)
-		priv->current_ecal = start_calendar_server_by_uid (itip, priv->calendar_uid, priv->type);
-	else 
-		priv->current_ecal = find_server (itip, priv->comp);
 
 	switch (priv->method) {
 	case ICAL_METHOD_PUBLISH:
 		itip_desc = _("<b>%s</b> has published task information.");
 		itip_title = _("Task Information");
-		options = get_publish_options (priv->current_ecal ? FALSE : TRUE);
+		options = get_publish_options ();
+		show_selector = TRUE;
 		break;
 	case ICAL_METHOD_REQUEST:
+		/* FIXME Does this need to handle like events above? */
 		if (priv->delegator_address != NULL)
 			itip_desc = _("<b>%s</b> requests %s to perform a task.");
 		else
 			itip_desc = _("<b>%s</b> requests you perform a task.");
 		itip_title = _("Task Proposal");
-		options = get_request_options (priv->current_ecal ? FALSE : TRUE);
+		options = get_request_options ();
+		show_selector = TRUE;
 		break;
 	case ICAL_METHOD_ADD:
+		/* FIXME Whats going on here? */
 		itip_desc = _("<b>%s</b> wishes to add to an existing task.");
 		itip_title = _("Task Update");
-		options = get_publish_options (priv->current_ecal ? FALSE : TRUE);
+		options = get_publish_options ();
 		break;
 	case ICAL_METHOD_REFRESH:
 		itip_desc = _("<b>%s</b> wishes to receive the latest task information.");
@@ -1353,6 +1442,9 @@ show_current_todo (EItipControl *itip)
 	case ICAL_METHOD_CANCEL:
 		itip_desc = _("<b>%s</b> has cancelled a task.");
 		itip_title = _("Task Cancellation");
+		/* FIXME priv->current_ecal will always be NULL so the
+		 * user won't see an error message, the OK button will
+		 * just be de-sensitized */
 		options = get_cancel_options (priv->current_ecal ? TRUE : FALSE, ICAL_VTODO_COMPONENT);
 
 		/* Provide extra info, since might not be in the component */
@@ -1366,6 +1458,11 @@ show_current_todo (EItipControl *itip)
 
 	write_html (itip, itip_desc, itip_title, options);
 	g_free (options);
+
+	if (priv->calendar_uid)
+		priv->current_ecal = start_calendar_server_by_uid (itip, priv->calendar_uid, priv->type);
+	else 
+		find_server (itip, priv->comp, show_selector);
 }
 
 static void
@@ -2004,23 +2101,6 @@ send_freebusy (EItipControl *itip)
 }
 
 static void
-source_selected_cb (ESourceOptionMenu *esom, ESource *source, gpointer data)
-{
-	EItipControl *itip = data;
-	EItipControlPrivate *priv;
-	ECal *ecal = NULL;
-	
-	priv = itip->priv;
-
-	ecal = start_calendar_server (itip, source, priv->type);
-	if (!ecal) {
-		/* FIXME Show error dialog */
-	}
-
-	priv->current_ecal = ecal;
-}
-
-static void
 url_requested_cb (GtkHTML *html, const gchar *url, GtkHTMLStream *handle, gpointer data)
 {	unsigned char buffer[4096];
 	int len, fd;
@@ -2045,128 +2125,355 @@ url_requested_cb (GtkHTML *html, const g
 	close (fd);
 }
 
+static void
+option_activated_cb (GtkWidget *widget, gpointer data)
+{
+	EItipControl *itip = E_ITIP_CONTROL (data);	
+	EItipControlPrivate *priv;
+	
+	priv = itip->priv;
+
+	priv->action = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), ACTION_DATA));
+}
+
+static void
+add_option (EItipControl *itip, GtkWidget *menu, const char *text, char action) 
+{
+	GtkWidget *item;
+	
+	item = gtk_menu_item_new_with_label (text);
+	g_signal_connect (item, "activate", G_CALLBACK (option_activated_cb), itip);
+	g_object_set_data (G_OBJECT (item), ACTION_DATA, GINT_TO_POINTER ((int)action));
+	gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+	gtk_widget_show (item);
+	
+}
+
+static void
+insert_boxes (GtkHTMLEmbedded *eb, EItipControl *itip)
+{
+	EItipControlPrivate *priv;
+	
+	priv = itip->priv;
+
+	priv->vbox = gtk_vbox_new (FALSE, 12);
+	g_object_add_weak_pointer (G_OBJECT (priv->vbox), ((gpointer *)&priv->vbox));	
+
+	gtk_container_add (GTK_CONTAINER (eb), priv->vbox);
+	gtk_widget_show (priv->vbox);
+
+	priv->hbox = gtk_hbox_new (FALSE, 6);
+	g_object_add_weak_pointer (G_OBJECT (priv->hbox), ((gpointer *)&priv->hbox));
+
+	gtk_box_pack_start (GTK_BOX (priv->vbox), priv->hbox, FALSE, TRUE, 0);
+	gtk_widget_show (priv->hbox);
+}
+
+static void
+insert_label (GtkWidget *hbox) 
+{
+	GtkWidget *label;
+	char *text;
+	
+	text = g_strdup_printf ("<b>%s</b>", _("Choose an action:"));
+	label = gtk_label_new (NULL);
+	gtk_label_set_markup (GTK_LABEL (label), text);
+	g_free (text);
+
+	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
+	gtk_widget_show (label);	
+}
+
+static void
+rsvp_clicked_cb (GtkWidget *widget, gpointer data)
+{
+	EItipControl *itip = E_ITIP_CONTROL (data);	
+	EItipControlPrivate *priv;
+	
+	priv = itip->priv;
+
+	priv->rsvp = TRUE;
+}
+
+static void
+insert_rsvp (GtkWidget *hbox, EItipControl *itip) 
+{
+	GtkWidget *btn;
+	
+	btn = gtk_check_button_new_with_label ("RSVP");
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (btn), TRUE);
+
+	g_signal_connect (btn, "clicked", G_CALLBACK (rsvp_clicked_cb), itip);
+
+	gtk_box_pack_start (GTK_BOX (hbox), btn, FALSE, TRUE, 0);
+	gtk_widget_show (btn);	
+}
+
+static void
+insert_ok (GtkWidget *hbox, EItipControl *itip) 
+{
+	EItipControlPrivate *priv;
+	
+	priv = itip->priv;
+	
+	priv->ok = gtk_button_new_from_stock (GTK_STOCK_OK);
+	g_object_add_weak_pointer (G_OBJECT (priv->ok), ((gpointer *)&priv->ok));
+
+	g_signal_connect (priv->ok, "clicked", G_CALLBACK (ok_clicked_cb), itip);
+
+	set_ok_sens (itip);
+
+	gtk_box_pack_start (GTK_BOX (hbox), priv->ok, FALSE, TRUE, 0);
+	gtk_widget_show (priv->ok);	
+}
+
 static gboolean
-object_requested_cb (GtkHTML *html, GtkHTMLEmbedded *eb, gpointer data) 
+publish_options_object (EItipControl *itip, GtkHTML *html, GtkHTMLEmbedded *eb)
 {
-	EItipControl *itip = E_ITIP_CONTROL (data);
 	EItipControlPrivate *priv;
-	GtkWidget *esom;
-	ESource *source = NULL;
-	char *uid;
+	GtkWidget *option, *menu;
 	
-	priv = itip->priv;	
+	priv = itip->priv;
 
-	switch (priv->type) {
-	case E_CAL_SOURCE_TYPE_EVENT:
-		uid = calendar_config_get_primary_calendar ();
-		break;
-	case E_CAL_SOURCE_TYPE_TODO:
-		uid = calendar_config_get_primary_tasks ();
-		break;
-	default:
-		return FALSE;
-	}	
+	insert_boxes (eb, itip);
+	insert_label (priv->hbox);
+
+	option = gtk_option_menu_new ();
 	
-	if (uid) {
-		source = e_source_list_peek_source_by_uid (priv->source_lists[priv->type], uid);
-		g_free (uid);
-	}
-	if (!source) {
-		/* Try to create a default if there isn't one */
-		source = e_source_list_peek_source_any (priv->source_lists[priv->type]);
-	}
+	menu = gtk_menu_new ();
 
-	esom = e_source_option_menu_new (priv->source_lists[priv->type]);
-	g_signal_connect_object (esom, "source_selected",
-				 G_CALLBACK (source_selected_cb), 
-				 itip, 0);
+	add_option (itip, menu, _("Update"), 'U');
+	priv->action = 'U';
+	
+	gtk_option_menu_set_menu (GTK_OPTION_MENU (option), menu);
 
-	gtk_container_add (GTK_CONTAINER (eb), esom);
-	gtk_widget_show (esom);
+	gtk_box_pack_start (GTK_BOX (priv->hbox), option, FALSE, TRUE, 0);
+	gtk_widget_show (option);
 
-	/* FIXME What if there is no source? */
-	if (source)
-		e_source_option_menu_select (E_SOURCE_OPTION_MENU (esom), source);
+	insert_ok (priv->hbox, itip);
 
 	return TRUE;
 }
 
-static void
-ok_clicked_cb (GtkHTML *html, const gchar *method, const gchar *url, const gchar *encoding, gpointer data)
+static gboolean
+request_options_object (EItipControl *itip, GtkHTML *html, GtkHTMLEmbedded *eb)
 {
-	EItipControl *itip = E_ITIP_CONTROL (data);
 	EItipControlPrivate *priv;
-	gchar **fields;
-	gboolean rsvp = FALSE, status = FALSE;
-	int i;
+	GtkWidget *option, *menu;
+	
+	priv = itip->priv;
+
+	insert_boxes (eb, itip);
+	insert_label (priv->hbox);
+	
+	option = gtk_option_menu_new ();
+	
+	menu = gtk_menu_new ();
+
+	add_option (itip, menu, _("Accept"), 'A');
+	add_option (itip, menu, _("Tentatively accept"), 'T');
+	add_option (itip, menu, _("Decline"), 'D');
+	priv->action = 'A';
+	
+	gtk_option_menu_set_menu (GTK_OPTION_MENU (option), menu);
 
+	gtk_box_pack_start (GTK_BOX (priv->hbox), option, FALSE, TRUE, 0);
+	gtk_widget_show (option);
+
+	insert_rsvp (priv->hbox, itip);
+	insert_ok (priv->hbox, itip);
+
+	return TRUE;
+}
+
+static gboolean
+freebusy_options_object (EItipControl *itip, GtkHTML *html, GtkHTMLEmbedded *eb)
+{
+	EItipControlPrivate *priv;
+	GtkWidget *option, *menu;
+	
 	priv = itip->priv;
 
-	fields = g_strsplit (encoding, "&", -1);
-	for (i = 0; fields[i] != NULL; i++) {
-		gchar **key_value;
+	insert_boxes (eb, itip);
+	insert_label (priv->hbox);
 
-		key_value = g_strsplit (fields[i], "=", 2);
+	option = gtk_option_menu_new ();
+	
+	menu = gtk_menu_new ();
 
-		if (key_value[0] != NULL && !strcmp (key_value[0], "action")) {
-			if (key_value[1] == NULL)
-				break;
+	add_option (itip, menu, _("Send Free/Busy Information"), 'F');
+	priv->action = 'F';
+	
+	gtk_option_menu_set_menu (GTK_OPTION_MENU (option), menu);
 
-			switch (key_value[1][0]) {
-			case 'U':
-				update_item (itip);
-				break;
-			case 'A':
-				status = change_status (priv->ical_comp, priv->my_address, 
-							ICAL_PARTSTAT_ACCEPTED);
-				if (status) {
-					e_cal_component_rescan (priv->comp);
-					update_item (itip);
-				}
-				break;
-			case 'T':
-				status = change_status (priv->ical_comp, priv->my_address,
-							ICAL_PARTSTAT_TENTATIVE);
-				if (status) {
-					e_cal_component_rescan (priv->comp);
-					update_item (itip);
-				}
-				break;
-			case 'D':
-				status = change_status (priv->ical_comp, priv->my_address,
-							ICAL_PARTSTAT_DECLINED);
-				if (status) {
-					e_cal_component_rescan (priv->comp);
-					update_item (itip);
-				}
-				break;
-			case 'F':
-				send_freebusy (itip);
-				break;
-			case 'R':
-				update_attendee_status (itip);
-				break;
-			case 'S':
-				send_item (itip);
-				break;
-			case 'C':
-				update_item (itip);
-				break;
-			}
-		}
+	gtk_container_add (GTK_CONTAINER (priv->hbox), option);
+	gtk_widget_show (option);
+
+	insert_ok (priv->hbox, itip);
+
+	return TRUE;
+}
+
+static gboolean
+reply_options_object (EItipControl *itip, GtkHTML *html, GtkHTMLEmbedded *eb)
+{
+	EItipControlPrivate *priv;
+	GtkWidget *option, *menu;
+	
+	priv = itip->priv;
+
+	insert_boxes (eb, itip);
+	insert_label (priv->hbox);
+
+	option = gtk_option_menu_new ();
+	
+	menu = gtk_menu_new ();
+
+	add_option (itip, menu, _("Update respondent status"), 'R');
+	priv->action = 'R';
+	
+	gtk_option_menu_set_menu (GTK_OPTION_MENU (option), menu);
+
+	gtk_container_add (GTK_CONTAINER (priv->hbox), option);
+	gtk_widget_show (option);
+
+	insert_ok (priv->hbox, itip);
+
+	return TRUE;
+}
+
+static gboolean
+refresh_options_object (EItipControl *itip, GtkHTML *html, GtkHTMLEmbedded *eb)
+{
+	EItipControlPrivate *priv;
+	GtkWidget *option, *menu;
+	
+	priv = itip->priv;
+
+	insert_boxes (eb, itip);
+	insert_label (priv->hbox);
+
+	option = gtk_option_menu_new ();
+	
+	menu = gtk_menu_new ();
+
+	add_option (itip, menu, _("Send Latest Information"), 'S');
+	priv->action = 'R';
+	
+	gtk_option_menu_set_menu (GTK_OPTION_MENU (option), menu);
+
+	gtk_container_add (GTK_CONTAINER (priv->hbox), option);
+	gtk_widget_show (option);
+
+	insert_ok (priv->hbox, itip);
+
+	return TRUE;
+}
+
+static gboolean
+cancel_options_object (EItipControl *itip, GtkHTML *html, GtkHTMLEmbedded *eb)
+{
+	EItipControlPrivate *priv;
+	GtkWidget *option, *menu;
+	
+	priv = itip->priv;
+
+	insert_boxes (eb, itip);
+	insert_label (priv->hbox);
+
+	option = gtk_option_menu_new ();
+	
+	menu = gtk_menu_new ();
+
+	add_option (itip, menu, _("Cancel"), 'C');
+	priv->action = 'C';
+	
+	gtk_option_menu_set_menu (GTK_OPTION_MENU (option), menu);
+
+	gtk_container_add (GTK_CONTAINER (priv->hbox), option);
+	gtk_widget_show (option);
+
+	insert_ok (priv->hbox, itip);
+
+	return TRUE;
+}
+
+static gboolean
+object_requested_cb (GtkHTML *html, GtkHTMLEmbedded *eb, gpointer data) 
+{
+	EItipControl *itip = E_ITIP_CONTROL (data);
 
-		if (key_value[0] != NULL && !strcmp (key_value[0], "rsvp"))
-			if (*key_value[1] == '1')
-				rsvp = TRUE;
+	if (!strcmp (eb->classid, "itip:publish_options"))
+		return publish_options_object (itip, html, eb);
+	else if (!strcmp (eb->classid, "itip:request_options"))
+		return request_options_object (itip, html, eb);
+	else if (!strcmp (eb->classid, "itip:freebusy_options"))
+		return freebusy_options_object (itip, html, eb);
+	else if (!strcmp (eb->classid, "itip:reply_options"))
+		return reply_options_object (itip, html, eb);
+	else if (!strcmp (eb->classid, "itip:refresh_options"))
+		return refresh_options_object (itip, html, eb);
+	else if (!strcmp (eb->classid, "itip:cancel_options"))
+		return cancel_options_object (itip, html, eb);
+	
+	return FALSE;
+}
 
-		g_strfreev (key_value);
+static void
+ok_clicked_cb (GtkWidget *widget, gpointer data)
+{
+	EItipControl *itip = E_ITIP_CONTROL (data);
+	EItipControlPrivate *priv;
+	gboolean status = FALSE;
+
+	priv = itip->priv;
 
+	switch (priv->action) {
+	case 'U':
+		update_item (itip);
+		break;
+	case 'A':
+		status = change_status (priv->ical_comp, priv->my_address, 
+					ICAL_PARTSTAT_ACCEPTED);
+		if (status) {
+			e_cal_component_rescan (priv->comp);
+			update_item (itip);
+		}
+		break;
+	case 'T':
+		status = change_status (priv->ical_comp, priv->my_address,
+					ICAL_PARTSTAT_TENTATIVE);
+		if (status) {
+			e_cal_component_rescan (priv->comp);
+			update_item (itip);
+		}
+		break;
+	case 'D':
+		status = change_status (priv->ical_comp, priv->my_address,
+					ICAL_PARTSTAT_DECLINED);
+		if (status) {
+			e_cal_component_rescan (priv->comp);
+			update_item (itip);
+		}
+		break;
+	case 'F':
+		send_freebusy (itip);
+		break;
+	case 'R':
+		update_attendee_status (itip);
+		break;
+	case 'S':
+		send_item (itip);
+		break;
+	case 'C':
+		update_item (itip);
+		break;
 	}
-	g_strfreev (fields);
+
 	if (e_cal_get_save_schedules (priv->current_ecal))
 		return;
 
-	if (rsvp && status) {
+	if (priv->rsvp && status) {
 		ECalComponent *comp = NULL;
 		ECalComponentVType vtype;
 		icalcomponent *ical_comp;


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