diff options
-rw-r--r-- | calendar/ChangeLog | 43 | ||||
-rw-r--r-- | calendar/gui/e-itip-control.c | 821 |
2 files changed, 606 insertions, 258 deletions
diff --git a/calendar/ChangeLog b/calendar/ChangeLog index 054b809548..47f87e44ff 100644 --- a/calendar/ChangeLog +++ b/calendar/ChangeLog @@ -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): diff --git a/calendar/gui/e-itip-control.c b/calendar/gui/e-itip-control.c index 23ca5f9301..983b56b4e0 100644 --- a/calendar/gui/e-itip-control.c +++ b/calendar/gui/e-itip-control.c @@ -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 (EItipControl *itip, const char *uid, ECalSourceTyp 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, ECalComponent *comp) 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 gchar *itip_desc, const gchar *itip_title, static char* -get_publish_options (gboolean selector) -{ - char *html; - - html = g_strdup_printf ("<form><b>%s</b> " - "<select NAME=\"action\" SIZE=\"1\"> " - "<option VALUE=\"U\">%s</option>" - "</select>    " - "<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; +get_publish_options (void) +{ + return g_strdup_printf ("<object classid=\"itip:publish_options\"></object>"); } static char* -get_request_options (gboolean selector) -{ - char *html; - - html = g_strdup_printf ("<form><b>%s</b> " - "<select NAME=\"action\" SIZE=\"1\"> " - "<option VALUE=\"A\">%s</option> " - "<option VALUE=\"T\">%s</option> " - "<option VALUE=\"D\">%s</option></select>  " - "<input TYPE=\"checkbox\" name=\"rsvp\" value=\"1\" checked>%s  " - "<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; +get_request_options (void) +{ + return g_strdup_printf ("<object classid=\"itip:request_options\"></object>"); } static char* get_request_fb_options () { - return g_strdup_printf ("<form><b>%s</b> " - "<select NAME=\"action\" SIZE=\"1\"> " - "<option VALUE=\"F\">%s</option></select>    " - "<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> " - "<select NAME=\"action\" SIZE=\"1\"> " - "<option VALUE=\"R\">%s</option></select>    " - "<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> " - "<select NAME=\"action\" SIZE=\"1\"> " - "<option VALUE=\"S\">%s</option></select>    " - "<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, icalcomponent_kind kind) return NULL; } } - - return g_strdup_printf ("<form><b>%s</b> " - "<select NAME=\"action\" SIZE=\"1\"> " - "<option VALUE=\"C\">%s</option></select>    " - "<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,7 +1365,10 @@ show_current_event (EItipControl *itip) case ICAL_METHOD_CANCEL: itip_desc = _("<b>%s</b> has cancelled a meeting."); itip_title = _("Meeting Cancellation"); - options = get_cancel_options (priv->current_ecal ? TRUE : FALSE, ICAL_VEVENT_COMPONENT); + /* 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 (TRUE, ICAL_VEVENT_COMPONENT); /* Provide extra info, since might not be in the component */ adjust_item (itip, priv->comp); @@ -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,7 +1442,10 @@ show_current_todo (EItipControl *itip) case ICAL_METHOD_CANCEL: itip_desc = _("<b>%s</b> has cancelled a task."); itip_title = _("Task Cancellation"); - options = get_cancel_options (priv->current_ecal ? TRUE : FALSE, ICAL_VTODO_COMPONENT); + /* 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 (TRUE, ICAL_VTODO_COMPONENT); /* Provide extra info, since might not be in the component */ adjust_item (itip, priv->comp); @@ -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 gchar *url, GtkHTMLStream *handle, gpoint 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; +} - if (key_value[0] != NULL && !strcmp (key_value[0], "rsvp")) - if (*key_value[1] == '1') - rsvp = 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); - g_strfreev (key_value); + 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 (!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; +} + +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; |